Skip to content

Commit b4524d1

Browse files
committed
* change in mulle_objc_object_get_property_value where now a strategy value is passed as an int, containing multiple bits (like atomicity)
* the impcache gained a lot of callbacks, and the Objective-C methods were changed to use them. The callbacks were also renamed to make them a bit more telling * protocolclasses `+inititalize` is now run on each adopting class and subclass (this is freaky and useful) * slightly improved method search traces * -release and -retain are no long fast methods, since they are usually inlined anyway this frees up two slots that are put to other use * new `for` functions for methodlists, propertylists etc. (still experimental) * functions that use method calls (like `mulle_objc_object_call_dealloc` now) * add support for the `noautorelease` @Property attribute fixes for tagged pointer float/double code
1 parent 68172d8 commit b4524d1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2651
-1416
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ build-*
7272
coverage*.html
7373
*.gcda
7474
*.gcno
75+
/demo/
7576
cola/wilted/
76-
demo/
7777
*.executable

src/mulle-objc-builtin.h

+40-12
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ static inline void assert_same_mulle_allocator( struct _mulle_objc_object *sel
145145
# define assert_same_mulle_allocator( self, value)
146146
#endif
147147

148+
enum mulle_objc_property_accessor_strategy
149+
{
150+
mulle_objc_property_accessor_autorelease = 0x0, // default
151+
mulle_objc_property_accessor_noautorelease = 0x1, // getter
152+
mulle_objc_property_accessor_atomic = 0x2, // getter + setter
153+
mulle_objc_property_accessor_copy = 0x4, // setter
154+
mulle_objc_property_accessor_mutable_copy = 0x8 // setter
155+
};
156+
157+
148158
//
149159
// this is called by the compiler for retain or copy of objects only
150160
// TODO: conceivably move this out of the runtime. This should optimize
@@ -155,30 +165,30 @@ static inline void
155165
mulle_objc_methodid_t _cmd,
156166
ptrdiff_t offset,
157167
struct _mulle_objc_object *value,
158-
char is_atomic,
159-
char is_copy)
168+
int strategy)
160169
{
161170
void **p_ivar;
162171
void *old;
163172

164173
if( ! self)
165174
return;
166175

167-
if( is_copy)
176+
if( strategy & mulle_objc_property_accessor_copy)
168177
{
169-
if( is_copy == 2) // da apple way
178+
if( strategy & mulle_objc_property_accessor_mutable_copy) // da apple way
170179
value = mulle_objc_object_call_mutablecopy( value);
171180
else
172181
value = mulle_objc_object_call_copy( value);
173182
}
174183
else
175-
mulle_objc_object_retain( value);
184+
mulle_objc_object_call_retain( value);
176185

177186
assert_same_mulle_allocator( self, value);
178187

179188
p_ivar = (void **) &((char *) self)[ offset];
180-
if( is_atomic)
189+
if( strategy & mulle_objc_property_accessor_atomic)
181190
{
191+
// TODO: old and wrong (fix)
182192
old = _mulle_atomic_pointer_set( (mulle_atomic_pointer_t *) p_ivar, value);
183193
mulle_objc_object_call_autorelease( old);
184194
}
@@ -189,22 +199,40 @@ static inline void
189199
}
190200
}
191201

192-
202+
MULLE_C_ALWAYS_INLINE
193203
static inline void *
194204
mulle_objc_object_get_property_value( void *self,
195205
mulle_objc_methodid_t _cmd,
196206
ptrdiff_t offset,
197-
char is_atomic)
207+
int strategy)
198208
{
199-
void **p_ivar;
209+
void **p_ivar;
210+
void *value;
211+
struct _mulle_objc_foundation *foundation;
212+
struct _mulle_objc_universe *universe;
200213

201214
if( ! self)
202215
return( NULL);
203216

204217
p_ivar = (void **) &((char *) self)[ offset];
205-
if( is_atomic)
206-
return( _mulle_atomic_pointer_read( (mulle_atomic_pointer_t *) p_ivar));
207-
return( *p_ivar);
218+
if( strategy & mulle_objc_property_accessor_atomic)
219+
{
220+
// TODO: wrong (fix!) can race with autorelease
221+
value = _mulle_atomic_pointer_read( (mulle_atomic_pointer_t *) p_ivar);
222+
}
223+
else
224+
value = *p_ivar;
225+
226+
if( strategy & mulle_objc_property_accessor_noautorelease)
227+
return( value);
228+
229+
if( value)
230+
{
231+
universe = _mulle_objc_object_get_universe( value);
232+
foundation = _mulle_objc_universe_get_foundation( universe);
233+
value = (*foundation->retain_autorelease)( value);
234+
}
235+
return( value);
208236
}
209237

