Merge branch 'master' into newabi

main
David Chisnall 9 years ago
commit 12d1ea62a4

@ -1,3 +1,6 @@
os:
- linux
- osx
language: cpp
compiler: clang
script:

@ -13,8 +13,6 @@ set(libobjc_VERSION 4.6)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions")
# Build configuration
add_definitions( -DGNUSTEP -D__OBJC_RUNTIME_INTERNAL__=1)
# Probably not needed anymore?
add_definitions( -D_XOPEN_SOURCE=700 -D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
set(libobjc_ASM_SRCS
block_trampolines.S

@ -1,6 +1,8 @@
GNUstep Objective-C Runtime
===========================
[![Build Status](https://travis-ci.org/gnustep/libobjc2.svg?branch=master)](https://travis-ci.org/gnustep/libobjc2)
The GNUstep Objective-C runtime is designed as a drop-in replacement for the
GCC runtime. It supports both a legacy and a modern ABI, allowing code
compiled with old versions of GCC to be supported without requiring
@ -465,3 +467,4 @@ be used directly. If it does not exist, ARC will implement its own
`-_ARCCompatibleAutoreleasePool` then it must call `objc_autoreleasePoolPush()`
and `objc_autoreleasePoolPop()` to manage autoreleased object storage and call
`objc_autorelease()` in its `-addObject:` method.

@ -5,7 +5,7 @@
# List of single-file tests.
set(TESTS
#alignTest.m
alignTest.m
AllocatePair.m
AssociatedObject.m
AssociatedObject2.m
@ -26,6 +26,7 @@ set(TESTS
WeakBlock_arc.m
WeakReferences_arc.m
ivar_arc.m
IVarOverlap.m
objc_msgSend.m
msgInterpose.m
NilException.m
@ -58,10 +59,10 @@ endfunction(addtest_flags)
foreach(TEST_SOURCE ${TESTS})
get_filename_component(TEST ${TEST_SOURCE} NAME_WE)
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.0" ${TEST_SOURCE})
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.0" ${TEST_SOURCE})
addtest_flags("${TEST}_legacy" "-O0 -fobjc-runtime=gnustep-1.7" ${TEST_SOURCE})
addtest_flags("${TEST}_legacy_optimised" "-O3 -fobjc-runtime=gnustep-1.7" ${TEST_SOURCE})
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.0 -UNDEBUG" ${TEST_SOURCE})
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.0 -UNDEBUG" ${TEST_SOURCE})
addtest_flags("${TEST}_legacy" "-O0 -fobjc-runtime=gnustep-1.7 -UNDEBUG" ${TEST_SOURCE})
addtest_flags("${TEST}_legacy_optimised" "-O3 -fobjc-runtime=gnustep-1.7 -UNDEBUG" ${TEST_SOURCE})
endforeach()
# Tests that are more than a single file.

@ -0,0 +1,30 @@
#import <stdio.h>
#import "../objc/objc.h"
#import "../objc/runtime.h"
#import "../objc/Object.h"
#include "Test.h"
#import <sys/types.h>
#import <sys/stat.h>
@interface Dummy : Test
{
id objOne;
struct stat statBuf;
BOOL flagOne;
}
@end
@implementation Dummy
- (void)test
{
assert((char*)&statBuf+sizeof(struct stat) <= (char*)&flagOne);
}
@end
int main(int argc, char *argv[])
{
[[Dummy new] test];
return 0;
}

@ -6,6 +6,20 @@
#pragma GCC diagnostic ignored "-Wobjc-property-no-attribute"
// Clang < 3 doesn't exist usefully, so we can skip tests for it. Clang 3.5
// adds proper metadata for weak properties, earlier ones don't, so don't fail
// the tests because of known compiler bugs.
#ifndef __clang_minor__
#define WEAK_ATTR ATTR("W", ""),
#define WEAK_STR "W,"
#elif (__clang_major__ < 4) && (__clang_minor__ < 5)
#define WEAK_ATTR
#define WEAK_STR
#else
#define WEAK_ATTR ATTR("W", ""),
#define WEAK_STR "W,"
#endif
enum FooManChu { FOO, MAN, CHU };
struct YorkshireTeaStruct { int pot; signed char lady; };
typedef struct YorkshireTeaStruct YorkshireTeaStructType;
@ -281,7 +295,7 @@ static BOOL testPropertyForProperty_alt(objc_property_t p,
attrsList = property_copyAttributeList(p, NULL);
OPT_ASSERT(0 != attrsList);
objc_property_attribute_t *ra;
for (attrsCount = 0, ra = attrsList; ra->name != NULL; attrsCount++, ra++) {}
for (attrsCount = 0, ra = attrsList; (ra->name != NULL) && (attrsCount < size); attrsCount++, ra++) {}
OPT_ASSERT(attrsCount == size);
free(attrsList);
for (unsigned int index=0; index<size; index++) {
@ -384,45 +398,44 @@ static void testAddPropertyForClass(Class testClass)
ATTR("R", ""),
ATTR("&", ""),
ATTR("C", ""),
ATTR("W", ""),
WEAK_ATTR
ATTR("D", ""),
ATTR("V", "backingIvar"))));
testPropertyForProperty(class_getProperty(testClass, "addProperty4"),
"addProperty4", "T@,R,&,C,W,D,VbackingIvar", ATTRS(ATTR("T", "@"),
"addProperty4", "T@,R,&,C," WEAK_STR "D,VbackingIvar", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
ATTR("C", ""),
ATTR("W", ""),
WEAK_ATTR
ATTR("D", ""),
ATTR("V", "backingIvar")));
assert(class_addProperty(testClass, "addProperty5", ATTRS(ATTR("T", "@"),
ATTR("D", ""),
ATTR("W", ""),
WEAK_ATTR
ATTR("C", ""),
ATTR("&", ""),
ATTR("R", ""),
ATTR("V", "backingIvar"))));
// The only concession to MacOS X is that we reorder the attributes string
#if __APPLE__
testPropertyForProperty(class_getProperty(testClass, "addProperty5"),
"addProperty5", "T@,D,W,C,&,R,VbackingIvar", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
ATTR("C", ""),
ATTR("W", ""),
if (!testPropertyForProperty_alt(class_getProperty(testClass, "addProperty5"),
"addProperty5", "T@,D," WEAK_STR "C,&,R,VbackingIvar", ATTRS(ATTR("T", "@"),
ATTR("D", ""),
ATTR("V", "backingIvar")));
#else
testPropertyForProperty(class_getProperty(testClass, "addProperty5"),
"addProperty5", "T@,R,&,C,W,D,VbackingIvar", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
WEAK_ATTR
ATTR("C", ""),
ATTR("W", ""),
ATTR("D", ""),
ATTR("V", "backingIvar")));
#endif
ATTR("&", ""),
ATTR("R", ""),
ATTR("V", "backingIvar")), NO))
{
testPropertyForProperty(class_getProperty(testClass, "addProperty5"),
"addProperty5", "T@,R,&,C," WEAK_STR "D,VbackingIvar", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
ATTR("C", ""),
WEAK_ATTR
ATTR("D", ""),
ATTR("V", "backingIvar")));
}
assert(class_addProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "@"))));
testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
@ -546,24 +559,27 @@ int main(void)
ATTR("N", ""),
ATTR("V", "intNonatomic")));
testProperty("idReadonlyCopyNonatomic", "T@,R,C,N,VidReadonlyCopyNonatomic", ATTRS(ATTR("T", "@"),
ATTR("C", ""),
ATTR("R", ""),
ATTR("N", ""),
ATTR("V", "idReadonlyCopyNonatomic")));
testProperty("idReadonlyRetainNonatomic", "T@,R,&,N,VidReadonlyRetainNonatomic", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
ATTR("N", ""),
ATTR("V", "idReadonlyRetainNonatomic")));
/**
* The weak attribute was not present for earlier versions of clang, so we test
* for all variants that the compiler may produce.
*/
if (!testProperty_alt("idReadonlyWeakNonatomic", "T@,R,W,N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
if (!testProperty_alt("idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("N", ""),
ATTR("V", "idReadonlyWeakNonatomic")), NO))
{
testProperty("idReadonlyWeakNonatomic", "T@,R,N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
testProperty("idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
WEAK_ATTR
ATTR("N", ""),
ATTR("V", "idReadonlyWeakNonatomic")));
}
@ -622,15 +638,18 @@ int main(void)
ATTR("N", "")));
testPropertyForProtocol(testProto, "idReadonlyCopyNonatomic", "T@,R,C,N", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("C", ""),
ATTR("N", "")));
testPropertyForProtocol(testProto, "idReadonlyRetainNonatomic", "T@,R,&,N", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
ATTR("&", ""),
ATTR("N", "")));
/*
* Again, different clang versions emit slightly different property declarations.
*/
if (!testPropertyForProtocol_alt(testProto, "idReadonlyWeakNonatomic", "T@,R,W,N", ATTRS(ATTR("T", "@"),
if (!testPropertyForProtocol_alt(testProto, "idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N", ATTRS(ATTR("T", "@"),
ATTR("R", ""),
WEAK_ATTR
ATTR("N", "")), NO))
{

@ -36,7 +36,52 @@ typedef double __attribute__((vector_size(32))) v4d;
}
@end
typedef int v4si __attribute__ ((vector_size (16)));
@interface Foo : Test
{
v4si var;
}
- (void)check;
@end
@implementation Foo
- (void)check
{
size_t addr = (size_t)&var;
fprintf(stderr, "self: %p Addr: %p\n", self, &var);
assert(addr % 16 == 0);
}
@end
#if __has_attribute(objc_root_class)
__attribute__((objc_root_class))
#endif
@interface StringLikeTest
{
Class isa;
char* c_string;
int len;
}
@end
@implementation StringLikeTest
+ (Class)class
{
return self;
}
@end
int main(void)
{
[[Vector alloc] permute];
[[Foo new] check];
Ivar v_isa = class_getInstanceVariable([StringLikeTest class], "isa");
Ivar v_c_string = class_getInstanceVariable([StringLikeTest class], "c_string");
Ivar v_len = class_getInstanceVariable([StringLikeTest class], "len");
ptrdiff_t o_isa = ivar_getOffset(v_isa);
ptrdiff_t o_c_string = ivar_getOffset(v_c_string);
assert(o_isa == 0);
assert(o_c_string == sizeof(Class));
assert(o_isa < o_c_string);
assert(o_c_string < ivar_getOffset(v_len));
}

@ -20,14 +20,29 @@ int dealloc = 0;
}
@end
@interface EmptySubFoo : Foo
@end
@implementation EmptySubFoo
@end
@interface NonEmptySubFoo : Foo
{
__strong id ignored;
}
@end
@implementation NonEmptySubFoo
@end
void setIvar(id obj, const char * name, id val)
{
object_setIvar(obj, class_getInstanceVariable(object_getClass(obj), name), val);
}
int main(void)
void testIvarsOn(Foo* f)
{
Foo *f = [Foo new];
dealloc = 0;
Dealloc *d = [Dealloc new];
__unsafe_unretained Dealloc *dead;
setIvar(f, "w", d);
@ -48,5 +63,15 @@ int main(void)
setIvar(f, "s", nil);
assert(dealloc == 1);
assert(f->s == nil);
return 0;
}
int main (void)
{
/* Test for ivars in the same class */
testIvarsOn([Foo new]);
/* Test for ivars in the superclass (receiver ivar list empty) */
testIvarsOn([EmptySubFoo new]);
/* Test for ivars in the superclass (receiver ivar list non-empty) */
testIvarsOn([NonEmptySubFoo new]);
return 0;
}

@ -220,7 +220,7 @@ static inline void initAutorelease(void)
{
if (Nil == AutoreleasePool)
{
AutoreleasePool = objc_getRequiredClass("NSAutoreleasePool");
AutoreleasePool = objc_getClass("NSAutoreleasePool");
if (Nil == AutoreleasePool)
{
useARCAutoreleasePool = YES;

@ -822,6 +822,13 @@ PRIVATE void objc_send_initialize(id object)
objc_send_initialize((id)class->super_class);
}
// Lock the runtime while we're creating dtables and before we acquire any
// other locks. This prevents a lock-order reversal when
// dtable_for_class is called from something holding the runtime lock while
// we're still holding the initialize lock. We should ensure that we never
// acquire the runtime lock after acquiring the initialize lock.
LOCK_RUNTIME();
// Superclass +initialize might possibly send a message to this class, in
// which case this method would be called again. See NSObject and
// NSAutoreleasePool +initialize interaction in GNUstep.
@ -829,19 +836,17 @@ PRIVATE void objc_send_initialize(id object)
{
// We know that initialization has started because the flag is set.
// Check that it's finished by grabbing the class lock. This will be
// released once the class has been fully initialized
// released once the class has been fully initialized. The runtime
// lock needs to be released first to prevent a deadlock between the
// runtime lock and the class-specific lock.
UNLOCK_RUNTIME();
objc_sync_enter((id)meta);
objc_sync_exit((id)meta);
assert(dtable_for_class(class) != uninstalled_dtable);
return;
}
// Lock the runtime while we're creating dtables and before we acquire any
// other locks. This prevents a lock-order reversal when
// dtable_for_class is called from something holding the runtime lock while
// we're still holding the initialize lock. We should ensure that we never
// acquire the runtime lock after acquiring the initialize lock.
LOCK_RUNTIME();
LOCK_OBJECT_FOR_SCOPE((id)meta);
LOCK(&initialize_lock);
if (objc_test_class_flag(class, objc_class_flag_initialized))

@ -1,3 +1,4 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@ -69,6 +70,7 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
*/
if (class->ivars)
{
long cumulative_fudge = 0;
for (i = 0 ; i < class->ivars->count ; i++)
{
struct objc_ivar *ivar = &class->ivars->ivar_list[i];
@ -78,8 +80,26 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
// then we will need to ensure that we are properly aligned again.
long ivar_size = (i+1 == class->ivars->count)
? (class_size - ivar->offset)
: ivar->offset - class->ivars->ivar_list[i+1].offset;
: class->ivars->ivar_list[i+1].offset - ivar->offset ;
assert(ivar_size > 0);
// FIXME: use alignment
ivar->offset += cumulative_fudge;
// We only need to do the realignment for things that are
// bigger than a pointer, and we don't need to do it in GC mode
// where we don't add any extra padding.
if (!isGCEnabled && (ivar_size > sizeof(void*)))
{
long offset = ivar_start + ivar->offset + sizeof(intptr_t);
// For now, assume that nothing needs to be more than 16-byte aligned.
// This is not correct for AVX vectors, but we probably
// can't do anything about that for now (as malloc is only
// giving us 16-byte aligned memory)
long fudge = 16 - (offset % 16);
ivar->offset += fudge;
class->instance_size += fudge;
cumulative_fudge += fudge;
assert((ivar_start + ivar->offset + sizeof(intptr_t)) % 16 == 0);
}
ivar->offset += ivar_start;
/* If we're using the new ABI then we also set up the faster ivar
* offset variables.

@ -1,6 +1,7 @@
#include "objc/runtime.h"
#include "objc/objc-arc.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -520,64 +521,62 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
attrs[count].value = types;
count++;
}
if (checkAttribute(property->attributes, OBJC_PR_readonly))
{
attrs[count].name = "R";
attrs[count].value = "";
count++;
}
if (checkAttribute(property->attributes, OBJC_PR_copy))
{
attrs[count].name = "C";
attrs[count].value = "";
count++;
}
if (checkAttribute(property->attributes, OBJC_PR_retain) ||
checkAttribute(property->attributes2, OBJC_PR_strong))
// If the compiler provides a type encoding string, then it's more
// informative than the bitfields and should be treated as canonical. If
// the compiler didn't provide a type encoding string, then this will
// create a best-effort one.
const char *attributes = property_getAttributes(property);
for (int i=strlen(types)+1 ; attributes[i] != 0 ; i++)
{
attrs[count].name = "&";
attrs[count].value = "";
count++;
}
if (checkAttribute(property->attributes2, OBJC_PR_dynamic) &&
!checkAttribute(property->attributes2, OBJC_PR_synthesized))
{
attrs[count].name = "D";
attrs[count].value = "";
count++;
}
if (checkAttribute(property->attributes2, OBJC_PR_weak))
{
attrs[count].name = "W";
attrs[count].value = "";
count++;
}
if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
{
attrs[count].name = "N";
assert(count<12);
if (attributes[i] == ',')
{
// Comma is never the last character in the string, so this should
// never push us past the end.
i++;
}
attrs[count].value = "";
switch (attributes[i])
{
case 'R':
attrs[count].name = "R";
break;
case 'C':
attrs[count].name = "C";
break;
case '&':
attrs[count].name = "&";
break;
case 'D':
attrs[count].name = "D";
break;
case 'W':
attrs[count].name = "W";
break;
case 'N':
attrs[count].name = "N";
break;
case 'G':
attrs[count].name = "G";
attrs[count].value = property->getter_name;
i += strlen(attrs[count].value);
break;
case 'S':
attrs[count].name = "S";
attrs[count].value = property->setter_name;
i += strlen(attrs[count].value);
break;
case 'V':
attrs[count].name = "V";
attrs[count].value = attributes+i+1;
i += strlen(attributes+i)-1;
break;
default:
i++;
continue;
}
count++;
}
if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
{
attrs[count].name = "G";
attrs[count].value = property->getter_name;
count++;
}
if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
{
attrs[count].name = "S";
attrs[count].value = property->setter_name;
count++;
}
const char *name = property_getIVar(property);
if (name != NULL)
{
attrs[count].name = "V";
attrs[count].value = name;
count++;
}
objc_property_attribute_t *propAttrs = calloc(sizeof(objc_property_attribute_t), count);
memcpy(propAttrs, attrs, count * sizeof(objc_property_attribute_t));
if (NULL != outCount)
@ -702,6 +701,7 @@ char *property_copyAttributeValue(objc_property_t property,
const char *attributeName)
{
if ((NULL == property) || (NULL == attributeName)) { return NULL; }
const char *attributes = property_getAttributes(property);
switch (attributeName[0])
{
case 'T':
@ -710,9 +710,13 @@ char *property_copyAttributeValue(objc_property_t property,
return (NULL == types) ? NULL : strdup(types);
}
case 'D':
case 'R':
case 'W':
case 'C':
case '&':
case 'N':
{
return checkAttribute(property->attributes2, OBJC_PR_dynamic) &&
!checkAttribute(property->attributes2, OBJC_PR_synthesized) ? strdup("") : 0;
return strchr(attributes, attributeName[0]) ? strdup("") : 0;
}
case 'V':
{
@ -726,27 +730,6 @@ char *property_copyAttributeValue(objc_property_t property,
{
return strdup(property->getter_name);
}
case 'R':
{
return checkAttribute(property->attributes, OBJC_PR_readonly) ? strdup("") : 0;
}
case 'W':
{
return checkAttribute(property->attributes2, OBJC_PR_weak) ? strdup("") : 0;
}
case 'C':
{
return checkAttribute(property->attributes, OBJC_PR_copy) ? strdup("") : 0;
}
case '&':
{
return checkAttribute(property->attributes, OBJC_PR_retain) ||
checkAttribute(property->attributes2, OBJC_PR_strong) ? strdup("") : 0;
}
case 'N':
{
return checkAttribute(property->attributes, OBJC_PR_nonatomic) ? strdup("") : 0;
}
}
return 0;
}

Loading…
Cancel
Save