Merge remote-tracking branch 'upstream/master' into HEAD

main
Dustin Howett 8 years ago
commit 7fb4f5684f

@ -19,8 +19,21 @@ int main(void)
@autoreleasepool { @autoreleasepool {
Associated *object = [Associated new]; Associated *object = [Associated new];
Test *holder = [[Test new] autorelease]; Test *holder = [[Test new] autorelease];
objc_setAssociatedObject(object, &objc_setAssociatedObjectKey, holder, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, object, OBJC_ASSOCIATION_RETAIN);
[object release]; [object release];
} assert(!deallocCalled);
}
// dealloc should be called when holder is released during pool drain
assert(deallocCalled);
deallocCalled = NO;
Associated *object = [Associated new];
Test *holder = [Test new];
objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, object, OBJC_ASSOCIATION_RETAIN);
[object release]; // commuted into associated object storage
objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, nil, OBJC_ASSOCIATION_ASSIGN);
[holder release];
assert(deallocCalled); assert(deallocCalled);
} }

@ -33,6 +33,7 @@ set(TESTS
MethodArguments.m MethodArguments.m
zeroSizedIVar.m zeroSizedIVar.m
exchange.m exchange.m
hash_table_delete.c
setSuperclass.m setSuperclass.m
) )

@ -0,0 +1,64 @@
#include <stdbool.h>
#include <stdint.h>
struct test_struct {
uintptr_t key;
};
struct test_struct null_placeholder = {0};
static int test_compare(const void *key, const struct test_struct test) {
return (uintptr_t)key == test.key;
}
// force hash collisions
static uint32_t test_key_hash(const void *ptr) {
return ((uint32_t)(uintptr_t)ptr)>>2;
}
static uint32_t test_value_hash(const struct test_struct test) {
return test.key>>2;
}
static int test_is_null(const struct test_struct test) {
return test.key == 0;
}
#define MAP_TABLE_NAME test
#define MAP_TABLE_COMPARE_FUNCTION test_compare
#define MAP_TABLE_VALUE_TYPE struct test_struct
#define MAP_TABLE_VALUE_NULL test_is_null
#define MAP_TABLE_HASH_KEY test_key_hash
#define MAP_TABLE_HASH_VALUE test_value_hash
#define MAP_TABLE_VALUE_PLACEHOLDER null_placeholder
#define MAP_TABLE_ACCESS_BY_REFERENCE 1
#define MAP_TABLE_SINGLE_THREAD 1
#define MAP_TABLE_NO_LOCK 1
#include "../hash_table.h"
int main(int argc, char *argv[])
{
test_table *testTable;
test_initialize(&testTable, 128);
struct test_struct one, two, three;
one.key = 1;
two.key = 2;
three.key = 3;
test_insert(testTable, one);
test_insert(testTable, two);
test_insert(testTable, three);
test_remove(testTable, (void*)2);
test_remove(testTable, (void*)1);
struct test_struct *pthree = test_table_get(testTable, (void*)3);
if (!pthree) {
fprintf(stderr, "failed to find value (key=3) inserted into hash table\n");
return 1;
}
return 0;
}

