summaryrefslogtreecommitdiff
path: root/packages/objcrtl/src/objcrtl.pas
blob: 49c40d23972457fe54b05b643606c30a9707eaf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
{
  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.