Clean up the low memory profile. Now passes all GNUstep-base and EtoileFoundation tests, just like the default profileand uses 5-10% less (total) RAM in GORM. Worth benchmarking to see how much performance this costs.

Updated the release announcement.
main
theraven 15 years ago
parent f0974cb415
commit f9d1b5f356

@ -6,8 +6,18 @@ libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. Highlights of this for use with GNUstep and other Objective-C programs. Highlights of this
release include: release include:
- Support for the associated reference APIs introduced with OS X 10.6 - Support for the associated reference APIs introduced with OS X 10.6. This
- Better hiding of local symbols allows storing arbitrary objects associated with another object.
- Concurrent, thread-safe, +initialize. The runtime will now send +initialize
messages to different classes concurrently in multiple threads, but still
ensures that no class receives another message until it has returned from
+initialize. Exceptions can now safely propagate out of +initialize methods.
- Better hiding of local symbols. Now the internal runtime functions are not
visible from outside of the runtime.
- Dispatch table updates have been improved. Category loading no longer
triggers dtable creation and partial dtable updates are faster.
- Improvements to the low memory profile. Uses 5-10% less memory running Gorm,
and now passes the entire GNUstep and EtoileFoundation test suites.
You may obtain the code for this release from subversion at the following You may obtain the code for this release from subversion at the following
subversion branch: subversion branch:

@ -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);

Loading…
Cancel
Save