{ objcrtl.pas Copyright (C) 2009 Dmitry Boyarintsev This unit is a pascal binding for dynamic Objective-C Run-time Library headers included with XCode 3.1.2 The original copyright note of is kept on each include file } unit objcrtl; {$mode objfpc}{$H+} interface uses dynlibs; const DefaultObjCLibName : AnsiString = 'libobjc.A.dylib'; { Overview -------- This document describes the Mac OS X Objective-C 2.0 runtime library support functions and data structures. The functions are implemented in the shared library found at /usr/lib/libobjc.A.dylib. This shared library provides support for the dynamic properties of the Objective-C language, and as such is linked to by all Objective-C applications. This reference is useful primarily for developing bridge layers between Objective-C and other languages, or for low-level debugging. You typically do not need to use the Objective-C runtime library directly when programming in Objective-C. The Mac OS X implementation of the Objective-C runtime library is unique to the Mac OS X platform. For other platforms, the GNU Compiler Collection provides a different implementation with a similar API. This document covers only the Mac OS X implementation. The low-level Objective-C runtime API is significantly updated in Mac OS X version 10.5. Many functions and all existing data structures are replaced with new functions. The old functions and structures are deprecated in 32-bit and absent in 64-bit mode. The API constrains several values to 32-bit ints even in 64-bit mode—class count, protocol count, methods per class, ivars per class, arguments per method, sizeof(all arguments) per method, and class version number. In addition, the new Objective-C ABI (not described here) further constrains sizeof(anInstance) to 32 bits, and three other values to 24 bits—methods per class, ivars per class, and sizeof(a single ivar). Finally, the obsolete NXHashTable and NXMapTable are limited to 4 billion items. “Deprecated” below means “deprecated in Mac OS X version 10.5 for 32-bit code, and disallowed for 64-bit code. Legacy and Modern Versions -------------------------- There are two versions of the Objective-C runtime—“modern” and “legacy”. The modern version was introduced with Objective-C 2.0 and includes a number of new features. The programming interface for the legacy version of the runtime is described in Objective-C 1 Runtime Reference; the programming interface for the modern version of the runtime is described in Objective-C 2.0 Runtime Reference. The most notable new feature is that instance variables in the modern runtime are “non-fragile”: * In the legacy runtime, if you change the layout of instance variables in a class, you must recompile classes that inherit from it. * In the modern runtime, if you change the layout of instance variables in a class, you do not have to recompile classes that inherit from it. In addition, the modern runtime supports instance variable synthesis for declared properties (see Declared Properties in The Objective-C 2.0 Programming Language). Platforms --------- iPhone applications and 64-bit programs on Mac OS X v10.5 and later use the modern version of the runtime. Other programs (32-bit programs on Mac OS X desktop) use the legacy version of the runtime. } type //todo: types MUST BE declared properly as 2.0 opaques SEL = Pointer; IMP = Pointer; id = Pointer; //?? size_t = LongWord; _Class = Pointer; Ivar = Pointer; PProtocol = Pointer; PArrayPProtocol = Pointer; BOOL = Boolean; PIvar = Pointer; Method = Pointer; PMethod = Pointer; Protocol = Pointer; objc_property_t = Pointer; Pobjc_property_t = Pointer; uint8_t = byte; Pobjc_method_description = Pointer; ptrdiff_t = Pointer; objc_method_description = Pointer; TMutationHandlerProc = Pointer; pobjc_super = ^objc_super; objc_super = packed record reciever : id; class_ : _class; end; var sel_getName : function (sel: SEL): PChar; cdecl = nil; sel_registerName : function (str: PChar): SEL; cdecl = nil; object_getClassName : function (obj: id): PChar; cdecl = nil; object_getIndexedIvars : function (obj: id ): Pointer; cdecl = nil; sel_isMapped: function (sel: SEL): Boolean; cdecl = nil; sel_getUid: function (const str: PChar): SEL; cdecl = nil; object_copy : function (obj:id; size:size_t):id; cdecl = nil; object_dispose : function (obj:id):id; cdecl = nil; object_getClass : function (obj:id): _Class; cdecl = nil; object_setClass : function (obj:id; cls: _Class):_Class; cdecl = nil; object_getIvar : function (obj:id; ivar:Ivar):id; cdecl = nil; object_setIvar : procedure (obj:id; ivar:Ivar; value:id); cdecl = nil; object_setInstanceVariable : function (obj:id; name:pchar; value:pointer):Ivar; cdecl = nil; object_getInstanceVariable : function (obj:id; name:pchar; var outValue: Pointer):Ivar; cdecl = nil; objc_getClass : function (name:pchar):id; cdecl = nil; objc_getMetaClass : function (name:pchar):id; cdecl = nil; objc_lookUpClass : function (name:pchar):id; cdecl = nil; objc_getRequiredClass : function (name:pchar):id; cdecl = nil; objc_getFutureClass : function (name:pchar):_Class; cdecl = nil; objc_setFutureClass : procedure (cls:_Class; name:pchar); cdecl = nil; objc_getClassList : function (buffer:pClass; bufferCount:longint):longint; cdecl = nil; objc_getProtocol : function (name:pchar): PProtocol; cdecl = nil; objc_copyProtocolList : function (outCount:pdword):PArrayPProtocol; cdecl = nil; class_getName : function (cls:_Class):PChar; cdecl = nil; class_isMetaClass : function (cls:_Class):BOOL; cdecl = nil; class_getSuperclass : function (cls:_Class):_Class; cdecl = nil; class_setSuperclass : function (cls: _Class; newSuper: _Class): _Class; cdecl = nil; class_getVersion : function (cls:_Class):longint; cdecl = nil; class_setVersion : procedure (cls:_Class; version:longint); cdecl = nil; class_getInstanceSize : function (cls:_Class):size_t; cdecl = nil; class_getInstanceVariable : function (cls:_Class; name:pchar):Ivar; cdecl = nil; class_getClassVariable : function (cls:_Class; name:pchar):Ivar; cdecl = nil; class_copyIvarList : function (cls:_Class; outCount:pdword):PIvar; cdecl = nil; class_getInstanceMethod : function (cls:_Class; name:SEL):Method; cdecl = nil; class_getClassMethod : function (cls:_Class; name:SEL):Method; cdecl = nil; class_getMethodImplementation : function (cls:_Class; name:SEL):IMP; cdecl = nil; class_getMethodImplementation_stret : function (cls:_Class; name:SEL):IMP; cdecl = nil; class_respondsToSelector : function (cls:_Class; sel:SEL):BOOL; cdecl = nil; class_copyMethodList : function (cls:_Class; outCount:pdword):PMethod; cdecl = nil; class_conformsToProtocol : function (cls:_Class; var protocol: Protocol):BOOL; cdecl = nil; class_copyProtocolList : function (cls:_Class; var outCount: dword):PArrayPProtocol; cdecl = nil; class_getProperty : function (cls:_Class; name: pchar): objc_property_t; cdecl = nil; class_copyPropertyList : function (cls:_Class; var Count:dword):Pobjc_property_t; cdecl = nil; class_getIvarLayout : function (cls:_Class):Pchar; cdecl = nil; class_getWeakIvarLayout : function (cls:_Class):Pchar; cdecl = nil; class_createInstance : function (cls:_Class; extraBytes:size_t):id; cdecl = nil; objc_allocateClassPair : function (superclass:_Class; name:pchar; extraBytes:size_t):_Class; cdecl = nil; objc_registerClassPair : procedure (cls:_Class); cdecl = nil; objc_duplicateClass : function (original:_Class; name:pchar; extraBytes:size_t):_Class; cdecl = nil; objc_disposeClassPair : procedure (cls:_Class); cdecl = nil; class_addMethod : function (cls:_Class; name:SEL; imp:IMP; types:pchar):BOOL; cdecl = nil; class_replaceMethod : function (cls:_Class; name:SEL; imp:IMP; types:pchar):IMP; cdecl = nil; class_addIvar: function (cls:_Class; name:pchar; size:size_t; alignment:uint8_t; types:pchar):BOOL; cdecl = nil; class_addProtocol : function (cls:_Class; protocol:pProtocol):BOOL; cdecl = nil; class_setIvarLayout : procedure (cls:_Class; layout:pchar); cdecl = nil; class_setWeakIvarLayout : procedure (cls:_Class; layout:pchar); cdecl = nil; method_getName : function (m:Method):SEL; cdecl = nil; method_getImplementation : function (m:Method):IMP; cdecl = nil; method_getTypeEncoding : function (m:Method):Pchar; cdecl = nil; method_getNumberOfArguments : function (m:Method):dword; cdecl = nil; method_copyReturnType : function (m:Method):Pchar; cdecl = nil; method_copyArgumentType : function (m:Method; index:dword):Pchar; cdecl = nil; method_getReturnType : procedure (m:Method; dst:pchar; dst_len:size_t); cdecl = nil; method_getArgumentType : procedure (m:Method; index:dword; dst:pchar; dst_len:size_t); cdecl = nil; method_getDescription : function (m: Method) : Pobjc_method_description; cdecl = nil; method_setImplementation: function (m:Method; imp:IMP):IMP; cdecl = nil; method_exchangeImplementations : procedure (m1:Method; m2:Method); cdecl = nil; ivar_getName : function (v:Ivar):Pchar; cdecl = nil; ivar_getTypeEncoding : function (v:Ivar):Pchar; cdecl = nil; ivar_getOffset : function (v:Ivar):ptrdiff_t; cdecl = nil; property_getName :function (_property:objc_property_t):Pchar; cdecl = nil; property_getAttributes : function (_property:objc_property_t):Pchar; cdecl = nil; protocol_conformsToProtocol : function (proto:pProtocol; other:pProtocol):BOOL; cdecl = nil; protocol_isEqual : function (proto:pProtocol; other:pProtocol):BOOL; cdecl = nil; protocol_getMethodDescription : function (p: PProtocol; aSel: SEL; isRequiredMethod, isInstanceMethod: BOOL): objc_method_description; cdecl = nil; protocol_copyMethodDescriptionList : function (p: PProtocol; isRequiredMethod, isInstanceMethod: BOOL ; var outCount: LongWord): Pobjc_method_description; cdecl = nil; protocol_getProperty : function (proto:PProtocol; name:pchar; isRequiredProperty:BOOL; isInstanceProperty:BOOL):objc_property_t; cdecl = nil; protocol_copyPropertyList : function (proto:PProtocol; outCount:pdword):Pobjc_property_t; cdecl = nil; protocol_copyProtocolList : function (proto:PProtocol; outCount:pdword):PArrayPProtocol; cdecl = nil; objc_copyImageNames : function (var outCount:dword): PPchar; cdecl = nil; class_getImageName : function (cls:_Class):Pchar; cdecl = nil; objc_copyClassNamesForImage : function (image:pchar; var outCount: Dword):PPchar; cdecl = nil; sel_isEqual : function (lhs:SEL; rhs:SEL):BOOL; cdecl = nil; objc_enumerationMutation : procedure (_para1:id); cdecl = nil; objc_setEnumerationMutationHandler : procedure (handler:TMutationHandlerProc); cdecl = nil; objc_setForwardHandler: procedure (fwd:pointer; fwd_stret:pointer); cdecl = nil; {$WARNINGS OFF} // warning: cdecl'ared funtions have no high parameter objc_msgSend : function (self: id; op: SEL; param3: array of const): id; cdecl = nil; objc_msgSendSuper : function (super: pobjc_super; op: SEL; param3: array of const): id; cdecl = nil; objc_msgSend_stret : procedure (stret: Pointer; self: id; op: SEL; param3: array of const); cdecl= nil; objc_msgSend_stretreg : function (self: id; op: SEL; param3: array of const): id; cdecl= nil; objc_msgSendSuper_stret : procedure (stret: Pointer; super: pobjc_super; op: SEL; param3: array of const); cdecl = nil; objc_msgSend_fpret : function (self: id; op: SEL; param3: array of const): double; cdecl = nil; {$WARNINGS ON} method_invoke : function (receiver: id; m: Method {, ...}): id= nil; method_invoke_stret : procedure (receiver: id; m: Method{ , ...})= nil; objc_collect : procedure (options: LongWord); cdecl= nil; objc_collectingEnabled : function : BOOL; cdecl= nil; const _C_ID = '@'; _C_CLASS = '#'; _C_SEL = ':'; _C_CHR = 'c'; _C_UCHR = 'C'; _C_SHT = 's'; _C_USHT = 'S'; _C_INT = 'i'; _C_UINT = 'I'; _C_LNG = 'l'; _C_ULNG = 'L'; _C_FLT = 'f'; _C_DBL = 'd'; _C_BFLD = 'b'; _C_VOID = 'v'; _C_UNDEF = '?'; _C_PTR = '^'; _C_CHARPTR = '*'; _C_ARY_B = '['; _C_ARY_E = ']'; _C_UNION_B = '('; _C_UNION_E = ')'; _C_STRUCT_B = '{'; _C_STRUCT_E = '}'; _C_PASOBJ = _C_PTR + _C_VOID; _C_SELF_AND_SEL = '@:'; // objc-exception.h // compiler reserves a setjmp buffer + 4 words as localExceptionData type Tobjc_exception_throw = procedure (exception: id); cdecl; Tobjc_exception_try_enter = procedure (localExceptionData: Pointer); cdecl; Tobjc_exception_try_exit = procedure (localExceptionData: Pointer); cdecl; Tobjc_exception_extract = function (localExceptionData: Pointer): id; cdecl; Tobjc_exception_match = function (exceptionClass:_Class; exception:id ): Integer; cdecl; var objc_exception_throw : Tobjc_exception_throw = nil; objc_exception_try_enter : Tobjc_exception_try_enter = nil; objc_exception_try_exit : Tobjc_exception_try_exit = nil; objc_exception_extract : Tobjc_exception_extract = nil; objc_exception_match : Tobjc_exception_match = nil; type pobjc_exception_functions_t = ^objc_exception_functions_t; objc_exception_functions_t = packed record version : Integer; throw_exc : Tobjc_exception_throw; // version 0 try_enter : Tobjc_exception_try_enter; // version 0 try_exit : Tobjc_exception_try_exit; // version 0 extract : Tobjc_exception_extract; // version 0 match : Tobjc_exception_match; // version 0 end; // get table; version tells how many var objc_exception_get_functions : procedure (var table: objc_exception_functions_t); cdecl = nil; objc_exception_set_functions : procedure (table: pobjc_exception_functions_t); cdecl = nil; // __LP64__ // 64-bit only functions { typedef id (*objc_exception_preprocessor)(id exception); typedef int (*objc_exception_matcher)(Class catch_type, id exception); typedef void (*objc_uncaught_exception_handler)(id exception); typedef void (*objc_exception_handler)(id unused, void *context); OBJC_EXPORT void objc_exception_throw(id exception); OBJC_EXPORT void objc_exception_rethrow(void); OBJC_EXPORT id objc_begin_catch(void *exc_buf); OBJC_EXPORT void objc_end_catch(void); OBJC_EXPORT uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context); OBJC_EXPORT void objc_removeExceptionHandler(uintptr_t token); OBJC_EXPORT objc_exception_preprocessor objc_setExceptionPreprocessor(objc_exception_preprocessor fn); OBJC_EXPORT objc_exception_matcher objc_setExceptionMatcher(objc_exception_matcher fn); OBJC_EXPORT objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn); } // objc-sync.h var // Begin synchronizing on 'obj'. // Allocates recursive pthread_mutex associated with 'obj' if needed. // Returns OBJC_SYNC_SUCCESS once lock is acquired. objc_sync_enter: function (obj: id): Integer; cdecl = nil; // End synchronizing on 'obj'. // Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR objc_sync_exit : function (obj: id) : Integer; cdecl = nil; // Temporarily release lock on 'obj' and wait for another thread to notify on 'obj' // Return OBJC_SYNC_SUCCESS, OBJC_SYNC_NOT_OWNING_THREAD_ERROR, OBJC_SYNC_TIMED_OUT objc_sync_wait : function (obj: id; milliSecondsMaxWait: Int64): Integer; cdecl = nil; // Wake up another thread waiting on 'obj' // Return OBJC_SYNC_SUCCESS, OBJC_SYNC_NOT_OWNING_THREAD_ERROR objc_sync_notify : function (obj: id): Integer; cdecl = nil; // Wake up all threads waiting on 'obj' // Return OBJC_SYNC_SUCCESS, OBJC_SYNC_NOT_OWNING_THREAD_ERROR objc_sync_notifyAll : function (obj: id): Integer; cdecl = nil; const OBJC_SYNC_SUCCESS = 0; OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1; OBJC_SYNC_TIMED_OUT = -2; OBJC_SYNC_NOT_INITIALIZED = -3; // since exception handling does not change from version to version // it's nice to make a common RTL loading function for exception functions. // this proc, MUST BE called by run-time initialization proc! function LoadDefaultObjCExepction(hnd: TLibHandle): Boolean; function LoadDefaultObjCSync(hnd: TLibHandle): Boolean; function LoadDefaultObjCMessaging(hnd: TLibHandle): Boolean; implementation function LoadDefaultObjCExepction(hnd: TLibHandle): Boolean; begin Result := hnd <> 0; if not Result then Exit; objc_exception_throw := Tobjc_exception_throw(GetProcedureAddress(hnd, 'objc_exception_throw')); objc_exception_try_enter := Tobjc_exception_try_enter(GetProcedureAddress(hnd, 'objc_exception_try_enter')); objc_exception_try_exit := Tobjc_exception_try_exit(GetProcedureAddress(hnd, 'objc_exception_try_exit')); objc_exception_extract := Tobjc_exception_extract(GetProcedureAddress(hnd, 'objc_exception_extract')); objc_exception_match := Tobjc_exception_match(GetProcedureAddress(hnd, 'objc_exception_match')); end; function LoadDefaultObjCSync(hnd: TLibHandle): Boolean; begin Result := hnd <> 0; if not Result then Exit; Pointer(objc_sync_enter) := GetProcedureAddress(hnd, 'objc_sync_enter'); Pointer(objc_sync_exit) := GetProcedureAddress(hnd, 'objc_sync_exit'); Pointer(objc_sync_wait) := GetProcedureAddress(hnd, 'objc_sync_wait'); Pointer(objc_sync_notify) := GetProcedureAddress(hnd, 'objc_sync_notify'); Pointer(objc_sync_notifyAll) := GetProcedureAddress(hnd, 'objc_sync_notifyAll'); end; function LoadDefaultObjCMessaging(hnd: TLibHandle): Boolean; begin Pointer(objc_msgSend) := GetProcedureAddress(hnd, 'objc_msgSend'); Pointer(objc_msgSendSuper) := GetProcedureAddress(hnd, 'objc_msgSendSuper'); Pointer(objc_msgSend_stret) := GetProcedureAddress(hnd, 'objc_msgSend_stret'); Pointer(objc_msgSendSuper_stret) := GetProcedureAddress(hnd, 'objc_msgSendSuper_stret'); {$ifndef CPUPOWERPC} // arm also uses objc_msgSend_fpret? Pointer(objc_msgSend_fpret) := GetProcedureAddress(hnd, 'objc_msgSend_fpret'); Pointer(objc_msgSend_stretreg) := GetProcedureAddress(hnd, 'objc_msgSend'); {$else} Pointer(objc_msgSend_fpret) := GetProcedureAddress(hnd, 'objc_msgSend'); Pointer(objc_msgSend_stretreg) := GetProcedureAddress(hnd, 'objc_msgSend_stret'); {$endif} Result := true; end; initialization end.