@ -1,3 +1,4 @@
# define __BSD_VISIBLE 1
# include <stdio.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdlib.h>
# include "objc/runtime.h"
# include "objc/runtime.h"
@ -165,27 +166,9 @@ static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx)
dtable - > slots [ dtable - > slot_count + + ] . idx = idx ;
dtable - > slots [ dtable - > slot_count + + ] . idx = idx ;
}
}
static void update_dtable ( dtable_t dtable )
static void add_slot_to_dtable ( uint32_t idx , dtable_t dtable , uint32_t
old_slot_count , struct objc_method * m , Class cls )
{
{
Class cls = dtable - > cls ;
if ( NULL = = cls - > methods ) { return ; }
SparseArray * methods = SparseArrayNewWithDepth ( dtable_depth ) ;
collectMethodsForMethodListToSparseArray ( ( void * ) cls - > methods , methods , YES ) ;
if ( NULL = = dtable - > slots )
{
dtable - > slots = calloc ( sizeof ( struct slots_list ) , 16 ) ;
dtable - > slot_size = 16 ;
}
uint32_t old_slot_count = dtable - > slot_count ;
struct objc_method * m ;
uint32_t idx = 0 ;
while ( ( m = SparseArrayNext ( methods , & idx ) ) )
{
uint32_t idx = m - > selector - > index ;
struct slots_list * s = find_slot ( idx , dtable - > slots , old_slot_count ) ;
struct slots_list * s = find_slot ( idx , dtable - > slots , old_slot_count ) ;
if ( NULL ! = s )
if ( NULL ! = s )
{
{
@ -206,6 +189,31 @@ static void update_dtable(dtable_t dtable)
}
}
}
}
}
}
static void update_dtable ( dtable_t dtable )
{
Class cls = dtable - > cls ;
if ( NULL = = cls - > methods ) { return ; }
SparseArray * methods = SparseArrayNewWithDepth ( dtable_depth ) ;
collectMethodsForMethodListToSparseArray ( ( void * ) cls - > methods , methods , YES ) ;
if ( NULL = = dtable - > slots )
{
dtable - > slots = calloc ( sizeof ( struct slots_list ) , 16 ) ;
dtable - > slot_size = 16 ;
}
uint32_t old_slot_count = dtable - > slot_count ;
struct objc_method * m ;
uint32_t idx = 0 ;
while ( ( m = SparseArrayNext ( methods , & idx ) ) )
{
add_slot_to_dtable ( m - > selector - > index , dtable , old_slot_count , m , cls ) ;
# ifdef TYPE_DEPENDENT_DISPATCH
add_slot_to_dtable ( get_untyped_idx ( m - > selector ) , dtable , old_slot_count , m , cls ) ;
# endif
}
mergesort ( dtable - > slots , dtable - > slot_count , sizeof ( struct slots_list ) ,
mergesort ( dtable - > slots , dtable - > slot_count , sizeof ( struct slots_list ) ,
slot_cmp ) ;
slot_cmp ) ;
SparseArrayDestroy ( methods ) ;
SparseArrayDestroy ( methods ) ;
@ -223,6 +231,11 @@ PRIVATE void objc_update_dtable_for_class(Class cls)
update_dtable ( dtable ) ;
update_dtable ( dtable ) ;
}
}
PRIVATE void add_method_list_to_class ( Class cls ,
struct objc_method_list * list )
{
objc_update_dtable_for_class ( cls ) ;
}
PRIVATE struct objc_slot * objc_dtable_lookup ( dtable_t dtable , uint32_t uid )
PRIVATE struct objc_slot * objc_dtable_lookup ( dtable_t dtable , uint32_t uid )
{
{
@ -246,17 +259,21 @@ PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid)
slot = s - > slot ;
slot = s - > slot ;
int i = HASH_UID ( uid ) ;
int i = HASH_UID ( uid ) ;
volatile struct cache_line * cache = & dtable - > cache [ i ] ;
volatile struct cache_line * cache = & dtable - > cache [ i ] ;
cache - > idx = 0 ;
// Simplified multiword atomic exchange. First we write a value that
// is an invalid but recognisable UID and then a memory barrier. Then
// we complete the update and set the index pointer if and only if
// there have been no other modifications in the meantime
cache - > idx = - uid ;
__sync_synchronize ( ) ;
cache - > version = slot - > version ;
cache - > version = slot - > version ;
cache - > slot = slot ;
cache - > slot = slot ;
__sync_synchronize ( ) ;
__sync_bool_compare_and_swap ( & cache - > idx , - uid , uid ) ;
cache - > idx = uid ;
return slot ;
return slot ;
}
}
if ( NULL ! = dtable - > cls - > super_class )
if ( NULL ! = dtable - > cls - > super_class )
{
{
return objc_dtable_lookup ( dtable - > cls - > super_class - > dtable , uid ) ;
return objc_dtable_lookup ( dtable_for_class ( dtable - > cls - > super_class ) , uid ) ;
}
}
return NULL ;
return NULL ;
}
}
@ -274,7 +291,7 @@ PRIVATE void free_dtable(dtable_t dtable)
{
{
free ( dtable - > slots ) ;
free ( dtable - > slots ) ;
}
}
DESTROY_LOCK ( dtable - > lock ) ;
DESTROY_LOCK ( & dtable - > lock ) ;
free ( dtable ) ;
free ( dtable ) ;
}
}
@ -585,13 +602,6 @@ PRIVATE void objc_send_initialize(id object)
// If this class is already initialized (e.g. in another thread), give up.
// If this class is already initialized (e.g. in another thread), give up.
if ( objc_test_class_flag ( class , objc_class_flag_initialized ) ) { return ; }
if ( objc_test_class_flag ( class , objc_class_flag_initialized ) ) { return ; }
// Grab a lock to make sure we are only sending one +initialize message at
// once.
//
// NOTE: Ideally, we would actually lock on the class object using
// objc_sync_enter(). This should be fixed once sync.m contains a (fast)
// special case for classes.
// Make sure that the class is resolved.
// Make sure that the class is resolved.
objc_resolve_class ( class ) ;
objc_resolve_class ( class ) ;