forked from gnustep/libobjc2
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for fast-path alloc / init methods and direct methods.
The fast paths follow the pattern that we established for fast ARC: Framework base classes can opt in by implementing a `+_TrivialAllocInit` method. This opt-in behaviour is inherited and is removed implicitly in any subclass that implements alloc or init methods (alloc and init are treated independently). Compilers can emit calls to `objc_alloc(cls)` instead of `[cls alloc]`, `objc_allocWithZone(cls)` instead of `[cls allocWithZone: NULL]`, and `objc_alloc_init` instead of `[[cls alloc] init]`. Direct methods don't require very much support in the runtime. Apple reuses their fast path for `-self` (which is supported only in the Apple fork of clang, not the upstream version) for a fast init. Given that the first few fields of the runtime's class structure have been stable for around 30 years, I'm happy moving the flags word (and the initialised bit, in particular) into the public ABI. This lets us do a fast-path check for whether a class is initialised in class methods and call `objc_send_initialize` if it isn't. This function is now exposed as part of the public ABI, it was there already and does the relevant checks without invoking any of the message-sending machinery. Fixes gnustep#165 gnustep#169
- Loading branch information
1 parent
6528090
commit 377a81d
Showing
12 changed files
with
339 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#include "Test.h" | ||
|
||
#if !__has_attribute(objc_direct) | ||
int main() | ||
{ | ||
return 77; | ||
} | ||
#else | ||
|
||
static BOOL initializeCalled; | ||
static BOOL directMethodCalled; | ||
|
||
@interface HasDirect : Test | ||
+ (void)clsDirect __attribute__((objc_direct)); | ||
- (int)instanceDirect __attribute__((objc_direct)); | ||
@end | ||
@implementation HasDirect | ||
+ (void)initialize | ||
{ | ||
initializeCalled = YES; | ||
} | ||
+ (void)clsDirect | ||
{ | ||
directMethodCalled = YES; | ||
} | ||
- (int)instanceDirect | ||
{ | ||
return 42; | ||
} | ||
@end | ||
|
||
int main(void) | ||
{ | ||
[HasDirect clsDirect]; | ||
assert(directMethodCalled); | ||
assert(initializeCalled); | ||
HasDirect *obj = [HasDirect new]; | ||
assert([obj instanceDirect] == 42); | ||
obj = nil; | ||
assert([obj instanceDirect] == 0); | ||
return 0; | ||
} | ||
|
||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#if __clang_major__ < 18 | ||
// Skip this test if clang is too old to support it. | ||
int main(void) | ||
{ | ||
return 77; | ||
} | ||
#else | ||
#include "Test.h" | ||
#include <stdio.h> | ||
|
||
static BOOL called; | ||
|
||
typedef struct _NSZone NSZone; | ||
|
||
@interface ShouldAlloc : Test @end | ||
@interface ShouldAllocWithZone : Test @end | ||
@interface ShouldInit : Test @end | ||
@interface ShouldInit2 : Test @end | ||
|
||
@interface NoAlloc : Test @end | ||
@interface NoInit : Test @end | ||
@interface NoInit2 : NoInit @end | ||
|
||
@implementation ShouldAlloc | ||
+ (instancetype)alloc | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
@end | ||
@implementation ShouldAllocWithZone | ||
+ (instancetype)allocWithZone: (NSZone*)aZone | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
@end | ||
@implementation ShouldInit | ||
- (instancetype)init | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return self; | ||
} | ||
@end | ||
@implementation ShouldInit2 | ||
+ (instancetype)alloc | ||
{ | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
- (instancetype)init | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return self; | ||
} | ||
@end | ||
|
||
@implementation NoAlloc | ||
+ (void)_TrivialAllocInit{} | ||
+ (instancetype)alloc | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
+ (instancetype)allocWithZone: (NSZone*)aZone | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
@end | ||
@implementation NoInit | ||
+ (void)_TrivialAllocInit{} | ||
- (instancetype)init | ||
{ | ||
called = YES; | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return self; | ||
} | ||
@end | ||
@implementation NoInit2 | ||
+ (instancetype)alloc | ||
{ | ||
fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); | ||
return [super alloc]; | ||
} | ||
@end | ||
|
||
int main(void) | ||
{ | ||
called = NO; | ||
[ShouldAlloc alloc]; | ||
assert(called); | ||
|
||
[ShouldAllocWithZone allocWithZone: NULL]; | ||
assert(called); | ||
called = NO; | ||
|
||
called = NO; | ||
[[ShouldInit alloc] init]; | ||
assert(called); | ||
|
||
called = NO; | ||
[[ShouldInit2 alloc] init]; | ||
assert(called); | ||
|
||
called = NO; | ||
[NoAlloc alloc]; | ||
assert(!called); | ||
|
||
[NoAlloc allocWithZone: NULL]; | ||
assert(!called); | ||
called = NO; | ||
|
||
called = NO; | ||
[[NoInit alloc] init]; | ||
assert(!called); | ||
|
||
called = NO; | ||
[[NoInit2 alloc] init]; | ||
assert(!called); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.