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
release include:
- Support for the associated reference APIs introduced with OS X 10.6
- Better hiding of local symbols
- Support for the associated reference APIs introduced with OS X 10.6. This
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
subversion branch:

@ -1,3 +1,4 @@
#define __BSD_VISIBLE 1
#include <stdio.h>
#include <stdlib.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;
}
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);
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),
slot_cmp);
SparseArrayDestroy(methods);
@ -223,6 +231,11 @@ PRIVATE void objc_update_dtable_for_class(Class cls)
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)
{
@ -246,17 +259,21 @@ PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid)
slot = s->slot;
int i = HASH_UID(uid);
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->slot = slot;
__sync_synchronize();
cache->idx = uid;
__sync_bool_compare_and_swap(&cache->idx, -uid, uid);
return slot;
}
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;
}
@ -274,7 +291,7 @@ PRIVATE void free_dtable(dtable_t dtable)
{
free(dtable->slots);
}
DESTROY_LOCK(dtable->lock);
DESTROY_LOCK(&dtable->lock);
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 (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.
objc_resolve_class(class);

Loading…
Cancel
Save