Skip to content

Commit

Permalink
RECONSIDER: recognize selectors that have been pre-hashed by the comp…
Browse files Browse the repository at this point in the history
…iler
  • Loading branch information
bviglietta authored and DHowett committed Jan 22, 2018
1 parent 6ae101d commit c8ecc35
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 10 deletions.
9 changes: 6 additions & 3 deletions abi_version.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ enum
{
gcc_abi = 8,
gnustep_abi = 9,
gc_abi = 10
gc_abi = 10,
selhash_abi = 11,
};

/**
Expand All @@ -45,9 +46,11 @@ static struct objc_abi_version known_abis[] =
/* GCC ABI. */
{gcc_abi, gcc_abi, gnustep_abi, sizeof(struct objc_module_abi_8)},
/* Non-fragile ABI. */
{gnustep_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_8)},
{gnustep_abi, gcc_abi, selhash_abi, sizeof(struct objc_module_abi_8)},
/* GC ABI. Adds a field describing the GC mode. */
{gc_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_10)}
{gc_abi, gcc_abi, selhash_abi, sizeof(struct objc_module_abi_10)},
/* ABI with hash in selector */
{selhash_abi, gcc_abi, selhash_abi, sizeof(struct objc_module_abi_11)}
};

static int known_abi_count =
Expand Down
9 changes: 8 additions & 1 deletion loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,15 @@ void __objc_load_module(struct objc_module_abi_8 *module)
// Register all of the selectors used in this module.
if (symbols->selectors)
{
objc_register_selector_array(symbols->selectors,
if (module->version < 11) {
// the module has the old selector format
objc_register_selector_array8(symbols->selectors,
symbols->selector_count);
}
else {
objc_register_selector_array(symbols->selectors,
symbols->selector_count);
}
}

unsigned short defs = 0;
Expand Down
13 changes: 13 additions & 0 deletions module.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ struct objc_module_abi_10
int gc_mode;
};

struct objc_module_abi_11
{
/**
* Inherited fields from version 10 of the ABI.
*/
struct objc_module_abi_10 old;

/**
* Flags for configuration of this module. Currently unused.
*/
uint32_t flags;
};

/**
* List of static instances of a named class provided in this module.
*/
Expand Down
35 changes: 33 additions & 2 deletions selector.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* test to see whether a selector is polymorphic and allows enumeration of all
* type encodings for a given selector.
*
* This is the same size as an objc_selector, so we can allocate them from the
* This is <= the size of an objc_selector, so we can allocate them from the
* objc_selector pool.
*
* Note: For ABI v10, we can probably do something a bit more sensible here and
Expand All @@ -19,8 +19,9 @@ struct sel_type_list

/**
* Structure used to store selectors in the list.
This is the selctor from abi version 8.
*/
struct objc_selector
struct objc_selector8
{
union
{
Expand All @@ -41,6 +42,36 @@ struct objc_selector
const char * types;
};

/**
* Structure used to store selectors in the list.
*/
struct objc_selector
{
union
{
/**
* The name of this selector. Used for unregistered selectors.
*/
const char *name;
/**
* The index of this selector in the selector table. When a selector
* is registered with the runtime, its name is replaced by an index
* uniquely identifying this selector. The index is used for dispatch.
*/
uintptr_t index;
};

/**
* The Objective-C type encoding of the message identified by this selector.
*/
const char * types;

/**
* Hash value for this selector (calculated from its name and type)
*/
_Atomic uint32_t hash;
};

/**
* Returns the untyped variant of a selector.
*/
Expand Down
50 changes: 46 additions & 4 deletions selector_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <stdatomic.h>
#include "lock.h"
#include "objc/runtime.h"
#include "method_list.h"
Expand Down Expand Up @@ -205,11 +206,11 @@ static int selector_equal(const void *k,
}

/**
* Hash a selector.
* Calculate the hash for the selector. Should match with the implementation
* in the compiler.
*/
static inline uint32_t hash_selector(const void *s)
static inline uint32_t selector_create_hash(SEL sel)
{
SEL sel = (SEL)s;
uint32_t hash = 5381;
const char *str = sel_getNameNonUnique(sel);
uint32_t c;
Expand Down Expand Up @@ -238,6 +239,28 @@ static inline uint32_t hash_selector(const void *s)
return hash;
}

/**
* Hash a selector
*/
static inline uint32_t hash_selector(const void *s)
{
struct objc_selector * sel = (struct objc_selector *)s;
uint32_t hash = atomic_load_explicit(&sel->hash, memory_order_relaxed);

if (hash == 0) {
// selectors can be created from methods or from older ABIs and
// won't have a hash yet. So calculate and cache it.
// Use atomic operations because this may not be happening
// under any lock.
hash = selector_create_hash(sel);
atomic_store_explicit(&sel->hash, hash, memory_order_relaxed);
}
else {
assert(hash == selector_create_hash(sel));
}
return hash;
}

#define MAP_TABLE_NAME selector
#define MAP_TABLE_SINGLE_THREAD
#define MAP_TABLE_COMPARE_FUNCTION selector_identical
Expand Down Expand Up @@ -289,7 +312,7 @@ static SEL selector_lookup(const char *name, const char *types)
}
static inline void add_selector_to_table(SEL aSel, int32_t uid, uint32_t idx)
{
DEBUG_LOG("Sel %s uid: %d, idx: %d, hash: %d\n", sel_getNameNonUnique(aSel), uid, idx, hash_selector(aSel));
DEBUG_LOG("Sel %s uid: %d, idx: %d, hash: %08x\n", sel_getNameNonUnique(aSel), uid, idx, aSel->hash);
struct sel_type_list *typeList =
(struct sel_type_list *)selector_pool_alloc();
typeList->value = aSel->name;
Expand Down Expand Up @@ -333,6 +356,7 @@ static inline void register_selector_locked(SEL aSel)
untyped = selector_pool_alloc();
untyped->name = aSel->name;
untyped->types = 0;
untyped->hash = 0;
DEBUG_LOG("Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
add_selector_to_table(untyped, idx, idx);
// If we are in type dependent dispatch mode, the uid for the typed
Expand Down Expand Up @@ -405,6 +429,7 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
copy = selector_pool_alloc();
copy->name = aSel->name;
copy->types = (NULL == aSel->types) ? NULL : aSel->types;
copy->hash = aSel->hash;
if (copyArgs)
{
SEL untyped = selector_lookup(aSel->name, 0);
Expand Down Expand Up @@ -610,6 +635,23 @@ PRIVATE void objc_register_selector_array(SEL selectors, unsigned long count)
objc_register_selector(&selectors[i]);
}
}
PRIVATE void objc_register_selector_array8(struct objc_selector8 * selectors, unsigned long count)
{
// GCC is broken and always sets the count to 0, so we ignore count until
// we can throw stupid and buggy compilers in the bin.
for (unsigned long i = 0; (NULL != selectors[i].name); i++)
{
SEL copy = selector_pool_alloc();
copy->name = selectors[i].name;
copy->types = selectors[i].types;
copy->hash = selector_create_hash(copy);
SEL registered = objc_register_selector(copy);

// the selector from the metadata needs to updated to the unique
// id instead of the name
selectors[i].name = registered->name;
}
}


/**
Expand Down

0 comments on commit c8ecc35

Please sign in to comment.