/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
* 2018, 2019
* Jonathan Schleifer <js@heap.zone>
*
* All rights reserved.
*
* This file is part of ObjFW. It may be distributed under the terms of the
* Q Public License 1.0, which can be found in the file LICENSE.QPL included in
* the packaging of this file.
*
* Alternatively, it may be distributed under the terms of the GNU General
* Public License, either version 2 or 3, which can be found in the file
* LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
* file.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#import "ObjFW_RT.h"
#import "private.h"
#import "macros.h"
#ifdef OF_SELUID24
# define SEL_MAX 0xFFFFFF
# define SEL_SIZE 3
#else
# define SEL_MAX 0xFFFF
# define SEL_SIZE 2
#endif
static struct objc_hashtable *selectors = NULL;
static uint32_t selectors_cnt = 0;
static struct objc_sparsearray *selector_names = NULL;
static void **free_list = NULL;
static size_t free_list_cnt = 0;
void
objc_register_selector(struct objc_abi_selector *sel)
{
struct objc_selector *rsel;
const char *name;
if (selectors_cnt > SEL_MAX)
OBJC_ERROR("Out of selector slots!");
if (selectors == NULL)
selectors = objc_hashtable_new(
objc_hash_string, objc_equal_string, 2);
else if ((rsel = objc_hashtable_get(selectors, sel->name)) != NULL) {
((struct objc_selector *)sel)->uid = rsel->uid;
return;
}
if (selector_names == NULL)
selector_names = objc_sparsearray_new(SEL_SIZE);
name = sel->name;
rsel = (struct objc_selector *)sel;
rsel->uid = selectors_cnt++;
objc_hashtable_set(selectors, name, rsel);
objc_sparsearray_set(selector_names, (uint32_t)rsel->uid, (void *)name);
}
SEL
sel_registerName(const char *name)
{
const struct objc_abi_selector *rsel;
struct objc_abi_selector *sel;
objc_global_mutex_lock();
if (selectors != NULL &&
(rsel = objc_hashtable_get(selectors, name)) != NULL) {
objc_global_mutex_unlock();
return (SEL)rsel;
}
if ((sel = malloc(sizeof(struct objc_abi_selector))) == NULL)
OBJC_ERROR("Not enough memory to allocate selector!");
if ((sel->name = of_strdup(name)) == NULL)
OBJC_ERROR("Not enough memory to allocate selector!");
sel->types = NULL;
if ((free_list = realloc(free_list,
sizeof(void *) * (free_list_cnt + 2))) == NULL)
OBJC_ERROR("Not enough memory to allocate selector!");
free_list[free_list_cnt++] = sel;
free_list[free_list_cnt++] = (char *)sel->name;
objc_register_selector(sel);
objc_global_mutex_unlock();
return (SEL)sel;
}
void
objc_register_all_selectors(struct objc_abi_symtab *symtab)
{
struct objc_abi_selector *sel;
if (symtab->sel_refs == NULL)
return;
for (sel = symtab->sel_refs; sel->name != NULL; sel++)
objc_register_selector(sel);
}
const char *
sel_getName(SEL sel)
{
const char *ret;
objc_global_mutex_lock();
ret = objc_sparsearray_get(selector_names, (uint32_t)sel->uid);
objc_global_mutex_unlock();
return ret;
}
bool
sel_isEqual(SEL sel1, SEL sel2)
{
return (sel1->uid == sel2->uid);
}
void
objc_unregister_all_selectors(void)
{
objc_hashtable_free(selectors);
objc_sparsearray_free(selector_names);
if (free_list != NULL) {
for (size_t i = 0; i < free_list_cnt; i++)
free(free_list[i]);
free(free_list);
}
selectors = NULL;
selectors_cnt = 0;
selector_names = NULL;
free_list = NULL;
free_list_cnt = 0;
}