rtti.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. { Run-Time type information routines }
  12. { the tk* constants are now declared in system.inc }
  13. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  14. {$define USE_PACKED}
  15. {$endif}
  16. {$ifdef VER2_6}
  17. {$define USE_PACKED}
  18. {$endif}
  19. type
  20. PRecordElement=^TRecordElement;
  21. TRecordElement=
  22. {$ifdef USE_PACKED}
  23. packed
  24. {$endif USE_PACKED}
  25. record
  26. TypeInfo: Pointer;
  27. {$ifdef VER2_6}
  28. Offset: Longint;
  29. {$else}
  30. Offset: SizeInt;
  31. {$endif}
  32. end;
  33. PRecordInfoFull=^TRecordInfoFull;
  34. TRecordInfoFull=
  35. {$ifdef USE_PACKED}
  36. packed
  37. {$endif USE_PACKED}
  38. record
  39. Size: Longint;
  40. {$if FPC_FULLVERSION>30100}
  41. InitTable: Pointer;
  42. {$endif FPC_FULLVERSION>30100}
  43. Count: Longint;
  44. { Elements: array[count] of TRecordElement }
  45. end;
  46. {$if FPC_FULLVERSION>30100}
  47. TRTTIRecVarOp=procedure(ARec: Pointer);
  48. TRTTIRecCloneOp=procedure(ASrc, ADest: Pointer);
  49. PRTTIRecordOpVMT=^TRTTIRecordOpVMT;
  50. TRTTIRecordOpVMT=
  51. {$ifdef USE_PACKED}
  52. packed
  53. {$endif USE_PACKED}
  54. record
  55. Initialize: TRTTIRecVarOp;
  56. Finalize: TRTTIRecVarOp;
  57. Copy: TRTTIRecVarOp;
  58. Clone: TRTTIRecCloneOp;
  59. end;
  60. PRecordInfoInit=^TRecordInfoInit;
  61. TRecordInfoInit=
  62. {$ifdef USE_PACKED}
  63. packed
  64. {$endif USE_PACKED}
  65. record
  66. Size: Longint;
  67. Terminator: Pointer;
  68. RecordOp: PRTTIRecordOpVMT;
  69. Count: Longint;
  70. { Elements: array[count] of TRecordElement }
  71. end;
  72. {$endif FPC_FULLVERSION>30100}
  73. PArrayInfo=^TArrayInfo;
  74. TArrayInfo=
  75. {$ifdef USE_PACKED}
  76. packed
  77. {$endif USE_PACKED}
  78. record
  79. Size: SizeInt;
  80. ElCount: SizeInt;
  81. ElInfo: Pointer;
  82. DimCount: Byte;
  83. Dims:array[0..255] of Pointer;
  84. end;
  85. function RTTIArraySize(typeInfo: Pointer): SizeInt;
  86. begin
  87. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  88. {$ifdef VER2_6}
  89. result:=PArrayInfo(typeInfo)^.Size*PArrayInfo(typeInfo)^.ElCount;
  90. {$else}
  91. result:=PArrayInfo(typeInfo)^.Size;
  92. {$endif}
  93. end;
  94. function RTTIRecordSize(typeInfo: Pointer): SizeInt;
  95. begin
  96. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  97. result:=PRecordInfoFull(typeInfo)^.Size;
  98. end;
  99. {$if FPC_FULLVERSION>30100}
  100. function RTTIRecordOp(typeInfo: Pointer; var initrtti: Pointer): PRecordInfoInit; inline;
  101. begin
  102. { find init table and management operators }
  103. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  104. result:=typeInfo;
  105. { check terminator, maybe we are already in init table }
  106. if Assigned(result^.Terminator) then
  107. begin
  108. { point to more optimal initrtti }
  109. initrtti:=PRecordInfoFull(result)^.InitTable;
  110. { and point to management operators in our init table }
  111. result:=aligntoptr(initrtti+2+PByte(initrtti)[1]);
  112. end
  113. end;
  114. {$endif FPC_FULLVERSION>30100}
  115. function RTTISize(typeInfo: Pointer): SizeInt;
  116. begin
  117. case PByte(typeinfo)^ of
  118. tkAString,tkWString,tkUString,
  119. tkInterface,tkDynarray:
  120. result:=sizeof(Pointer);
  121. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  122. tkVariant:
  123. result:=sizeof(TVarData);
  124. {$endif FPC_HAS_FEATURE_VARIANTS}
  125. tkArray:
  126. result:=RTTIArraySize(typeinfo);
  127. tkObject,tkRecord:
  128. result:=RTTIRecordSize(typeinfo);
  129. else
  130. result:=-1;
  131. end;
  132. end;
  133. { if you modify this procedure, fpc_copy must be probably modified as well }
  134. procedure RecordRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
  135. var
  136. count,
  137. i : longint;
  138. begin
  139. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  140. {$if FPC_FULLVERSION>30100}
  141. Count:=PRecordInfoInit(typeInfo)^.Count;
  142. Inc(PRecordInfoInit(typeInfo));
  143. {$else FPC_FULLVERSION>30100}
  144. Count:=PRecordInfoFull(typeInfo)^.Count;
  145. Inc(PRecordInfoFull(typeInfo));
  146. {$endif FPC_FULLVERSION>30100}
  147. { Process elements }
  148. for i:=1 to count Do
  149. begin
  150. rttiproc(Data+PRecordElement(typeInfo)^.Offset,PRecordElement(typeInfo)^.TypeInfo);
  151. Inc(PRecordElement(typeInfo));
  152. end;
  153. end;
  154. { if you modify this procedure, fpc_copy must be probably modified as well }
  155. {$ifdef VER2_6}
  156. procedure ArrayRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
  157. var
  158. i: SizeInt;
  159. begin
  160. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  161. { Process elements }
  162. for I:=0 to PArrayInfo(typeInfo)^.ElCount-1 do
  163. rttiproc(Data+(I*PArrayInfo(typeInfo)^.Size),PArrayInfo(typeInfo)^.ElInfo);
  164. end;
  165. {$else}
  166. procedure ArrayRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
  167. var
  168. i,Count,ElSize: SizeInt;
  169. Info: Pointer;
  170. begin
  171. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  172. Count:=PArrayInfo(typeInfo)^.ElCount;
  173. { no elements to process => exit }
  174. if Count = 0 then
  175. Exit;
  176. ElSize:=PArrayInfo(typeInfo)^.Size div Count;
  177. Info:=PArrayInfo(typeInfo)^.ElInfo;
  178. { Process elements }
  179. for I:=0 to Count-1 do
  180. rttiproc(Data+(I*ElSize),Info);
  181. end;
  182. {$endif}
  183. Procedure fpc_Initialize (Data,TypeInfo : pointer);[Public,Alias : 'FPC_INITIALIZE']; compilerproc;
  184. begin
  185. case PByte(TypeInfo)^ of
  186. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  187. tkDynArray,
  188. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  189. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  190. tkAstring,
  191. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  192. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  193. tkWstring,tkUString,
  194. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  195. tkInterface:
  196. PPchar(Data)^:=Nil;
  197. tkArray:
  198. arrayrtti(data,typeinfo,@int_initialize);
  199. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  200. tkObject,
  201. {$endif FPC_HAS_FEATURE_OBJECTS}
  202. tkRecord:
  203. {$if FPC_FULLVERSION>30100}
  204. { if possible try to use more optimal initrtti }
  205. with RTTIRecordOp(typeinfo, typeinfo)^ do
  206. begin
  207. recordrtti(data,typeinfo,@int_initialize);
  208. if Assigned(recordop) and Assigned(recordop^.Initialize) then
  209. recordop^.Initialize(data);
  210. end;
  211. {$else FPC_FULLVERSION>30100}
  212. recordrtti(data,typeinfo,@int_initialize);
  213. {$endif FPC_FULLVERSION>30100}
  214. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  215. tkVariant:
  216. variant_init(PVarData(Data)^);
  217. {$endif FPC_HAS_FEATURE_VARIANTS}
  218. end;
  219. end;
  220. Procedure fpc_finalize (Data,TypeInfo: Pointer);[Public,Alias : 'FPC_FINALIZE']; compilerproc;
  221. begin
  222. case PByte(TypeInfo)^ of
  223. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  224. tkAstring :
  225. fpc_AnsiStr_Decr_Ref(PPointer(Data)^);
  226. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  227. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  228. tkUstring :
  229. fpc_UnicodeStr_Decr_Ref(PPointer(Data)^);
  230. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  231. tkWstring :
  232. fpc_WideStr_Decr_Ref(PPointer(Data)^);
  233. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  234. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  235. tkArray :
  236. arrayrtti(data,typeinfo,@int_finalize);
  237. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  238. tkObject,
  239. {$endif FPC_HAS_FEATURE_OBJECTS}
  240. tkRecord:
  241. {$if FPC_FULLVERSION>30100}
  242. { if possible try to use more optimal initrtti }
  243. with RTTIRecordOp(typeinfo, typeinfo)^ do
  244. begin
  245. if Assigned(recordop) and Assigned(recordop^.Finalize) then
  246. recordop^.Finalize(data);
  247. recordrtti(data,typeinfo,@int_finalize);
  248. end;
  249. {$else FPC_FULLVERSION>30100}
  250. recordrtti(data,typeinfo,@int_finalize);
  251. {$endif FPC_FULLVERSION>30100}
  252. tkInterface:
  253. Intf_Decr_Ref(PPointer(Data)^);
  254. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  255. tkDynArray:
  256. fpc_dynarray_clear(PPointer(Data)^,TypeInfo);
  257. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  258. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  259. tkVariant:
  260. variant_clear(PVarData(Data)^);
  261. {$endif FPC_HAS_FEATURE_VARIANTS}
  262. end;
  263. end;
  264. Procedure fpc_Addref(Data,TypeInfo : Pointer); [Public,alias : 'FPC_ADDREF']; compilerproc;
  265. begin
  266. case PByte(TypeInfo)^ of
  267. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  268. tkAstring :
  269. fpc_AnsiStr_Incr_Ref(PPointer(Data)^);
  270. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  271. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  272. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  273. tkWstring :
  274. fpc_WideStr_Incr_Ref(PPointer(Data)^);
  275. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  276. tkUstring :
  277. fpc_UnicodeStr_Incr_Ref(PPointer(Data)^);
  278. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  279. tkArray :
  280. arrayrtti(data,typeinfo,@int_addref);
  281. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  282. tkobject,
  283. {$endif FPC_HAS_FEATURE_OBJECTS}
  284. tkrecord :
  285. {$if FPC_FULLVERSION>30100}
  286. { find init table }
  287. with RTTIRecordOp(typeinfo, typeinfo)^ do
  288. {$endif FPC_FULLVERSION>30100}
  289. begin
  290. recordrtti(data,typeinfo,@int_addref);
  291. {$if FPC_FULLVERSION>30100}
  292. if Assigned(recordop) and Assigned(recordop^.Copy) then
  293. recordop^.Copy(Data);
  294. {$endif FPC_FULLVERSION>30100}
  295. end;
  296. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  297. tkDynArray:
  298. fpc_dynarray_incr_ref(PPointer(Data)^);
  299. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  300. tkInterface:
  301. Intf_Incr_Ref(PPointer(Data)^);
  302. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  303. tkVariant:
  304. variant_addref(pvardata(Data)^);
  305. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  306. end;
  307. end;
  308. { define alias for internal use in the system unit }
  309. Function fpc_Copy_internal (Src, Dest, TypeInfo : Pointer) : SizeInt;[external name 'FPC_COPY'];
  310. Function fpc_Copy (Src, Dest, TypeInfo : Pointer) : SizeInt;[Public,alias : 'FPC_COPY']; compilerproc;
  311. var
  312. Temp: pbyte;
  313. copiedsize,
  314. expectedoffset,
  315. count,
  316. offset,
  317. i: SizeInt;
  318. info: pointer;
  319. begin
  320. result:=sizeof(pointer);
  321. case PByte(TypeInfo)^ of
  322. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  323. tkAstring:
  324. fpc_AnsiStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  325. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  326. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  327. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  328. tkWstring:
  329. fpc_WideStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  330. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  331. tkUstring:
  332. fpc_UnicodeStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  333. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  334. tkArray:
  335. begin
  336. Temp:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  337. {$ifdef VER2_6}
  338. { Process elements }
  339. for I:=0 to PArrayInfo(Temp)^.ElCount-1 do
  340. fpc_Copy_internal(Src+(I*PArrayInfo(Temp)^.Size),Dest+(I*PArrayInfo(Temp)^.Size),PArrayInfo(Temp)^.ElInfo);
  341. Result:=PArrayInfo(Temp)^.Size*PArrayInfo(Temp)^.ElCount;
  342. {$else}
  343. Result:=PArrayInfo(Temp)^.Size;
  344. Count:=PArrayInfo(Temp)^.ElCount;
  345. { no elements to process => exit }
  346. if Count = 0 then
  347. Exit;
  348. Info:=PArrayInfo(Temp)^.ElInfo;
  349. copiedsize:=Result div Count;
  350. Offset:=0;
  351. { Process elements }
  352. for I:=1 to Count do
  353. begin
  354. fpc_Copy_internal(Src+Offset,Dest+Offset,Info);
  355. inc(Offset,copiedsize);
  356. end;
  357. {$endif}
  358. end;
  359. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  360. tkobject,
  361. {$endif FPC_HAS_FEATURE_OBJECTS}
  362. tkrecord:
  363. {$if FPC_FULLVERSION>30100}
  364. { find init table }
  365. with RTTIRecordOp(typeinfo, typeinfo)^ do
  366. {$endif FPC_FULLVERSION>30100}
  367. begin
  368. Temp:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  369. {$if FPC_FULLVERSION>30100}
  370. if Assigned(recordop) and Assigned(recordop^.Clone) then
  371. recordop^.Clone(Src,Dest)
  372. else
  373. begin
  374. Result:=Size;
  375. Inc(PRecordInfoInit(Temp));
  376. {$else FPC_FULLVERSION>30100}
  377. Result:=PRecordInfoFull(Temp)^.Size;
  378. Count:=PRecordInfoFull(Temp)^.Count;
  379. Inc(PRecordInfoFull(Temp));
  380. {$endif FPC_FULLVERSION>30100}
  381. expectedoffset:=0;
  382. { Process elements with rtti }
  383. for i:=1 to Count Do
  384. begin
  385. Info:=PRecordElement(Temp)^.TypeInfo;
  386. Offset:=PRecordElement(Temp)^.Offset;
  387. Inc(PRecordElement(Temp));
  388. if Offset>expectedoffset then
  389. move((Src+expectedoffset)^,(Dest+expectedoffset)^,Offset-expectedoffset);
  390. copiedsize:=fpc_Copy_internal(Src+Offset,Dest+Offset,Info);
  391. expectedoffset:=Offset+copiedsize;
  392. end;
  393. { elements remaining? }
  394. if result>expectedoffset then
  395. move((Src+expectedoffset)^,(Dest+expectedoffset)^,Result-expectedoffset);
  396. {$if FPC_FULLVERSION>30100}
  397. end;
  398. {$endif FPC_FULLVERSION>30100}
  399. end;
  400. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  401. tkDynArray:
  402. fpc_dynarray_assign(PPointer(Dest)^,PPointer(Src)^,typeinfo);
  403. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  404. tkInterface:
  405. fpc_intf_assign(PPointer(Dest)^,PPointer(Src)^);
  406. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  407. tkVariant:
  408. begin
  409. VarCopyProc(pvardata(dest)^,pvardata(src)^);
  410. result:=sizeof(tvardata);
  411. end;
  412. {$endif FPC_HAS_FEATURE_VARIANTS}
  413. end;
  414. end;
  415. { For internal use by the compiler, because otherwise $x- can cause trouble. }
  416. { Generally disabling extended syntax checking for all compilerprocs may }
  417. { have unintended side-effects }
  418. procedure fpc_Copy_proc (Src, Dest, TypeInfo : Pointer);compilerproc; inline;
  419. begin
  420. fpc_copy_internal(src,dest,typeinfo);
  421. end;
  422. procedure fpc_initialize_array(data,typeinfo : pointer;count : SizeInt); [public,alias:'FPC_INITIALIZE_ARRAY']; compilerproc;
  423. var
  424. i, size : SizeInt;
  425. begin
  426. size:=RTTISize(typeinfo);
  427. if size>0 then
  428. for i:=0 to count-1 do
  429. int_initialize(data+size*i,typeinfo);
  430. end;
  431. procedure fpc_finalize_array(data,typeinfo : pointer;count : SizeInt); [Public,Alias:'FPC_FINALIZE_ARRAY']; compilerproc;
  432. var
  433. i, size: SizeInt;
  434. begin
  435. size:=RTTISize(typeinfo);
  436. if size>0 then
  437. for i:=0 to count-1 do
  438. int_finalize(data+size*i,typeinfo);
  439. end;
  440. procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_ADDREF_ARRAY']; compilerproc;
  441. var
  442. i, size: SizeInt;
  443. begin
  444. size:=RTTISize(typeinfo);
  445. if size>0 then
  446. for i:=0 to count-1 do
  447. int_addref(data+size*i,typeinfo);
  448. end;
  449. { The following two procedures are now obsolete, needed only for bootstrapping }
  450. procedure fpc_decref (Data, TypeInfo : Pointer);[Public,alias : 'FPC_DECREF']; compilerproc;
  451. begin
  452. int_finalize(Data,TypeInfo);
  453. end;
  454. procedure fpc_decref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_DECREF_ARRAY']; compilerproc;
  455. begin
  456. int_finalizeArray(data,typeinfo,count);
  457. end;
  458. procedure InitializeArray(p, typeInfo: Pointer; count: SizeInt);
  459. external name 'FPC_INITIALIZE_ARRAY';
  460. procedure FinalizeArray(p, typeInfo: Pointer; count: SizeInt);
  461. external name 'FPC_FINALIZE_ARRAY';
  462. procedure CopyArray(dest, source, typeInfo: Pointer; count: SizeInt);
  463. var
  464. i, size: SizeInt;
  465. begin
  466. size:=RTTISize(typeInfo);
  467. if size>0 then
  468. for i:=0 to count-1 do
  469. fpc_Copy_internal(source+size*i, dest+size*i, typeInfo);
  470. end;