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

main
Dustin Howett 8 years ago
commit 7fb4f5684f

@ -19,8 +19,21 @@ int main(void)
@autoreleasepool {
Associated *object = [Associated new];
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];
}
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);
}

@ -33,6 +33,7 @@ set(TESTS
MethodArguments.m
zeroSizedIVar.m
exchange.m
hash_table_delete.c
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_spinlock(lock);
}
r->policy = policy;
id old = r->object;
r->object = obj;
if (OBJC_ASSOCIATION_ASSIGN != r->policy)
@try
{
objc_release(old);
if (OBJC_ASSOCIATION_ASSIGN != r->policy)
{
objc_release(r->object);
}
}
@finally
{
r->policy = policy;
r->object = obj;
}
if (needLock)
{

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

@ -392,6 +392,22 @@ static void PREFIX(_remove)(PREFIX(_table) *table, void *key)
MAP_LOCK();
PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key);
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
// everything
if (0 == cell->secondMaps)

@ -5,6 +5,10 @@
#ifndef __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_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_GCINVISIBLE 0x20
#ifdef __cplusplus
}
#endif
#endif // __LIBOBJC_ENCODING_H_INCLUDED__

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

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

@ -198,7 +198,11 @@ typedef struct
#ifdef __GNUC
# define _OBJC_NULL_PTR __null
#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
# define _OBJC_NULL_PTR ((void*)0)
#endif

@ -17,7 +17,7 @@
# define ASSERT(x) assert(x)
#else
# 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
#define LIKELY(x) __builtin_expect(x, 1)

Loading…
Cancel
Save