210238

src/mulle-objc-cache.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct _mulle_objc_cache *mulle_objc_cache_new( mulle_objc_cache_uint_t size,
6767
cache = _mulle_allocator_calloc( allocator, 1, s_cache);
6868
errno = preserve;
6969

70-
mulle_objc_cache_init( cache, size);
70+
_mulle_objc_cache_init( cache, size);
7171

7272
return( cache);
7373
}
@@ -233,7 +233,7 @@ unsigned int mulle_objc_cache_calculate_fillpercentage( struct _mulle_objc_cac
233233
return( 0);
234234

235235
n = (intptr_t) _mulle_atomic_pointer_read( &cache->n);
236-
return( (unsigned int) (n * 100 + (cache->size / 2)) / cache->size);
236+
return( (unsigned int) (n * 100 + (cache->size / 2)) / cache->size);
237237
}
238238

239239

src/mulle-objc-cache.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ struct _mulle_objc_cache
106106

107107

108108
// incoming cache must have been zero filled already
109-
static inline void mulle_objc_cache_init( struct _mulle_objc_cache *cache,
109+
static inline void _mulle_objc_cache_init( struct _mulle_objc_cache *cache,
110110
mulle_objc_cache_uint_t size)
111111
{
112112
assert( ! (sizeof( struct _mulle_objc_cacheentry) & (sizeof( struct _mulle_objc_cacheentry) - 1)));

src/mulle-objc-call.c

+87-46
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@
6060

6161
// we can't do the FCS code here, because its just super slow if
6262
// the constant isn't known.
63-
// This is like call2, except that we need do check the first
64-
// cache entry.
63+
// This is like call_cache_collision, except that we still need do check the
64+
// first cache entry.
6565
MULLE_C_NEVER_INLINE
6666
void *mulle_objc_object_call( void *obj,
6767
mulle_objc_methodid_t methodid,
@@ -169,29 +169,6 @@ void mulle_objc_implementation_trace( mulle_objc_implementation_t imp,
169169

170170

171171

172-
static void mulle_objc_object_fail_thread_affinity( struct _mulle_objc_object *obj,
173-
mulle_thread_t affinity_thread,
174-
char *name)
175-
{
176-
struct _mulle_objc_universe *universe;
177-
struct _mulle_objc_class *cls;
178-
int ismeta;
179-
180-
cls = _mulle_objc_object_get_isa( obj);
181-
ismeta = _mulle_objc_class_is_metaclass( cls);
182-
universe = _mulle_objc_class_get_universe( cls);
183-
184-
mulle_objc_universe_fail_generic( universe,
185-
"%s <%s %p> with affinity to thread %p gets a -%s call from thread %p",
186-
ismeta ? "Class" : "Object",
187-
_mulle_objc_class_get_name( cls),
188-
obj,
189-
affinity_thread,
190-
name,
191-
mulle_thread_self());
192-
}
193-
194-
195172
// MEMO: TAO and the Cache
196173
//
197174
// When we do TAO, we need to call this often. The idea is that all methods
@@ -278,9 +255,11 @@ void mulle_objc_object_taocheck_call( void *obj,
278255
case _mulle_objc_methodfamily_init :
279256
case _mulle_objc_methodfamily_dealloc :
280257
return;
258+
default :
259+
break;
281260
}
282261

283-
// forward: is not "methodid", that's what we foward to
262+
// forward: is not "methodid", that's what we forward to
284263
if( method->descriptor.methodid == MULLE_OBJC_FORWARD_METHODID)
285264
return;
286265

@@ -291,7 +270,7 @@ void mulle_objc_object_taocheck_call( void *obj,
291270
if( _mulle_objc_universe_is_deinitializing( universe))
292271
return;
293272

294-
mulle_objc_object_fail_thread_affinity( obj, object_thread, _mulle_objc_descriptor_get_name( desc));
273+
mulle_objc_universe_fail_wrongthread( universe, obj, object_thread, desc);
295274
}
296275

297276

@@ -310,6 +289,7 @@ static void *_mulle_objc_object_callback_class( void *obj,
310289
mulle_objc_implementation_t imp;
311290
mulle_functionpointer_t p;
312291
struct _mulle_objc_cache *cache;
292+
struct _mulle_objc_impcache *icache;
313293
struct _mulle_objc_cacheentry *entries;
314294
struct _mulle_objc_cacheentry *entry;
315295
struct _mulle_objc_method *method;
@@ -339,7 +319,8 @@ static void *_mulle_objc_object_callback_class( void *obj,
339319

340320
if( ! entry->key.uniqueid)
341321
{
342-
method = _mulle_objc_class_refresh_method_nofail( cls, methodid);
322+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
323+
method = (*icache->callback.refresh_method_nofail)( cls, methodid);
343324
imp = _mulle_objc_method_get_implementation( method);
344325
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
345326
break;
@@ -358,13 +339,14 @@ static void *_mulle_objc_object_callback_class( void *obj,
358339
// collision, it skips the first found entry. This method is put into
359340
// the method cache, you don't call it directly.
360341
//
361-
static void *_mulle_objc_object_callback2( void *obj,
362-
mulle_objc_methodid_t methodid,
363-
void *parameter)
342+
static void *_mulle_objc_object_callback_cache_collision( void *obj,
343+
mulle_objc_methodid_t methodid,
344+
void *parameter)
364345
{
365346
mulle_objc_implementation_t imp;
366347
mulle_functionpointer_t p;
367348
struct _mulle_objc_cache *cache;
349+
struct _mulle_objc_impcache *icache;
368350
struct _mulle_objc_cacheentry *entries;
369351
struct _mulle_objc_cacheentry *entry;
370352
struct _mulle_objc_method *method;
@@ -395,7 +377,8 @@ static void *_mulle_objc_object_callback2( void *obj,
395377

396378
if( ! entry->key.uniqueid)
397379
{
398-
method = _mulle_objc_class_refresh_method_nofail( cls, methodid);
380+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
381+
method = (*icache->callback.refresh_method_nofail)( cls, methodid);
399382
imp = _mulle_objc_method_get_implementation( method);
400383
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
401384
break;
@@ -407,20 +390,48 @@ static void *_mulle_objc_object_callback2( void *obj,
407390
}
408391

409392

393+
//
394+
// this function is called, when there is no entry in the cache
395+
//
396+
static void *_mulle_objc_object_callback_cache_miss( void *obj,
397+
mulle_objc_methodid_t methodid,
398+
void *parameter)
399+
{
400+
mulle_objc_implementation_t imp;
401+
struct _mulle_objc_method *method;
402+
struct _mulle_objc_class *cls;
403+
struct _mulle_objc_impcache *icache;
404+
struct _mulle_objc_cache *cache;
405+
struct _mulle_objc_cacheentry *entries;
406+
407+
assert( mulle_objc_uniqueid_is_sane( methodid));
408+
409+
cls = _mulle_objc_object_get_isa( obj);
410+
entries = _mulle_objc_cachepivot_get_entries_atomic( &cls->cachepivot.pivot);
411+
cache = _mulle_objc_cacheentry_get_cache_from_entries( entries);
412+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
413+
method = (*icache->callback.refresh_method_nofail)( cls, methodid);
414+
imp = _mulle_objc_method_get_implementation( method);
415+
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
416+
return( (*imp)( obj, methodid, parameter));
417+
}
418+
419+
410420
//
411421
// This function is called, when the first inline cache check gave a
412422
// collision, it skips the first found entry. This is not called directly
413423
// but placed into the method cache.
414424
//
415425
static void *
416-
_mulle_objc_object_call_superback( void *obj,
426+
_mulle_objc_object_callback_super( void *obj,
417427
mulle_objc_methodid_t methodid,
418428
void *parameter,
419429
mulle_objc_superid_t superid,
420430
struct _mulle_objc_class *cls)
421431
{
422432
mulle_objc_implementation_t imp;
423433
struct _mulle_objc_cache *cache;
434+
struct _mulle_objc_impcache *icache;
424435
struct _mulle_objc_cacheentry *entries;
425436
struct _mulle_objc_cacheentry *entry;
426437
struct _mulle_objc_method *method;
@@ -445,7 +456,8 @@ static void *
445456
}
446457
if( ! entry->key.uniqueid)
447458
{
448-
method = _mulle_objc_class_refresh_supermethod_nofail( cls, superid);
459+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
460+
method = (*icache->callback.refresh_supermethod_nofail)( cls, superid);
449461
imp = _mulle_objc_method_get_implementation( method);
450462
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
451463
break;
@@ -458,14 +470,15 @@ static void *
458470

459471

460472
static void *
461-
_mulle_objc_object_call_superback2( void *obj,
462-
mulle_objc_methodid_t methodid,
463-
void *parameter,
464-
mulle_objc_superid_t superid,
465-
struct _mulle_objc_class *cls)
473+
_mulle_objc_object_callback_super_cache_collision( void *obj,
474+
mulle_objc_methodid_t methodid,
475+
void *parameter,
476+
mulle_objc_superid_t superid,
477+
struct _mulle_objc_class *cls)
466478
{
467479
mulle_objc_implementation_t imp;
468480
struct _mulle_objc_cache *cache;
481+
struct _mulle_objc_impcache *icache;
469482
struct _mulle_objc_cacheentry *entries;
470483
struct _mulle_objc_cacheentry *entry;
471484
struct _mulle_objc_method *method;
@@ -492,7 +505,8 @@ static void *
492505

493506
if( ! entry->key.uniqueid)
494507
{
495-
method = _mulle_objc_class_refresh_supermethod_nofail( cls, superid);
508+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
509+
method = (*icache->callback.refresh_supermethod_nofail)( cls, superid);
496510
imp = _mulle_objc_method_get_implementation( method);
497511
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
498512
break;
@@ -502,15 +516,43 @@ static void *
502516
}
503517

504518

505-
void _mulle_objc_impcache_init_normal_callbacks( struct _mulle_objc_impcache *p)
519+
static void *
520+
_mulle_objc_object_callback_super_cache_miss( void *obj,
521+
mulle_objc_methodid_t methodid,
522+
void *parameter,
523+
mulle_objc_superid_t superid,
524+
struct _mulle_objc_class *cls)
506525
{
507-
p->call = _mulle_objc_object_callback_class;
508-
p->call2 = _mulle_objc_object_callback2;
509-
p->supercall = _mulle_objc_object_call_superback; // public actually
510-
p->supercall2 = _mulle_objc_object_call_superback2;
526+
mulle_objc_implementation_t imp;
527+
struct _mulle_objc_method *method;
528+
struct _mulle_objc_impcache *icache;
529+
struct _mulle_objc_cache *cache;
530+
struct _mulle_objc_cacheentry *entries;
531+
532+
entries = _mulle_objc_cachepivot_get_entries_atomic( &cls->cachepivot.pivot);
533+
cache = _mulle_objc_cacheentry_get_cache_from_entries( entries);
534+
icache = _mulle_objc_cache_get_impcache_from_cache( cache);
535+
method = (*icache->callback.refresh_supermethod_nofail)( cls, superid);
536+
imp = _mulle_objc_method_get_implementation( method);
537+
imp = _mulle_objc_implementation_debug( imp, obj, methodid, parameter, cls);
538+
return( (*imp)( obj, methodid, parameter));
511539
}
512540

513541

542+
struct _mulle_objc_impcache_callback _mulle_objc_impcache_callback_normal =
543+
{
544+
.call = _mulle_objc_object_callback_class,
545+
.call_cache_collision = _mulle_objc_object_callback_cache_collision,
546+
.call_cache_miss = _mulle_objc_object_callback_cache_miss,
547+
.supercall = _mulle_objc_object_callback_super, // public actually
548+
.supercall_cache_collision = _mulle_objc_object_callback_super_cache_collision,
549+
.supercall_cache_miss = _mulle_objc_object_callback_super_cache_miss,
550+
551+
.refresh_method_nofail = _mulle_objc_class_refresh_method_nofail,
552+
.refresh_supermethod_nofail = _mulle_objc_class_refresh_supermethod_nofail
553+
};
554+
555+
514556
// need to call cls->call to prepare caches
515557

516558
#pragma mark - multiple objects call
@@ -557,7 +599,6 @@ void mulle_objc_objects_call( void **objects,
557599
assert( imp);
558600
}
559601

560-
// this should use mulle_objc_implementation_invoke
561602
mulle_objc_implementation_invoke( lastSelIMP[ i], p, methodid, params);
562603
}
563604
}

0 commit comments

Comments
 (0)