├── APPLE_LICENSE ├── ReleaseNotes.rtf ├── libobjc.order ├── markgc.cpp ├── objc.sln ├── objc.suo ├── objc.vcproj ├── objc.xcodeproj └── project.pbxproj ├── objcrt └── objcrt.vcproj ├── prebuild.bat ├── runtime ├── Messengers.subproj │ ├── objc-msg-arm.s │ ├── objc-msg-arm64.s │ ├── objc-msg-i386.s │ ├── objc-msg-simulator-i386.s │ ├── objc-msg-simulator-x86_64.s │ ├── objc-msg-win32.m │ └── objc-msg-x86_64.s ├── NSObjCRuntime.h ├── NSObject.h ├── NSObject.mm ├── Object.h ├── Object.mm ├── OldClasses.subproj │ ├── List.h │ └── List.m ├── Protocol.h ├── Protocol.mm ├── a1a2-blocktramps-arm.s ├── a1a2-blocktramps-arm64.s ├── a1a2-blocktramps-i386.s ├── a1a2-blocktramps-x86_64.s ├── a2a3-blocktramps-arm.s ├── a2a3-blocktramps-i386.s ├── a2a3-blocktramps-x86_64.s ├── hashtable.h ├── hashtable2.h ├── hashtable2.mm ├── llvm-AlignOf.h ├── llvm-DenseMap.h ├── llvm-DenseMapInfo.h ├── llvm-MathExtras.h ├── llvm-type_traits.h ├── maptable.h ├── maptable.mm ├── message.h ├── objc-abi.h ├── objc-accessors.h ├── objc-accessors.mm ├── objc-api.h ├── objc-auto-dump.h ├── objc-auto-dump.mm ├── objc-auto.h ├── objc-auto.mm ├── objc-block-trampolines.mm ├── objc-cache-old.h ├── objc-cache-old.mm ├── objc-cache.h ├── objc-cache.mm ├── objc-class-old.mm ├── objc-class.h ├── objc-class.mm ├── objc-config.h ├── objc-env.h ├── objc-errors.mm ├── objc-exception.h ├── objc-exception.mm ├── objc-externalref.mm ├── objc-file-old.h ├── objc-file-old.mm ├── objc-file.h ├── objc-file.mm ├── objc-gdb.h ├── objc-initialize.h ├── objc-initialize.mm ├── objc-internal.h ├── objc-layout.mm ├── objc-load.h ├── objc-load.mm ├── objc-loadmethod.h ├── objc-loadmethod.mm ├── objc-lockdebug.h ├── objc-lockdebug.mm ├── objc-object.h ├── objc-opt.mm ├── objc-os.h ├── objc-os.mm ├── objc-private.h ├── objc-probes.d ├── objc-references.h ├── objc-references.mm ├── objc-runtime-new.h ├── objc-runtime-new.mm ├── objc-runtime-old.h ├── objc-runtime-old.mm ├── objc-runtime.h ├── objc-runtime.mm ├── objc-sel-old.mm ├── objc-sel-set.h ├── objc-sel-set.mm ├── objc-sel-table.s ├── objc-sel.mm ├── objc-sync.h ├── objc-sync.mm ├── objc-typeencoding.mm ├── objc-weak.h ├── objc-weak.mm ├── objc.h ├── objcrt.c ├── objcrt.h └── runtime.h ├── test ├── ARRBase.h ├── ARRBase.m ├── ARRLayouts.m ├── ARRMRR.h ├── ARRMRR.m ├── MRRARR.h ├── MRRARR.m ├── MRRBase.h ├── MRRBase.m ├── Makefile ├── accessors.m ├── accessors2.m ├── addMethod.m ├── addProtocol.m ├── applescriptobjc.m ├── applescriptobjc2.m ├── arr-cast.m ├── arr-weak.m ├── association-cf.m ├── association.m ├── atomicProperty.mm ├── badAltHandler.m ├── badCache.m ├── badTagClass.m ├── badTagIndex.m ├── bigrc.m ├── blocksAsImps.m ├── cacheflush.h ├── cacheflush.m ├── cacheflush0.m ├── cacheflush2.m ├── cacheflush3.m ├── category.m ├── cdtors.mm ├── classgetclass.m ├── classname.m ├── classpair.m ├── classversion.m ├── concurrentcat.m ├── concurrentcat_category.m ├── copyIvarList.m ├── copyMethodList.m ├── copyPropertyList.m ├── createInstance.m ├── customrr-cat1.m ├── customrr-cat2.m ├── customrr-nsobject-awz.m ├── customrr-nsobject-none.m ├── customrr-nsobject-rr.m ├── customrr-nsobject-rrawz.m ├── customrr-nsobject.m ├── customrr.m ├── customrr2.m ├── definitions.c ├── designatedinit.m ├── duplicateClass.m ├── duplicatedClasses.m ├── evil-category-0.m ├── evil-category-00.m ├── evil-category-000.m ├── evil-category-1.m ├── evil-category-2.m ├── evil-category-3.m ├── evil-category-4.m ├── evil-category-def.m ├── evil-class-0.m ├── evil-class-00.m ├── evil-class-000.m ├── evil-class-1.m ├── evil-class-2.m ├── evil-class-3.m ├── evil-class-4.m ├── evil-class-5.m ├── evil-class-def.m ├── evil-main.m ├── exc.m ├── exchangeImp.m ├── foreach.m ├── forward.m ├── forwardDefault.m ├── forwardDefaultStret.m ├── future.h ├── future.m ├── future0.m ├── future2.m ├── gc-main.m ├── gc.c ├── gc.m ├── gcenforcer-nogc-1.m ├── gcenforcer-nogc-2.m ├── gcenforcer-noobjc.m ├── gcenforcer-requiresgc-1.m ├── gcenforcer-requiresgc-2.m ├── gcenforcer-supportsgc.m ├── gcenforcer.m ├── gdb.m ├── getMethod.m ├── ignoredSelector.m ├── ignoredSelector2.m ├── imageorder.h ├── imageorder.m ├── imageorder1.m ├── imageorder2.m ├── imageorder3.m ├── includes.c ├── initialize.m ├── initializeVersusWeak.m ├── instanceSize.m ├── ismeta.m ├── ivar.m ├── ivarSlide.h ├── ivarSlide.m ├── ivarSlide1.m ├── layout.m ├── literals.m ├── load-noobjc.m ├── load-noobjc2.m ├── load-noobjc3.m ├── load-order.m ├── load-order1.m ├── load-order2.m ├── load-order3.m ├── load-parallel.m ├── load-parallel0.m ├── load-parallel00.m ├── load-reentrant.m ├── load-reentrant2.m ├── load.m ├── methodArgs.m ├── methodListSize.m ├── method_getName.m ├── msgSend.m ├── nilAPIArgs.m ├── nonpointerisa.m ├── nopool.m ├── nscdtors.mm ├── nsexc.m ├── nsobject.m ├── nsprotocol.m ├── objectCopy.m ├── property.m ├── propertyDesc.m ├── protocol.m ├── protocol_copyMethodList.m ├── protocol_copyPropertyList.m ├── protocol_cw.m ├── rawisa.m ├── readClassPair.m ├── resolve.m ├── rr-autorelease-fast.m ├── rr-autorelease-fastarc.m ├── rr-autorelease-stacklogging.m ├── rr-autorelease.m ├── rr-autorelease2.m ├── rr-nsautorelease.m ├── rr-sidetable.m ├── runtime.m ├── sel.m ├── setSuper.m ├── subscripting.m ├── super.m ├── synchronized-counter.m ├── synchronized-grid.m ├── synchronized.m ├── taggedNSPointers.m ├── taggedPointers.m ├── taggedPointersDisabled.m ├── tbi.c ├── test.h ├── test.pl ├── testroot.i ├── unload.h ├── unload.m ├── unload2.m ├── unload3.c ├── unload4.m ├── unwind.m ├── verify-exports.pl ├── weak.h ├── weak.m ├── weak2.m ├── weakcopy.m ├── weakframework-missing.m ├── weakframework-not-missing.m ├── weakimport-missing.m ├── weakimport-not-missing.m ├── weakrace.m ├── xref.m └── zone.m ├── unexported_symbols ├── version.bat └── version.rc /objc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual C++ Express 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objc", "objc.vcproj", "{B3408263-0CF1-47BE-83CC-56070EFC9BC1}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objcrt", "objcrt\objcrt.vcproj", "{E38C1996-8B3D-4050-A4B2-DC85957B047D}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1} = {B3408263-0CF1-47BE-83CC-56070EFC9BC1} 9 | EndProjectSection 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Win32 = Debug|Win32 14 | DebugDLL|Win32 = DebugDLL|Win32 15 | Release|Win32 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.Build.0 = Debug|Win32 20 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 21 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 22 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.ActiveCfg = Release|Win32 23 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.Build.0 = Release|Win32 24 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.Build.0 = Debug|Win32 26 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.ActiveCfg = Debug|Win32 27 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.Build.0 = Debug|Win32 28 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.ActiveCfg = Release|Win32 29 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /objc.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opensource-apple/objc4/cd5e62a5597ea7a31dccef089317abb3a661c154/objc.suo -------------------------------------------------------------------------------- /objcrt/objcrt.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 24 | 28 | 31 | 34 | 38 | 39 | 47 | 51 | 54 | 57 | 61 | 62 | 63 | 64 | 65 | 66 | 71 | 74 | 75 | 76 | 81 | 84 | 85 | 86 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /prebuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo prebuild: installing headers 4 | xcopy /Y "%ProjectDir%runtime\objc.h" "%DSTROOT%\AppleInternal\include\objc\" 5 | xcopy /Y "%ProjectDir%runtime\objc-api.h" "%DSTROOT%\AppleInternal\include\objc\" 6 | xcopy /Y "%ProjectDir%runtime\objc-auto.h" "%DSTROOT%\AppleInternal\include\objc\" 7 | xcopy /Y "%ProjectDir%runtime\objc-exception.h" "%DSTROOT%\AppleInternal\include\objc\" 8 | xcopy /Y "%ProjectDir%runtime\message.h" "%DSTROOT%\AppleInternal\include\objc\" 9 | xcopy /Y "%ProjectDir%runtime\runtime.h" "%DSTROOT%\AppleInternal\include\objc\" 10 | xcopy /Y "%ProjectDir%runtime\hashtable.h" "%DSTROOT%\AppleInternal\include\objc\" 11 | xcopy /Y "%ProjectDir%runtime\hashtable2.h" "%DSTROOT%\AppleInternal\include\objc\" 12 | xcopy /Y "%ProjectDir%runtime\maptable.h" "%DSTROOT%\AppleInternal\include\objc\" 13 | 14 | echo prebuild: setting version 15 | version 16 | -------------------------------------------------------------------------------- /runtime/NSObjCRuntime.h: -------------------------------------------------------------------------------- 1 | /* NSObjCRuntime.h 2 | Copyright (c) 1994-2012, Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef _OBJC_NSOBJCRUNTIME_H_ 6 | #define _OBJC_NSOBJCRUNTIME_H_ 7 | 8 | #include 9 | #include 10 | 11 | #if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 12 | typedef long NSInteger; 13 | typedef unsigned long NSUInteger; 14 | #else 15 | typedef int NSInteger; 16 | typedef unsigned int NSUInteger; 17 | #endif 18 | 19 | #define NSIntegerMax LONG_MAX 20 | #define NSIntegerMin LONG_MIN 21 | #define NSUIntegerMax ULONG_MAX 22 | 23 | #define NSINTEGER_DEFINED 1 24 | 25 | #ifndef NS_DESIGNATED_INITIALIZER 26 | #if __has_attribute(objc_designated_initializer) 27 | #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 28 | #else 29 | #define NS_DESIGNATED_INITIALIZER 30 | #endif 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /runtime/NSObject.h: -------------------------------------------------------------------------------- 1 | /* NSObject.h 2 | Copyright (c) 1994-2012, Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef _OBJC_NSOBJECT_H_ 6 | #define _OBJC_NSOBJECT_H_ 7 | 8 | #if __OBJC__ 9 | 10 | #include 11 | #include 12 | 13 | @class NSString, NSMethodSignature, NSInvocation; 14 | 15 | @protocol NSObject 16 | 17 | - (BOOL)isEqual:(id)object; 18 | @property (readonly) NSUInteger hash; 19 | 20 | @property (readonly) Class superclass; 21 | - (Class)class OBJC_SWIFT_UNAVAILABLE("use 'anObject.dynamicType' instead"); 22 | - (instancetype)self; 23 | 24 | - (id)performSelector:(SEL)aSelector; 25 | - (id)performSelector:(SEL)aSelector withObject:(id)object; 26 | - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; 27 | 28 | - (BOOL)isProxy; 29 | 30 | - (BOOL)isKindOfClass:(Class)aClass; 31 | - (BOOL)isMemberOfClass:(Class)aClass; 32 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol; 33 | 34 | - (BOOL)respondsToSelector:(SEL)aSelector; 35 | 36 | - (instancetype)retain OBJC_ARC_UNAVAILABLE; 37 | - (oneway void)release OBJC_ARC_UNAVAILABLE; 38 | - (instancetype)autorelease OBJC_ARC_UNAVAILABLE; 39 | - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE; 40 | 41 | - (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; 42 | 43 | @property (readonly, copy) NSString *description; 44 | @optional 45 | @property (readonly, copy) NSString *debugDescription; 46 | 47 | @end 48 | 49 | 50 | __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0) 51 | OBJC_ROOT_CLASS 52 | OBJC_EXPORT 53 | @interface NSObject { 54 | Class isa OBJC_ISA_AVAILABILITY; 55 | } 56 | 57 | + (void)load; 58 | 59 | + (void)initialize; 60 | - (instancetype)init 61 | #if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER 62 | NS_DESIGNATED_INITIALIZER 63 | #endif 64 | ; 65 | 66 | + (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead"); 67 | + (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead"); 68 | + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead"); 69 | - (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer"); 70 | 71 | - (void)finalize; 72 | 73 | - (id)copy; 74 | - (id)mutableCopy; 75 | 76 | + (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; 77 | + (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; 78 | 79 | + (BOOL)instancesRespondToSelector:(SEL)aSelector; 80 | + (BOOL)conformsToProtocol:(Protocol *)protocol; 81 | - (IMP)methodForSelector:(SEL)aSelector; 82 | + (IMP)instanceMethodForSelector:(SEL)aSelector; 83 | - (void)doesNotRecognizeSelector:(SEL)aSelector; 84 | 85 | - (id)forwardingTargetForSelector:(SEL)aSelector __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); 86 | - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""); 87 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(""); 88 | 89 | + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(""); 90 | 91 | - (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE; 92 | - (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE; 93 | 94 | + (BOOL)isSubclassOfClass:(Class)aClass; 95 | 96 | + (BOOL)resolveClassMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); 97 | + (BOOL)resolveInstanceMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); 98 | 99 | + (NSUInteger)hash; 100 | + (Class)superclass; 101 | + (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead"); 102 | + (NSString *)description; 103 | + (NSString *)debugDescription; 104 | 105 | @end 106 | 107 | #endif 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /runtime/Protocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2003, 2006-2007 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | Protocol.h 25 | Copyright 1991-1996 NeXT Software, Inc. 26 | */ 27 | 28 | #ifndef _OBJC_PROTOCOL_H_ 29 | #define _OBJC_PROTOCOL_H_ 30 | 31 | #if !__OBJC__ 32 | 33 | // typedef Protocol is here: 34 | #include 35 | 36 | 37 | #elif __OBJC2__ 38 | 39 | #include 40 | 41 | // All methods of class Protocol are unavailable. 42 | // Use the functions in objc/runtime.h instead. 43 | 44 | __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0) 45 | @interface Protocol : NSObject 46 | @end 47 | 48 | 49 | #else 50 | 51 | #include 52 | 53 | __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0) 54 | @interface Protocol : Object 55 | { 56 | @private 57 | char *protocol_name OBJC2_UNAVAILABLE; 58 | struct objc_protocol_list *protocol_list OBJC2_UNAVAILABLE; 59 | struct objc_method_description_list *instance_methods OBJC2_UNAVAILABLE; 60 | struct objc_method_description_list *class_methods OBJC2_UNAVAILABLE; 61 | } 62 | 63 | /* Obtaining attributes intrinsic to the protocol */ 64 | 65 | - (const char *)name OBJC2_UNAVAILABLE; 66 | 67 | /* Testing protocol conformance */ 68 | 69 | - (BOOL) conformsTo: (Protocol *)aProtocolObject OBJC2_UNAVAILABLE; 70 | 71 | /* Looking up information specific to a protocol */ 72 | 73 | - (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel 74 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_2_0,__IPHONE_2_0); 75 | - (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel 76 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_2_0,__IPHONE_2_0); 77 | 78 | @end 79 | 80 | #endif 81 | 82 | #endif /* _OBJC_PROTOCOL_H_ */ 83 | -------------------------------------------------------------------------------- /runtime/a1a2-blocktramps-arm.s: -------------------------------------------------------------------------------- 1 | #if __arm__ 2 | 3 | #include 4 | #include 5 | 6 | .syntax unified 7 | 8 | .text 9 | 10 | .private_extern __a1a2_tramphead 11 | .private_extern __a1a2_firsttramp 12 | .private_extern __a1a2_trampend 13 | 14 | // Trampoline machinery assumes the trampolines are Thumb function pointers 15 | #if !__thumb2__ 16 | # error sorry 17 | #endif 18 | 19 | .thumb 20 | .thumb_func __a1a2_tramphead 21 | .thumb_func __a1a2_firsttramp 22 | .thumb_func __a1a2_trampend 23 | 24 | .align PAGE_MAX_SHIFT 25 | __a1a2_tramphead: 26 | /* 27 | r0 == self 28 | r12 == pc of trampoline's first instruction + PC bias 29 | lr == original return address 30 | */ 31 | 32 | mov r1, r0 // _cmd = self 33 | 34 | // Trampoline's data is one page before the trampoline text. 35 | // Also correct PC bias of 4 bytes. 36 | sub r12, #PAGE_MAX_SIZE 37 | ldr r0, [r12, #-4] // self = block object 38 | ldr pc, [r0, #12] // tail call block->invoke 39 | // not reached 40 | 41 | // Align trampolines to 8 bytes 42 | .align 3 43 | 44 | .macro TrampolineEntry 45 | mov r12, pc 46 | b __a1a2_tramphead 47 | .align 3 48 | .endmacro 49 | 50 | .macro TrampolineEntryX16 51 | TrampolineEntry 52 | TrampolineEntry 53 | TrampolineEntry 54 | TrampolineEntry 55 | 56 | TrampolineEntry 57 | TrampolineEntry 58 | TrampolineEntry 59 | TrampolineEntry 60 | 61 | TrampolineEntry 62 | TrampolineEntry 63 | TrampolineEntry 64 | TrampolineEntry 65 | 66 | TrampolineEntry 67 | TrampolineEntry 68 | TrampolineEntry 69 | TrampolineEntry 70 | .endmacro 71 | 72 | .macro TrampolineEntryX256 73 | TrampolineEntryX16 74 | TrampolineEntryX16 75 | TrampolineEntryX16 76 | TrampolineEntryX16 77 | 78 | TrampolineEntryX16 79 | TrampolineEntryX16 80 | TrampolineEntryX16 81 | TrampolineEntryX16 82 | 83 | TrampolineEntryX16 84 | TrampolineEntryX16 85 | TrampolineEntryX16 86 | TrampolineEntryX16 87 | 88 | TrampolineEntryX16 89 | TrampolineEntryX16 90 | TrampolineEntryX16 91 | TrampolineEntryX16 92 | .endmacro 93 | 94 | .private_extern __a1a2_firsttramp 95 | __a1a2_firsttramp: 96 | // 2048-2 trampolines to fill 16K page 97 | TrampolineEntryX256 98 | TrampolineEntryX256 99 | TrampolineEntryX256 100 | TrampolineEntryX256 101 | 102 | TrampolineEntryX256 103 | TrampolineEntryX256 104 | TrampolineEntryX256 105 | 106 | TrampolineEntryX16 107 | TrampolineEntryX16 108 | TrampolineEntryX16 109 | TrampolineEntryX16 110 | 111 | TrampolineEntryX16 112 | TrampolineEntryX16 113 | TrampolineEntryX16 114 | TrampolineEntryX16 115 | 116 | TrampolineEntryX16 117 | TrampolineEntryX16 118 | TrampolineEntryX16 119 | TrampolineEntryX16 120 | 121 | TrampolineEntryX16 122 | TrampolineEntryX16 123 | TrampolineEntryX16 124 | 125 | TrampolineEntry 126 | TrampolineEntry 127 | TrampolineEntry 128 | TrampolineEntry 129 | 130 | TrampolineEntry 131 | TrampolineEntry 132 | TrampolineEntry 133 | TrampolineEntry 134 | 135 | TrampolineEntry 136 | TrampolineEntry 137 | TrampolineEntry 138 | TrampolineEntry 139 | 140 | TrampolineEntry 141 | TrampolineEntry 142 | // TrampolineEntry 143 | // TrampolineEntry 144 | 145 | .private_extern __a1a2_trampend 146 | __a1a2_trampend: 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /runtime/a1a2-blocktramps-arm64.s: -------------------------------------------------------------------------------- 1 | #if __arm64__ 2 | 3 | #include 4 | 5 | .text 6 | 7 | .private_extern __a1a2_tramphead 8 | .private_extern __a1a2_firsttramp 9 | .private_extern __a1a2_trampend 10 | 11 | .align PAGE_MAX_SHIFT 12 | __a1a2_tramphead: 13 | L_a1a2_tramphead: 14 | /* 15 | x0 == self 16 | x17 == address of called trampoline's data (1 page before its code) 17 | lr == original return address 18 | */ 19 | 20 | mov x1, x0 // _cmd = self 21 | ldr x0, [x17] // self = block object 22 | ldr x16, [x0, #16] // tail call block->invoke 23 | br x16 24 | 25 | // pad up to TrampolineBlockPagePair header size 26 | nop 27 | nop 28 | 29 | .macro TrampolineEntry 30 | // load address of trampoline data (one page before this instruction) 31 | adr x17, -PAGE_MAX_SIZE 32 | b L_a1a2_tramphead 33 | .endmacro 34 | 35 | .macro TrampolineEntryX16 36 | TrampolineEntry 37 | TrampolineEntry 38 | TrampolineEntry 39 | TrampolineEntry 40 | 41 | TrampolineEntry 42 | TrampolineEntry 43 | TrampolineEntry 44 | TrampolineEntry 45 | 46 | TrampolineEntry 47 | TrampolineEntry 48 | TrampolineEntry 49 | TrampolineEntry 50 | 51 | TrampolineEntry 52 | TrampolineEntry 53 | TrampolineEntry 54 | TrampolineEntry 55 | .endmacro 56 | 57 | .macro TrampolineEntryX256 58 | TrampolineEntryX16 59 | TrampolineEntryX16 60 | TrampolineEntryX16 61 | TrampolineEntryX16 62 | 63 | TrampolineEntryX16 64 | TrampolineEntryX16 65 | TrampolineEntryX16 66 | TrampolineEntryX16 67 | 68 | TrampolineEntryX16 69 | TrampolineEntryX16 70 | TrampolineEntryX16 71 | TrampolineEntryX16 72 | 73 | TrampolineEntryX16 74 | TrampolineEntryX16 75 | TrampolineEntryX16 76 | TrampolineEntryX16 77 | .endmacro 78 | 79 | .align 3 80 | .private_extern __a1a2_firsttramp 81 | __a1a2_firsttramp: 82 | // 2048-3 trampolines to fill 16K page 83 | TrampolineEntryX256 84 | TrampolineEntryX256 85 | TrampolineEntryX256 86 | TrampolineEntryX256 87 | 88 | TrampolineEntryX256 89 | TrampolineEntryX256 90 | TrampolineEntryX256 91 | 92 | TrampolineEntryX16 93 | TrampolineEntryX16 94 | TrampolineEntryX16 95 | TrampolineEntryX16 96 | 97 | TrampolineEntryX16 98 | TrampolineEntryX16 99 | TrampolineEntryX16 100 | TrampolineEntryX16 101 | 102 | TrampolineEntryX16 103 | TrampolineEntryX16 104 | TrampolineEntryX16 105 | TrampolineEntryX16 106 | 107 | TrampolineEntryX16 108 | TrampolineEntryX16 109 | TrampolineEntryX16 110 | 111 | TrampolineEntry 112 | TrampolineEntry 113 | TrampolineEntry 114 | TrampolineEntry 115 | 116 | TrampolineEntry 117 | TrampolineEntry 118 | TrampolineEntry 119 | TrampolineEntry 120 | 121 | TrampolineEntry 122 | TrampolineEntry 123 | TrampolineEntry 124 | TrampolineEntry 125 | 126 | TrampolineEntry 127 | // TrampolineEntry 128 | // TrampolineEntry 129 | // TrampolineEntry 130 | 131 | .private_extern __a1a2_trampend 132 | __a1a2_trampend: 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /runtime/a2a3-blocktramps-arm.s: -------------------------------------------------------------------------------- 1 | #if __arm__ 2 | 3 | #include 4 | #include 5 | 6 | .syntax unified 7 | 8 | .text 9 | 10 | .private_extern __a2a3_tramphead 11 | .private_extern __a2a3_firsttramp 12 | .private_extern __a2a3_trampend 13 | 14 | // Trampoline machinery assumes the trampolines are Thumb function pointers 15 | #if !__thumb2__ 16 | # error sorry 17 | #endif 18 | 19 | .thumb 20 | .thumb_func __a2a3_tramphead 21 | .thumb_func __a2a3_firsttramp 22 | .thumb_func __a2a3_trampend 23 | 24 | .align PAGE_MAX_SHIFT 25 | __a2a3_tramphead: 26 | /* 27 | r1 == self 28 | r12 == pc of trampoline's first instruction + PC bias 29 | lr == original return address 30 | */ 31 | 32 | mov r2, r1 // _cmd = self 33 | 34 | // Trampoline's data is one page before the trampoline text. 35 | // Also correct PC bias of 4 bytes. 36 | sub r12, #PAGE_MAX_SIZE 37 | ldr r1, [r12, #-4] // self = block object 38 | ldr pc, [r1, #12] // tail call block->invoke 39 | // not reached 40 | 41 | // Align trampolines to 8 bytes 42 | .align 3 43 | 44 | .macro TrampolineEntry 45 | mov r12, pc 46 | b __a2a3_tramphead 47 | .align 3 48 | .endmacro 49 | 50 | .macro TrampolineEntryX16 51 | TrampolineEntry 52 | TrampolineEntry 53 | TrampolineEntry 54 | TrampolineEntry 55 | 56 | TrampolineEntry 57 | TrampolineEntry 58 | TrampolineEntry 59 | TrampolineEntry 60 | 61 | TrampolineEntry 62 | TrampolineEntry 63 | TrampolineEntry 64 | TrampolineEntry 65 | 66 | TrampolineEntry 67 | TrampolineEntry 68 | TrampolineEntry 69 | TrampolineEntry 70 | .endmacro 71 | 72 | .macro TrampolineEntryX256 73 | TrampolineEntryX16 74 | TrampolineEntryX16 75 | TrampolineEntryX16 76 | TrampolineEntryX16 77 | 78 | TrampolineEntryX16 79 | TrampolineEntryX16 80 | TrampolineEntryX16 81 | TrampolineEntryX16 82 | 83 | TrampolineEntryX16 84 | TrampolineEntryX16 85 | TrampolineEntryX16 86 | TrampolineEntryX16 87 | 88 | TrampolineEntryX16 89 | TrampolineEntryX16 90 | TrampolineEntryX16 91 | TrampolineEntryX16 92 | .endmacro 93 | 94 | .private_extern __a2a3_firsttramp 95 | __a2a3_firsttramp: 96 | // 2048-2 trampolines to fill 16K page 97 | TrampolineEntryX256 98 | TrampolineEntryX256 99 | TrampolineEntryX256 100 | TrampolineEntryX256 101 | 102 | TrampolineEntryX256 103 | TrampolineEntryX256 104 | TrampolineEntryX256 105 | 106 | TrampolineEntryX16 107 | TrampolineEntryX16 108 | TrampolineEntryX16 109 | TrampolineEntryX16 110 | 111 | TrampolineEntryX16 112 | TrampolineEntryX16 113 | TrampolineEntryX16 114 | TrampolineEntryX16 115 | 116 | TrampolineEntryX16 117 | TrampolineEntryX16 118 | TrampolineEntryX16 119 | TrampolineEntryX16 120 | 121 | TrampolineEntryX16 122 | TrampolineEntryX16 123 | TrampolineEntryX16 124 | 125 | TrampolineEntry 126 | TrampolineEntry 127 | TrampolineEntry 128 | TrampolineEntry 129 | 130 | TrampolineEntry 131 | TrampolineEntry 132 | TrampolineEntry 133 | TrampolineEntry 134 | 135 | TrampolineEntry 136 | TrampolineEntry 137 | TrampolineEntry 138 | TrampolineEntry 139 | 140 | TrampolineEntry 141 | TrampolineEntry 142 | // TrampolineEntry 143 | // TrampolineEntry 144 | 145 | .private_extern __a2a3_trampend 146 | __a2a3_trampend: 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /runtime/hashtable.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /runtime/objc-accessors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef _OBJC_ACCESSORS_H_ 25 | #define _OBJC_ACCESSORS_H_ 26 | 27 | #include 28 | #include 29 | 30 | __BEGIN_DECLS 31 | 32 | #if SUPPORT_GC 33 | 34 | extern void objc_setProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy); 35 | extern id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic); 36 | 37 | extern void objc_setProperty_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy); 38 | extern id objc_getProperty_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic); 39 | 40 | #endif 41 | 42 | __END_DECLS 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /runtime/objc-auto-dump.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc-auto-dump.h 3 | // objc 4 | // The raw dump file format 5 | // See objc-gdb.h for the primitive. 6 | // 7 | // Created by Blaine Garst on 12/8/08. 8 | // Copyright 2008 Apple, Inc. All rights reserved. 9 | // 10 | #ifndef _OBJC_AUTO_DUMP_H_ 11 | #define _OBJC_AUTO_DUMP_H_ 12 | 13 | /* 14 | * Raw file format definitions 15 | */ 16 | 17 | // must be unique in first letter... 18 | // RAW FORMAT 19 | #define HEADER "dumpster" 20 | #define THREAD 't' 21 | #define LOCAL 'l' 22 | #define NODE 'n' 23 | #define REGISTER 'r' 24 | #define ROOT 'g' 25 | #define WEAK 'w' 26 | #define CLASS 'c' 27 | #define END 'e' 28 | 29 | #define SixtyFour 1 30 | #define Little 2 31 | 32 | /* 33 | 34 | Raw format, not that anyone should really care. Most programs should use the cooked file reader. 35 | 36 | * 37 |
:= 'd' 'u' 'm' 'p' 's' 't' 'e' 'r' ; the HEADER string 38 | := SixtyFour? + Little? ; architecture 39 | := | | | | 40 | := * ; the triple 41 | := 'r' longLength [bytes] ; the register bank 42 | := 't' longLength [bytes] ; the stack 43 | := 'l' [long] ; a thread local node 44 | := 'g' longAddress longValue 45 | := 'n' longAddress longSize intLayout longRefcount longIsa? 46 | := 'w' longAddress longValue 47 | := 'c' longAddress 48 | := intLength [bytes] ; no null byte 49 | := intLength [bytes] ; including 0 byte at end 50 | := intLength [bytes] ; including 0 byte at end 51 | := 'e' 52 | 53 | */ 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /runtime/objc-cache-old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef _OBJC_CACHE_OLD_H 25 | #define _OBJC_CACHE_OLD_H 26 | 27 | #include "objc-private.h" 28 | 29 | __BEGIN_DECLS 30 | 31 | extern IMP _cache_getImp(Class cls, SEL sel); 32 | extern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp); 33 | 34 | extern void flush_cache(Class cls); 35 | extern bool _cache_fill(Class cls, Method meth, SEL sel); 36 | extern void _cache_addForwardEntry(Class cls, SEL sel); 37 | extern IMP _cache_addIgnoredEntry(Class cls, SEL sel); 38 | extern void _cache_free(Cache cache); 39 | extern void _cache_collect(bool collectALot); 40 | 41 | __END_DECLS 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /runtime/objc-cache.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _OBJC_CACHE_H 3 | #define _OBJC_CACHE_H 4 | 5 | #include "objc-private.h" 6 | 7 | __BEGIN_DECLS 8 | 9 | extern IMP cache_getImp(Class cls, SEL sel); 10 | 11 | extern void cache_fill(Class cls, SEL sel, IMP imp, id receiver); 12 | 13 | extern void cache_erase_nolock(Class cls); 14 | 15 | extern void cache_delete(Class cls); 16 | 17 | extern void cache_collect(bool collectALot); 18 | 19 | __END_DECLS 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /runtime/objc-class.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-file-old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef _OBJC_FILE_OLD_H 25 | #define _OBJC_FILE_OLD_H 26 | 27 | #if !__OBJC2__ 28 | 29 | #include "objc-os.h" 30 | 31 | struct objc_module; 32 | struct old_protocol; 33 | struct old_class; 34 | 35 | __BEGIN_DECLS 36 | 37 | extern struct objc_module *_getObjcModules(const header_info *hi, size_t *nmodules); 38 | extern SEL *_getObjcSelectorRefs(const header_info *hi, size_t *nmess); 39 | extern struct old_protocol **_getObjcProtocols(const header_info *hi, size_t *nprotos); 40 | extern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses); 41 | extern const char *_getObjcClassNames(const header_info *hi, size_t *size); 42 | 43 | __END_DECLS 44 | 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /runtime/objc-file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef _OBJC_FILE_NEW_H 25 | #define _OBJC_FILE_NEW_H 26 | 27 | #if __OBJC2__ 28 | 29 | #include "objc-runtime-new.h" 30 | 31 | // classref_t is not fixed up at launch; use remapClass() to convert 32 | 33 | extern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count); 34 | extern message_ref_t *_getObjc2MessageRefs(const header_info *hi, size_t *count); 35 | extern Class*_getObjc2ClassRefs(const header_info *hi, size_t *count); 36 | extern Class*_getObjc2SuperRefs(const header_info *hi, size_t *count); 37 | extern classref_t *_getObjc2ClassList(const header_info *hi, size_t *count); 38 | extern classref_t *_getObjc2NonlazyClassList(const header_info *hi, size_t *count); 39 | extern category_t **_getObjc2CategoryList(const header_info *hi, size_t *count); 40 | extern category_t **_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count); 41 | extern protocol_t **_getObjc2ProtocolList(const header_info *hi, size_t *count); 42 | extern protocol_t **_getObjc2ProtocolRefs(const header_info *hi, size_t *count); 43 | using Initializer = void(*)(void); 44 | extern Initializer* getLibobjcInitializers(const header_info *hi, size_t *count); 45 | 46 | extern classref_t *_getObjc2NonlazyClassList(const headerType *mhdr, size_t *count); 47 | extern category_t **_getObjc2NonlazyCategoryList(const headerType *mhdr, size_t *count); 48 | extern Initializer* getLibobjcInitializers(const headerType *mhdr, size_t *count); 49 | 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /runtime/objc-initialize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005-2006 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef _OBJC_INITIALIZE_H 25 | #define _OBJC_INITIALIZE_H 26 | 27 | #include "objc-private.h" 28 | 29 | __BEGIN_DECLS 30 | 31 | struct _objc_initializing_classes; 32 | 33 | extern void _class_initialize(Class cls); 34 | 35 | extern void _destroyInitializingClassList(struct _objc_initializing_classes *list); 36 | 37 | __END_DECLS 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /runtime/objc-load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2001, 2005-2006 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * objc-load.h 25 | * Copyright 1988-1996, NeXT Software, Inc. 26 | */ 27 | 28 | #ifndef _OBJC_LOAD_H_ 29 | #define _OBJC_LOAD_H_ 30 | 31 | #include 32 | 33 | #include 34 | 35 | /* dynamically loading Mach-O object files that contain Objective-C code */ 36 | 37 | OBJC_EXPORT long objc_loadModules ( 38 | char *modlist[], 39 | void *errStream, 40 | void (*class_callback) (Class, Category), 41 | /*headerType*/ struct mach_header **hdr_addr, 42 | char *debug_file 43 | ) OBJC2_UNAVAILABLE; 44 | OBJC_EXPORT int objc_loadModule ( 45 | char * moduleName, 46 | void (*class_callback) (Class, Category), 47 | int * errorCode 48 | ) OBJC2_UNAVAILABLE; 49 | OBJC_EXPORT long objc_unloadModules( 50 | void *errorStream, /* input (optional) */ 51 | void (*unloadCallback)(Class, Category) /* input (optional) */ 52 | ) OBJC2_UNAVAILABLE; 53 | 54 | #endif /* _OBJC_LOAD_H_ */ 55 | -------------------------------------------------------------------------------- /runtime/objc-loadmethod.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2006 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | /*********************************************************************** 25 | * objc-loadmethod.h 26 | * Support for +load methods. 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_LOADMETHOD_H 30 | #define _OBJC_LOADMETHOD_H 31 | 32 | #include "objc-private.h" 33 | 34 | __BEGIN_DECLS 35 | 36 | extern void add_class_to_loadable_list(Class cls); 37 | extern void add_category_to_loadable_list(Category cat); 38 | extern void remove_class_from_loadable_list(Class cls); 39 | extern void remove_category_from_loadable_list(Category cat); 40 | 41 | extern void call_load_methods(void); 42 | 43 | __END_DECLS 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /runtime/objc-probes.d: -------------------------------------------------------------------------------- 1 | provider objc_runtime 2 | { 3 | probe objc_exception_throw(void *id); 4 | probe objc_exception_rethrow(); 5 | }; 6 | -------------------------------------------------------------------------------- /runtime/objc-references.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * objc-references.h 25 | */ 26 | 27 | #ifndef _OBJC_REFERENCES_H_ 28 | #define _OBJC_REFERENCES_H_ 29 | 30 | #include "objc-api.h" 31 | #include "objc-config.h" 32 | 33 | __BEGIN_DECLS 34 | 35 | extern void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy); 36 | extern id _object_get_associative_reference(id object, void *key); 37 | extern void _object_remove_assocations(id object); 38 | 39 | __END_DECLS 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /runtime/objc-runtime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-sel-set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | /* 25 | * objc-sel-set.h 26 | * A set of SELs used for SEL uniquing. 27 | */ 28 | 29 | #ifndef _OBJC_SEL_SET_H_ 30 | #define _OBJC_SEL_SET_H_ 31 | 32 | #if !__OBJC2__ 33 | 34 | #include 35 | #include "objc-os.h" 36 | 37 | __BEGIN_DECLS 38 | 39 | struct __objc_sel_set; 40 | 41 | extern struct __objc_sel_set *__objc_sel_set_create(size_t selrefCount); 42 | extern SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate); 43 | extern void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value); 44 | 45 | __END_DECLS 46 | 47 | #endif 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /runtime/objc-sel-table.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if __LP64__ 5 | # define PTR(x) .quad x 6 | #else 7 | # define PTR(x) .long x 8 | #endif 9 | 10 | .section __TEXT,__objc_opt_ro 11 | .align 3 12 | .private_extern __objc_opt_data 13 | __objc_opt_data: 14 | .long 13 /* table.version */ 15 | .long 0 /* table.selopt_offset */ 16 | .long 0 /* table.headeropt_offset */ 17 | .long 0 /* table.clsopt_offset */ 18 | .space PAGE_MAX_SIZE-16 19 | 20 | /* space for selopt, smax/capacity=262144, blen/mask=262143+1 */ 21 | .space 262144 /* mask tab */ 22 | .space 524288 /* checkbytes */ 23 | .space 524288*4 /* offsets */ 24 | 25 | /* space for clsopt, smax/capacity=32768, blen/mask=16383+1 */ 26 | .space 16384 /* mask tab */ 27 | .space 32768 /* checkbytes */ 28 | .space 32768*12 /* offsets to name and class and header_info */ 29 | .space PAGE_MAX_SIZE /* some duplicate classes */ 30 | 31 | /* space for protocolopt, smax/capacity=8192, blen/mask=4095+1 */ 32 | .space 4096 /* mask tab */ 33 | .space 8192 /* checkbytes */ 34 | .space 8192*4 /* offsets */ 35 | 36 | 37 | .section __DATA,__objc_opt_rw 38 | .align 3 39 | .private_extern __objc_opt_rw_data 40 | __objc_opt_rw_data: 41 | /* space for header_info structures */ 42 | .space 32768 43 | 44 | /* space for 8192 protocols */ 45 | #if __LP64__ 46 | .space 8192 * 11 * 8 47 | #else 48 | .space 8192 * 11 * 4 49 | #endif 50 | 51 | 52 | /* section of pointers that the shared cache optimizer wants to know about */ 53 | .section __DATA,__objc_opt_ptrs 54 | .align 3 55 | 56 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE && __i386__ 57 | // old ABI 58 | .globl .objc_class_name_Protocol 59 | PTR(.objc_class_name_Protocol) 60 | #else 61 | // new ABI 62 | .globl _OBJC_CLASS_$_Protocol 63 | PTR(_OBJC_CLASS_$_Protocol) 64 | #endif 65 | -------------------------------------------------------------------------------- /runtime/objc-sync.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2002, 2006 Apple Inc. All Rights Reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef __OBJC_SNYC_H_ 25 | #define __OBJC_SNYC_H_ 26 | 27 | #include 28 | 29 | 30 | /** 31 | * Begin synchronizing on 'obj'. 32 | * Allocates recursive pthread_mutex associated with 'obj' if needed. 33 | * 34 | * @param obj The object to begin synchronizing on. 35 | * 36 | * @return OBJC_SYNC_SUCCESS once lock is acquired. 37 | */ 38 | OBJC_EXPORT int objc_sync_enter(id obj) 39 | __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); 40 | 41 | /** 42 | * End synchronizing on 'obj'. 43 | * 44 | * @param obj The objet to end synchronizing on. 45 | * 46 | * @return OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR 47 | */ 48 | OBJC_EXPORT int objc_sync_exit(id obj) 49 | __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); 50 | 51 | // The wait/notify functions have never worked correctly and no longer exist. 52 | OBJC_EXPORT int objc_sync_wait(id obj, long long milliSecondsMaxWait) 53 | UNAVAILABLE_ATTRIBUTE; 54 | OBJC_EXPORT int objc_sync_notify(id obj) 55 | UNAVAILABLE_ATTRIBUTE; 56 | OBJC_EXPORT int objc_sync_notifyAll(id obj) 57 | UNAVAILABLE_ATTRIBUTE; 58 | 59 | enum { 60 | OBJC_SYNC_SUCCESS = 0, 61 | OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1, 62 | OBJC_SYNC_TIMED_OUT = -2, 63 | OBJC_SYNC_NOT_INITIALIZED = -3 64 | }; 65 | 66 | 67 | #endif // __OBJC_SNYC_H_ 68 | -------------------------------------------------------------------------------- /runtime/objcrt.c: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | #include 5 | #include "objcrt.h" 6 | 7 | // Boundary symbols for metadata sections 8 | 9 | #pragma section(".objc_module_info$A",long,read,write) 10 | #pragma data_seg(".objc_module_info$A") 11 | static uintptr_t __objc_modStart = 0; 12 | #pragma section(".objc_module_info$C",long,read,write) 13 | #pragma data_seg(".objc_module_info$C") 14 | static uintptr_t __objc_modEnd = 0; 15 | 16 | #pragma section(".objc_protocol$A",long,read,write) 17 | #pragma data_seg(".objc_protocol$A") 18 | static uintptr_t __objc_protoStart = 0; 19 | #pragma section(".objc_protocol$C",long,read,write) 20 | #pragma data_seg(".objc_protocol$C") 21 | static uintptr_t __objc_protoEnd = 0; 22 | 23 | #pragma section(".objc_image_info$A",long,read,write) 24 | #pragma data_seg(".objc_image_info$A") 25 | static uintptr_t __objc_iiStart = 0; 26 | #pragma section(".objc_image_info$C",long,read,write) 27 | #pragma data_seg(".objc_image_info$C") 28 | static uintptr_t __objc_iiEnd = 0; 29 | 30 | #pragma section(".objc_message_refs$A",long,read,write) 31 | #pragma data_seg(".objc_message_refs$A") 32 | static uintptr_t __objc_selrefsStart = 0; 33 | #pragma section(".objc_message_refs$C",long,read,write) 34 | #pragma data_seg(".objc_message_refs$C") 35 | static uintptr_t __objc_selrefsEnd = 0; 36 | 37 | #pragma section(".objc_class_refs$A",long,read,write) 38 | #pragma data_seg(".objc_class_refs$A") 39 | static uintptr_t __objc_clsrefsStart = 0; 40 | #pragma section(".objc_class_refs$C",long,read,write) 41 | #pragma data_seg(".objc_class_refs$C") 42 | static uintptr_t __objc_clsrefsEnd = 0; 43 | 44 | #pragma data_seg() 45 | 46 | // Merge all metadata into .data 47 | // fixme order these by usage? 48 | #pragma comment(linker, "/MERGE:.objc_module_info=.data") 49 | #pragma comment(linker, "/MERGE:.objc_protocol=.data") 50 | #pragma comment(linker, "/MERGE:.objc_image_info=.data") 51 | #pragma comment(linker, "/MERGE:.objc_message_refs=.data") 52 | #pragma comment(linker, "/MERGE:.objc_class_refs=.data") 53 | 54 | 55 | // Image initializers 56 | 57 | static void *__hinfo = NULL; // cookie from runtime 58 | extern IMAGE_DOS_HEADER __ImageBase; // this image's header 59 | 60 | static int __objc_init(void) 61 | { 62 | objc_sections sections = { 63 | 5, 64 | &__objc_modStart, &__objc_modEnd, 65 | &__objc_protoStart, &__objc_protoEnd, 66 | &__objc_iiStart, &__objc_iiEnd, 67 | &__objc_selrefsStart, &__objc_selrefsEnd, 68 | &__objc_clsrefsStart, &__objc_clsrefsEnd, 69 | }; 70 | __hinfo = _objc_init_image((HMODULE)&__ImageBase, §ions); 71 | return 0; 72 | } 73 | 74 | static void __objc_unload(void) 75 | { 76 | _objc_unload_image((HMODULE)&__ImageBase, __hinfo); 77 | } 78 | 79 | static int __objc_load(void) 80 | { 81 | _objc_load_image((HMODULE)&__ImageBase, __hinfo); 82 | return 0; 83 | } 84 | 85 | // run _objc_init_image ASAP 86 | #pragma section(".CRT$XIAA",long,read,write) 87 | #pragma data_seg(".CRT$XIAA") 88 | static void *__objc_init_fn = &__objc_init; 89 | 90 | // run _objc_load_image (+load methods) after all other initializers; 91 | // otherwise constant NSStrings are not initialized yet 92 | #pragma section(".CRT$XCUO",long,read,write) 93 | #pragma data_seg(".CRT$XCUO") 94 | static void *__objc_load_fn = &__objc_load; 95 | 96 | // _objc_unload_image is called by atexit(), not by an image terminator 97 | 98 | #pragma data_seg() 99 | -------------------------------------------------------------------------------- /runtime/objcrt.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBJC_RT_H_ 2 | #define _OBJC_RT_H_ 3 | 4 | #include 5 | 6 | 7 | typedef struct { 8 | int count; // number of pointer pairs that follow 9 | void *modStart; 10 | void *modEnd; 11 | void *protoStart; 12 | void *protoEnd; 13 | void *iiStart; 14 | void *iiEnd; 15 | void *selrefsStart; 16 | void *selrefsEnd; 17 | void *clsrefsStart; 18 | void *clsrefsEnd; 19 | } objc_sections; 20 | 21 | OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects); 22 | OBJC_EXPORT void _objc_load_image(HMODULE image, void *hinfo); 23 | OBJC_EXPORT void _objc_unload_image(HMODULE image, void *hinfo); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/ARRBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // ARRBase.h 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ARRBase : NSObject 12 | @property long number; 13 | @property(retain) id object; 14 | @property void *pointer; 15 | @property(weak) __weak id delegate; 16 | @end 17 | -------------------------------------------------------------------------------- /test/ARRBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // ARRBase.m 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ARRBase.h" 10 | 11 | #if 1 12 | @interface ARRBase () { 13 | @private 14 | long number; 15 | id object; 16 | void *pointer; 17 | __weak id delegate; 18 | } 19 | @end 20 | #endif 21 | 22 | @implementation ARRBase 23 | @synthesize number, object, pointer, delegate; 24 | @end 25 | -------------------------------------------------------------------------------- /test/ARRLayouts.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG MEM=arc CC=clang 3 | TEST_BUILD 4 | $C{COMPILE_NOLINK_NOMEM} -c $DIR/MRRBase.m 5 | $C{COMPILE_NOLINK_NOMEM} -c $DIR/MRRARR.m 6 | $C{COMPILE_NOLINK} -c $DIR/ARRBase.m 7 | $C{COMPILE_NOLINK} -c $DIR/ARRMRR.m 8 | $C{COMPILE} -fobjc-arc $DIR/ARRLayouts.m -x none MRRBase.o MRRARR.o ARRBase.o ARRMRR.o -framework Foundation -o ARRLayouts.out 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #import 14 | #import 15 | #import 16 | 17 | #import "ARRMRR.h" 18 | #import "MRRARR.h" 19 | 20 | @interface NSObject (Layouts) 21 | + (const char *)strongLayout; 22 | + (const char *)weakLayout; 23 | @end 24 | 25 | void printlayout(const char *name, const uint8_t *layout) 26 | { 27 | if (! getenv("VERBOSE")) return; 28 | 29 | testprintf("%s: ", name); 30 | 31 | if (!layout) { 32 | fprintf(stderr, "NULL\n"); 33 | return; 34 | } 35 | 36 | const uint8_t *c; 37 | for (c = layout; *c; c++) { 38 | fprintf(stderr, "%02x ", *c); 39 | } 40 | 41 | fprintf(stderr, "00\n"); 42 | } 43 | 44 | @implementation NSObject (Layouts) 45 | 46 | + (const char *)strongLayout { 47 | const uint8_t *layout = class_getIvarLayout(self); 48 | printlayout("strong", layout); 49 | return (const char *)layout; 50 | } 51 | 52 | + (const char *)weakLayout { 53 | const uint8_t *weakLayout = class_getWeakIvarLayout(self); 54 | printlayout("weak", weakLayout); 55 | return (const char *)weakLayout; 56 | } 57 | 58 | + (Ivar)instanceVariable:(const char *)name { 59 | return class_getInstanceVariable(self, name); 60 | } 61 | 62 | @end 63 | 64 | int main (int argc __unused, const char * argv[] __unused) { 65 | // Under ARR, layout strings are relative to the class' own ivars. 66 | testassert(strcmp([ARRBase strongLayout], "\x11\x20") == 0); 67 | testassert(strcmp([ARRBase weakLayout], "\x31") == 0); 68 | testassert([MRRBase strongLayout] == NULL); 69 | testassert([MRRBase weakLayout] == NULL); 70 | testassert(strcmp([ARRMRR strongLayout], "\x01") == 0); 71 | testassert([ARRMRR weakLayout] == NULL); 72 | testassert([MRRARR strongLayout] == NULL); 73 | testassert([MRRARR weakLayout] == NULL); 74 | 75 | // now check consistency between dynamic accessors and KVC, etc. 76 | ARRMRR *am = [ARRMRR new]; 77 | MRRARR *ma = [MRRARR new]; 78 | 79 | NSString *am_description = [[NSString alloc] initWithFormat:@"%s %p", "ARRMRR", am]; 80 | NSString *ma_description = [[NSString alloc] initWithFormat:@"%s %p", "MRRARR", ma]; 81 | 82 | am.number = M_PI; 83 | object_setIvar(am, [ARRMRR instanceVariable:"object"], am_description); 84 | testassert(CFGetRetainCount(objc_unretainedPointer(am_description)) == 1); 85 | am.pointer = @selector(ARRMRR); 86 | object_setIvar(am, [ARRMRR instanceVariable:"delegate"], ma); 87 | testassert(CFGetRetainCount(objc_unretainedPointer(ma)) == 1); 88 | 89 | ma.number = M_E; 90 | object_setIvar(ma, [MRRARR instanceVariable:"object"], ma_description); 91 | testassert(CFGetRetainCount(objc_unretainedPointer(ma_description)) == 2); 92 | ma.pointer = @selector(MRRARR); 93 | ma.delegate = am; 94 | object_setIvar(ma, [MRRARR instanceVariable:"delegate"], am); 95 | testassert(CFGetRetainCount(objc_unretainedPointer(am)) == 1); 96 | 97 | succeed(__FILE__); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /test/ARRMRR.h: -------------------------------------------------------------------------------- 1 | // 2 | // ARRMRR.h 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MRRBase.h" 10 | 11 | @interface ARRMRR : MRRBase 12 | @property(retain) id dataSource; 13 | @end 14 | -------------------------------------------------------------------------------- /test/ARRMRR.m: -------------------------------------------------------------------------------- 1 | // 2 | // ARRMRR.m 3 | // 4 | 5 | #import "ARRMRR.h" 6 | 7 | @implementation ARRMRR 8 | 9 | @synthesize dataSource; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /test/MRRARR.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRRARR.h 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ARRBase.h" 10 | 11 | @interface MRRARR : ARRBase 12 | @property(retain) id dataSource; 13 | @end 14 | -------------------------------------------------------------------------------- /test/MRRARR.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRRARR.m 3 | // 4 | 5 | #import "MRRARR.h" 6 | 7 | @implementation MRRARR 8 | 9 | @synthesize dataSource; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /test/MRRBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRRBase.h 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MRRBase : NSObject 12 | @property double number; 13 | @property(retain) id object; 14 | @property void *pointer; 15 | @property(weak) __weak id delegate; 16 | @end 17 | -------------------------------------------------------------------------------- /test/MRRBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRRBase.m 3 | // TestARRLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MRRBase.h" 10 | 11 | #if 1 12 | @interface MRRBase () { 13 | @private 14 | double number; 15 | id object; 16 | void *pointer; 17 | __weak id delegate; 18 | } 19 | @end 20 | #endif 21 | 22 | @implementation MRRBase 23 | @synthesize number, object, pointer, delegate; 24 | @end 25 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # quick test 2 | all: 3 | perl test.pl $(MAKEFLAGS) 4 | 5 | # default-arch but otherwise comprehensive test for buildbot 6 | buildbot: 7 | perl test.pl $(MAKEFLAGS) MEM=mrc,arc,gc CC=clang LANGUAGE=objc,objc++ 8 | 9 | # comprehensive tests 10 | mac macos macosx: 11 | perl test.pl $(MAKEFLAGS) ARCH=x86_64,i386 MEM=mrc,arc,gc CC=clang LANGUAGE=objc,objc++ 12 | 13 | iphonesimulator: 14 | perl test.pl $(MAKEFLAGS) ARCH=i386 SDK=iphonesimulator MEM=mrc,arc CC=clang LANGUAGE=objc,objc++ 15 | 16 | iphoneos: 17 | perl test.pl $(MAKEFLAGS) ARCH=armv6,armv7 SDK=iphoneos MEM=mrc,arc CC=clang LANGUAGE=objc,objc++ 18 | 19 | clean: 20 | @ perl test.pl clean 21 | -------------------------------------------------------------------------------- /test/accessors.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #import 4 | #import 5 | #import 6 | #include "test.h" 7 | 8 | @interface Test : NSObject { 9 | NSString *_value; 10 | // _object is at the last optimized property offset 11 | id _object __attribute__((aligned(64))); 12 | } 13 | @property(readonly) Class cls; 14 | @property(copy) NSString *value; 15 | @property(assign) id object; 16 | @end 17 | 18 | typedef struct { 19 | void *isa; 20 | void *_value; 21 | // _object is at the last optimized property offset 22 | void *_object __attribute__((aligned(64))); 23 | } TestDefs; 24 | 25 | @implementation Test 26 | 27 | // Question: why can't this code be automatically generated? 28 | 29 | #if !__has_feature(objc_arc) 30 | - (void)dealloc { 31 | self.value = nil; 32 | self.object = nil; 33 | [super dealloc]; 34 | } 35 | #endif 36 | 37 | - (Class)cls { return objc_getProperty(self, _cmd, 0, YES); } 38 | 39 | - (NSString*)value { return (NSString*) objc_getProperty(self, _cmd, offsetof(TestDefs, _value), YES); } 40 | - (void)setValue:(NSString*)inValue { objc_setProperty(self, _cmd, offsetof(TestDefs, _value), inValue, YES, YES); } 41 | 42 | - (id)object { return objc_getProperty(self, _cmd, offsetof(TestDefs, _object), YES); } 43 | - (void)setObject:(id)inObject { objc_setProperty(self, _cmd, offsetof(TestDefs, _object), inObject, YES, NO); } 44 | 45 | - (NSString *)description { 46 | return [NSString stringWithFormat:@"value = %@, object = %@", self.value, self.object]; 47 | } 48 | 49 | @end 50 | 51 | int main() { 52 | PUSH_POOL { 53 | 54 | NSMutableString *value = [NSMutableString stringWithUTF8String:"test"]; 55 | id object = [NSNumber numberWithInt:11]; 56 | Test *t = AUTORELEASE([Test new]); 57 | t.value = value; 58 | [value setString:@"yuck"]; // mutate the string. 59 | testassert(t.value != value); // must copy, since it was mutable. 60 | testassert([t.value isEqualToString:@"test"]); 61 | 62 | Class testClass = [Test class]; 63 | Class cls = t.cls; 64 | testassert(testClass == cls); 65 | cls = t.cls; 66 | testassert(testClass == cls); 67 | 68 | t.object = object; 69 | t.object = object; 70 | 71 | // NSLog(@"t.object = %@, t.value = %@", t.object, t.value); 72 | // NSLog(@"t.object = %@, t.value = %@", t.object, t.value); // second call will optimized getters. 73 | 74 | } POP_POOL; 75 | 76 | succeed(__FILE__); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /test/applescriptobjc.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=macosx 2 | // TEST_CFLAGS -framework AppleScriptObjC -framework Foundation 3 | 4 | // Verify that trivial AppleScriptObjC apps run with GC off. 5 | 6 | #include 7 | #include "test.h" 8 | 9 | int main() 10 | { 11 | [NSBundle class]; 12 | testassert(!objc_collectingEnabled()); 13 | succeed(__FILE__); 14 | } 15 | -------------------------------------------------------------------------------- /test/applescriptobjc2.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework AppleScriptObjC -framework Foundation 2 | // TEST_CONFIG MEM=gc 3 | 4 | // Verify that non-trivial AppleScriptObjC apps run with GC ON. 5 | 6 | #include 7 | #include "test.h" 8 | 9 | @interface NonTrivial : NSObject @end 10 | @implementation NonTrivial @end 11 | 12 | int main() 13 | { 14 | [NSBundle class]; 15 | testassert(objc_collectingEnabled()); 16 | succeed(__FILE__); 17 | } 18 | -------------------------------------------------------------------------------- /test/arr-cast.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | // objc.h redefines these calls into bridge casts. 6 | // This test verifies that the function implementations are exported. 7 | __BEGIN_DECLS 8 | extern void *retainedObject(void *arg) __asm__("_objc_retainedObject"); 9 | extern void *unretainedObject(void *arg) __asm__("_objc_unretainedObject"); 10 | extern void *unretainedPointer(void *arg) __asm__("_objc_unretainedPointer"); 11 | __END_DECLS 12 | 13 | int main() 14 | { 15 | void *p = (void*)&main; 16 | testassert(p == retainedObject(p)); 17 | testassert(p == unretainedObject(p)); 18 | testassert(p == unretainedPointer(p)); 19 | succeed(__FILE__); 20 | } 21 | -------------------------------------------------------------------------------- /test/association-cf.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework CoreFoundation 2 | 3 | #include 4 | #include 5 | 6 | #include "test.h" 7 | 8 | #if __has_feature(objc_arc) 9 | 10 | int main() 11 | { 12 | testwarn("rdar://11368528 confused by Foundation"); 13 | succeed(__FILE__); 14 | } 15 | 16 | #else 17 | 18 | int main() 19 | { 20 | // rdar://6164781 setAssociatedObject on pure-CF object crashes LP64 21 | 22 | id obj; 23 | id array = objc_retainedObject(CFArrayCreate(0, 0, 0, 0)); 24 | testassert(array); 25 | 26 | testassert(! objc_getClass("NSCFArray")); 27 | 28 | objc_setAssociatedObject(array, (void*)1, array, OBJC_ASSOCIATION_ASSIGN); 29 | 30 | obj = objc_getAssociatedObject(array, (void*)1); 31 | testassert(obj == array); 32 | 33 | RELEASE_VAR(array); 34 | 35 | succeed(__FILE__); 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /test/association.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | static int values; 8 | static int supers; 9 | static int subs; 10 | 11 | static const char *key = "key"; 12 | 13 | 14 | @interface Value : NSObject @end 15 | @interface Super : NSObject @end 16 | @interface Sub : NSObject @end 17 | 18 | @interface Super2 : NSObject @end 19 | @interface Sub2 : NSObject @end 20 | 21 | @implementation Super 22 | -(id) init 23 | { 24 | // rdar://8270243 don't lose associations after isa swizzling 25 | 26 | id value = [Value new]; 27 | objc_setAssociatedObject(self, &key, value, OBJC_ASSOCIATION_RETAIN); 28 | RELEASE_VAR(value); 29 | 30 | object_setClass(self, [Sub class]); 31 | 32 | return self; 33 | } 34 | 35 | -(void) dealloc 36 | { 37 | supers++; 38 | SUPER_DEALLOC(); 39 | } 40 | -(void) finalize 41 | { 42 | supers++; 43 | [super finalize]; 44 | } 45 | 46 | @end 47 | 48 | @implementation Sub 49 | -(void) dealloc 50 | { 51 | subs++; 52 | SUPER_DEALLOC(); 53 | } 54 | -(void) finalize 55 | { 56 | subs++; 57 | [super finalize]; 58 | } 59 | @end 60 | 61 | @implementation Super2 62 | -(id) init 63 | { 64 | // rdar://9617109 don't lose associations after isa swizzling 65 | 66 | id value = [Value new]; 67 | object_setClass(self, [Sub2 class]); 68 | objc_setAssociatedObject(self, &key, value, OBJC_ASSOCIATION_RETAIN); 69 | RELEASE_VAR(value); 70 | object_setClass(self, [Super2 class]); 71 | 72 | return self; 73 | } 74 | 75 | -(void) dealloc 76 | { 77 | supers++; 78 | SUPER_DEALLOC(); 79 | } 80 | -(void) finalize 81 | { 82 | supers++; 83 | [super finalize]; 84 | } 85 | 86 | @end 87 | 88 | @implementation Sub2 89 | -(void) dealloc 90 | { 91 | subs++; 92 | SUPER_DEALLOC(); 93 | } 94 | -(void) finalize 95 | { 96 | subs++; 97 | [super finalize]; 98 | } 99 | @end 100 | 101 | @implementation Value 102 | -(void) dealloc { 103 | values++; 104 | SUPER_DEALLOC(); 105 | } 106 | -(void) finalize { 107 | values++; 108 | [super finalize]; 109 | } 110 | @end 111 | 112 | 113 | int main() 114 | { 115 | testonthread(^{ 116 | int i; 117 | for (i = 0; i < 100; i++) { 118 | RELEASE_VALUE([[Super alloc] init]); 119 | } 120 | }); 121 | testcollect(); 122 | 123 | testassert(supers == 0); 124 | testassert(subs > 0); 125 | testassert(subs == values); 126 | 127 | 128 | supers = 0; 129 | subs = 0; 130 | values = 0; 131 | 132 | testonthread(^{ 133 | int i; 134 | for (i = 0; i < 100; i++) { 135 | RELEASE_VALUE([[Super2 alloc] init]); 136 | } 137 | }); 138 | testcollect(); 139 | 140 | testassert(supers > 0); 141 | testassert(subs == 0); 142 | testassert(supers == values); 143 | 144 | succeed(__FILE__); 145 | } 146 | -------------------------------------------------------------------------------- /test/atomicProperty.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG CC=clang 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #import 7 | 8 | class SerialNumber { 9 | size_t _number; 10 | public: 11 | SerialNumber() : _number(42) {} 12 | SerialNumber(const SerialNumber &number) : _number(number._number + 1) {} 13 | SerialNumber &operator=(const SerialNumber &number) { _number = number._number + 1; return *this; } 14 | 15 | int operator==(const SerialNumber &number) { return _number == number._number; } 16 | int operator!=(const SerialNumber &number) { return _number != number._number; } 17 | }; 18 | 19 | @interface TestAtomicProperty : NSObject { 20 | SerialNumber number; 21 | } 22 | @property(atomic) SerialNumber number; 23 | @end 24 | 25 | @implementation TestAtomicProperty 26 | 27 | @synthesize number; 28 | 29 | @end 30 | 31 | int main() 32 | { 33 | PUSH_POOL { 34 | SerialNumber number; 35 | TestAtomicProperty *test = [TestAtomicProperty new]; 36 | test.number = number; 37 | testassert(test.number != number); 38 | } POP_POOL; 39 | 40 | succeed(__FILE__); 41 | } 42 | -------------------------------------------------------------------------------- /test/badAltHandler.m: -------------------------------------------------------------------------------- 1 | // for OBJC2 mac only 2 | /* TEST_CONFIG OS=macosx ARCH=x86_64 3 | TEST_CRASHES 4 | 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: objc_removeExceptionHandler\(\) called with unknown alt handler; this is probably a bug in multithreaded AppKit use. Set environment variable OBJC_DEBUG_ALT_HANDLERS=YES or break in objc_alt_handler_error\(\) to debug. 7 | CRASHED: SIGILL 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | /* 16 | rdar://6888838 17 | Mail installs an alt handler on one thread and deletes it on another. 18 | This confuses the alt handler machinery, which halts the process. 19 | */ 20 | 21 | uintptr_t Token; 22 | 23 | void handler(id unused __unused, void *context __unused) 24 | { 25 | } 26 | 27 | int main() 28 | { 29 | #if __clang__ && __cplusplus 30 | // alt handlers need the objc personality 31 | // catch (id) workaround forces the objc personality 32 | @try { 33 | testwarn("rdar://9183014 clang uses wrong exception personality"); 34 | } @catch (id e __unused) { 35 | } 36 | #endif 37 | 38 | @try { 39 | // Install 4 alt handlers 40 | uintptr_t t1, t2, t3, t4; 41 | t1 = objc_addExceptionHandler(&handler, NULL); 42 | t2 = objc_addExceptionHandler(&handler, NULL); 43 | t3 = objc_addExceptionHandler(&handler, NULL); 44 | t4 = objc_addExceptionHandler(&handler, NULL); 45 | 46 | // Remove 3 of them. 47 | objc_removeExceptionHandler(t1); 48 | objc_removeExceptionHandler(t2); 49 | objc_removeExceptionHandler(t3); 50 | 51 | // Create an alt handler on another thread 52 | // that collides with one of the removed handlers 53 | testonthread(^{ 54 | @try { 55 | Token = objc_addExceptionHandler(&handler, NULL); 56 | } @catch (...) { 57 | } 58 | }); 59 | 60 | // Incorrectly remove the other thread's handler 61 | objc_removeExceptionHandler(Token); 62 | // Remove the 4th handler 63 | objc_removeExceptionHandler(t4); 64 | 65 | // Install 8 more handlers. 66 | // If the other thread's handler was not ignored, 67 | // this will fail. 68 | objc_addExceptionHandler(&handler, NULL); 69 | objc_addExceptionHandler(&handler, NULL); 70 | objc_addExceptionHandler(&handler, NULL); 71 | objc_addExceptionHandler(&handler, NULL); 72 | objc_addExceptionHandler(&handler, NULL); 73 | objc_addExceptionHandler(&handler, NULL); 74 | objc_addExceptionHandler(&handler, NULL); 75 | objc_addExceptionHandler(&handler, NULL); 76 | } @catch (...) { 77 | } 78 | 79 | // This should have crashed earlier. 80 | fail(__FILE__); 81 | } 82 | -------------------------------------------------------------------------------- /test/badCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_RUN_OUTPUT 4 | objc1 5 | OK: badCache.m 6 | OR 7 | crash now 8 | objc\[\d+\]: Method cache corrupted.* 9 | objc\[\d+\]: .* 10 | objc\[\d+\]: .* 11 | objc\[\d+\]: .* 12 | objc\[\d+\]: .* 13 | objc\[\d+\]: Method cache corrupted\. 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | 19 | #include "test.h" 20 | 21 | #if !__OBJC2__ || __arm__ 22 | 23 | int main() 24 | { 25 | fprintf(stderr, "objc1\n"); 26 | succeed(__FILE__); 27 | } 28 | 29 | #else 30 | 31 | #include "testroot.i" 32 | 33 | #if __LP64__ 34 | typedef uint32_t mask_t; 35 | #else 36 | typedef uint16_t mask_t; 37 | #endif 38 | 39 | struct bucket_t { 40 | uintptr_t sel; 41 | uintptr_t imp; 42 | }; 43 | 44 | struct cache_t { 45 | struct bucket_t *buckets; 46 | mask_t mask; 47 | mask_t occupied; 48 | }; 49 | 50 | struct class_t { 51 | void *isa; 52 | void *supercls; 53 | struct cache_t cache; 54 | }; 55 | 56 | @interface Subclass : TestRoot @end 57 | @implementation Subclass @end 58 | 59 | int main() 60 | { 61 | Class cls = [TestRoot class]; 62 | id obj = [cls new]; 63 | [obj self]; 64 | 65 | struct cache_t *cache = &((__bridge struct class_t *)cls)->cache; 66 | 67 | # define COUNT 4 68 | struct bucket_t *buckets = calloc(sizeof(struct bucket_t), COUNT+1); 69 | for (int i = 0; i < COUNT; i++) { 70 | buckets[i].sel = ~0; 71 | buckets[i].imp = ~0; 72 | } 73 | buckets[COUNT].sel = 1; 74 | buckets[COUNT].imp = (uintptr_t)buckets; 75 | 76 | cache->mask = COUNT-1; 77 | cache->occupied = 0; 78 | cache->buckets = buckets; 79 | 80 | fprintf(stderr, "crash now\n"); 81 | [obj self]; 82 | 83 | fail("should have crashed"); 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /test/badTagClass.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: tag index 7 used for two different classes \(was 0x[0-9a-fA-F]+ NSObject, now 0x[0-9a-fA-F]+ TestRoot\) 5 | CRASHED: SIG(ILL|TRAP) 6 | OR 7 | no tagged pointers 8 | OK: badTagClass.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #include "testroot.i" 14 | 15 | #include 16 | #include 17 | 18 | #if OBJC_HAVE_TAGGED_POINTERS 19 | 20 | int main() 21 | { 22 | // re-registration and nil registration allowed 23 | _objc_registerTaggedPointerClass(OBJC_TAG_7, [NSObject class]); 24 | _objc_registerTaggedPointerClass(OBJC_TAG_7, [NSObject class]); 25 | _objc_registerTaggedPointerClass(OBJC_TAG_7, nil); 26 | _objc_registerTaggedPointerClass(OBJC_TAG_7, [NSObject class]); 27 | 28 | // colliding registration disallowed 29 | _objc_registerTaggedPointerClass(OBJC_TAG_7, [TestRoot class]); 30 | 31 | fail(__FILE__); 32 | } 33 | 34 | #else 35 | 36 | int main() 37 | { 38 | fprintf(stderr, "no tagged pointers\n"); 39 | succeed(__FILE__); 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /test/badTagIndex.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: tag index 8 is too large. 5 | CRASHED: SIG(ILL|TRAP) 6 | OR 7 | no tagged pointers 8 | OK: badTagIndex.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | 14 | #include 15 | #include 16 | 17 | #if OBJC_HAVE_TAGGED_POINTERS 18 | 19 | int main() 20 | { 21 | _objc_registerTaggedPointerClass((objc_tag_index_t)8, [NSObject class]); 22 | fail(__FILE__); 23 | } 24 | 25 | #else 26 | 27 | int main() 28 | { 29 | fprintf(stderr, "no tagged pointers\n"); 30 | succeed(__FILE__); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /test/bigrc.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | /* 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: Deallocator object 0x[0-9a-fA-F]+ overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug 5 | OK: bigrc.m 6 | OR 7 | no overrelease enforcement 8 | OK: bigrc.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #include "testroot.i" 14 | 15 | static size_t LOTS; 16 | 17 | @interface Deallocator : TestRoot @end 18 | @implementation Deallocator 19 | 20 | -(void)dealloc 21 | { 22 | id o = self; 23 | size_t rc = 1; 24 | 25 | 26 | testprintf("Retain a lot during dealloc\n"); 27 | 28 | testassert(rc == 1); 29 | testassert([o retainCount] == rc); 30 | do { 31 | [o retain]; 32 | if (rc % 0x100000 == 0) testprintf("%zx/%zx ++\n", rc, LOTS); 33 | } while (++rc < LOTS); 34 | 35 | testassert([o retainCount] == rc); 36 | 37 | do { 38 | [o release]; 39 | if (rc % 0x100000 == 0) testprintf("%zx/%zx --\n", rc, LOTS); 40 | } while (--rc > 1); 41 | 42 | testassert(rc == 1); 43 | testassert([o retainCount] == rc); 44 | 45 | 46 | testprintf("Overrelease during dealloc\n"); 47 | 48 | // Not all architectures enforce this. 49 | #if !SUPPORT_NONPOINTER_ISA 50 | testwarn("no overrelease enforcement"); 51 | fprintf(stderr, "no overrelease enforcement\n"); 52 | #endif 53 | [o release]; 54 | 55 | [super dealloc]; 56 | } 57 | 58 | @end 59 | 60 | 61 | int main() 62 | { 63 | Deallocator *o = [Deallocator new]; 64 | size_t rc = 1; 65 | 66 | [o retain]; 67 | 68 | uintptr_t isa = *(uintptr_t *)o; 69 | if (isa & 1) { 70 | // Assume refcount in high bits. 71 | LOTS = 1 << (4 + __builtin_clzll(isa)); 72 | testprintf("LOTS %zu via cntlzw\n", LOTS); 73 | } else { 74 | LOTS = 0x1000000; 75 | testprintf("LOTS %zu via guess\n", LOTS); 76 | } 77 | 78 | [o release]; 79 | 80 | 81 | testprintf("Retain a lot\n"); 82 | 83 | testassert(rc == 1); 84 | testassert([o retainCount] == rc); 85 | do { 86 | [o retain]; 87 | if (rc % 0x100000 == 0) testprintf("%zx/%zx ++\n", rc, LOTS); 88 | } while (++rc < LOTS); 89 | 90 | testassert([o retainCount] == rc); 91 | 92 | do { 93 | [o release]; 94 | if (rc % 0x100000 == 0) testprintf("%zx/%zx --\n", rc, LOTS); 95 | } while (--rc > 1); 96 | 97 | testassert(rc == 1); 98 | testassert([o retainCount] == rc); 99 | 100 | 101 | testprintf("tryRetain a lot\n"); 102 | 103 | id w; 104 | objc_storeWeak(&w, o); 105 | testassert(w == o); 106 | 107 | testassert(rc == 1); 108 | testassert([o retainCount] == rc); 109 | do { 110 | objc_loadWeakRetained(&w); 111 | if (rc % 0x100000 == 0) testprintf("%zx/%zx ++\n", rc, LOTS); 112 | } while (++rc < LOTS); 113 | 114 | testassert([o retainCount] == rc); 115 | 116 | do { 117 | [o release]; 118 | if (rc % 0x100000 == 0) testprintf("%zx/%zx --\n", rc, LOTS); 119 | } while (--rc > 1); 120 | 121 | testassert(rc == 1); 122 | testassert([o retainCount] == rc); 123 | 124 | testprintf("dealloc\n"); 125 | 126 | testassert(TestRootDealloc == 0); 127 | testassert(w != nil); 128 | [o release]; 129 | testassert(TestRootDealloc == 1); 130 | testassert(w == nil); 131 | 132 | succeed(__FILE__); 133 | } 134 | -------------------------------------------------------------------------------- /test/cacheflush.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.h" 3 | 4 | @interface TestRoot(cat) 5 | +(int)classMethod; 6 | -(int)instanceMethod; 7 | @end 8 | -------------------------------------------------------------------------------- /test/cacheflush.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/cacheflush0.m -o cacheflush0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/cacheflush2.m -x none cacheflush0.dylib -o cacheflush2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/cacheflush3.m -x none cacheflush0.dylib -o cacheflush3.dylib -dynamiclib 6 | $C{COMPILE} $DIR/cacheflush.m -x none cacheflush0.dylib -o cacheflush.out 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | #include 12 | #include 13 | 14 | #include "cacheflush.h" 15 | 16 | @interface Sub : TestRoot @end 17 | @implementation Sub @end 18 | 19 | 20 | int main() 21 | { 22 | TestRoot *sup = [TestRoot new]; 23 | Sub *sub = [Sub new]; 24 | 25 | // Fill method cache 26 | testassert(1 == [TestRoot classMethod]); 27 | testassert(1 == [sup instanceMethod]); 28 | testassert(1 == [TestRoot classMethod]); 29 | testassert(1 == [sup instanceMethod]); 30 | 31 | testassert(1 == [Sub classMethod]); 32 | testassert(1 == [sub instanceMethod]); 33 | testassert(1 == [Sub classMethod]); 34 | testassert(1 == [sub instanceMethod]); 35 | 36 | // Dynamically load a category 37 | dlopen("cacheflush2.dylib", 0); 38 | 39 | // Make sure old cache results are gone 40 | testassert(2 == [TestRoot classMethod]); 41 | testassert(2 == [sup instanceMethod]); 42 | 43 | testassert(2 == [Sub classMethod]); 44 | testassert(2 == [sub instanceMethod]); 45 | 46 | // Dynamically load another category 47 | dlopen("cacheflush3.dylib", 0); 48 | 49 | // Make sure old cache results are gone 50 | testassert(3 == [TestRoot classMethod]); 51 | testassert(3 == [sup instanceMethod]); 52 | 53 | testassert(3 == [Sub classMethod]); 54 | testassert(3 == [sub instanceMethod]); 55 | 56 | // fixme test subclasses 57 | 58 | // fixme test objc_flush_caches(), class_addMethod(), class_addMethods() 59 | 60 | succeed(__FILE__); 61 | } 62 | -------------------------------------------------------------------------------- /test/cacheflush0.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | #include "testroot.i" 3 | 4 | @implementation TestRoot(cat) 5 | +(int)classMethod { return 1; } 6 | -(int)instanceMethod { return 1; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/cacheflush2.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | 3 | @implementation TestRoot (Category2) 4 | +(int)classMethod { return 2; } 5 | -(int)instanceMethod { return 2; } 6 | @end 7 | -------------------------------------------------------------------------------- /test/cacheflush3.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | 3 | @implementation TestRoot (Category3) 4 | +(int)classMethod { return 3; } 5 | -(int)instanceMethod { return 3; } 6 | @end 7 | -------------------------------------------------------------------------------- /test/category.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -Wl,-no_objc_category_merging 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | 8 | static int state = 0; 9 | 10 | @interface Super : TestRoot @end 11 | @implementation Super 12 | -(void)instancemethod { fail("-instancemethod not overridden by category"); } 13 | +(void)method { fail("+method not overridden by category"); } 14 | @end 15 | 16 | @interface Super (Category) @end 17 | @implementation Super (Category) 18 | +(void)method { 19 | testprintf("in [Super(Category) method]\n"); 20 | testassert(self == [Super class]); 21 | testassert(state == 0); 22 | state = 1; 23 | } 24 | -(void)instancemethod { 25 | testprintf("in [Super(Category) instancemethod]\n"); 26 | testassert(object_getClass(self) == [Super class]); 27 | testassert(state == 1); 28 | state = 2; 29 | } 30 | @end 31 | 32 | @interface Super (PropertyCategory) 33 | @property int i; 34 | @end 35 | @implementation Super (PropertyCategory) 36 | - (int)i { return 0; } 37 | - (void)setI:(int)value { (void)value; } 38 | @end 39 | 40 | // rdar://5086110 memory smasher in category with class method and property 41 | @interface Super (r5086110) 42 | @property int property5086110; 43 | @end 44 | @implementation Super (r5086110) 45 | +(void)method5086110 { 46 | fail("method method5086110 called!"); 47 | } 48 | - (int)property5086110 { fail("property5086110 called!"); return 0; } 49 | - (void)setProperty5086110:(int)value { fail("setProperty5086110 called!"); (void)value; } 50 | @end 51 | 52 | 53 | @interface PropertyClass : Super { 54 | int q; 55 | } 56 | @property(readonly) int q; 57 | @end 58 | @implementation PropertyClass 59 | @synthesize q; 60 | @end 61 | 62 | @interface PropertyClass (PropertyCategory) 63 | @property int q; 64 | @end 65 | @implementation PropertyClass (PropertyCategory) 66 | @dynamic q; 67 | @end 68 | 69 | 70 | int main() 71 | { 72 | // methods introduced by category 73 | state = 0; 74 | [Super method]; 75 | [[Super new] instancemethod]; 76 | testassert(state == 2); 77 | 78 | // property introduced by category 79 | objc_property_t p = class_getProperty([Super class], "i"); 80 | testassert(p); 81 | testassert(0 == strcmp(property_getName(p), "i")); 82 | testassert(property_getAttributes(p)); 83 | 84 | // methods introduced by category's property 85 | Method m; 86 | m = class_getInstanceMethod([Super class], @selector(i)); 87 | testassert(m); 88 | m = class_getInstanceMethod([Super class], @selector(setI:)); 89 | testassert(m); 90 | 91 | // class's property shadowed by category's property 92 | objc_property_t *plist = class_copyPropertyList([PropertyClass class], NULL); 93 | testassert(plist); 94 | testassert(plist[0]); 95 | testassert(0 == strcmp(property_getName(plist[0]), "q")); 96 | testassert(0 == strcmp(property_getAttributes(plist[0]), "Ti,D")); 97 | testassert(plist[1]); 98 | testassert(0 == strcmp(property_getName(plist[1]), "q")); 99 | testassert(0 == strcmp(property_getAttributes(plist[1]), "Ti,R,Vq")); 100 | testassert(!plist[2]); 101 | free(plist); 102 | 103 | succeed(__FILE__); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /test/classgetclass.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #import 7 | 8 | @interface Foo:NSObject 9 | @end 10 | @implementation Foo 11 | @end 12 | 13 | int main() 14 | { 15 | #if __OBJC2__ 16 | testassert(gdb_class_getClass([Foo class]) == [Foo class]); 17 | #endif 18 | 19 | succeed(__FILE__); 20 | } 21 | -------------------------------------------------------------------------------- /test/classname.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | 8 | @interface Fake : TestRoot @end 9 | @implementation Fake @end 10 | 11 | int main() 12 | { 13 | TestRoot *obj = [TestRoot new]; 14 | Class __unsafe_unretained * buf = (Class *)objc_unretainedPointer(obj); 15 | *buf = [Fake class]; 16 | 17 | testassert(object_getClass(obj) == [Fake class]); 18 | testassert(object_setClass(obj, [TestRoot class]) == [Fake class]); 19 | testassert(object_getClass(obj) == [TestRoot class]); 20 | testassert(object_setClass(nil, [TestRoot class]) == nil); 21 | 22 | testassert(malloc_size(buf) >= sizeof(id)); 23 | bzero(buf, malloc_size(buf)); 24 | testassert(object_setClass(obj, [TestRoot class]) == nil); 25 | 26 | testassert(object_getClass(obj) == [TestRoot class]); 27 | testassert(object_getClass([TestRoot class]) == object_getClass([TestRoot class])); 28 | testassert(object_getClass(nil) == Nil); 29 | 30 | testassert(0 == strcmp(object_getClassName(obj), "TestRoot")); 31 | testassert(0 == strcmp(object_getClassName([TestRoot class]), "TestRoot")); 32 | testassert(0 == strcmp(object_getClassName(nil), "nil")); 33 | 34 | testassert(0 == strcmp(class_getName([TestRoot class]), "TestRoot")); 35 | testassert(0 == strcmp(class_getName(object_getClass([TestRoot class])), "TestRoot")); 36 | testassert(0 == strcmp(class_getName(nil), "nil")); 37 | 38 | succeed(__FILE__); 39 | } 40 | -------------------------------------------------------------------------------- /test/classversion.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | int main() 8 | { 9 | Class cls = [TestRoot class]; 10 | testassert(class_getVersion(cls) == 0); 11 | testassert(class_getVersion(object_getClass(cls)) > 5); 12 | class_setVersion(cls, 100); 13 | testassert(class_getVersion(cls) == 100); 14 | 15 | testassert(class_getVersion(Nil) == 0); 16 | class_setVersion(Nil, 100); 17 | 18 | succeed(__FILE__); 19 | } 20 | -------------------------------------------------------------------------------- /test/concurrentcat_category.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #import 4 | 5 | @interface TargetClass : NSObject 6 | @end 7 | 8 | @interface TargetClass(LoadedMethods) 9 | - (void) m0; 10 | - (void) m1; 11 | - (void) m2; 12 | - (void) m3; 13 | - (void) m4; 14 | - (void) m5; 15 | - (void) m6; 16 | - (void) m7; 17 | - (void) m8; 18 | - (void) m9; 19 | - (void) m10; 20 | - (void) m11; 21 | - (void) m12; 22 | - (void) m13; 23 | - (void) m14; 24 | - (void) m15; 25 | @end 26 | 27 | @interface TN:TargetClass 28 | @end 29 | 30 | @implementation TN 31 | - (void) m1 { [super m1]; } 32 | - (void) m3 { [self m1]; } 33 | 34 | - (void) m2 35 | { 36 | [self willChangeValueForKey: @"m4"]; 37 | [self didChangeValueForKey: @"m4"]; 38 | } 39 | 40 | - (void)observeValueForKeyPath:(NSString *) keyPath 41 | ofObject:(id)object 42 | change:(NSDictionary *)change 43 | context:(void *)context 44 | { 45 | // suppress warning 46 | keyPath = nil; 47 | object = nil; 48 | change = nil; 49 | context = NULL; 50 | } 51 | @end 52 | 53 | @implementation TargetClass(LoadedMethods) 54 | - (void) m0 { ; } 55 | - (void) m1 { ; } 56 | - (void) m2 { ; } 57 | - (void) m3 { ; } 58 | - (void) m4 { ; } 59 | - (void) m5 { ; } 60 | - (void) m6 { ; } 61 | - (void) m7 { ; } 62 | - (void) m8 { ; } 63 | - (void) m9 { ; } 64 | - (void) m10 { ; } 65 | - (void) m11 { ; } 66 | - (void) m12 { ; } 67 | - (void) m13 { ; } 68 | - (void) m14 { ; } 69 | - (void) m15 { ; } 70 | @end 71 | -------------------------------------------------------------------------------- /test/copyIvarList.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #include 7 | 8 | OBJC_ROOT_CLASS 9 | @interface SuperIvars { 10 | id isa; 11 | int ivar1; 12 | int ivar2; 13 | } @end 14 | @implementation SuperIvars @end 15 | 16 | @interface SubIvars : SuperIvars { 17 | int ivar3; 18 | int ivar4; 19 | } @end 20 | @implementation SubIvars @end 21 | 22 | OBJC_ROOT_CLASS 23 | @interface FourIvars { 24 | int ivar1; 25 | int ivar2; 26 | int ivar3; 27 | int ivar4; 28 | } @end 29 | @implementation FourIvars @end 30 | 31 | OBJC_ROOT_CLASS 32 | @interface NoIvars { } @end 33 | @implementation NoIvars @end 34 | 35 | static int isNamed(Ivar iv, const char *name) 36 | { 37 | return (0 == strcmp(name, ivar_getName(iv))); 38 | } 39 | 40 | int main() 41 | { 42 | Ivar *ivars; 43 | unsigned int count; 44 | Class cls; 45 | 46 | cls = objc_getClass("SubIvars"); 47 | testassert(cls); 48 | 49 | count = 100; 50 | ivars = class_copyIvarList(cls, &count); 51 | testassert(ivars); 52 | testassert(count == 2); 53 | testassert(isNamed(ivars[0], "ivar3")); 54 | testassert(isNamed(ivars[1], "ivar4")); 55 | // ivars[] should be null-terminated 56 | testassert(ivars[2] == NULL); 57 | free(ivars); 58 | 59 | cls = objc_getClass("SuperIvars"); 60 | testassert(cls); 61 | 62 | count = 100; 63 | ivars = class_copyIvarList(cls, &count); 64 | testassert(ivars); 65 | testassert(count == 3); 66 | testassert(isNamed(ivars[0], "isa")); 67 | testassert(isNamed(ivars[1], "ivar1")); 68 | testassert(isNamed(ivars[2], "ivar2")); 69 | // ivars[] should be null-terminated 70 | testassert(ivars[3] == NULL); 71 | free(ivars); 72 | 73 | // Check null-termination - this ivar list block would be 16 bytes 74 | // if it weren't for the terminator 75 | cls = objc_getClass("FourIvars"); 76 | testassert(cls); 77 | 78 | count = 100; 79 | ivars = class_copyIvarList(cls, &count); 80 | testassert(ivars); 81 | testassert(count == 4); 82 | testassert(malloc_size(ivars) >= 5 * sizeof(Ivar)); 83 | testassert(ivars[3] != NULL); 84 | testassert(ivars[4] == NULL); 85 | free(ivars); 86 | 87 | // Check NULL count parameter 88 | ivars = class_copyIvarList(cls, NULL); 89 | testassert(ivars); 90 | testassert(ivars[4] == NULL); 91 | testassert(ivars[3] != NULL); 92 | free(ivars); 93 | 94 | // Check NULL class parameter 95 | count = 100; 96 | ivars = class_copyIvarList(NULL, &count); 97 | testassert(!ivars); 98 | testassert(count == 0); 99 | 100 | // Check NULL class and count 101 | ivars = class_copyIvarList(NULL, NULL); 102 | testassert(!ivars); 103 | 104 | // Check class with no ivars 105 | cls = objc_getClass("NoIvars"); 106 | testassert(cls); 107 | 108 | count = 100; 109 | ivars = class_copyIvarList(cls, &count); 110 | testassert(!ivars); 111 | testassert(count == 0); 112 | 113 | succeed(__FILE__); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /test/copyPropertyList.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #include 7 | 8 | OBJC_ROOT_CLASS 9 | @interface SuperProps { id isa; int prop1; int prop2; } 10 | @property int prop1; 11 | @property int prop2; 12 | @end 13 | @implementation SuperProps 14 | @synthesize prop1; 15 | @synthesize prop2; 16 | @end 17 | 18 | @interface SubProps : SuperProps { int prop3; int prop4; } 19 | @property int prop3; 20 | @property int prop4; 21 | @end 22 | @implementation SubProps 23 | @synthesize prop3; 24 | @synthesize prop4; 25 | @end 26 | 27 | OBJC_ROOT_CLASS 28 | @interface FourProps { int prop1; int prop2; int prop3; int prop4; } 29 | @property int prop1; 30 | @property int prop2; 31 | @property int prop3; 32 | @property int prop4; 33 | @end 34 | @implementation FourProps 35 | @synthesize prop1; 36 | @synthesize prop2; 37 | @synthesize prop3; 38 | @synthesize prop4; 39 | @end 40 | 41 | OBJC_ROOT_CLASS 42 | @interface NoProps @end 43 | @implementation NoProps @end 44 | 45 | static int isNamed(objc_property_t p, const char *name) 46 | { 47 | return (0 == strcmp(name, property_getName(p))); 48 | } 49 | 50 | int main() 51 | { 52 | objc_property_t *props; 53 | unsigned int count; 54 | Class cls; 55 | 56 | cls = objc_getClass("SubProps"); 57 | testassert(cls); 58 | 59 | count = 100; 60 | props = class_copyPropertyList(cls, &count); 61 | testassert(props); 62 | testassert(count == 2); 63 | testassert((isNamed(props[0], "prop3") && isNamed(props[1], "prop4")) || 64 | (isNamed(props[1], "prop3") && isNamed(props[0], "prop4"))); 65 | // props[] should be null-terminated 66 | testassert(props[2] == NULL); 67 | free(props); 68 | 69 | cls = objc_getClass("SuperProps"); 70 | testassert(cls); 71 | 72 | count = 100; 73 | props = class_copyPropertyList(cls, &count); 74 | testassert(props); 75 | testassert(count == 2); 76 | testassert((isNamed(props[0], "prop1") && isNamed(props[1], "prop2")) || 77 | (isNamed(props[1], "prop1") && isNamed(props[0], "prop2"))); 78 | // props[] should be null-terminated 79 | testassert(props[2] == NULL); 80 | free(props); 81 | 82 | // Check null-termination - this property list block would be 16 bytes 83 | // if it weren't for the terminator 84 | cls = objc_getClass("FourProps"); 85 | testassert(cls); 86 | 87 | count = 100; 88 | props = class_copyPropertyList(cls, &count); 89 | testassert(props); 90 | testassert(count == 4); 91 | testassert(malloc_size(props) >= 5 * sizeof(objc_property_t)); 92 | testassert(props[3] != NULL); 93 | testassert(props[4] == NULL); 94 | free(props); 95 | 96 | // Check NULL count parameter 97 | props = class_copyPropertyList(cls, NULL); 98 | testassert(props); 99 | testassert(props[4] == NULL); 100 | testassert(props[3] != NULL); 101 | free(props); 102 | 103 | // Check NULL class parameter 104 | count = 100; 105 | props = class_copyPropertyList(NULL, &count); 106 | testassert(!props); 107 | testassert(count == 0); 108 | 109 | // Check NULL class and count 110 | props = class_copyPropertyList(NULL, NULL); 111 | testassert(!props); 112 | 113 | // Check class with no properties 114 | cls = objc_getClass("NoProps"); 115 | testassert(cls); 116 | 117 | count = 100; 118 | props = class_copyPropertyList(cls, &count); 119 | testassert(!props); 120 | testassert(count == 0); 121 | 122 | succeed(__FILE__); 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /test/createInstance.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,gc 2 | // TEST_CFLAGS -Wno-deprecated-declarations 3 | 4 | #import 5 | #import 6 | #ifndef OBJC_NO_GC 7 | #include 8 | #else 9 | static BOOL auto_zone_is_valid_pointer(void *a, void *b) { return a||b; } 10 | #endif 11 | #include "test.h" 12 | 13 | OBJC_ROOT_CLASS 14 | @interface Super { @public id isa; } @end 15 | @implementation Super 16 | +(void) initialize { } 17 | +(Class) class { return self; } 18 | @end 19 | 20 | @interface Sub : Super { int array[128]; } @end 21 | @implementation Sub @end 22 | 23 | int main() 24 | { 25 | Super *s; 26 | 27 | s = class_createInstance([Super class], 0); 28 | testassert(s); 29 | testassert(object_getClass(s) == [Super class]); 30 | testassert(malloc_size(s) >= class_getInstanceSize([Super class])); 31 | if (objc_collectingEnabled()) testassert(auto_zone_is_valid_pointer(objc_collectableZone(), s)); 32 | 33 | object_dispose(s); 34 | 35 | s = class_createInstance([Sub class], 0); 36 | testassert(s); 37 | testassert(object_getClass(s) == [Sub class]); 38 | testassert(malloc_size(s) >= class_getInstanceSize([Sub class])); 39 | if (objc_collectingEnabled()) testassert(auto_zone_is_valid_pointer(objc_collectableZone(), s)); 40 | 41 | object_dispose(s); 42 | 43 | s = class_createInstance([Super class], 100); 44 | testassert(s); 45 | testassert(object_getClass(s) == [Super class]); 46 | testassert(malloc_size(s) >= class_getInstanceSize([Super class]) + 100); 47 | if (objc_collectingEnabled()) testassert(auto_zone_is_valid_pointer(objc_collectableZone(), s)); 48 | 49 | object_dispose(s); 50 | 51 | s = class_createInstance([Sub class], 100); 52 | testassert(s); 53 | testassert(object_getClass(s) == [Sub class]); 54 | testassert(malloc_size(s) >= class_getInstanceSize([Sub class]) + 100); 55 | if (objc_collectingEnabled()) testassert(auto_zone_is_valid_pointer(objc_collectableZone(), s)); 56 | 57 | object_dispose(s); 58 | 59 | s = class_createInstance(Nil, 0); 60 | testassert(!s); 61 | 62 | succeed(__FILE__); 63 | } 64 | -------------------------------------------------------------------------------- /test/customrr-cat1.m: -------------------------------------------------------------------------------- 1 | @interface InheritingSubCat @end 2 | 3 | @interface InheritingSubCat (NonClobberingCategory) @end 4 | 5 | @implementation InheritingSubCat (NonClobberingCategory) 6 | -(id) unrelatedMethod { return self; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/customrr-cat2.m: -------------------------------------------------------------------------------- 1 | @interface InheritingSubCat @end 2 | 3 | @interface InheritingSubCat (ClobberingCategory) @end 4 | 5 | @implementation InheritingSubCat (ClobberingCategory) 6 | -(int) retainCount { return 1; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/customrr-nsobject-awz.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-awz.out -DSWIZZLE_AWZ=1 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 12 | OK: customrr-nsobject-awz.out 13 | END 14 | 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /test/customrr-nsobject-none.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-none.out 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | OK: customrr-nsobject-none.out 12 | END 13 | 14 | */ 15 | 16 | -------------------------------------------------------------------------------- /test/customrr-nsobject-rr.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-rr.out -DSWIZZLE_RELEASE=1 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM RR: NSObject 12 | OK: customrr-nsobject-rr.out 13 | END 14 | 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /test/customrr-nsobject-rrawz.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-rrawz.out -DSWIZZLE_RELEASE=1 -DSWIZZLE_AWZ=1 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 12 | objc\[\d+\]: CUSTOM RR: NSObject 13 | OK: customrr-nsobject-rrawz.out 14 | END 15 | 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /test/customrr2.m: -------------------------------------------------------------------------------- 1 | // These options must match customrr.m 2 | // TEST_CONFIG MEM=mrc 3 | /* 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/customrr.m -fvisibility=default -o customrr2.out -DTEST_EXCHANGEIMPLEMENTATIONS=1 6 | $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat1.m -o customrr-cat1.dylib 7 | $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat2.m -o customrr-cat2.dylib 8 | END 9 | */ 10 | -------------------------------------------------------------------------------- /test/definitions.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | // DO NOT include anything else here 4 | #include 5 | // DO NOT include anything else here 6 | Class c = Nil; 7 | SEL s; 8 | IMP i; 9 | id o = nil; 10 | BOOL b = YES; 11 | BOOL b2 = NO; 12 | #if !__has_feature(objc_arc) 13 | __strong void *p; 14 | #endif 15 | id __unsafe_unretained u; 16 | id __weak w; 17 | 18 | void fn(void) __unused; 19 | void fn(void) { 20 | id __autoreleasing a __unused; 21 | } 22 | 23 | #if __llvm__ && !__clang__ 24 | // llvm-gcc defines _NSConcreteGlobalBlock wrong 25 | #else 26 | // rdar://10118972 wrong type inference for blocks returning YES and NO 27 | BOOL (^block1)(void) = ^{ return YES; }; 28 | BOOL (^block2)(void) = ^{ return NO; }; 29 | #endif 30 | 31 | #include "test.h" 32 | 33 | int main() 34 | { 35 | testassert(YES); 36 | testassert(!NO); 37 | #if __cplusplus 38 | testwarn("rdar://12371870 -Wnull-conversion"); 39 | testassert(!(bool)nil); 40 | testassert(!(bool)Nil); 41 | #else 42 | testassert(!nil); 43 | testassert(!Nil); 44 | #endif 45 | 46 | #if __has_feature(objc_bool) 47 | // YES[array] is disallowed for objc just as true[array] is for C++ 48 | #else 49 | // this will fail if YES and NO do not have enough parentheses 50 | int array[2] = { 888, 999 }; 51 | testassert(NO[array] == 888); 52 | testassert(YES[array] == 999); 53 | #endif 54 | 55 | succeed(__FILE__); 56 | } 57 | -------------------------------------------------------------------------------- /test/designatedinit.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | /* TEST_BUILD_OUTPUT 3 | .*designatedinit.m:\d+:\d+: warning: designated initializer should only invoke a designated initializer on 'super'.* 4 | .*designatedinit.m:\d+:\d+: note: .* 5 | .*designatedinit.m:\d+:\d+: warning: method override for the designated initializer of the superclass '-init' not found.* 6 | .*NSObject.h:\d+:\d+: note: .* 7 | END */ 8 | 9 | #define NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER 1 10 | #include "test.h" 11 | #include 12 | 13 | @interface C : NSObject 14 | -(id) initWithInt:(int)i NS_DESIGNATED_INITIALIZER; 15 | @end 16 | 17 | @implementation C 18 | -(id) initWithInt:(int)__unused i { 19 | return [self init]; 20 | } 21 | @end 22 | 23 | int main() 24 | { 25 | succeed(__FILE__); 26 | } 27 | -------------------------------------------------------------------------------- /test/duplicatedClasses.m: -------------------------------------------------------------------------------- 1 | // TEST_ENV OBJC_DEBUG_DUPLICATE_CLASSES=YES 2 | // TEST_CRASHES 3 | /* 4 | TEST_RUN_OUTPUT 5 | objc\[\d+\]: Class GKScore is implemented in both [^\s]+ and [^\s]+ One of the two will be used. Which one is undefined. 6 | CRASHED: SIG(ILL|TRAP) 7 | OR 8 | OK: duplicatedClasses.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #include "testroot.i" 14 | 15 | @interface GKScore : TestRoot @end 16 | @implementation GKScore @end 17 | 18 | int main() 19 | { 20 | if (objc_collectingEnabled()) { 21 | testwarn("rdar://19042235 test disabled because GameKit is not GC"); 22 | succeed(__FILE__); 23 | } 24 | void *dl = dlopen("/System/Library/Frameworks/GameKit.framework/GameKit", RTLD_LAZY); 25 | if (!dl) fail("couldn't open GameKit"); 26 | fail("should have crashed already"); 27 | } 28 | -------------------------------------------------------------------------------- /test/evil-category-0.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/evil-category-0.m -dynamiclib -o libevil.dylib 6 | $C{COMPILE} $DIR/evil-main.m -x none -DNOT_EVIL libevil.dylib -o evil-category-0.out 7 | END 8 | */ 9 | 10 | // NOT EVIL version 11 | 12 | #define EVIL_INSTANCE_METHOD 0 13 | #define EVIL_CLASS_METHOD 0 14 | 15 | #define OMIT_CAT 0 16 | #define OMIT_NL_CAT 0 17 | 18 | #include "evil-category-def.m" 19 | -------------------------------------------------------------------------------- /test/evil-category-00.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-category-00.m $DIR/evil-main.m -o evil-category-00.out 9 | END 10 | 11 | TEST_RUN_OUTPUT 12 | CRASHED: SIGSEGV 13 | END 14 | */ 15 | 16 | // NOT EVIL version: apps are allowed through (then crash in +load) 17 | 18 | #define EVIL_INSTANCE_METHOD 1 19 | #define EVIL_CLASS_METHOD 1 20 | 21 | #define OMIT_CAT 0 22 | #define OMIT_NL_CAT 0 23 | 24 | #include "evil-category-def.m" 25 | -------------------------------------------------------------------------------- /test/evil-category-000.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/evil-category-000.m -dynamiclib -o libevil.dylib 6 | $C{COMPILE} $DIR/evil-main.m -x none -DNOT_EVIL libevil.dylib -o evil-category-000.out 7 | END 8 | */ 9 | 10 | // NOT EVIL version: category omitted from all lists 11 | 12 | #define EVIL_INSTANCE_METHOD 1 13 | #define EVIL_CLASS_METHOD 1 14 | 15 | #define OMIT_CAT 1 16 | #define OMIT_NL_CAT 1 17 | 18 | #include "evil-category-def.m" 19 | -------------------------------------------------------------------------------- /test/evil-category-1.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-category-1.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-category-1.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_INSTANCE_METHOD 1 19 | #define EVIL_CLASS_METHOD 0 20 | 21 | #define OMIT_CAT 0 22 | #define OMIT_NL_CAT 0 23 | 24 | #include "evil-category-def.m" 25 | -------------------------------------------------------------------------------- /test/evil-category-2.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-category-2.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-category-2.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_INSTANCE_METHOD 0 19 | #define EVIL_CLASS_METHOD 1 20 | 21 | #define OMIT_CAT 0 22 | #define OMIT_NL_CAT 0 23 | 24 | #include "evil-category-def.m" 25 | -------------------------------------------------------------------------------- /test/evil-category-3.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-category-3.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-category-3.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_INSTANCE_METHOD 0 19 | #define EVIL_CLASS_METHOD 1 20 | 21 | #define OMIT_CAT 1 22 | #define OMIT_NL_CAT 0 23 | 24 | #include "evil-category-def.m" 25 | -------------------------------------------------------------------------------- /test/evil-category-4.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-category-4.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-category-4.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_INSTANCE_METHOD 0 19 | #define EVIL_CLASS_METHOD 1 20 | 21 | #define OMIT_CAT 0 22 | #define OMIT_NL_CAT 1 23 | 24 | #include "evil-category-def.m" 25 | -------------------------------------------------------------------------------- /test/evil-category-def.m: -------------------------------------------------------------------------------- 1 | 2 | #if __OBJC2__ 3 | 4 | #include 5 | 6 | #if __LP64__ 7 | # define PTR " .quad " 8 | #else 9 | # define PTR " .long " 10 | #endif 11 | 12 | #define str(x) #x 13 | #define str2(x) str(x) 14 | 15 | __BEGIN_DECLS 16 | void nop(void) { } 17 | __END_DECLS 18 | 19 | asm( 20 | ".section __DATA,__objc_data \n" 21 | ".align 3 \n" 22 | "L_category: \n" 23 | PTR "L_cat_name \n" 24 | PTR "_OBJC_CLASS_$_NSObject \n" 25 | #if EVIL_INSTANCE_METHOD 26 | PTR "L_evil_methods \n" 27 | #else 28 | PTR "L_good_methods \n" 29 | #endif 30 | #if EVIL_CLASS_METHOD 31 | PTR "L_evil_methods \n" 32 | #else 33 | PTR "L_good_methods \n" 34 | #endif 35 | PTR "0 \n" 36 | PTR "0 \n" 37 | 38 | "L_evil_methods: \n" 39 | ".long 24 \n" 40 | ".long 1 \n" 41 | PTR "L_load \n" 42 | PTR "L_load \n" 43 | PTR str2(SHARED_REGION_BASE+SHARED_REGION_SIZE-PAGE_MAX_SIZE) " \n" 44 | 45 | "L_good_methods: \n" 46 | ".long 24 \n" 47 | ".long 1 \n" 48 | PTR "L_load \n" 49 | PTR "L_load \n" 50 | PTR "_nop \n" 51 | 52 | ".cstring \n" 53 | "L_cat_name: .ascii \"Evil\\0\" \n" 54 | "L_load: .ascii \"load\\0\" \n" 55 | 56 | ".section __DATA,__objc_catlist \n" 57 | #if !OMIT_CAT 58 | PTR "L_category \n" 59 | #endif 60 | 61 | ".section __DATA,__objc_nlcatlist \n" 62 | #if !OMIT_NL_CAT 63 | PTR "L_category \n" 64 | #endif 65 | 66 | ".text \n" 67 | ); 68 | 69 | // __OBJC2__ 70 | #endif 71 | 72 | void fn(void) { } 73 | -------------------------------------------------------------------------------- /test/evil-class-0.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/evil-class-0.m -dynamiclib -o libevil.dylib 6 | $C{COMPILE} $DIR/evil-main.m -x none -DNOT_EVIL libevil.dylib -o evil-class-0.out 7 | END 8 | */ 9 | 10 | // NOT EVIL version 11 | 12 | #define EVIL_SUPER 0 13 | #define EVIL_SUPER_META 0 14 | #define EVIL_SUB 0 15 | #define EVIL_SUB_META 0 16 | 17 | #define OMIT_SUPER 0 18 | #define OMIT_NL_SUPER 0 19 | #define OMIT_SUB 0 20 | #define OMIT_NL_SUB 0 21 | 22 | #include "evil-class-def.m" 23 | -------------------------------------------------------------------------------- /test/evil-class-00.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-class-00.m $DIR/evil-main.m -o evil-class-00.out 9 | END 10 | 11 | TEST_RUN_OUTPUT 12 | CRASHED: SIGSEGV 13 | END 14 | */ 15 | 16 | // NOT EVIL version: apps are allowed through (then crash in +load) 17 | 18 | #define EVIL_SUPER 0 19 | #define EVIL_SUPER_META 1 20 | #define EVIL_SUB 0 21 | #define EVIL_SUB_META 0 22 | 23 | #define OMIT_SUPER 1 24 | #define OMIT_NL_SUPER 1 25 | #define OMIT_SUB 1 26 | #define OMIT_NL_SUB 0 27 | 28 | #include "evil-class-def.m" 29 | -------------------------------------------------------------------------------- /test/evil-class-000.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/evil-class-000.m -dynamiclib -o libevil.dylib 6 | $C{COMPILE} $DIR/evil-main.m -x none -DNOT_EVIL libevil.dylib -o evil-class-000.out 7 | END 8 | */ 9 | 10 | // NOT EVIL version: all classes omitted from all lists 11 | 12 | #define EVIL_SUPER 1 13 | #define EVIL_SUPER_META 1 14 | #define EVIL_SUB 1 15 | #define EVIL_SUB_META 1 16 | 17 | #define OMIT_SUPER 1 18 | #define OMIT_NL_SUPER 1 19 | #define OMIT_SUB 1 20 | #define OMIT_NL_SUB 1 21 | 22 | #include "evil-class-def.m" 23 | -------------------------------------------------------------------------------- /test/evil-class-1.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-class-1.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-class-1.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_SUPER 1 19 | #define EVIL_SUPER_META 0 20 | #define EVIL_SUB 0 21 | #define EVIL_SUB_META 0 22 | 23 | #define OMIT_SUPER 0 24 | #define OMIT_NL_SUPER 0 25 | #define OMIT_SUB 0 26 | #define OMIT_NL_SUB 0 27 | 28 | #include "evil-class-def.m" 29 | -------------------------------------------------------------------------------- /test/evil-class-2.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-class-2.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-class-2.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_SUPER 0 19 | #define EVIL_SUPER_META 1 20 | #define EVIL_SUB 0 21 | #define EVIL_SUB_META 0 22 | 23 | #define OMIT_SUPER 0 24 | #define OMIT_NL_SUPER 0 25 | #define OMIT_SUB 0 26 | #define OMIT_NL_SUB 0 27 | 28 | #include "evil-class-def.m" 29 | -------------------------------------------------------------------------------- /test/evil-class-3.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-class-3.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-class-3.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_SUPER 0 19 | #define EVIL_SUPER_META 0 20 | #define EVIL_SUB 1 21 | #define EVIL_SUB_META 0 22 | 23 | #define OMIT_SUPER 0 24 | #define OMIT_NL_SUPER 0 25 | #define OMIT_SUB 0 26 | #define OMIT_NL_SUB 0 27 | 28 | #include "evil-class-def.m" 29 | -------------------------------------------------------------------------------- /test/evil-class-4.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_CONFIG OS=iphoneos 5 | TEST_CRASHES 6 | 7 | TEST_BUILD 8 | $C{COMPILE} $DIR/evil-class-4.m -dynamiclib -o libevil.dylib 9 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-class-4.out 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 14 | CRASHED: SIG(ILL|TRAP) 15 | END 16 | */ 17 | 18 | #define EVIL_SUPER 0 19 | #define EVIL_SUPER_META 0 20 | #define EVIL_SUB 0 21 | #define EVIL_SUB_META 1 22 | 23 | #define OMIT_SUPER 0 24 | #define OMIT_NL_SUPER 0 25 | #define OMIT_SUB 0 26 | #define OMIT_NL_SUB 0 27 | 28 | #include "evil-class-def.m" 29 | -------------------------------------------------------------------------------- /test/evil-class-5.m: -------------------------------------------------------------------------------- 1 | /* 2 | rdar://8553305 3 | 4 | TEST_DISABLED rdar://19200100 5 | 6 | TEST_CONFIG OS=iphoneos 7 | TEST_CRASHES 8 | 9 | TEST_BUILD 10 | $C{COMPILE} $DIR/evil-class-5.m -dynamiclib -o libevil.dylib 11 | $C{COMPILE} $DIR/evil-main.m -x none libevil.dylib -o evil-class-5.out 12 | END 13 | 14 | TEST_RUN_OUTPUT 15 | objc\[\d+\]: bad method implementation \(0x[0-9a-f]+ at 0x[0-9a-f]+\) 16 | CRASHED: SIG(ILL|TRAP) 17 | END 18 | */ 19 | 20 | #define EVIL_SUPER 0 21 | #define EVIL_SUPER_META 1 22 | #define EVIL_SUB 0 23 | #define EVIL_SUB_META 0 24 | 25 | #define OMIT_SUPER 1 26 | #define OMIT_NL_SUPER 1 27 | #define OMIT_SUB 1 28 | #define OMIT_NL_SUB 0 29 | 30 | #include "evil-class-def.m" 31 | -------------------------------------------------------------------------------- /test/evil-main.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern void fn(void); 4 | 5 | int main(int argc __unused, char **argv) 6 | { 7 | fn(); 8 | 9 | #if TARGET_OS_EMBEDDED && !defined(NOT_EVIL) 10 | #pragma unused (argv) 11 | fail("All that is necessary for the triumph of evil is that good men do nothing."); 12 | #else 13 | succeed(basename(argv[0])); 14 | #endif 15 | } 16 | -------------------------------------------------------------------------------- /test/forwardDefault.m: -------------------------------------------------------------------------------- 1 | /* 2 | no arc, rdar://11368528 confused by Foundation 3 | TEST_CONFIG MEM=mrc,gc 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: \+\[NSObject fakeorama\]: unrecognized selector sent to instance 0x[0-9a-fA-F]+ \(no message forward handler is installed\) 7 | CRASHED: SIG(ILL|TRAP) 8 | OR 9 | not OBJC2 10 | objc\[\d+\]: NSObject: Does not recognize selector forward:: \(while forwarding fakeorama\) 11 | CRASHED: SIG(ILL|TRAP) 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | 17 | #include 18 | 19 | @interface NSObject (Fake) 20 | -(void)fakeorama; 21 | @end 22 | 23 | int main() 24 | { 25 | #if !__OBJC2__ 26 | fprintf(stderr, "not OBJC2\n"); 27 | #endif 28 | [NSObject fakeorama]; 29 | fail("should have crashed"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/forwardDefaultStret.m: -------------------------------------------------------------------------------- 1 | /* 2 | no arc, rdar://11368528 confused by Foundation 3 | TEST_CONFIG MEM=mrc,gc 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: \+\[NSObject fakeorama\]: unrecognized selector sent to instance 0x[0-9a-fA-F]+ \(no message forward handler is installed\) 7 | CRASHED: SIG(ILL|TRAP) 8 | OR 9 | not OBJC2 10 | objc\[\d+\]: NSObject: Does not recognize selector forward:: \(while forwarding fakeorama\) 11 | CRASHED: SIG(ILL|TRAP) 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | 17 | #include 18 | 19 | @interface NSObject (Fake) 20 | -(struct stret)fakeorama; 21 | @end 22 | 23 | int main() 24 | { 25 | #if !__OBJC2__ 26 | fprintf(stderr, "not OBJC2\n"); 27 | #endif 28 | [NSObject fakeorama]; 29 | fail("should have crashed"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/future.h: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | @interface Sub1 : TestRoot 4 | +(int)method; 5 | +(Class)classref; 6 | @end 7 | 8 | @interface Sub2 : TestRoot 9 | +(int)method; 10 | +(Class)classref; 11 | @end 12 | 13 | @interface SubSub1 : Sub1 @end 14 | 15 | @interface SubSub2 : Sub2 @end 16 | -------------------------------------------------------------------------------- /test/future.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/future0.m -o future0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/future2.m -x none future0.dylib -o future2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/future.m -x none future0.dylib -o future.out 6 | END 7 | */ 8 | 9 | #include "test.h" 10 | 11 | #if __has_feature(objc_arc) 12 | 13 | int main() 14 | { 15 | testwarn("rdar://10041403 future class API is not ARC-compatible"); 16 | succeed(__FILE__); 17 | } 18 | 19 | 20 | #else 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "future.h" 27 | 28 | @implementation Sub2 29 | +(int)method { 30 | return 2; 31 | } 32 | +(Class)classref { 33 | return [Sub2 class]; 34 | } 35 | @end 36 | 37 | @implementation SubSub2 38 | +(int)method { 39 | return 1 + [super method]; 40 | } 41 | @end 42 | 43 | int main() 44 | { 45 | Class oldTestRoot; 46 | Class oldSub1; 47 | Class newSub1; 48 | 49 | // objc_getFutureClass with existing class 50 | oldTestRoot = objc_getFutureClass("TestRoot"); 51 | testassert(oldTestRoot == [TestRoot class]); 52 | testassert(! _class_isFutureClass(oldTestRoot)); 53 | 54 | // objc_getFutureClass with missing class 55 | oldSub1 = objc_getFutureClass("Sub1"); 56 | testassert(oldSub1); 57 | testassert(malloc_size(objc_unretainedPointer(oldSub1)) > 0); 58 | testassert(objc_getClass("Sub1") == Nil); 59 | testassert(_class_isFutureClass(oldSub1)); 60 | testassert(0 == strcmp(class_getName(oldSub1), "Sub1")); 61 | testassert(object_getClass(oldSub1) == Nil); // CF expects this 62 | 63 | // objc_getFutureClass a second time 64 | testassert(oldSub1 == objc_getFutureClass("Sub1")); 65 | 66 | // Load class Sub1 67 | dlopen("future2.dylib", 0); 68 | 69 | // Verify use of future class 70 | newSub1 = objc_getClass("Sub1"); 71 | testassert(oldSub1 == newSub1); 72 | testassert(newSub1 == [newSub1 classref]); 73 | testassert(newSub1 == class_getSuperclass(objc_getClass("SubSub1"))); 74 | testassert(! _class_isFutureClass(newSub1)); 75 | 76 | testassert(1 == [oldSub1 method]); 77 | testassert(1 == [newSub1 method]); 78 | 79 | succeed(__FILE__); 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /test/future0.m: -------------------------------------------------------------------------------- 1 | #include "future.h" 2 | #include "testroot.i" 3 | -------------------------------------------------------------------------------- /test/future2.m: -------------------------------------------------------------------------------- 1 | #include "future.h" 2 | 3 | 4 | @implementation Sub1 5 | +(Class)classref { 6 | return [Sub1 class]; 7 | } 8 | +(int)method { 9 | return 1; 10 | } 11 | @end 12 | 13 | @implementation SubSub1 14 | +(int)method { 15 | return 1 + [super method]; 16 | } 17 | @end 18 | -------------------------------------------------------------------------------- /test/gc-main.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | OBJC_ROOT_CLASS 4 | @interface Main @end 5 | @implementation Main @end 6 | 7 | int main(int argc __attribute__((unused)), char **argv) 8 | { 9 | succeed(basename(argv[0])); 10 | } 11 | -------------------------------------------------------------------------------- /test/gc.c: -------------------------------------------------------------------------------- 1 | int GC(void) { return 42; } 2 | -------------------------------------------------------------------------------- /test/gc.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | OBJC_ROOT_CLASS 4 | @interface GC @end 5 | @implementation GC @end 6 | 7 | // silence "no debug symbols in executable" warning 8 | void foo(void) { } 9 | -------------------------------------------------------------------------------- /test/gcenforcer-nogc-1.m: -------------------------------------------------------------------------------- 1 | // gc-off app loading gc-off dylib: should work 2 | 3 | /* 4 | TEST_CONFIG MEM=mrc,arc OS=macosx 5 | 6 | TEST_BUILD 7 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 8 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 9 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 10 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 11 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 12 | 13 | $C{COMPILE} $DIR/gc-main.m -x none libnogc.dylib -o gcenforcer-nogc-1.out 14 | END 15 | */ 16 | -------------------------------------------------------------------------------- /test/gcenforcer-nogc-2.m: -------------------------------------------------------------------------------- 1 | // gc-on app loading gc-off dylib: should crash 2 | 3 | /* 4 | TEST_CONFIG MEM=gc OS=macosx 5 | TEST_CRASHES 6 | 7 | TEST_RUN_OUTPUT 8 | objc\[\d+\]: '.*libnogc.dylib' was not compiled with -fobjc-gc or -fobjc-gc-only, but the application requires GC 9 | objc\[\d+\]: \*\*\* GC capability of application and some libraries did not match 10 | CRASHED: SIGILL 11 | END 12 | 13 | TEST_BUILD 14 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 15 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 16 | $C{COMPILE} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 17 | $C{COMPILE} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 18 | $C{COMPILE} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 19 | 20 | $C{COMPILE} $DIR/gc-main.m -x none libnogc.dylib -o gcenforcer-nogc-2.out 21 | END 22 | */ 23 | -------------------------------------------------------------------------------- /test/gcenforcer-noobjc.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=macosx 3 | 4 | TEST_BUILD 5 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 6 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 7 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 8 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 9 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 10 | 11 | $C{COMPILE} $DIR/gc-main.m -x none libnoobjc.dylib -o gcenforcer-noobjc.out 12 | END 13 | */ 14 | -------------------------------------------------------------------------------- /test/gcenforcer-requiresgc-1.m: -------------------------------------------------------------------------------- 1 | // gc-off app loading gc-required dylib: should crash 2 | // linker sees librequiresgc.fake.dylib, runtime uses librequiresgc.dylib 3 | 4 | /* 5 | TEST_CONFIG MEM=mrc,arc OS=macosx 6 | TEST_CRASHES 7 | 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: '.*librequiresgc.dylib' was compiled with -fobjc-gc-only, but the application does not support GC 10 | objc\[\d+\]: \*\*\* GC capability of application and some libraries did not match 11 | CRASHED: SIGILL 12 | END 13 | 14 | TEST_BUILD 15 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 16 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 17 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 18 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 19 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 20 | 21 | $C{COMPILE} $DIR/gc-main.m -x none librequiresgc.fake.dylib -o gcenforcer-requiresgc-1.out 22 | END 23 | */ 24 | -------------------------------------------------------------------------------- /test/gcenforcer-requiresgc-2.m: -------------------------------------------------------------------------------- 1 | // gc-off app loading gc-required dylib: should crash 2 | // linker sees librequiresgc.fake.dylib, runtime uses librequiresgc.dylib 3 | 4 | /* 5 | TEST_CONFIG MEM=gc OS=macosx 6 | 7 | TEST_BUILD 8 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 9 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 10 | $C{COMPILE} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 11 | $C{COMPILE} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 12 | $C{COMPILE} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 13 | 14 | $C{COMPILE} $DIR/gc-main.m -x none librequiresgc.fake.dylib -o gcenforcer-requiresgc-2.out 15 | END 16 | */ 17 | -------------------------------------------------------------------------------- /test/gcenforcer-supportsgc.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=macosx 3 | 4 | TEST_BUILD 5 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 6 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 7 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 8 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 9 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 10 | 11 | $C{COMPILE} $DIR/gc-main.m -x none libsupportsgc.dylib -o gcenforcer-supportsgc.out 12 | END 13 | */ 14 | -------------------------------------------------------------------------------- /test/gcenforcer.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=macosx 3 | 4 | TEST_BUILD 5 | $C{COMPILE_C} $DIR/gc.c -dynamiclib -o libnoobjc.dylib 6 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libnogc.dylib 7 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o libsupportsgc.dylib -fobjc-gc 8 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.dylib -fobjc-gc-only 9 | $C{COMPILE_NOMEM} $DIR/gc.m -dynamiclib -o librequiresgc.fake.dylib -fobjc-gc -install_name librequiresgc.dylib 10 | 11 | $C{COMPILE} $DIR/gcenforcer.m -o gcenforcer.out 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | #include 17 | #include 18 | 19 | int main() 20 | { 21 | int i; 22 | for (i = 0; i < 1000; i++) { 23 | testassert(dlopen_preflight("libsupportsgc.dylib")); 24 | testassert(dlopen_preflight("libnoobjc.dylib")); 25 | 26 | if (objc_collectingEnabled()) { 27 | testassert(dlopen_preflight("librequiresgc.dylib")); 28 | testassert(! dlopen_preflight("libnogc.dylib")); 29 | } else { 30 | testassert(! dlopen_preflight("librequiresgc.dylib")); 31 | testassert(dlopen_preflight("libnogc.dylib")); 32 | } 33 | } 34 | 35 | succeed(__FILE__); 36 | } 37 | -------------------------------------------------------------------------------- /test/gdb.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -Wno-deprecated-declarations 2 | 3 | #include "test.h" 4 | 5 | #if TARGET_OS_IPHONE 6 | 7 | int main() 8 | { 9 | succeed(__FILE__); 10 | } 11 | 12 | #else 13 | 14 | #include "testroot.i" 15 | #include 16 | #include 17 | 18 | int main() 19 | { 20 | // Class hashes 21 | #if __OBJC2__ 22 | 23 | Class result; 24 | 25 | // Class should not be realized yet 26 | // fixme not true during class hash rearrangement 27 | // result = NXMapGet(gdb_objc_realized_classes, "TestRoot"); 28 | // testassert(!result); 29 | 30 | [TestRoot class]; 31 | // Now class should be realized 32 | 33 | result = (Class)objc_unretainedObject(NXMapGet(gdb_objc_realized_classes, "TestRoot")); 34 | testassert(result); 35 | testassert(result == [TestRoot class]); 36 | 37 | result = (Class)objc_unretainedObject(NXMapGet(gdb_objc_realized_classes, "DoesNotExist")); 38 | testassert(!result); 39 | 40 | #else 41 | 42 | struct objc_class query; 43 | Class result; 44 | 45 | query.name = "TestRoot"; 46 | result = (Class)NXHashGet(_objc_debug_class_hash, &query); 47 | testassert(result); 48 | testassert((id)result == [TestRoot class]); 49 | 50 | query.name = "DoesNotExist"; 51 | result = (Class)NXHashGet(_objc_debug_class_hash, &query); 52 | testassert(!result); 53 | 54 | #endif 55 | 56 | succeed(__FILE__); 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /test/ignoredSelector2.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=gc 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | // This test must use CF and test ignoredSelector must not use CF. 5 | 6 | #include "test.h" 7 | #include 8 | 9 | int main() 10 | { 11 | if (objc_collectingEnabled()) { 12 | // ARC RR functions don't retain and don't hit the side table. 13 | __block int count; 14 | testblock_t testblock = ^{ 15 | for (int i = 0; i < count; i++) { 16 | id obj = [NSObject new]; 17 | objc_retain(obj); 18 | objc_retain(obj); 19 | objc_release(obj); 20 | } 21 | }; 22 | count = 100; 23 | testonthread(testblock); 24 | testonthread(testblock); 25 | leak_mark(); 26 | count = 10000000; 27 | testonthread(testblock); 28 | #if __OBJC_GC__ 29 | testwarn("rdar://19042235 possible leaks suppressed under GC"); 30 | leak_check(2000); 31 | #else 32 | leak_check(0); 33 | #endif 34 | } 35 | 36 | succeed(__FILE__); 37 | } 38 | -------------------------------------------------------------------------------- /test/imageorder.h: -------------------------------------------------------------------------------- 1 | extern int state; 2 | extern int cstate; 3 | 4 | OBJC_ROOT_CLASS 5 | @interface Super { id isa; } 6 | +(void) method; 7 | +(void) method0; 8 | @end 9 | 10 | @interface Super (cat1) 11 | +(void) method1; 12 | @end 13 | 14 | @interface Super (cat2) 15 | +(void) method2; 16 | @end 17 | 18 | @interface Super (cat3) 19 | +(void) method3; 20 | @end 21 | -------------------------------------------------------------------------------- /test/imageorder.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/imageorder1.m -o imageorder1.dylib -dynamiclib 4 | $C{COMPILE} $DIR/imageorder2.m -x none imageorder1.dylib -o imageorder2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/imageorder3.m -x none imageorder2.dylib imageorder1.dylib -o imageorder3.dylib -dynamiclib 6 | $C{COMPILE} $DIR/imageorder.m -x none imageorder3.dylib imageorder2.dylib imageorder1.dylib -o imageorder.out 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | #include "imageorder.h" 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | // +load methods and C static initializers 18 | testassert(state == 3); 19 | testassert(cstate == 3); 20 | 21 | Class cls = objc_getClass("Super"); 22 | testassert(cls); 23 | 24 | // make sure all categories arrived 25 | state = -1; 26 | [Super method0]; 27 | testassert(state == 0); 28 | [Super method1]; 29 | testassert(state == 1); 30 | [Super method2]; 31 | testassert(state == 2); 32 | [Super method3]; 33 | testassert(state == 3); 34 | 35 | // make sure imageorder3.dylib is the last category to attach 36 | state = 0; 37 | [Super method]; 38 | testassert(state == 3); 39 | 40 | succeed(__FILE__); 41 | } 42 | -------------------------------------------------------------------------------- /test/imageorder1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | int state = -1; 5 | int cstate = 0; 6 | 7 | static void c1(void) __attribute__((constructor)); 8 | static void c1(void) 9 | { 10 | testassert(state == 1); // +load before C/C++ 11 | testassert(cstate == 0); 12 | cstate = 1; 13 | } 14 | 15 | 16 | #if __clang__ 17 | #pragma clang diagnostic push 18 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 19 | #endif 20 | 21 | @implementation Super (cat1) 22 | +(void) method { 23 | fail("+[Super(cat1) method] not replaced!"); 24 | } 25 | +(void) method1 { 26 | state = 1; 27 | } 28 | +(void) load { 29 | testassert(state == 0); 30 | state = 1; 31 | } 32 | @end 33 | 34 | #if __clang__ 35 | #pragma clang diagnostic pop 36 | #endif 37 | 38 | 39 | @implementation Super 40 | +(void) initialize { } 41 | +(void) method { 42 | fail("+[Super method] not replaced!"); 43 | } 44 | +(void) method0 { 45 | state = 0; 46 | } 47 | +(void) load { 48 | testassert(state == -1); 49 | state = 0; 50 | } 51 | @end 52 | 53 | -------------------------------------------------------------------------------- /test/imageorder2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | static void c2(void) __attribute__((constructor)); 5 | static void c2(void) 6 | { 7 | testassert(state == 2); // +load before C/C++ 8 | testassert(cstate == 1); 9 | cstate = 2; 10 | } 11 | 12 | 13 | #if __clang__ 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 16 | #endif 17 | 18 | @implementation Super (cat2) 19 | +(void) method { 20 | fail("+[Super(cat2) method] not replaced!"); 21 | } 22 | +(void) method2 { 23 | state = 2; 24 | } 25 | +(void) load { 26 | testassert(state == 1); 27 | state = 2; 28 | } 29 | @end 30 | 31 | #if __clang__ 32 | #pragma clang diagnostic pop 33 | #endif 34 | -------------------------------------------------------------------------------- /test/imageorder3.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | static void c3(void) __attribute__((constructor)); 5 | static void c3(void) 6 | { 7 | testassert(state == 3); // +load before C/C++ 8 | testassert(cstate == 2); 9 | cstate = 3; 10 | } 11 | 12 | 13 | #if __clang__ 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 16 | #endif 17 | 18 | @implementation Super (cat3) 19 | +(void) method { 20 | state = 3; 21 | } 22 | +(void) method3 { 23 | state = 3; 24 | } 25 | +(void) load { 26 | testassert(state == 2); 27 | state = 3; 28 | } 29 | @end 30 | 31 | #if __clang__ 32 | #pragma clang diagnostic pop 33 | #endif 34 | -------------------------------------------------------------------------------- /test/includes.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | // Verify that all headers can be included in any language. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #if !TARGET_OS_IPHONE 28 | #include 29 | #include 30 | #include 31 | #endif 32 | 33 | #include "test.h" 34 | 35 | int main() 36 | { 37 | succeed(__FILE__); 38 | } 39 | -------------------------------------------------------------------------------- /test/initializeVersusWeak.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=arc 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | // Problem: If weak reference operations provoke +initialize, the runtime 5 | // can deadlock (recursive weak lock, or lock inversion between weak lock 6 | // and +initialize lock). 7 | // Solution: object_setClass() and objc_storeWeak() perform +initialize 8 | // if needed so that no weakly-referenced object can ever have an 9 | // un-+initialized isa. 10 | 11 | #include 12 | #include 13 | #include "test.h" 14 | 15 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 16 | #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign" 17 | 18 | // This is StripedMap's pointer hash 19 | uintptr_t hash(id obj) { 20 | uintptr_t addr = (uintptr_t)obj; 21 | return ((addr >> 4) ^ (addr >> 9)) % 64; 22 | } 23 | 24 | bool sameAlignment(id o1, id o2) 25 | { 26 | return hash(o1) == hash(o2); 27 | } 28 | 29 | // Return a new string object that uses the same striped weak locks as `obj`. 30 | NSMutableString *newAlignedString(id obj) 31 | { 32 | NSMutableArray *strings = [NSMutableArray new]; 33 | NSMutableString *result; 34 | do { 35 | result = [NSMutableString new]; 36 | [strings addObject:result]; 37 | } while (!sameAlignment(obj, result)); 38 | return result; 39 | } 40 | 41 | 42 | __weak NSObject *weak1; 43 | __weak NSMutableString *weak2; 44 | NSMutableString *strong2; 45 | 46 | @interface A : NSObject @end 47 | @implementation A 48 | +(void)initialize { 49 | weak2 = strong2; // weak store #2 50 | strong2 = nil; 51 | } 52 | @end 53 | 54 | void testA() 55 | { 56 | // Weak store #1 provokes +initialize which performs weak store #2. 57 | // Solution: weak store #1 runs +initialize if needed 58 | // without holding locks. 59 | @autoreleasepool { 60 | A *obj = [A new]; 61 | strong2 = newAlignedString(obj); 62 | [obj addObserver:obj forKeyPath:@"foo" options:0 context:0]; 63 | weak1 = obj; // weak store #1 64 | [obj removeObserver:obj forKeyPath:@"foo"]; 65 | obj = nil; 66 | } 67 | } 68 | 69 | 70 | __weak NSObject *weak3; 71 | __weak NSMutableString *weak4; 72 | NSMutableString *strong4; 73 | 74 | @interface B : NSObject @end 75 | @implementation B 76 | +(void)initialize { 77 | weak4 = strong4; // weak store #4 78 | strong4 = nil; 79 | } 80 | @end 81 | 82 | 83 | void testB() 84 | { 85 | // Weak load #3 provokes +initialize which performs weak store #4. 86 | // Solution: object_setClass() runs +initialize if needed 87 | // without holding locks. 88 | @autoreleasepool { 89 | B *obj = [B new]; 90 | strong4 = newAlignedString(obj); 91 | weak3 = obj; 92 | [obj addObserver:obj forKeyPath:@"foo" options:0 context:0]; 93 | [weak3 self]; // weak load #3 94 | [obj removeObserver:obj forKeyPath:@"foo"]; 95 | obj = nil; 96 | } 97 | } 98 | 99 | 100 | __weak id weak5; 101 | 102 | @interface C : NSObject @end 103 | @implementation C 104 | +(void)initialize { 105 | weak5 = [self new]; 106 | } 107 | @end 108 | 109 | void testC() 110 | { 111 | // +initialize performs a weak store of itself. 112 | // Make sure the retry in objc_storeWeak() doesn't spin. 113 | @autoreleasepool { 114 | [C self]; 115 | } 116 | } 117 | 118 | 119 | int main() 120 | { 121 | alarm(10); // replace hangs with crashes 122 | 123 | testA(); 124 | testB(); 125 | testC(); 126 | 127 | succeed(__FILE__); 128 | } 129 | 130 | -------------------------------------------------------------------------------- /test/instanceSize.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | 8 | @interface Sub1 : TestRoot { 9 | // id isa; // 0..4 10 | BOOL b; // 4..5 11 | } 12 | @end 13 | 14 | @implementation Sub1 @end 15 | 16 | @interface Sub2 : Sub1 { 17 | // id isa // 0..4 0..8 18 | // BOOL b // 4..5 8..9 19 | BOOL b2; // 5..6 9..10 20 | id o; // 8..12 16..24 21 | } 22 | @end 23 | @implementation Sub2 @end 24 | 25 | @interface Sub3 : Sub1 { 26 | // id isa; // 0..4 0..8 27 | // BOOL b; // 4..5 8..9 28 | id o; // 8..12 16..24 29 | BOOL b2; // 12..13 24..25 30 | } 31 | @end 32 | @implementation Sub3 @end 33 | 34 | int main() 35 | { 36 | testassert(sizeof(id) == class_getInstanceSize([TestRoot class])); 37 | testassert(2*sizeof(id) == class_getInstanceSize([Sub1 class])); 38 | testassert(3*sizeof(id) == class_getInstanceSize([Sub2 class])); 39 | testassert(4*sizeof(id) == class_getInstanceSize([Sub3 class])); 40 | 41 | #if !__has_feature(objc_arc) 42 | id o; 43 | 44 | o = [TestRoot new]; 45 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 46 | RELEASE_VAR(o); 47 | o = [Sub1 new]; 48 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 49 | RELEASE_VAR(o); 50 | o = [Sub2 new]; 51 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 52 | RELEASE_VAR(o); 53 | o = [Sub3 new]; 54 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 55 | RELEASE_VAR(o); 56 | #endif 57 | 58 | succeed(__FILE__); 59 | } 60 | -------------------------------------------------------------------------------- /test/ismeta.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | int main() 8 | { 9 | testassert(!class_isMetaClass([TestRoot class])); 10 | testassert(class_isMetaClass(object_getClass([TestRoot class]))); 11 | testassert(!class_isMetaClass(nil)); 12 | succeed(__FILE__); 13 | } 14 | -------------------------------------------------------------------------------- /test/ivarSlide.h: -------------------------------------------------------------------------------- 1 | @interface Super : TestRoot { 2 | @public 3 | #if OLD 4 | // nothing 5 | #else 6 | char superIvar; 7 | #endif 8 | } 9 | @end 10 | 11 | 12 | @interface ShrinkingSuper : TestRoot { 13 | @public 14 | #if OLD 15 | id superIvar[5]; 16 | __weak id superIvar2[5]; 17 | #else 18 | // nothing 19 | #endif 20 | } 21 | @end; 22 | 23 | 24 | @interface MoreStrongSuper : TestRoot { 25 | @public 26 | #if OLD 27 | void *superIvar; 28 | #else 29 | id superIvar; 30 | #endif 31 | } 32 | @end; 33 | 34 | 35 | @interface MoreWeakSuper : TestRoot { 36 | @public 37 | #if OLD 38 | id superIvar; 39 | #else 40 | __weak id superIvar; 41 | #endif 42 | } 43 | @end; 44 | 45 | @interface MoreWeak2Super : TestRoot { 46 | @public 47 | #if OLD 48 | void *superIvar; 49 | #else 50 | __weak id superIvar; 51 | #endif 52 | } 53 | @end; 54 | 55 | @interface LessStrongSuper : TestRoot { 56 | @public 57 | #if OLD 58 | id superIvar; 59 | #else 60 | void *superIvar; 61 | #endif 62 | } 63 | @end; 64 | 65 | @interface LessWeakSuper : TestRoot { 66 | @public 67 | #if OLD 68 | __weak id superIvar; 69 | #else 70 | id superIvar; 71 | #endif 72 | } 73 | @end; 74 | 75 | @interface LessWeak2Super : TestRoot { 76 | @public 77 | #if OLD 78 | __weak id superIvar; 79 | #else 80 | void *superIvar; 81 | #endif 82 | } 83 | @end; 84 | 85 | @interface NoGCChangeSuper : TestRoot { 86 | @public 87 | intptr_t d; 88 | char superc1; 89 | #if OLD 90 | // nothing 91 | #else 92 | char superc2; 93 | #endif 94 | } 95 | @end 96 | 97 | @interface RunsOf15 : TestRoot { 98 | @public 99 | id scan1; 100 | intptr_t skip15[15]; 101 | id scan15[15]; 102 | intptr_t skip15_2[15]; 103 | id scan15_2[15]; 104 | #if OLD 105 | // nothing 106 | #else 107 | intptr_t skip1; 108 | #endif 109 | } 110 | @end 111 | -------------------------------------------------------------------------------- /test/ivarSlide1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | #define OLD 0 6 | #include "ivarSlide.h" 7 | 8 | #include "testroot.i" 9 | 10 | @implementation Super @end 11 | 12 | @implementation ShrinkingSuper @end 13 | 14 | @implementation MoreStrongSuper @end 15 | @implementation LessStrongSuper @end 16 | @implementation MoreWeakSuper @end 17 | @implementation MoreWeak2Super @end 18 | @implementation LessWeakSuper @end 19 | @implementation LessWeak2Super @end 20 | @implementation NoGCChangeSuper @end 21 | @implementation RunsOf15 @end 22 | -------------------------------------------------------------------------------- /test/layout.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=gc OS=macosx 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | @class NSObject; 8 | 9 | void printlayout(const char *name, const uint8_t *layout) 10 | { 11 | testprintf("%s: ", name); 12 | 13 | if (!layout) { 14 | testprintf("NULL\n"); 15 | return; 16 | } 17 | 18 | const uint8_t *c; 19 | for (c = layout; *c; c++) { 20 | testprintf("%02x ", *c); 21 | } 22 | 23 | testprintf("00\n"); 24 | } 25 | 26 | OBJC_ROOT_CLASS 27 | @interface Super { id isa; } @end 28 | @implementation Super @end 29 | 30 | 31 | // strong: 0c 00 (0a00 without structs) 32 | // weak: NULL 33 | @interface AllScanned : Super { 34 | id id1; 35 | NSObject *o1; 36 | __strong void *v1; 37 | __strong intptr_t *i1; 38 | __strong long *l1; 39 | /* fixme 40 | struct { 41 | id id1; 42 | id id2; 43 | } str; 44 | */ 45 | id arr1[4]; 46 | } 47 | @end 48 | @implementation AllScanned @end 49 | 50 | // strong: 00 51 | // weak: 1b 00 (18 00 without structs) 52 | @interface AllWeak : Super { 53 | __weak id id1; 54 | __weak NSObject *o1; 55 | __weak void *v1; 56 | __weak intptr_t *i1; 57 | __weak long *l1; 58 | /* fixme 59 | struct { 60 | __weak id id1; 61 | __weak id id2; 62 | } str; 63 | */ 64 | __weak id arr1[4]; 65 | } 66 | @end 67 | @implementation AllWeak @end 68 | 69 | // strong: "" 70 | // weak: NULL 71 | OBJC_ROOT_CLASS 72 | @interface NoScanned { long i; } @end 73 | @implementation NoScanned @end 74 | 75 | int main() 76 | { 77 | const uint8_t *layout; 78 | 79 | layout = class_getIvarLayout(objc_getClass("AllScanned")); 80 | printlayout("AllScanned", layout); 81 | layout = class_getWeakIvarLayout(objc_getClass("AllScanned")); 82 | printlayout("AllScanned weak", layout); 83 | // testassert(0 == strcmp(layout, "\x0a")); 84 | 85 | layout = class_getIvarLayout(objc_getClass("AllWeak")); 86 | printlayout("AllWeak", layout); 87 | layout = class_getWeakIvarLayout(objc_getClass("AllWeak")); 88 | printlayout("AllWeak weak", layout); 89 | // testassert(0 == strcmp(layout, "")); 90 | 91 | layout = class_getIvarLayout(objc_getClass("NoScanned")); 92 | printlayout("NoScanned", layout); 93 | // testassert(0 == strcmp(layout, "")); 94 | 95 | succeed(__FILE__); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /test/literals.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=arc,mrc CC=clang LANGUAGE=objc,objc++ 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #include "test.h" 10 | 11 | int main() { 12 | PUSH_POOL { 13 | 14 | #if __has_feature(objc_bool) // placeholder until we get a more precise macro. 15 | NSArray *array = @[ @1, @2, @YES, @NO, @"Hello", @"World" ]; 16 | testassert([array count] == 6); 17 | NSDictionary *dict = @{ @"Name" : @"John Q. Public", @"Age" : @42 }; 18 | testassert([dict count] == 2); 19 | NSDictionary *numbers = @{ @"π" : @M_PI, @"e" : @M_E }; 20 | testassert([[numbers objectForKey:@"π"] doubleValue] == M_PI); 21 | testassert([[numbers objectForKey:@"e"] doubleValue] == M_E); 22 | 23 | BOOL yesBool = YES; 24 | BOOL noBool = NO; 25 | array = @[ 26 | @(true), 27 | @(YES), 28 | [NSNumber numberWithBool:YES], 29 | @YES, 30 | @(yesBool), 31 | @((BOOL)YES), 32 | 33 | @(false), 34 | @(NO), 35 | [NSNumber numberWithBool:NO], 36 | @NO, 37 | @(noBool), 38 | @((BOOL)NO), 39 | ]; 40 | NSData * jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:nil]; 41 | NSString * string = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 42 | #if __cplusplus 43 | testassert([string isEqualToString:@"[true,true,true,true,true,true,false,false,false,false,false,false]"]); 44 | #else 45 | // C99 @(true) and @(false) evaluate to @(1) and @(0). 46 | testassert([string isEqualToString:@"[1,true,true,true,true,true,0,false,false,false,false,false]"]); 47 | #endif 48 | 49 | #endif 50 | 51 | } POP_POOL; 52 | 53 | succeed(__FILE__); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/load-noobjc.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-noobjc.m -o load-noobjc.out 4 | $C{COMPILE} $DIR/load-noobjc2.m -o libload-noobjc2.dylib -bundle -bundle_loader load-noobjc.out 5 | $C{COMPILE} $DIR/load-noobjc3.m -o libload-noobjc3.dylib -bundle -bundle_loader load-noobjc.out 6 | END 7 | */ 8 | 9 | #include "test.h" 10 | 11 | #if !__OBJC2__ 12 | // old runtime can't fix this deadlock 13 | 14 | int main() 15 | { 16 | succeed(__FILE__); 17 | } 18 | 19 | #else 20 | 21 | #include 22 | 23 | int state = 0; 24 | semaphore_t go; 25 | 26 | void *thread(void *arg __unused) 27 | { 28 | objc_registerThreadWithCollector(); 29 | dlopen("libload-noobjc2.dylib", RTLD_LAZY); 30 | fail("dlopen should not have returned"); 31 | } 32 | 33 | int main() 34 | { 35 | semaphore_create(mach_task_self(), &go, SYNC_POLICY_FIFO, 0); 36 | 37 | pthread_t th; 38 | pthread_create(&th, nil, &thread, nil); 39 | 40 | // Wait for thread to stop in libload-noobjc2's +load method. 41 | semaphore_wait(go); 42 | 43 | // run nooobjc3's constructor function. 44 | // There's no objc code here so it shouldn't require the +load lock. 45 | void *dlh = dlopen("libload-noobjc3.dylib", RTLD_LAZY); 46 | testassert(dlh); 47 | testassert(state == 1); 48 | 49 | succeed(__FILE__); 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /test/load-noobjc2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #if __OBJC2__ 3 | 4 | extern semaphore_t go; 5 | 6 | OBJC_ROOT_CLASS 7 | @interface noobjc @end 8 | @implementation noobjc 9 | +(void)load 10 | { 11 | semaphore_signal(go); 12 | while (1) sleep(1); 13 | } 14 | @end 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /test/load-noobjc3.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #if __OBJC2__ 4 | 5 | extern int state; 6 | 7 | __attribute__((constructor)) 8 | static void ctor(void) 9 | { 10 | state = 1; 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /test/load-order.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-order3.m -o load-order3.dylib -dynamiclib 4 | $C{COMPILE} $DIR/load-order2.m -o load-order2.dylib -x none load-order3.dylib -dynamiclib 5 | $C{COMPILE} $DIR/load-order1.m -o load-order1.dylib -x none load-order3.dylib load-order2.dylib -dynamiclib 6 | $C{COMPILE} $DIR/load-order.m -o load-order.out -x none load-order3.dylib load-order2.dylib load-order1.dylib 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | 12 | extern int state1, state2, state3; 13 | 14 | int main() 15 | { 16 | testassert(state1 == 1 && state2 == 2 && state3 == 3); 17 | succeed(__FILE__); 18 | } 19 | -------------------------------------------------------------------------------- /test/load-order1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern int state2, state3; 4 | 5 | int state1 = 0; 6 | 7 | OBJC_ROOT_CLASS 8 | @interface One @end 9 | @implementation One 10 | +(void)load 11 | { 12 | testassert(state2 == 2 && state3 == 3); 13 | state1 = 1; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /test/load-order2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern int state3; 4 | 5 | int state2 = 0; 6 | 7 | OBJC_ROOT_CLASS 8 | @interface Two @end 9 | @implementation Two 10 | +(void)load 11 | { 12 | testassert(state3 == 3); 13 | state2 = 2; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /test/load-order3.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int state3 = 0; 4 | 5 | OBJC_ROOT_CLASS 6 | @interface Three @end 7 | @implementation Three 8 | +(void)load 9 | { 10 | state3 = 3; 11 | } 12 | @end 13 | -------------------------------------------------------------------------------- /test/load-parallel.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-parallel00.m -o load-parallel00.dylib -dynamiclib 4 | $C{COMPILE} $DIR/load-parallel.m -x none load-parallel00.dylib -o load-parallel.out -DCOUNT=10 5 | 6 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel0.dylib -dynamiclib -DN=0 7 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel1.dylib -dynamiclib -DN=1 8 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel2.dylib -dynamiclib -DN=2 9 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel3.dylib -dynamiclib -DN=3 10 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel4.dylib -dynamiclib -DN=4 11 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel5.dylib -dynamiclib -DN=5 12 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel6.dylib -dynamiclib -DN=6 13 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel7.dylib -dynamiclib -DN=7 14 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel8.dylib -dynamiclib -DN=8 15 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel9.dylib -dynamiclib -DN=9 16 | END 17 | */ 18 | 19 | #include "test.h" 20 | 21 | #include 22 | #include 23 | 24 | #ifndef COUNT 25 | #error -DCOUNT=c missing 26 | #endif 27 | 28 | extern int state; 29 | 30 | void *thread(void *arg) 31 | { 32 | uintptr_t num = (uintptr_t)arg; 33 | char *buf; 34 | 35 | objc_registerThreadWithCollector(); 36 | 37 | asprintf(&buf, "load-parallel%lu.dylib", (unsigned long)num); 38 | testprintf("%s\n", buf); 39 | void *dlh = dlopen(buf, RTLD_LAZY); 40 | if (!dlh) { 41 | fail("dlopen failed: %s", dlerror()); 42 | } 43 | free(buf); 44 | 45 | return NULL; 46 | } 47 | 48 | int main() 49 | { 50 | pthread_t t[COUNT]; 51 | uintptr_t i; 52 | 53 | for (i = 0; i < COUNT; i++) { 54 | pthread_create(&t[i], NULL, thread, (void *)i); 55 | } 56 | 57 | for (i = 0; i < COUNT; i++) { 58 | pthread_join(t[i], NULL); 59 | } 60 | 61 | testprintf("loaded %d/%d\n", state, COUNT*26); 62 | testassert(state == COUNT*26); 63 | 64 | succeed(__FILE__); 65 | } 66 | -------------------------------------------------------------------------------- /test/load-parallel0.m: -------------------------------------------------------------------------------- 1 | #ifndef N 2 | #error -DN=n missing 3 | #endif 4 | 5 | #import 6 | #include 7 | #include 8 | #include 9 | #include 10 | extern int state; 11 | 12 | #define CLASS0(n,nn) \ 13 | OBJC_ROOT_CLASS \ 14 | @interface C_##n##_##nn @end \ 15 | @implementation C_##n##_##nn \ 16 | +(void)load { OSAtomicIncrement32(&state); usleep(10); } \ 17 | @end 18 | 19 | #define CLASS(n,nn) CLASS0(n,nn) 20 | 21 | CLASS(a,N) 22 | CLASS(b,N) 23 | CLASS(c,N) 24 | CLASS(d,N) 25 | CLASS(e,N) 26 | CLASS(f,N) 27 | CLASS(g,N) 28 | CLASS(h,N) 29 | CLASS(i,N) 30 | CLASS(j,N) 31 | CLASS(k,N) 32 | CLASS(l,N) 33 | CLASS(m,N) 34 | CLASS(n,N) 35 | CLASS(o,N) 36 | CLASS(p,N) 37 | CLASS(q,N) 38 | CLASS(r,N) 39 | CLASS(s,N) 40 | CLASS(t,N) 41 | CLASS(u,N) 42 | CLASS(v,N) 43 | CLASS(w,N) 44 | CLASS(x,N) 45 | CLASS(y,N) 46 | CLASS(z,N) 47 | -------------------------------------------------------------------------------- /test/load-parallel00.m: -------------------------------------------------------------------------------- 1 | int state = 0; 2 | -------------------------------------------------------------------------------- /test/load-reentrant.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-reentrant.m -o load-reentrant.out 4 | $C{COMPILE} $DIR/load-reentrant2.m -o libload-reentrant2.dylib -bundle -bundle_loader load-reentrant.out 5 | END 6 | */ 7 | 8 | #include "test.h" 9 | #include 10 | 11 | int state1 = 0; 12 | int *state2_p; 13 | 14 | OBJC_ROOT_CLASS 15 | @interface One @end 16 | @implementation One 17 | +(void)load 18 | { 19 | state1 = 111; 20 | 21 | // Re-entrant +load doesn't get to complete until we do 22 | void *dlh = dlopen("libload-reentrant2.dylib", RTLD_LAZY); 23 | testassert(dlh); 24 | state2_p = (int *)dlsym(dlh, "state2"); 25 | testassert(state2_p); 26 | testassert(*state2_p == 0); 27 | 28 | state1 = 1; 29 | } 30 | @end 31 | 32 | int main() 33 | { 34 | testassert(state1 == 1 && state2_p && *state2_p == 2); 35 | succeed(__FILE__); 36 | } 37 | -------------------------------------------------------------------------------- /test/load-reentrant2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int state2 = 0; 4 | extern int state1; 5 | 6 | static void ctor(void) __attribute__((constructor)); 7 | static void ctor(void) 8 | { 9 | // should be called during One's dlopen(), before Two's +load 10 | testassert(state1 == 111); 11 | testassert(state2 == 0); 12 | } 13 | 14 | OBJC_ROOT_CLASS 15 | @interface Two @end 16 | @implementation Two 17 | +(void) load 18 | { 19 | // Does not run until One's +load completes 20 | testassert(state1 == 1); 21 | state2 = 2; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /test/load.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | int state = 0; 7 | int catstate = 0; 8 | int deallocstate = 0; 9 | 10 | @interface Deallocator : TestRoot @end 11 | @implementation Deallocator 12 | -(id)init { 13 | self = [super init]; 14 | if (objc_collectingEnabled()) { 15 | deallocstate = 1; 16 | } 17 | return self; 18 | } 19 | -(void)dealloc { 20 | deallocstate = 1; 21 | SUPER_DEALLOC(); 22 | } 23 | @end 24 | 25 | 26 | @interface Super : TestRoot @end 27 | @implementation Super 28 | +(void)initialize { 29 | if (self == [Super class]) { 30 | testprintf("in +[Super initialize]\n"); 31 | testassert(state == 2); 32 | state = 3; 33 | } else { 34 | testprintf("in +[Super initialize] on behalf of Sub\n"); 35 | testassert(state == 3); 36 | state = 4; 37 | } 38 | } 39 | -(void)load { fail("-[Super load] called!"); } 40 | +(void)load { 41 | testprintf("in +[Super load]\n"); 42 | testassert(state == 0); 43 | state = 1; 44 | } 45 | @end 46 | 47 | @interface Sub : Super { } @end 48 | @implementation Sub 49 | +(void)load { 50 | testprintf("in +[Sub load]\n"); 51 | testassert(state == 1); 52 | state = 2; 53 | } 54 | -(void)load { fail("-[Sub load] called!"); } 55 | @end 56 | 57 | @interface SubNoLoad : Super { } @end 58 | @implementation SubNoLoad @end 59 | 60 | @interface Super (Category) @end 61 | @implementation Super (Category) 62 | -(void)load { fail("-[Super(Category) load called!"); } 63 | +(void)load { 64 | testprintf("in +[Super(Category) load]\n"); 65 | testassert(state >= 1); 66 | catstate++; 67 | } 68 | @end 69 | 70 | 71 | @interface Sub (Category) @end 72 | @implementation Sub (Category) 73 | -(void)load { fail("-[Sub(Category) load called!"); } 74 | +(void)load { 75 | testprintf("in +[Sub(Category) load]\n"); 76 | testassert(state >= 2); 77 | catstate++; 78 | 79 | // test autorelease pool 80 | __autoreleasing id x; 81 | x = AUTORELEASE([Deallocator new]); 82 | } 83 | @end 84 | 85 | 86 | @interface SubNoLoad (Category) @end 87 | @implementation SubNoLoad (Category) 88 | -(void)load { fail("-[SubNoLoad(Category) load called!"); } 89 | +(void)load { 90 | testprintf("in +[SubNoLoad(Category) load]\n"); 91 | testassert(state >= 1); 92 | catstate++; 93 | } 94 | @end 95 | 96 | int main() 97 | { 98 | testassert(state == 2); 99 | testassert(catstate == 3); 100 | testassert(deallocstate == 1); 101 | [Sub class]; 102 | testassert(state == 4); 103 | testassert(catstate == 3); 104 | 105 | succeed(__FILE__); 106 | } 107 | -------------------------------------------------------------------------------- /test/methodListSize.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | // rdar://8052003 rdar://8077031 3 | 4 | #include "test.h" 5 | 6 | #include 7 | #include 8 | 9 | // add SELCOUNT methods to each of CLASSCOUNT classes 10 | #define CLASSCOUNT 100 11 | #define SELCOUNT 200 12 | 13 | int main() 14 | { 15 | int i, j; 16 | malloc_statistics_t start, end; 17 | 18 | Class root; 19 | root = objc_allocateClassPair(NULL, "Root", 0); 20 | objc_registerClassPair(root); 21 | 22 | Class classes[CLASSCOUNT]; 23 | for (i = 0; i < CLASSCOUNT; i++) { 24 | char *classname; 25 | asprintf(&classname, "GrP_class_%d", i); 26 | classes[i] = objc_allocateClassPair(root, classname, 0); 27 | objc_registerClassPair(classes[i]); 28 | free(classname); 29 | } 30 | 31 | SEL selectors[SELCOUNT]; 32 | for (i = 0; i < SELCOUNT; i++) { 33 | char *selname; 34 | asprintf(&selname, "GrP_sel_%d", i); 35 | selectors[i] = sel_registerName(selname); 36 | free(selname); 37 | } 38 | 39 | malloc_zone_statistics(NULL, &start); 40 | 41 | for (i = 0; i < CLASSCOUNT; i++) { 42 | for (j = 0; j < SELCOUNT; j++) { 43 | class_addMethod(classes[i], selectors[j], (IMP)main, ""); 44 | } 45 | } 46 | 47 | malloc_zone_statistics(NULL, &end); 48 | 49 | // expected: 3-word method struct plus two other words 50 | ssize_t expected = (sizeof(void*) * (3+2)) * SELCOUNT * CLASSCOUNT; 51 | ssize_t actual = end.size_in_use - start.size_in_use; 52 | testassert(actual < expected * 3); // allow generous fudge factor 53 | 54 | succeed(__FILE__); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/method_getName.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | #undef SUPPORT_NONPOINTER_ISA // remove test.h's definition 8 | #include "../runtime/objc-config.h" 9 | 10 | int main() { 11 | unsigned i; 12 | Class c = [NSObject class]; 13 | unsigned numMethods; 14 | Method *methods = class_copyMethodList(c, &numMethods); 15 | 16 | for (i=0; i method_getName crash on NSObject method when GC is enabled 18 | SEL aMethod; 19 | aMethod = method_getName(methods[i]); 20 | #if defined(kIgnore) 21 | if (aMethod == (SEL)kIgnore) 22 | fail(__FILE__); 23 | #endif 24 | } 25 | 26 | succeed(__FILE__); 27 | } 28 | -------------------------------------------------------------------------------- /test/nilAPIArgs.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #import 6 | 7 | int main() { 8 | // ensure various bits of API don't crash when tossed nil parameters 9 | class_conformsToProtocol(nil, nil); 10 | method_setImplementation(nil, NULL); 11 | 12 | succeed(__FILE__); 13 | } 14 | -------------------------------------------------------------------------------- /test/nopool.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | @implementation TestRoot (Loader) 7 | +(void)load 8 | { 9 | [[TestRoot new] autorelease]; 10 | testassert(TestRootAutorelease == 1); 11 | testassert(TestRootDealloc == 0); 12 | } 13 | @end 14 | 15 | int main() 16 | { 17 | // +load's autoreleased object should have deallocated 18 | testassert(TestRootDealloc == 1); 19 | 20 | [[TestRoot new] autorelease]; 21 | testassert(TestRootAutorelease == 2); 22 | 23 | objc_autoreleasePoolPop(objc_autoreleasePoolPush()); 24 | 25 | [[TestRoot new] autorelease]; 26 | testassert(TestRootAutorelease == 3); 27 | 28 | testonthread(^{ 29 | [[TestRoot new] autorelease]; 30 | testassert(TestRootAutorelease == 4); 31 | testassert(TestRootDealloc == 1); 32 | }); 33 | 34 | // thread's autoreleased object should have deallocated 35 | testassert(TestRootDealloc == 2); 36 | 37 | succeed(__FILE__); 38 | } 39 | -------------------------------------------------------------------------------- /test/nscdtors.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | // test cdtors, with NSObject instead of TestRoot as the root class 3 | 4 | #define USE_FOUNDATION 1 5 | #include "cdtors.mm" 6 | 7 | -------------------------------------------------------------------------------- /test/nsexc.m: -------------------------------------------------------------------------------- 1 | /* 2 | need exception-safe ARC for exception deallocation tests 3 | TEST_CFLAGS -fobjc-arc-exceptions -framework Foundation 4 | 5 | llvm-gcc unavoidably warns about our deliberately out-of-order handlers 6 | 7 | TEST_BUILD_OUTPUT 8 | In file included from .* 9 | .*exc.m: In function .* 10 | .*exc.m:\d+: warning: exception of type .* will be caught 11 | .*exc.m:\d+: warning: by earlier handler for .* 12 | .*exc.m:\d+: warning: exception of type .* will be caught 13 | .*exc.m:\d+: warning: by earlier handler for .* 14 | .*exc.m:\d+: warning: exception of type .* will be caught 15 | .*exc.m:\d+: warning: by earlier handler for .* 16 | OR 17 | END 18 | */ 19 | 20 | #define USE_FOUNDATION 1 21 | #include "exc.m" 22 | -------------------------------------------------------------------------------- /test/nsobject.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,gc 2 | 3 | #include "test.h" 4 | 5 | #import 6 | 7 | @interface Sub : NSObject @end 8 | @implementation Sub 9 | +(id)allocWithZone:(NSZone *)zone { 10 | testprintf("in +[Sub alloc]\n"); 11 | return [super allocWithZone:zone]; 12 | } 13 | -(void)dealloc { 14 | testprintf("in -[Sub dealloc]\n"); 15 | [super dealloc]; 16 | } 17 | @end 18 | 19 | 20 | // These declarations and definitions can be used 21 | // to check the compile-time type of an object. 22 | @interface NSObject (Checker) 23 | // fixme this isn't actually enforced 24 | +(void)NSObjectInstance __attribute__((unavailable)); 25 | @end 26 | @implementation NSObject (Checker) 27 | -(void)NSObjectInstance { } 28 | +(void)NSObjectClass { } 29 | @end 30 | @interface Sub (Checker) 31 | -(void)NSObjectInstance __attribute__((unavailable)); 32 | +(void)NSObjectClass __attribute__((unavailable)); 33 | @end 34 | @implementation Sub (Checker) 35 | -(void)SubInstance { } 36 | +(void)SubClass { } 37 | @end 38 | 39 | int main() 40 | { 41 | PUSH_POOL { 42 | [[Sub new] autorelease]; 43 | } POP_POOL; 44 | 45 | // Verify that dot syntax on class objects works with some instance methods 46 | // (void)NSObject.self; fixme 47 | (void)NSObject.class; 48 | (void)NSObject.superclass; 49 | (void)NSObject.hash; 50 | (void)NSObject.description; 51 | (void)NSObject.debugDescription; 52 | 53 | // Verify that some methods return the correct type. 54 | Class cls; 55 | NSObject *nsobject = nil; 56 | Sub *subobject = nil; 57 | 58 | cls = [NSObject self]; 59 | cls = [Sub self]; 60 | nsobject = [nsobject self]; 61 | subobject = [subobject self]; 62 | [[NSObject self] NSObjectClass]; 63 | [[nsobject self] NSObjectInstance]; 64 | [[Sub self] SubClass]; 65 | [[subobject self] SubInstance]; 66 | 67 | // fixme 68 | // cls = NSObject.self; 69 | // cls = Sub.self; 70 | // [NSObject.self NSObjectClass]; 71 | // [nsobject.self NSObjectInstance]; 72 | // [Sub.self SubClass]; 73 | // [subobject.self SubInstance]; 74 | 75 | cls = [NSObject class]; 76 | cls = [nsobject class]; 77 | cls = [Sub class]; 78 | cls = [subobject class]; 79 | [[NSObject class] NSObjectClass]; 80 | [[nsobject class] NSObjectClass]; 81 | [[Sub class] SubClass]; 82 | [[subobject class] SubClass]; 83 | 84 | cls = NSObject.class; 85 | cls = nsobject.class; 86 | cls = Sub.class; 87 | cls = subobject.class; 88 | [NSObject.class NSObjectClass]; 89 | [nsobject.class NSObjectClass]; 90 | [Sub.class SubClass]; 91 | [subobject.class SubClass]; 92 | 93 | 94 | cls = [NSObject superclass]; 95 | cls = [nsobject superclass]; 96 | cls = [Sub superclass]; 97 | cls = [subobject superclass]; 98 | [[NSObject superclass] NSObjectClass]; 99 | [[nsobject superclass] NSObjectClass]; 100 | [[Sub superclass] NSObjectClass]; 101 | [[subobject superclass] NSObjectClass]; 102 | 103 | cls = NSObject.superclass; 104 | cls = nsobject.superclass; 105 | cls = Sub.superclass; 106 | cls = subobject.superclass; 107 | [NSObject.superclass NSObjectClass]; 108 | [nsobject.superclass NSObjectClass]; 109 | [Sub.superclass NSObjectClass]; 110 | [subobject.superclass NSObjectClass]; 111 | 112 | 113 | succeed(__FILE__); 114 | } 115 | -------------------------------------------------------------------------------- /test/nsprotocol.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #if __OBJC2__ 6 | 7 | #include 8 | 9 | int main() 10 | { 11 | // Class Protocol is always a subclass of NSObject 12 | 13 | testassert(objc_getClass("NSObject")); 14 | 15 | Class cls = objc_getClass("Protocol"); 16 | testassert(class_getInstanceMethod(cls, sel_registerName("isProxy"))); 17 | testassert(class_getSuperclass(cls) == objc_getClass("NSObject")); 18 | 19 | succeed(__FILE__); 20 | } 21 | 22 | #else 23 | 24 | #include 25 | #include 26 | 27 | int main() 28 | { 29 | // Class Protocol is never a subclass of NSObject 30 | // CoreFoundation adds NSObject methods to Protocol when it loads 31 | 32 | testassert(objc_getClass("NSObject")); 33 | 34 | Class cls = objc_getClass("Protocol"); 35 | testassert(!class_getInstanceMethod(cls, sel_registerName("isProxy"))); 36 | testassert(class_getSuperclass(cls) != objc_getClass("NSObject")); 37 | 38 | void *dl = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_LAZY); 39 | testassert(dl); 40 | 41 | testassert(class_getInstanceMethod(cls, sel_registerName("isProxy"))); 42 | testassert(class_getSuperclass(cls) != objc_getClass("NSObject")); 43 | 44 | succeed(__FILE__); 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /test/objectCopy.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,gc 2 | 3 | #include "test.h" 4 | #include 5 | 6 | @interface Test : NSObject { 7 | @public 8 | char bytes[32-sizeof(void*)]; 9 | } 10 | @end 11 | @implementation Test 12 | @end 13 | 14 | 15 | int main() 16 | { 17 | Test *o0 = [Test new]; 18 | [o0 retain]; 19 | Test *o1 = class_createInstance([Test class], 32); 20 | [o1 retain]; 21 | id o2 = object_copy(o0, 0); 22 | id o3 = object_copy(o1, 0); 23 | id o4 = object_copy(o1, 32); 24 | testassert(malloc_size(o0) == 32); 25 | testassert(malloc_size(o1) == 64); 26 | testassert(malloc_size(o2) == 32); 27 | testassert(malloc_size(o3) == 32); 28 | testassert(malloc_size(o4) == 64); 29 | if (!objc_collecting_enabled()) { 30 | testassert([o0 retainCount] == 2); 31 | testassert([o1 retainCount] == 2); 32 | testassert([o2 retainCount] == 1); 33 | testassert([o3 retainCount] == 1); 34 | testassert([o4 retainCount] == 1); 35 | } 36 | succeed(__FILE__); 37 | } 38 | -------------------------------------------------------------------------------- /test/property.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | #include 8 | 9 | @interface Super : TestRoot { 10 | @public 11 | char superIvar; 12 | } 13 | 14 | @property(readonly) char superProp; 15 | @end 16 | 17 | @implementation Super 18 | @synthesize superProp = superIvar; 19 | @end 20 | 21 | 22 | @interface Sub : Super { 23 | @public 24 | uintptr_t subIvar; 25 | } 26 | @property(readonly) uintptr_t subProp; 27 | @end 28 | 29 | @implementation Sub 30 | @synthesize subProp = subIvar; 31 | @end 32 | 33 | 34 | int main() 35 | { 36 | /* 37 | Runtime layout of Sub: 38 | [0] isa 39 | [1] superIvar 40 | [2] subIvar 41 | */ 42 | 43 | objc_property_t prop; 44 | 45 | prop = class_getProperty([Sub class], "subProp"); 46 | testassert(prop); 47 | 48 | prop = class_getProperty([Super class], "superProp"); 49 | testassert(prop); 50 | testassert(prop == class_getProperty([Sub class], "superProp")); 51 | 52 | prop = class_getProperty([Super class], "subProp"); 53 | testassert(!prop); 54 | 55 | prop = class_getProperty(object_getClass([Sub class]), "subProp"); 56 | testassert(!prop); 57 | 58 | 59 | testassert(NULL == class_getProperty(NULL, "foo")); 60 | testassert(NULL == class_getProperty([Sub class], NULL)); 61 | testassert(NULL == class_getProperty(NULL, NULL)); 62 | 63 | succeed(__FILE__); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /test/protocol_copyPropertyList.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // need Foundation to get NSObject compatibility additions for class Protocol 3 | // because ARC calls [protocol retain] 4 | 5 | #include "test.h" 6 | #include 7 | #include 8 | #include 9 | 10 | @protocol SuperProps 11 | @property int prop1; 12 | @property int prop2; 13 | @end 14 | 15 | @protocol SubProps 16 | @property int prop3; 17 | @property int prop4; 18 | @end 19 | 20 | 21 | @protocol FourProps 22 | @property int prop1; 23 | @property int prop2; 24 | @property int prop3; 25 | @property int prop4; 26 | @end 27 | 28 | @protocol NoProps @end 29 | 30 | static int isNamed(objc_property_t p, const char *name) 31 | { 32 | return (0 == strcmp(name, property_getName(p))); 33 | } 34 | 35 | int main() 36 | { 37 | objc_property_t *props; 38 | unsigned int count; 39 | Protocol *proto; 40 | 41 | proto = @protocol(SubProps); 42 | testassert(proto); 43 | 44 | count = 100; 45 | props = protocol_copyPropertyList(proto, &count); 46 | testassert(props); 47 | testassert(count == 2); 48 | testassert((isNamed(props[0], "prop4") && isNamed(props[1], "prop3")) || 49 | (isNamed(props[0], "prop3") && isNamed(props[1], "prop4"))); 50 | // props[] should be null-terminated 51 | testassert(props[2] == NULL); 52 | free(props); 53 | 54 | proto = @protocol(SuperProps); 55 | testassert(proto); 56 | 57 | count = 100; 58 | props = protocol_copyPropertyList(proto, &count); 59 | testassert(props); 60 | testassert(count == 2); 61 | testassert((isNamed(props[0], "prop1") && isNamed(props[1], "prop2")) || 62 | (isNamed(props[0], "prop2") && isNamed(props[1], "prop1"))); 63 | // props[] should be null-terminated 64 | testassert(props[2] == NULL); 65 | free(props); 66 | 67 | // Check null-termination - this property list block would be 16 bytes 68 | // if it weren't for the terminator 69 | proto = @protocol(FourProps); 70 | testassert(proto); 71 | 72 | count = 100; 73 | props = protocol_copyPropertyList(proto, &count); 74 | testassert(props); 75 | testassert(count == 4); 76 | testassert(malloc_size(props) >= 5 * sizeof(objc_property_t)); 77 | testassert(props[3] != NULL); 78 | testassert(props[4] == NULL); 79 | free(props); 80 | 81 | // Check NULL count parameter 82 | props = protocol_copyPropertyList(proto, NULL); 83 | testassert(props); 84 | testassert(props[4] == NULL); 85 | testassert(props[3] != NULL); 86 | free(props); 87 | 88 | // Check NULL protocol parameter 89 | count = 100; 90 | props = protocol_copyPropertyList(NULL, &count); 91 | testassert(!props); 92 | testassert(count == 0); 93 | 94 | // Check NULL protocol and count 95 | props = protocol_copyPropertyList(NULL, NULL); 96 | testassert(!props); 97 | 98 | // Check protocol with no properties 99 | proto = @protocol(NoProps); 100 | testassert(proto); 101 | 102 | count = 100; 103 | props = protocol_copyPropertyList(proto, &count); 104 | testassert(!props); 105 | testassert(count == 0); 106 | 107 | succeed(__FILE__); 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /test/protocol_cw.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -Wno-deprecated-declarations 2 | 3 | #include "test.h" 4 | 5 | #if __OBJC2__ 6 | 7 | int main() 8 | { 9 | succeed(__FILE__); 10 | } 11 | 12 | #else 13 | 14 | // rdar://4951638 15 | 16 | #include 17 | #include 18 | 19 | char Protocol_name[] __attribute__((section("__OBJC,__class_names"))) = "Protocol"; 20 | 21 | struct st { 22 | void *isa; 23 | const char *protocol_name; 24 | void *protocol_list; 25 | void *instance_methods; 26 | void *class_methods; 27 | }; 28 | 29 | struct st Foo_protocol __attribute__((section("__OBJC,__protocol"))) = { Protocol_name, "Foo", 0, 0, 0 }; 30 | 31 | int main() 32 | { 33 | Protocol *foo = objc_getProtocol("Foo"); 34 | 35 | testassert(foo == (Protocol *)&Foo_protocol); 36 | testassert(0 == strcmp("Foo", [foo name])); 37 | succeed(__FILE__); 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /test/rawisa.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CFLAGS -Xlinker -sectcreate -Xlinker __DATA -Xlinker __objc_rawisa -Xlinker /dev/null 3 | TEST_ENV OBJC_PRINT_RAW_ISA=YES 4 | 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: RAW ISA: disabling non-pointer isa because the app has a __DATA,__objc_rawisa section 7 | (.* RAW ISA: .*\n)* 8 | OK: rawisa.m 9 | OR 10 | (.* RAW ISA: .*\n)* 11 | no __DATA,__rawisa support 12 | OK: rawisa.m 13 | END 14 | */ 15 | 16 | #include "test.h" 17 | 18 | int main() 19 | { 20 | fprintf(stderr, "\n"); 21 | #if ! (SUPPORT_NONPOINTER_ISA && TARGET_OS_MAC && !TARGET_OS_IPHONE) 22 | // only 64-bit Mac supports this 23 | fprintf(stderr, "no __DATA,__rawisa support\n"); 24 | #endif 25 | succeed(__FILE__); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /test/readClassPair.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #if !__OBJC2__ 6 | 7 | int main() 8 | { 9 | succeed(__FILE__); 10 | } 11 | 12 | #else 13 | 14 | #include 15 | 16 | // Reuse evil-class-def.m as a non-evil class definition. 17 | 18 | #define EVIL_SUPER 0 19 | #define EVIL_SUPER_META 0 20 | #define EVIL_SUB 0 21 | #define EVIL_SUB_META 0 22 | 23 | #define OMIT_SUPER 1 24 | #define OMIT_NL_SUPER 1 25 | #define OMIT_SUB 1 26 | #define OMIT_NL_SUB 1 27 | 28 | #include "evil-class-def.m" 29 | 30 | int main() 31 | { 32 | // This definition is ABI and is never allowed to change. 33 | testassert(OBJC_MAX_CLASS_SIZE == 32*sizeof(void*)); 34 | 35 | struct objc_image_info ii = { 0, 0 }; 36 | 37 | // Read a root class. 38 | testassert(!objc_getClass("Super")); 39 | 40 | extern intptr_t OBJC_CLASS_$_Super[OBJC_MAX_CLASS_SIZE/sizeof(void*)]; 41 | Class Super = objc_readClassPair((__bridge Class)(void*)&OBJC_CLASS_$_Super, &ii); 42 | testassert(Super); 43 | 44 | testassert(objc_getClass("Super") == Super); 45 | testassert(0 == strcmp(class_getName(Super), "Super")); 46 | testassert(class_getSuperclass(Super) == nil); 47 | testassert(class_getClassMethod(Super, @selector(load))); 48 | testassert(class_getInstanceMethod(Super, @selector(load))); 49 | testassert(class_getInstanceVariable(Super, "super_ivar")); 50 | testassert(class_getInstanceSize(Super) == sizeof(void*)); 51 | [Super load]; 52 | 53 | // Read a non-root class. 54 | testassert(!objc_getClass("Sub")); 55 | 56 | extern intptr_t OBJC_CLASS_$_Sub[OBJC_MAX_CLASS_SIZE/sizeof(void*)]; 57 | intptr_t Sub2_buf[OBJC_MAX_CLASS_SIZE/sizeof(void*)]; 58 | memcpy(Sub2_buf, &OBJC_CLASS_$_Sub, sizeof(Sub2_buf)); 59 | Class Sub = objc_readClassPair((__bridge Class)(void*)&OBJC_CLASS_$_Sub, &ii); 60 | testassert(Sub); 61 | 62 | testassert(0 == strcmp(class_getName(Sub), "Sub")); 63 | testassert(objc_getClass("Sub") == Sub); 64 | testassert(class_getSuperclass(Sub) == Super); 65 | testassert(class_getClassMethod(Sub, @selector(load))); 66 | testassert(class_getInstanceMethod(Sub, @selector(load))); 67 | testassert(class_getInstanceVariable(Sub, "sub_ivar")); 68 | testassert(class_getInstanceSize(Sub) == 2*sizeof(void*)); 69 | [Sub load]; 70 | 71 | // Reading a class whose name already exists fails. 72 | testassert(! objc_readClassPair((__bridge Class)(void*)Sub2_buf, &ii)); 73 | 74 | succeed(__FILE__); 75 | } 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /test/rr-autorelease-stacklogging.m: -------------------------------------------------------------------------------- 1 | // Test OBJC_DEBUG_POOL_ALLOCATION (which is also enabled by MallocStackLogging) 2 | 3 | // TEST_ENV OBJC_DEBUG_POOL_ALLOCATION=YES 4 | // TEST_CFLAGS -framework Foundation 5 | // TEST_CONFIG MEM=mrc 6 | 7 | #include "test.h" 8 | 9 | #define FOUNDATION 0 10 | #define NAME "rr-autorelease-stacklogging" 11 | 12 | #include "rr-autorelease2.m" 13 | -------------------------------------------------------------------------------- /test/rr-autorelease.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc 3 | 4 | #include "test.h" 5 | 6 | #define FOUNDATION 0 7 | #define NAME "rr-autorelease" 8 | 9 | #include "rr-autorelease2.m" 10 | -------------------------------------------------------------------------------- /test/rr-nsautorelease.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc 3 | 4 | #define FOUNDATION 1 5 | #define NAME "rr-nsautorelease" 6 | 7 | #include "rr-autorelease2.m" 8 | -------------------------------------------------------------------------------- /test/rr-sidetable.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc ARCH=x86_64 3 | 4 | // Stress-test nonpointer isa's side table retain count transfers. 5 | 6 | // x86_64 only. arm64's side table limit is high enough that bugs 7 | // are harder to reproduce. 8 | 9 | #include "test.h" 10 | #import 11 | 12 | #define OBJECTS 1 13 | #define LOOPS 256 14 | #define THREADS 16 15 | #if __x86_64__ 16 | # define RC_HALF (1ULL<<7) 17 | #else 18 | # error sorry 19 | #endif 20 | #define RC_DELTA RC_HALF 21 | 22 | static bool Deallocated = false; 23 | @interface Deallocator : NSObject @end 24 | @implementation Deallocator 25 | -(void)dealloc { 26 | Deallocated = true; 27 | [super dealloc]; 28 | } 29 | @end 30 | 31 | // This is global to avoid extra retains by the dispatch block objects. 32 | static Deallocator *obj; 33 | 34 | int main() { 35 | dispatch_queue_t queue = 36 | dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 37 | 38 | for (size_t i = 0; i < OBJECTS; i++) { 39 | obj = [Deallocator new]; 40 | 41 | dispatch_apply(THREADS, queue, ^(size_t i __unused) { 42 | for (size_t a = 0; a < LOOPS; a++) { 43 | for (size_t b = 0; b < RC_DELTA; b++) { 44 | [obj retain]; 45 | } 46 | for (size_t b = 0; b < RC_DELTA; b++) { 47 | [obj release]; 48 | } 49 | } 50 | }); 51 | 52 | testassert(!Deallocated); 53 | [obj release]; 54 | testassert(Deallocated); 55 | Deallocated = false; 56 | } 57 | 58 | succeed(__FILE__); 59 | } 60 | -------------------------------------------------------------------------------- /test/sel.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #include 7 | 8 | int main() 9 | { 10 | // Make sure @selector values are correctly fixed up 11 | testassert(@selector(foo) == sel_registerName("foo")); 12 | 13 | // sel_getName recognizes the zero SEL 14 | testassert(0 == strcmp("", sel_getName(0))); 15 | 16 | // GC-ignored selectors. 17 | #if __has_feature(objc_arc) 18 | 19 | // ARC dislikes `@selector(retain)` 20 | 21 | #else 22 | 23 | # if defined(__i386__) 24 | // sel_getName recognizes GC-ignored SELs 25 | if (objc_collectingEnabled()) { 26 | testassert(0 == strcmp("", 27 | sel_getName(@selector(retain)))); 28 | } else { 29 | testassert(0 == strcmp("retain", 30 | sel_getName(@selector(retain)))); 31 | } 32 | 33 | // _objc_search_builtins() shouldn't crash on GC-ignored SELs 34 | union { 35 | SEL sel; 36 | const char *ptr; 37 | } u; 38 | u.sel = @selector(retain); 39 | testassert(@selector(retain) == sel_registerName(u.ptr)); 40 | # endif 41 | 42 | #endif 43 | 44 | succeed(__FILE__); 45 | } 46 | -------------------------------------------------------------------------------- /test/setSuper.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -Wno-deprecated-declarations 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | @interface Super1 : TestRoot @end 8 | @implementation Super1 9 | +(int)classMethod { return 1; } 10 | -(int)instanceMethod { return 10000; } 11 | @end 12 | 13 | @interface Super2 : TestRoot @end 14 | @implementation Super2 15 | +(int)classMethod { return 2; } 16 | -(int)instanceMethod { return 20000; } 17 | @end 18 | 19 | @interface Sub : Super1 @end 20 | @implementation Sub 21 | +(int)classMethod { return [super classMethod] + 100; } 22 | -(int)instanceMethod { 23 | return [super instanceMethod] + 1000000; 24 | } 25 | @end 26 | 27 | int main() 28 | { 29 | Class cls; 30 | Sub *obj = [Sub new]; 31 | 32 | testassert(101 == [[Sub class] classMethod]); 33 | testassert(1010000 == [obj instanceMethod]); 34 | 35 | cls = class_setSuperclass([Sub class], [Super2 class]); 36 | 37 | testassert(cls == [Super1 class]); 38 | testassert(object_getClass(cls) == object_getClass([Super1 class])); 39 | 40 | testassert(102 == [[Sub class] classMethod]); 41 | testassert(1020000 == [obj instanceMethod]); 42 | 43 | succeed(__FILE__); 44 | } 45 | -------------------------------------------------------------------------------- /test/super.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | @interface Sub : TestRoot @end 8 | @implementation Sub @end 9 | 10 | int main() 11 | { 12 | // [super ...] messages are tested in msgSend.m 13 | 14 | testassert(class_getSuperclass([Sub class]) == [TestRoot class]); 15 | testassert(class_getSuperclass(object_getClass([Sub class])) == object_getClass([TestRoot class])); 16 | testassert(class_getSuperclass([TestRoot class]) == Nil); 17 | testassert(class_getSuperclass(object_getClass([TestRoot class])) == [TestRoot class]); 18 | testassert(class_getSuperclass(Nil) == Nil); 19 | 20 | succeed(__FILE__); 21 | } 22 | -------------------------------------------------------------------------------- /test/synchronized-counter.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // synchronized stress test 13 | // Single locked counter incremented by many threads. 14 | 15 | #if defined(__arm__) 16 | #define THREADS 16 17 | #define COUNT 1024*24 18 | #else 19 | // 64 / 1024*24 test takes about 20s on 4x2.6GHz Mac Pro 20 | #define THREADS 64 21 | #define COUNT 1024*24 22 | #endif 23 | 24 | static id lock; 25 | static int count; 26 | 27 | static void *threadfn(void *arg) 28 | { 29 | int n, d; 30 | int depth = 1 + (int)(intptr_t)arg % 4; 31 | 32 | objc_registerThreadWithCollector(); 33 | 34 | for (n = 0; n < COUNT; n++) { 35 | // Lock 36 | for (d = 0; d < depth; d++) { 37 | int err = objc_sync_enter(lock); 38 | testassert(err == OBJC_SYNC_SUCCESS); 39 | } 40 | 41 | // Increment 42 | count++; 43 | 44 | // Unlock 45 | for (d = 0; d < depth; d++) { 46 | int err = objc_sync_exit(lock); 47 | testassert(err == OBJC_SYNC_SUCCESS); 48 | } 49 | } 50 | 51 | // Verify lack of objc pthread data (should have used sync fast cache) 52 | #ifdef __PTK_FRAMEWORK_OBJC_KEY0 53 | testassert(! pthread_getspecific(__PTK_FRAMEWORK_OBJC_KEY0)); 54 | #endif 55 | 56 | return NULL; 57 | } 58 | 59 | int main() 60 | { 61 | pthread_t threads[THREADS]; 62 | int t; 63 | int err; 64 | 65 | lock = [[NSObject alloc] init]; 66 | 67 | // Verify objc pthread data on this thread (from +initialize) 68 | // Worker threads shouldn't have any because of sync fast cache. 69 | #ifdef __PTK_FRAMEWORK_OBJC_KEY0 70 | testassert(pthread_getspecific(__PTK_FRAMEWORK_OBJC_KEY0)); 71 | #endif 72 | 73 | // Start the threads 74 | for (t = 0; t < THREADS; t++) { 75 | pthread_create(&threads[t], NULL, &threadfn, (void*)(intptr_t)t); 76 | } 77 | 78 | // Wait for threads to finish 79 | for (t = 0; t < THREADS; t++) { 80 | pthread_join(threads[t], NULL); 81 | } 82 | 83 | // Verify lock: should be available 84 | // Verify count: should be THREADS*COUNT 85 | err = objc_sync_enter(lock); 86 | testassert(err == OBJC_SYNC_SUCCESS); 87 | testassert(count == THREADS*COUNT); 88 | 89 | succeed(__FILE__); 90 | } 91 | -------------------------------------------------------------------------------- /test/synchronized-grid.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // synchronized stress test 12 | // 2-D grid of counters and locks. 13 | // Each thread increments all counters some number of times. 14 | // To increment: 15 | // * thread picks a target [row][col] 16 | // * thread locks all locks [row][0] to [row][col], possibly recursively 17 | // * thread increments counter [row][col] 18 | // * thread unlocks all of the locks 19 | 20 | #if defined(__arm__) 21 | // 16 / 4 / 3 / 1024*8 test takes about 30s on 2nd gen iPod touch 22 | #define THREADS 16 23 | #define ROWS 4 24 | #define COLS 3 25 | #define COUNT 1024*8 26 | #else 27 | // 64 / 4 / 3 / 1024*8 test takes about 20s on 4x2.6GHz Mac Pro 28 | #define THREADS 64 29 | #define ROWS 4 30 | #define COLS 3 31 | #define COUNT 1024*8 32 | #endif 33 | 34 | static id locks[ROWS][COLS]; 35 | static int counts[ROWS][COLS]; 36 | 37 | 38 | static void *threadfn(void *arg) 39 | { 40 | int n, d; 41 | int depth = 1 + (int)(intptr_t)arg % 4; 42 | 43 | objc_registerThreadWithCollector(); 44 | 45 | for (n = 0; n < COUNT; n++) { 46 | int rrr = rand() % ROWS; 47 | int ccc = rand() % COLS; 48 | int rr, cc; 49 | for (rr = 0; rr < ROWS; rr++) { 50 | int r = (rrr+rr) % ROWS; 51 | for (cc = 0; cc < COLS; cc++) { 52 | int c = (ccc+cc) % COLS; 53 | int l; 54 | 55 | // Lock [r][0..c] 56 | // ... in that order to prevent deadlock 57 | for (l = 0; l <= c; l++) { 58 | for (d = 0; d < depth; d++) { 59 | int err = objc_sync_enter(locks[r][l]); 60 | testassert(err == OBJC_SYNC_SUCCESS); 61 | } 62 | } 63 | 64 | // Increment count [r][c] 65 | counts[r][c]++; 66 | 67 | // Unlock [r][0..c] 68 | // ... in that order to increase contention 69 | for (l = 0; l <= c; l++) { 70 | for (d = 0; d < depth; d++) { 71 | int err = objc_sync_exit(locks[r][l]); 72 | testassert(err == OBJC_SYNC_SUCCESS); 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | return NULL; 80 | } 81 | 82 | int main() 83 | { 84 | pthread_t threads[THREADS]; 85 | int r, c, t; 86 | 87 | for (r = 0; r < ROWS; r++) { 88 | for (c = 0; c < COLS; c++) { 89 | locks[r][c] = [[NSObject alloc] init]; 90 | } 91 | } 92 | 93 | // Start the threads 94 | for (t = 0; t < THREADS; t++) { 95 | pthread_create(&threads[t], NULL, &threadfn, (void*)(intptr_t)t); 96 | } 97 | 98 | // Wait for threads to finish 99 | for (t = 0; t < THREADS; t++) { 100 | pthread_join(threads[t], NULL); 101 | } 102 | 103 | // Verify locks: all should be available 104 | // Verify counts: all should be THREADS*COUNT 105 | for (r = 0; r < ROWS; r++) { 106 | for (c = 0; c < COLS; c++) { 107 | int err = objc_sync_enter(locks[r][c]); 108 | testassert(err == OBJC_SYNC_SUCCESS); 109 | testassert(counts[r][c] == THREADS*COUNT); 110 | } 111 | } 112 | 113 | succeed(__FILE__); 114 | } 115 | -------------------------------------------------------------------------------- /test/synchronized.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Basic @synchronized tests. 13 | 14 | 15 | #define WAIT_SEC 3 16 | 17 | static id obj; 18 | static semaphore_t go; 19 | static semaphore_t stop; 20 | 21 | void *thread(void *arg __unused) 22 | { 23 | int err; 24 | 25 | objc_registerThreadWithCollector(); 26 | 27 | // non-blocking sync_enter 28 | err = objc_sync_enter(obj); 29 | testassert(err == OBJC_SYNC_SUCCESS); 30 | 31 | semaphore_signal(go); 32 | // main thread: sync_exit of object locked on some other thread 33 | semaphore_wait(stop); 34 | 35 | err = objc_sync_exit(obj); 36 | testassert(err == OBJC_SYNC_SUCCESS); 37 | err = objc_sync_enter(obj); 38 | testassert(err == OBJC_SYNC_SUCCESS); 39 | 40 | semaphore_signal(go); 41 | // main thread: blocking sync_enter 42 | testassert(WAIT_SEC/3*3 == WAIT_SEC); 43 | sleep(WAIT_SEC/3); 44 | // recursive enter while someone waits 45 | err = objc_sync_enter(obj); 46 | testassert(err == OBJC_SYNC_SUCCESS); 47 | sleep(WAIT_SEC/3); 48 | // recursive exit while someone waits 49 | err = objc_sync_exit(obj); 50 | testassert(err == OBJC_SYNC_SUCCESS); 51 | sleep(WAIT_SEC/3); 52 | // sync_exit while someone waits 53 | err = objc_sync_exit(obj); 54 | testassert(err == OBJC_SYNC_SUCCESS); 55 | 56 | return NULL; 57 | } 58 | 59 | int main() 60 | { 61 | pthread_t th; 62 | int err; 63 | struct timeval start, end; 64 | 65 | obj = [[NSObject alloc] init]; 66 | 67 | // sync_exit of never-locked object 68 | err = objc_sync_exit(obj); 69 | testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR); 70 | 71 | semaphore_create(mach_task_self(), &go, 0, 0); 72 | semaphore_create(mach_task_self(), &stop, 0, 0); 73 | pthread_create(&th, NULL, &thread, NULL); 74 | semaphore_wait(go); 75 | 76 | // sync_exit of object locked on some other thread 77 | err = objc_sync_exit(obj); 78 | testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR); 79 | 80 | semaphore_signal(stop); 81 | semaphore_wait(go); 82 | 83 | // blocking sync_enter 84 | gettimeofday(&start, NULL); 85 | err = objc_sync_enter(obj); 86 | gettimeofday(&end, NULL); 87 | testassert(err == OBJC_SYNC_SUCCESS); 88 | // should have waited more than WAIT_SEC but less than WAIT_SEC+1 89 | // fixme hack: sleep(1) is ending 500 usec too early on x86_64 buildbot 90 | // (rdar://6456975) 91 | testassert(end.tv_sec*1000000LL+end.tv_usec >= 92 | start.tv_sec*1000000LL+start.tv_usec + WAIT_SEC*1000000LL 93 | - 3*500 /*hack*/); 94 | testassert(end.tv_sec*1000000LL+end.tv_usec < 95 | start.tv_sec*1000000LL+start.tv_usec + (1+WAIT_SEC)*1000000LL); 96 | 97 | err = objc_sync_exit(obj); 98 | testassert(err == OBJC_SYNC_SUCCESS); 99 | 100 | err = objc_sync_exit(obj); 101 | testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR); 102 | 103 | succeed(__FILE__); 104 | } 105 | -------------------------------------------------------------------------------- /test/taggedNSPointers.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #include "test.h" 4 | #include 5 | #import 6 | 7 | #if OBJC_HAVE_TAGGED_POINTERS 8 | 9 | void testTaggedNumber() 10 | { 11 | NSNumber *taggedNS = [NSNumber numberWithInt: 1234]; 12 | CFNumberRef taggedCF = (CFNumberRef)objc_unretainedPointer(taggedNS); 13 | int result; 14 | 15 | testassert( CFGetTypeID(taggedCF) == CFNumberGetTypeID() ); 16 | testassert(_objc_getClassForTag(OBJC_TAG_NSNumber) == [taggedNS class]); 17 | 18 | CFNumberGetValue(taggedCF, kCFNumberIntType, &result); 19 | testassert(result == 1234); 20 | 21 | testassert(_objc_isTaggedPointer(taggedCF)); 22 | testassert(_objc_getTaggedPointerTag(taggedCF) == OBJC_TAG_NSNumber); 23 | testassert(_objc_makeTaggedPointer(_objc_getTaggedPointerTag(taggedCF), _objc_getTaggedPointerValue(taggedCF)) == taggedCF); 24 | 25 | // do some generic object-y things to the taggedPointer instance 26 | CFRetain(taggedCF); 27 | CFRelease(taggedCF); 28 | 29 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 30 | [dict setObject: taggedNS forKey: @"fred"]; 31 | testassert(taggedNS == [dict objectForKey: @"fred"]); 32 | [dict setObject: @"bob" forKey: taggedNS]; 33 | testassert([@"bob" isEqualToString: [dict objectForKey: taggedNS]]); 34 | 35 | NSNumber *iM88 = [NSNumber numberWithInt:-88]; 36 | NSNumber *i12346 = [NSNumber numberWithInt: 12346]; 37 | NSNumber *i12347 = [NSNumber numberWithInt: 12347]; 38 | 39 | NSArray *anArray = [NSArray arrayWithObjects: iM88, i12346, i12347, nil]; 40 | testassert([anArray count] == 3); 41 | testassert([anArray indexOfObject: i12346] == 1); 42 | 43 | NSSet *aSet = [NSSet setWithObjects: iM88, i12346, i12347, nil]; 44 | testassert([aSet count] == 3); 45 | testassert([aSet containsObject: i12346]); 46 | 47 | [taggedNS performSelector: @selector(intValue)]; 48 | testassert(![taggedNS isProxy]); 49 | testassert([taggedNS isKindOfClass: [NSNumber class]]); 50 | testassert([taggedNS respondsToSelector: @selector(intValue)]); 51 | 52 | (void)[taggedNS description]; 53 | } 54 | 55 | int main() 56 | { 57 | PUSH_POOL { 58 | testTaggedNumber(); // should be tested by CF... our tests are wrong, wrong, wrong. 59 | } POP_POOL; 60 | 61 | succeed(__FILE__); 62 | } 63 | 64 | // OBJC_HAVE_TAGGED_POINTERS 65 | #else 66 | // not OBJC_HAVE_TAGGED_POINTERS 67 | 68 | // Tagged pointers not supported. Crash if an NSNumber actually 69 | // is a tagged pointer (which means this test is out of date). 70 | 71 | int main() 72 | { 73 | PUSH_POOL { 74 | testassert(*(void **)objc_unretainedPointer([NSNumber numberWithInt:1234])); 75 | } POP_POOL; 76 | 77 | succeed(__FILE__); 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /test/taggedPointersDisabled.m: -------------------------------------------------------------------------------- 1 | // TEST_ENV OBJC_DISABLE_TAGGED_POINTERS=YES 2 | // TEST_CRASHES 3 | /* 4 | TEST_RUN_OUTPUT 5 | objc\[\d+\]: tagged pointers are disabled 6 | CRASHED: SIG(ILL|TRAP) 7 | OR 8 | OK: taggedPointersDisabled.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #include 14 | 15 | #if !OBJC_HAVE_TAGGED_POINTERS 16 | 17 | int main() 18 | { 19 | succeed(__FILE__); 20 | } 21 | 22 | #else 23 | 24 | int main() 25 | { 26 | testassert(!_objc_taggedPointersEnabled()); 27 | _objc_registerTaggedPointerClass((objc_tag_index_t)0, nil); 28 | fail("should have crashed in _objc_registerTaggedPointerClass()"); 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /test/tbi.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=iphoneos ARCH=arm64 2 | 3 | #include "test.h" 4 | 5 | #ifndef __arm64__ 6 | #error wrong architecture for TBI hardware feature 7 | #endif 8 | 9 | volatile int x = 123456; 10 | 11 | int main(void) { 12 | testassert(*(int *)((unsigned long)&x | 0xFF00000000000000ul) == 123456); 13 | succeed(__FILE__); 14 | } 15 | -------------------------------------------------------------------------------- /test/unload.h: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | @interface SmallClass : TestRoot @end 4 | 5 | @interface BigClass : TestRoot @end 6 | 7 | -------------------------------------------------------------------------------- /test/unload2.m: -------------------------------------------------------------------------------- 1 | #include "unload.h" 2 | #include "testroot.i" 3 | #import 4 | 5 | @implementation SmallClass : TestRoot 6 | -(void)unload2_instance_method { } 7 | @end 8 | 9 | 10 | @implementation BigClass : TestRoot 11 | @end 12 | 13 | OBJC_ROOT_CLASS 14 | @interface UnusedClass { id isa; } @end 15 | @implementation UnusedClass @end 16 | 17 | 18 | @protocol SmallProtocol 19 | -(void)unload2_category_method; 20 | @end 21 | 22 | @interface SmallClass (Category) @end 23 | 24 | @implementation SmallClass (Category) 25 | -(void)unload2_category_method { } 26 | @end 27 | -------------------------------------------------------------------------------- /test/unload3.c: -------------------------------------------------------------------------------- 1 | // unload3: contains imageinfo but no other objc metadata 2 | // libobjc must not keep it open 3 | // DO NOT USE __OBJC2__; this is a C file. 4 | 5 | #include 6 | 7 | #if TARGET_OS_WIN32 || (TARGET_OS_MAC && TARGET_CPU_X86 && !TARGET_IPHONE_SIMULATOR) 8 | // old ABI 9 | int fake[2] __attribute__((section("__OBJC,__image_info"))) 10 | #else 11 | // new ABI 12 | int fake[2] __attribute__((section("__DATA,__objc_imageinfo"))) 13 | #endif 14 | = { 0, TARGET_IPHONE_SIMULATOR ? (1<<5) : 0 }; 15 | 16 | // silence "no debug symbols in executable" warning 17 | void fn(void) { } 18 | -------------------------------------------------------------------------------- /test/unload4.m: -------------------------------------------------------------------------------- 1 | // unload4: contains some objc metadata other than imageinfo 2 | // libobjc must keep it open 3 | 4 | #if __OBJC2__ 5 | int fake2 __attribute__((section("__DATA,__objc_foo"))) = 0; 6 | #else 7 | int fake2 __attribute__((section("__OBJC,__foo"))) = 0; 8 | #endif 9 | 10 | // getsectiondata() falls over if __TEXT has no contents 11 | const char *unload4 = "unload4"; 12 | -------------------------------------------------------------------------------- /test/unwind.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | #if !defined(__OBJC2__) 8 | 9 | int main() 10 | { 11 | succeed(__FILE__); 12 | } 13 | 14 | #else 15 | 16 | static int state; 17 | 18 | @interface Foo : NSObject @end 19 | @interface Bar : NSObject @end 20 | 21 | @interface Foo (Unimplemented) 22 | +(void)method; 23 | @end 24 | 25 | @implementation Bar @end 26 | 27 | @implementation Foo 28 | 29 | -(void)check { state++; } 30 | +(void)check { testassert(!"caught class object, not instance"); } 31 | 32 | static id exc; 33 | 34 | static void handler(id unused, void *ctx) __attribute__((used)); 35 | static void handler(id unused __unused, void *ctx __unused) 36 | { 37 | testassert(state == 3); state++; 38 | } 39 | 40 | +(BOOL) resolveClassMethod:(SEL)__unused name 41 | { 42 | testassert(state == 1); state++; 43 | #if !TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 44 | objc_addExceptionHandler(&handler, 0); 45 | testassert(state == 2); 46 | #else 47 | state++; // handler would have done this 48 | #endif 49 | state++; 50 | exc = [Foo new]; 51 | @throw exc; 52 | } 53 | 54 | 55 | @end 56 | 57 | int main() 58 | { 59 | int i; 60 | 61 | // unwind exception and alt handler through objc_msgSend() 62 | 63 | PUSH_POOL { 64 | 65 | state = 0; 66 | for (i = 0; i < 100000; i++) { 67 | @try { 68 | testassert(state == 0); state++; 69 | [Foo method]; 70 | testassert(0); 71 | } @catch (Bar *e) { 72 | testassert(0); 73 | } @catch (Foo *e) { 74 | testassert(e == exc); 75 | testassert(state == 4); state++; 76 | testassert(state == 5); [e check]; // state++ 77 | RELEASE_VAR(exc); 78 | } @catch (id e) { 79 | testassert(0); 80 | } @catch (...) { 81 | testassert(0); 82 | } @finally { 83 | testassert(state == 6); state++; 84 | } 85 | testassert(state == 7); state = 0; 86 | } 87 | 88 | } POP_POOL; 89 | 90 | succeed(__FILE__); 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /test/weak.h: -------------------------------------------------------------------------------- 1 | /* 2 | To test -weak-l or -weak-framework: 3 | * -DWEAK_IMPORT= 4 | * -DWEAK_FRAMEWORK=1 5 | * -UEMPTY when building the weak-not-missing library 6 | * -DEMPTY= when building the weak-missing library 7 | 8 | To test attribute((weak_import)): 9 | * -DWEAK_IMPORT=__attribute__((weak_import)) 10 | * -UWEAK_FRAMEWORK 11 | * -UEMPTY when building the weak-not-missing library 12 | * -DEMPTY= when building the weak-missing library 13 | 14 | */ 15 | 16 | #include "test.h" 17 | #include 18 | 19 | extern int state; 20 | 21 | WEAK_IMPORT OBJC_ROOT_CLASS 22 | @interface MissingRoot { 23 | id isa; 24 | } 25 | +(void) initialize; 26 | +(Class) class; 27 | +(id) alloc; 28 | -(id) init; 29 | -(void) dealloc; 30 | +(int) method; 31 | @end 32 | 33 | @interface MissingRoot (RR) 34 | -(id) retain; 35 | -(void) release; 36 | @end 37 | 38 | WEAK_IMPORT 39 | @interface MissingSuper : MissingRoot { 40 | @public 41 | int ivar; 42 | } 43 | @end 44 | 45 | OBJC_ROOT_CLASS 46 | @interface NotMissingRoot { 47 | id isa; 48 | } 49 | +(void) initialize; 50 | +(Class) class; 51 | +(id) alloc; 52 | -(id) init; 53 | -(void) dealloc; 54 | +(int) method; 55 | @end 56 | 57 | @interface NotMissingRoot (RR) 58 | -(id) retain; 59 | -(void) release; 60 | @end 61 | 62 | @interface NotMissingSuper : NotMissingRoot { 63 | @public 64 | int unused[100]; 65 | int ivar; 66 | } 67 | @end 68 | -------------------------------------------------------------------------------- /test/weak2.m: -------------------------------------------------------------------------------- 1 | // See instructions in weak.h 2 | 3 | #include "test.h" 4 | #include "weak.h" 5 | #include 6 | 7 | int state = 0; 8 | 9 | static void *noop_fn(void *self, SEL _cmd __unused) { 10 | return self; 11 | } 12 | static void *retain_fn(void *self, SEL _cmd __unused) { 13 | void * (*fn)(void *) = (typeof(fn))_objc_rootRetain; 14 | return fn(self); 15 | } 16 | static void release_fn(void *self, SEL _cmd __unused) { 17 | void (*fn)(void *) = (typeof(fn))_objc_rootRelease; 18 | fn(self); 19 | } 20 | static void *autorelease_fn(void *self, SEL _cmd __unused) { 21 | void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease; 22 | return fn(self); 23 | } 24 | 25 | #if !defined(EMPTY) 26 | 27 | @implementation MissingRoot 28 | +(void) initialize { } 29 | +(Class) class { return self; } 30 | +(id) alloc { return _objc_rootAlloc(self); } 31 | +(id) allocWithZone:(void*)zone { return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone); } 32 | -(id) init { return self; } 33 | -(void) dealloc { _objc_rootDealloc(self); } 34 | +(int) method { return 10; } 35 | +(void) load { 36 | class_addMethod(self, sel_registerName("retain"), (IMP)retain_fn, ""); 37 | class_addMethod(self, sel_registerName("release"), (IMP)release_fn, ""); 38 | class_addMethod(self, sel_registerName("autorelease"), (IMP)autorelease_fn, ""); 39 | 40 | class_addMethod(object_getClass(self), sel_registerName("retain"), (IMP)noop_fn, ""); 41 | class_addMethod(object_getClass(self), sel_registerName("release"), (IMP)noop_fn, ""); 42 | class_addMethod(object_getClass(self), sel_registerName("autorelease"), (IMP)noop_fn, ""); 43 | 44 | state++; 45 | } 46 | @end 47 | 48 | @implementation MissingSuper 49 | +(int) method { return 1+[super method]; } 50 | -(id) init { self = [super init]; ivar = 100; return self; } 51 | +(void) load { state++; } 52 | @end 53 | 54 | #endif 55 | 56 | @implementation NotMissingRoot 57 | +(void) initialize { } 58 | +(Class) class { return self; } 59 | +(id) alloc { return _objc_rootAlloc(self); } 60 | +(id) allocWithZone:(void*)zone { return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone); } 61 | -(id) init { return self; } 62 | -(void) dealloc { _objc_rootDealloc(self); } 63 | +(int) method { return 20; } 64 | +(void) load { 65 | class_addMethod(self, sel_registerName("retain"), (IMP)retain_fn, ""); 66 | class_addMethod(self, sel_registerName("release"), (IMP)release_fn, ""); 67 | class_addMethod(self, sel_registerName("autorelease"), (IMP)autorelease_fn, ""); 68 | 69 | class_addMethod(object_getClass(self), sel_registerName("retain"), (IMP)noop_fn, ""); 70 | class_addMethod(object_getClass(self), sel_registerName("release"), (IMP)noop_fn, ""); 71 | class_addMethod(object_getClass(self), sel_registerName("autorelease"), (IMP)noop_fn, ""); 72 | 73 | state++; 74 | } 75 | @end 76 | 77 | @implementation NotMissingSuper 78 | +(int) method { return 1+[super method]; } 79 | -(id) init { self = [super init]; ivar = 200; return self; } 80 | +(void) load { state++; } 81 | @end 82 | 83 | -------------------------------------------------------------------------------- /test/weakcopy.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #if __OBJC_GC__ && __cplusplus && __i386__ 6 | 7 | int main() 8 | { 9 | testwarn("rdar://19042235 test disabled for 32-bit objc++ GC because of unknown bit rot"); 10 | succeed(__FILE__); 11 | } 12 | 13 | #else 14 | 15 | #include "testroot.i" 16 | #include 17 | #include 18 | #include 19 | 20 | @interface Weak : TestRoot { 21 | @public 22 | __weak id value; 23 | } 24 | @end 25 | @implementation Weak 26 | @end 27 | 28 | Weak *oldObject; 29 | Weak *newObject; 30 | 31 | void *fn(void *arg __unused) 32 | { 33 | objc_registerThreadWithCollector(); 34 | 35 | return NULL; 36 | } 37 | 38 | int main() 39 | { 40 | testonthread(^{ 41 | TestRoot *value; 42 | 43 | PUSH_POOL { 44 | value = [TestRoot new]; 45 | testassert(value); 46 | oldObject = [Weak new]; 47 | testassert(oldObject); 48 | 49 | oldObject->value = value; 50 | testassert(oldObject->value == value); 51 | 52 | newObject = [oldObject copy]; 53 | testassert(newObject); 54 | testassert(newObject->value == oldObject->value); 55 | 56 | newObject->value = nil; 57 | testassert(newObject->value == nil); 58 | testassert(oldObject->value == value); 59 | } POP_POOL; 60 | 61 | testcollect(); 62 | TestRootDealloc = 0; 63 | TestRootFinalize = 0; 64 | RELEASE_VAR(value); 65 | }); 66 | 67 | testcollect(); 68 | testassert(TestRootDealloc || TestRootFinalize); 69 | 70 | #if defined(__OBJC_GC__) || __has_feature(objc_arc) 71 | testassert(oldObject->value == nil); 72 | #else 73 | testassert(oldObject->value != nil); 74 | #endif 75 | testassert(newObject->value == nil); 76 | 77 | RELEASE_VAR(newObject); 78 | RELEASE_VAR(oldObject); 79 | 80 | succeed(__FILE__); 81 | return 0; 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /test/weakframework-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -UEMPTY -dynamiclib -o libweakframework.dylib 4 | 5 | $C{COMPILE} $DIR/weakframework-missing.m -L. -weak-lweakframework -o weakframework-missing.out 6 | 7 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -DEMPTY= -dynamiclib -o libweakframework.dylib 8 | 9 | END 10 | */ 11 | 12 | #define WEAK_FRAMEWORK 1 13 | #define WEAK_IMPORT 14 | #include "weak.m" 15 | -------------------------------------------------------------------------------- /test/weakframework-not-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -UEMPTY -dynamiclib -o libweakframework.dylib 4 | 5 | $C{COMPILE} $DIR/weakframework-not-missing.m -L. -weak-lweakframework -o weakframework-not-missing.out 6 | END 7 | */ 8 | 9 | #define WEAK_FRAMEWORK 1 10 | #define WEAK_IMPORT 11 | #include "weak.m" 12 | -------------------------------------------------------------------------------- /test/weakimport-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -UEMPTY -dynamiclib -o libweakimport.dylib 4 | 5 | $C{COMPILE} $DIR/weakimport-missing.m -L. -weak-lweakimport -o weakimport-missing.out 6 | 7 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -DEMPTY= -dynamiclib -o libweakimport.dylib 8 | END 9 | */ 10 | 11 | // #define WEAK_FRAMEWORK 12 | #define WEAK_IMPORT __attribute__((weak_import)) 13 | #include "weak.m" 14 | -------------------------------------------------------------------------------- /test/weakimport-not-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -UEMPTY -dynamiclib -o libweakimport.dylib 4 | 5 | $C{COMPILE} $DIR/weakimport-not-missing.m -L. -weak-lweakimport -o weakimport-not-missing.out 6 | END 7 | */ 8 | 9 | // #define WEAK_FRAMEWORK 10 | #define WEAK_IMPORT __attribute__((weak_import)) 11 | #include "weak.m" 12 | -------------------------------------------------------------------------------- /test/weakrace.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include 5 | 6 | static semaphore_t go1; 7 | static semaphore_t go2; 8 | static semaphore_t done; 9 | 10 | #define VARCOUNT 100000 11 | static id obj; 12 | static id vars[VARCOUNT]; 13 | 14 | 15 | void *destroyer(void *arg __unused) 16 | { 17 | while (1) { 18 | semaphore_wait(go1); 19 | for (int i = 0; i < VARCOUNT; i++) { 20 | objc_destroyWeak(&vars[i]); 21 | } 22 | semaphore_signal(done); 23 | } 24 | } 25 | 26 | 27 | void *deallocator(void *arg __unused) 28 | { 29 | while (1) { 30 | semaphore_wait(go2); 31 | [obj release]; 32 | semaphore_signal(done); 33 | } 34 | } 35 | 36 | 37 | void cycle(void) 38 | { 39 | // rdar://12896779 objc_destroyWeak() versus weak clear in dealloc 40 | 41 | // Clean up from previous cycle - objc_destroyWeak() doesn't set var to nil 42 | for (int i = 0; i < VARCOUNT; i++) { 43 | vars[i] = nil; 44 | } 45 | 46 | obj = [NSObject new]; 47 | for (int i = 0; i < VARCOUNT; i++) { 48 | objc_storeWeak(&vars[i], obj); 49 | } 50 | 51 | // let destroyer start before deallocator runs 52 | semaphore_signal(go1); 53 | sched_yield(); 54 | semaphore_signal(go2); 55 | 56 | semaphore_wait(done); 57 | semaphore_wait(done); 58 | } 59 | 60 | 61 | int main() 62 | { 63 | semaphore_create(mach_task_self(), &go1, 0, 0); 64 | semaphore_create(mach_task_self(), &go2, 0, 0); 65 | semaphore_create(mach_task_self(), &done, 0, 0); 66 | 67 | pthread_t th[2]; 68 | pthread_create(&th[1], NULL, deallocator, NULL); 69 | pthread_create(&th[1], NULL, destroyer, NULL); 70 | 71 | for (int i = 0; i < 100; i++) { 72 | cycle(); 73 | } 74 | 75 | succeed(__FILE__); 76 | } 77 | -------------------------------------------------------------------------------- /test/xref.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "test.h" 8 | 9 | int main() 10 | { 11 | // rdar://8350188 External references (handles) 12 | 13 | id object = [NSObject new]; 14 | testassert(object); 15 | 16 | // STRONG 17 | objc_xref_t xref = _object_addExternalReference(object, OBJC_XREF_STRONG); 18 | testassert(xref); 19 | testassert(_object_readExternalReference(xref) == object); 20 | _object_removeExternalReference(xref); 21 | // TODO: expect a crash if a stale xref is used. 22 | 23 | // WEAK 24 | xref = _object_addExternalReference(object, OBJC_XREF_WEAK); 25 | testassert(xref); 26 | testassert(_object_readExternalReference(xref) == object); 27 | _object_removeExternalReference(xref); 28 | 29 | RELEASE_VAR(object); 30 | 31 | succeed(__FILE__); 32 | } 33 | -------------------------------------------------------------------------------- /test/zone.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | // Look for malloc zone "ObjC" iff OBJC_USE_INTERNAL_ZONE is set. 8 | // This fails if objc tries to allocate before checking its own 9 | // environment variables (rdar://6688423) 10 | 11 | int main() 12 | { 13 | if (is_guardmalloc()) { 14 | // guard malloc confuses this test 15 | succeed(__FILE__); 16 | } 17 | 18 | kern_return_t kr; 19 | vm_address_t *zones; 20 | unsigned int count, i; 21 | BOOL has_objc = NO, want_objc = NO; 22 | 23 | want_objc = (getenv("OBJC_USE_INTERNAL_ZONE") != NULL) ? YES : NO; 24 | testprintf("want objc %s\n", want_objc ? "YES" : "NO"); 25 | 26 | kr = malloc_get_all_zones(mach_task_self(), NULL, &zones, &count); 27 | testassert(!kr); 28 | for (i = 0; i < count; i++) { 29 | const char *name = malloc_get_zone_name((malloc_zone_t *)zones[i]); 30 | if (name) { 31 | BOOL is_objc = (0 == strcmp(name, "ObjC_Internal")) ? YES : NO; 32 | if (is_objc) has_objc = YES; 33 | testprintf("zone %s\n", name); 34 | } 35 | } 36 | 37 | testassert(want_objc == has_objc); 38 | 39 | succeed(__FILE__); 40 | } 41 | -------------------------------------------------------------------------------- /unexported_symbols: -------------------------------------------------------------------------------- 1 | .objc_class_name___IncompleteProtocol 2 | __Znam 3 | __ZnamRKSt9nothrow_t 4 | __Znwm 5 | __ZnwmRKSt9nothrow_t 6 | __ZdaPv 7 | __ZdaPvRKSt9nothrow_t 8 | __ZdlPv 9 | __ZdlPvRKSt9nothrow_t 10 | __ZTISt9bad_alloc 11 | __ZTISt9exception 12 | __ZTISt11logic_error 13 | __ZTISt12length_error 14 | __ZTSSt9bad_alloc 15 | __ZTSSt9exception 16 | __ZTSSt11logic_error 17 | __ZTSSt12length_error 18 | -------------------------------------------------------------------------------- /version.bat: -------------------------------------------------------------------------------- 1 | :: version.bat 2 | :: Writes version numbers from B&I into version.h for use by version.rc. 3 | 4 | @ECHO OFF 5 | 6 | :: Set default values for environment variables if not set by B&I 7 | IF "%OBJROOT%"=="" SET OBJROOT=. 8 | IF "%RC_PROJECTSOURCEVERSION%"=="" SET RC_PROJECTSOURCEVERSION=0.0 9 | IF "%RC_PROJECTBUILDVERSION%"=="" SET RC_PROJECTBUILDVERSION=0 10 | 11 | :: Get version numbers from environment variables 12 | SET major=1 13 | SET patch=0 14 | FOR /F "tokens=1* eol= delims=." %%i IN ("%RC_PROJECTSOURCEVERSION%") DO ( 15 | SET minor=%%i 16 | IF NOT "%%j"=="" SET patch=%%j 17 | ) 18 | SET build=%RC_PROJECTBUILDVERSION% 19 | 20 | ECHO version %major% . %minor% . %patch% . %build% 21 | 22 | :: Write version.h 23 | ECHO // This file is automatically generated by version.bat. > "%OBJROOT%\version.h" 24 | ECHO // DO NOT EDIT >> "%OBJROOT%\version.h" 25 | ECHO #define major %major% >> "%OBJROOT%\version.h" 26 | ECHO #define minor %minor% >> "%OBJROOT%\version.h" 27 | ECHO #define patch %patch% >> "%OBJROOT%\version.h" 28 | ECHO #define build %build% >> "%OBJROOT%\version.h" 29 | ECHO #define string "%major%,%minor%,%patch%,%build%" >> "%OBJROOT%\version.h" 30 | -------------------------------------------------------------------------------- /version.rc: -------------------------------------------------------------------------------- 1 | #include "Winver.h" 2 | 3 | // built by version.bat; sets variables major, minor, patch, build, string 4 | #include "version.h" 5 | 6 | VS_VERSION_INFO VERSIONINFO 7 | FILEVERSION major,minor,patch,build 8 | PRODUCTVERSION major,minor,patch,build 9 | FILEFLAGSMASK 0x17L 10 | #ifdef _DEBUG 11 | FILEFLAGS VS_FF_DEBUG 12 | #else 13 | FILEFLAGS 0x0L 14 | #endif 15 | FILEOS VOS_NT_WINDOWS32 16 | FILETYPE VFT_DLL 17 | FILESUBTYPE VFT2_UNKNOWN 18 | BEGIN 19 | BLOCK "StringFileInfo" 20 | BEGIN 21 | BLOCK "040904b0" 22 | BEGIN 23 | VALUE "CompanyName", "Apple Inc." 24 | VALUE "FileDescription", "Objective-C Runtime Library" 25 | VALUE "FileVersion", string 26 | VALUE "ProductVersion", string 27 | VALUE "ProductName", "objc4" 28 | VALUE "InternalName", "objc4" 29 | VALUE "LegalCopyright", "Copyright (C) 2007-2009, Apple Inc." 30 | VALUE "OriginalFilename", "objc.dll" 31 | END 32 | END 33 | BLOCK "VarFileInfo" 34 | BEGIN 35 | VALUE "Translation", 0x409, 1200 36 | END 37 | END 38 | 39 | --------------------------------------------------------------------------------