@ -166,12 +166,17 @@ static void setReference(struct reference_list *list,
lock = lock_for_pointer(r); lock = lock_for_pointer(r);
lock_spinlock(lock); lock_spinlock(lock);
} }
r->policy = policy; @try
id old = r->object;
r->object = obj;
if (OBJC_ASSOCIATION_ASSIGN != r->policy)
{ {
objc_release(old); if (OBJC_ASSOCIATION_ASSIGN != r->policy)
{
objc_release(r->object);
}
}
@finally
{
r->policy = policy;
r->object = obj;
} }
if (needLock) if (needLock)
{ {

@ -258,10 +258,10 @@ PRIVATE BOOL objc_resolve_class(Class cls)
PRIVATE void objc_resolve_class_links(void) PRIVATE void objc_resolve_class_links(void)
{ {
LOCK_RUNTIME_FOR_SCOPE(); LOCK_RUNTIME_FOR_SCOPE();
Class class = unresolved_class_list;
BOOL resolvedClass; BOOL resolvedClass;
do do
{ {
Class class = unresolved_class_list;
resolvedClass = NO; resolvedClass = NO;
while ((Nil != class)) while ((Nil != class))
{ {

@ -392,6 +392,22 @@ static void PREFIX(_remove)(PREFIX(_table) *table, void *key)
MAP_LOCK(); MAP_LOCK();
PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key); PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key);
if (NULL == cell) { return; } if (NULL == cell) { return; }
uint32_t hash = MAP_TABLE_HASH_KEY(key);
PREFIX(_table_cell) baseCell = PREFIX(_table_lookup)(table, hash);
if (baseCell && baseCell <= cell && cell - baseCell <= 32)
{
uint32_t jump = 1 << (cell - baseCell - 1);
if ((baseCell->secondMaps & jump))
{
// If we are removing a cell stored adjacent to its base due to hash
// collision, we have to clear the base cell's neighbor bit.
// Otherwise, a later remove can move the new placeholder value to the head
// which will cause further chained lookups to fail.
baseCell->secondMaps &= ~jump;
}
}
// If the cell contains a value, set it to the placeholder and shuffle up // If the cell contains a value, set it to the placeholder and shuffle up
// everything // everything
if (0 == cell->secondMaps) if (0 == cell->secondMaps)

@ -5,6 +5,10 @@
#ifndef __LIBOBJC_ENCODING_H_INCLUDED__ #ifndef __LIBOBJC_ENCODING_H_INCLUDED__
#define __LIBOBJC_ENCODING_H_INCLUDED__ #define __LIBOBJC_ENCODING_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
const char *objc_skip_type_qualifiers (const char *type); const char *objc_skip_type_qualifiers (const char *type);
const char *objc_skip_typespec(const char *type); const char *objc_skip_typespec(const char *type);
@ -71,4 +75,8 @@ void objc_layout_structure_get_info (struct objc_struct_layout *layout,
#define _F_ONEWAY 0x10 #define _F_ONEWAY 0x10
#define _F_GCINVISIBLE 0x20 #define _F_GCINVISIBLE 0x20
#ifdef __cplusplus
}
#endif
#endif // __LIBOBJC_ENCODING_H_INCLUDED__ #endif // __LIBOBJC_ENCODING_H_INCLUDED__

@ -2,6 +2,10 @@
#pragma clang system_header #pragma clang system_header
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* This file includes all of the hooks that can be used to alter the behaviour * This file includes all of the hooks that can be used to alter the behaviour
* of the runtime. * of the runtime.
@ -102,4 +106,6 @@ typedef IMP (*objc_tracing_hook)(id, SEL, IMP, int, void*);
*/ */
int objc_registerTracingHook(SEL, objc_tracing_hook); int objc_registerTracingHook(SEL, objc_tracing_hook);
#ifdef __cplusplus
}
#endif

@ -4,6 +4,11 @@
#ifndef __OBJC_ARC_INCLUDED__ #ifndef __OBJC_ARC_INCLUDED__
#define __OBJC_ARC_INCLUDED__ #define __OBJC_ARC_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* Autoreleases the argument. Equivalent to [obj autorelease]. * Autoreleases the argument. Equivalent to [obj autorelease].
*/ */
@ -138,5 +143,10 @@ unsigned long objc_arc_autorelease_count_np(void);
* this thread. * this thread.
*/ */
unsigned long objc_arc_autorelease_count_for_object_np(id); unsigned long objc_arc_autorelease_count_for_object_np(id);
#ifdef __cplusplus
}
#endif
#endif // __OBJC_ARC_INCLUDED__ #endif // __OBJC_ARC_INCLUDED__

@ -198,7 +198,11 @@ typedef struct
#ifdef __GNUC #ifdef __GNUC
# define _OBJC_NULL_PTR __null # define _OBJC_NULL_PTR __null
#elif defined(__cplusplus) #elif defined(__cplusplus)
# define _OBJC_NULL_PTR 0 # if __has_feature(cxx_nullptr)
# define _OBJC_NULL_PTR nullptr
# else
# define _OBJC_NULL_PTR 0
# endif
#else #else
# define _OBJC_NULL_PTR ((void*)0) # define _OBJC_NULL_PTR ((void*)0)
#endif #endif

@ -17,7 +17,7 @@
# define ASSERT(x) assert(x) # define ASSERT(x) assert(x)
#else #else
# define UNREACHABLE(x) __builtin_unreachable() # define UNREACHABLE(x) __builtin_unreachable()
# define ASSERT(x) do { if (x) __builtin_unreachable(); } while(0) # define ASSERT(x) do { if (!(x)) __builtin_unreachable(); } while(0)
#endif #endif
#define LIKELY(x) __builtin_expect(x, 1) #define LIKELY(x) __builtin_expect(x, 1)

Loading…
Cancel
Save