rtti.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. function RTTIArraySize(typeInfo: Pointer): SizeInt;
  13. begin
  14. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  15. result:=PArrayInfo(typeInfo)^.Size;
  16. end;
  17. function RTTIRecordSize(typeInfo: Pointer): SizeInt;
  18. begin
  19. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  20. { for size field init table is compatible with rtti table }
  21. result:=PRecordInfoFull(typeInfo)^.Size;
  22. end;
  23. function RTTIRecordOp(typeInfo: Pointer; var initrtti: Pointer): PRecordInfoInit; inline;
  24. begin
  25. { find init table and management operators }
  26. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  27. result:=typeInfo;
  28. { check terminator, maybe we are already in init table }
  29. if Assigned(result^.Terminator) then
  30. begin
  31. { point to more optimal initrtti }
  32. initrtti:=PRecordInfoFull(result)^.InitTable;
  33. { and point to management operators in our init table }
  34. result:=aligntoqword(initrtti+2+PByte(initrtti)[1]);
  35. end
  36. end;
  37. { result = manBuiltin means e.g. that initialization is simply zeroing and can be omitted if the memory is already zeroed, as in dynarr.inc. }
  38. function RTTIManagementAndSize(typeInfo: Pointer; op: TRTTIRecOpType; out size: SizeInt; maxInteresting: TRTTIManagement): TRTTIManagement;
  39. const
  40. Special = 49;
  41. ManagedSizes: array[TTypeKind] of uint8 = { 0 — unmanaged, Special — special, otherwise manBuiltin of that size. }
  42. (
  43. {tkUnknown} 0, {tkInteger} 0, {tkChar} 0, {tkEnumeration} 0, {tkFloat} 0,
  44. {tkSet} 0, {tkMethod} 0, {tkSString} 0, {tkLString} 0, {tkAString} sizeof(pointer),
  45. {tkWString} sizeof(pointer), {tkVariant} {$ifdef FPC_HAS_FEATURE_VARIANTS} sizeof(TVarData) {$else} 0 {$endif}, {tkArray} Special, {tkRecord} Special, {tkInterface} sizeof(pointer),
  46. {tkClass} 0, {tkObject} Special, {tkWChar} 0, {tkBool} 0, {tkInt64} 0, {tkQWord} 0,
  47. {tkDynArray} sizeof(pointer), {tkInterfaceRaw} 0, {tkProcVar} 0, {tkUString} sizeof(pointer), {tkUChar} 0,
  48. {tkHelper} 0, {tkFile} 0, {tkClassRef} 0, {tkPointer} 0
  49. );
  50. var
  51. ri: PRecordInfoInit;
  52. elem: PRecordElement;
  53. newMan: TRTTIManagement;
  54. _initrtti: pointer;
  55. elemCount,sample,_size: SizeInt;
  56. begin
  57. sample:=ManagedSizes[PTypeKind(typeinfo)^];
  58. size:=sample;
  59. if sample<>Special then
  60. result:=TRTTIManagement(ord(sample<>0)) { manNone(0) if sample = 0, manBuiltin(1) otherwise. }
  61. else if PTypeKind(typeinfo)^=tkArray then
  62. begin
  63. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  64. size:=PArrayInfo(typeInfo)^.Size;
  65. result:=RTTIManagementAndSize(PArrayInfo(typeInfo)^.ElInfo^, op, _size, maxInteresting);
  66. end
  67. else {tkObject, tkRecord}
  68. begin
  69. ri:=RTTIRecordOp(typeInfo, _initrtti);
  70. size:=ri^.Size;
  71. if Assigned(ri^.RecordOp) and Assigned(ri^.RecordOp^.Ops[op]) then
  72. exit(manCustom);
  73. result:=manNone;
  74. elem:=AlignTypeData(Pointer(@ri^.Count)+SizeOf(ri^.Count));
  75. for elemCount:=ri^.Count downto 1 do
  76. begin
  77. sample:=ManagedSizes[PTypeKind(elem^.TypeInfo^)^];
  78. if sample<>Special then
  79. newMan:=TRTTIManagement(ord(sample<>0)) { Avoid recursive call for simple fields. }
  80. else
  81. newMan:=RTTIManagementAndSize(elem^.TypeInfo^, op, _size, maxInteresting);
  82. if newMan>result then
  83. begin
  84. result:=newMan;
  85. if newMan>=maxInteresting then
  86. break;
  87. end;
  88. inc(elem);
  89. end;
  90. end;
  91. end;
  92. { if you modify this procedure, fpc_copy must be probably modified as well }
  93. procedure RecordRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
  94. var
  95. count,
  96. i : longint;
  97. begin
  98. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  99. Count:=PRecordInfoInit(typeInfo)^.Count;
  100. { Get element info, hacky, but what else can we do? }
  101. typeInfo:=AlignTypeData(Pointer(@PRecordInfoInit(typeInfo)^.Count)+SizeOf(PRecordInfoInit(typeInfo)^.Count));
  102. { Process elements }
  103. for i:=1 to count Do
  104. begin
  105. rttiproc(Data+PRecordElement(typeInfo)^.Offset,PRecordElement(typeInfo)^.TypeInfo^);
  106. Inc(PRecordElement(typeInfo));
  107. end;
  108. end;
  109. function RTTIRecordMopInitTable(ti: Pointer): PRTTIRecordOpOffsetTable;
  110. begin
  111. ti:=aligntoqword(ti+2+PByte(ti)[1]);
  112. Result:=PRecordInfoInit(ti)^.InitRecordOpTable;
  113. end;
  114. { if you modify this procedure, fpc_copy must be probably modified as well }
  115. procedure ArrayRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
  116. var
  117. i,Count,ElSize: SizeInt;
  118. Info: Pointer;
  119. begin
  120. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  121. Count:=PArrayInfo(typeInfo)^.ElCount;
  122. { no elements to process => exit }
  123. if Count = 0 then
  124. Exit;
  125. ElSize:=PArrayInfo(typeInfo)^.Size div Count;
  126. Info:=PArrayInfo(typeInfo)^.ElInfo^;
  127. { Process elements }
  128. for I:=0 to Count-1 do
  129. rttiproc(Data+(I*ElSize),Info);
  130. end;
  131. Procedure fpc_Initialize (Data,TypeInfo : pointer);[Public,Alias : 'FPC_INITIALIZE']; compilerproc;
  132. begin
  133. case PTypeKind(TypeInfo)^ of
  134. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  135. tkDynArray,
  136. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  137. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  138. tkAstring,
  139. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  140. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  141. tkWstring,tkUString,
  142. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  143. tkInterface:
  144. PPAnsiChar(Data)^:=Nil;
  145. tkArray:
  146. arrayrtti(data,typeinfo,@int_initialize);
  147. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  148. tkObject,
  149. {$endif FPC_HAS_FEATURE_OBJECTS}
  150. tkRecord:
  151. { if possible try to use more optimal initrtti }
  152. with RTTIRecordOp(typeinfo, typeinfo)^ do
  153. begin
  154. recordrtti(data,typeinfo,@int_initialize);
  155. if Assigned(recordop) and Assigned(recordop^.Initialize) then
  156. recordop^.Initialize(data);
  157. end;
  158. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  159. tkVariant:
  160. variant_init(PVarData(Data)^);
  161. {$endif FPC_HAS_FEATURE_VARIANTS}
  162. end;
  163. end;
  164. Procedure fpc_finalize (Data,TypeInfo: Pointer);[Public,Alias : 'FPC_FINALIZE']; compilerproc;
  165. begin
  166. case PTypeKind(TypeInfo)^ of
  167. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  168. tkAstring :
  169. fpc_AnsiStr_Decr_Ref(PPointer(Data)^);
  170. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  171. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  172. tkUstring :
  173. fpc_UnicodeStr_Decr_Ref(PPointer(Data)^);
  174. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  175. tkWstring :
  176. fpc_WideStr_Decr_Ref(PPointer(Data)^);
  177. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  178. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  179. tkArray :
  180. arrayrtti(data,typeinfo,@int_finalize);
  181. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  182. tkObject,
  183. {$endif FPC_HAS_FEATURE_OBJECTS}
  184. tkRecord:
  185. { if possible try to use more optimal initrtti }
  186. with RTTIRecordOp(typeinfo, typeinfo)^ do
  187. begin
  188. if Assigned(recordop) and Assigned(recordop^.Finalize) then
  189. recordop^.Finalize(data);
  190. recordrtti(data,typeinfo,@int_finalize);
  191. end;
  192. {$ifdef FPC_HAS_FEATURE_CLASSES}
  193. tkInterface:
  194. Intf_Decr_Ref(PPointer(Data)^);
  195. {$endif FPC_HAS_FEATURE_CLASSES}
  196. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  197. tkDynArray:
  198. fpc_dynarray_clear(PPointer(Data)^,TypeInfo);
  199. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  200. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  201. tkVariant:
  202. variant_clear(PVarData(Data)^);
  203. {$endif FPC_HAS_FEATURE_VARIANTS}
  204. end;
  205. end;
  206. Procedure fpc_Addref (Data,TypeInfo : Pointer); [Public,alias : 'FPC_ADDREF']; compilerproc;
  207. begin
  208. case PTypeKind(TypeInfo)^ of
  209. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  210. tkAstring :
  211. fpc_AnsiStr_Incr_Ref(PPointer(Data)^);
  212. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  213. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  214. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  215. tkWstring :
  216. fpc_WideStr_Incr_Ref(PPointer(Data)^);
  217. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  218. tkUstring :
  219. fpc_UnicodeStr_Incr_Ref(PPointer(Data)^);
  220. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  221. tkArray :
  222. arrayrtti(data,typeinfo,@int_addref);
  223. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  224. tkobject,
  225. {$endif FPC_HAS_FEATURE_OBJECTS}
  226. tkrecord :
  227. { find init table }
  228. with RTTIRecordOp(typeinfo, typeinfo)^ do
  229. begin
  230. recordrtti(data,typeinfo,@int_addref);
  231. if Assigned(recordop) and Assigned(recordop^.AddRef) then
  232. recordop^.AddRef(Data);
  233. end;
  234. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  235. tkDynArray:
  236. fpc_dynarray_incr_ref(PPointer(Data)^);
  237. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  238. {$ifdef FPC_HAS_FEATURE_CLASSES}
  239. tkInterface:
  240. Intf_Incr_Ref(PPointer(Data)^);
  241. {$endif FPC_HAS_FEATURE_CLASSES}
  242. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  243. tkVariant:
  244. variant_addref(pvardata(Data)^);
  245. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  246. end;
  247. end;
  248. { define alias for internal use in the system unit }
  249. Function fpc_Copy_internal (Src, Dest, TypeInfo : Pointer) : SizeInt;[external name 'FPC_COPY'];
  250. Function fpc_Copy (Src, Dest, TypeInfo : Pointer) : SizeInt;[Public,alias : 'FPC_COPY']; compilerproc;
  251. var
  252. Temp: pbyte;
  253. copiedsize,
  254. expectedoffset,
  255. EleCount,
  256. offset,
  257. i: SizeInt;
  258. info: pointer;
  259. begin
  260. result:=sizeof(pointer);
  261. case PTypeKind(TypeInfo)^ of
  262. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  263. tkAstring:
  264. fpc_AnsiStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  265. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  266. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  267. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  268. tkWstring:
  269. fpc_WideStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  270. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  271. tkUstring:
  272. fpc_UnicodeStr_Assign(PPointer(Dest)^,PPointer(Src)^);
  273. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  274. tkArray:
  275. begin
  276. Temp:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  277. Result:=PArrayInfo(Temp)^.Size;
  278. EleCount:=PArrayInfo(Temp)^.ElCount;
  279. { no elements to process => exit }
  280. if EleCount = 0 then
  281. Exit;
  282. Info:=PArrayInfo(Temp)^.ElInfo^;
  283. copiedsize:=Result div EleCount;
  284. Offset:=0;
  285. { Process elements }
  286. for I:=1 to EleCount do
  287. begin
  288. fpc_Copy_internal(Src+Offset,Dest+Offset,Info);
  289. inc(Offset,copiedsize);
  290. end;
  291. end;
  292. {$ifdef FPC_HAS_FEATURE_OBJECTS}
  293. tkobject,
  294. {$endif FPC_HAS_FEATURE_OBJECTS}
  295. tkrecord:
  296. { find init table }
  297. with RTTIRecordOp(typeinfo, typeinfo)^ do
  298. begin
  299. Temp:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  300. if Assigned(recordop) and Assigned(recordop^.Copy) then
  301. begin
  302. recordop^.Copy(Src,Dest);
  303. Result:=PRecordInfoFull(Temp)^.Size;
  304. end
  305. else
  306. begin
  307. Result:=PRecordInfoInit(Temp)^.Size;
  308. EleCount:=PRecordInfoInit(Temp)^.Count;
  309. { Get element info, hacky, but what else can we do? }
  310. Temp:=AlignTypeData(Pointer(@PRecordInfoInit(Temp)^.Count)+SizeOf(PRecordInfoInit(Temp)^.Count));
  311. expectedoffset:=0;
  312. { Process elements with rtti }
  313. for i:=1 to EleCount Do
  314. begin
  315. Offset:=PRecordElement(Temp)^.Offset;
  316. if Offset>expectedoffset then
  317. move((Src+expectedoffset)^,(Dest+expectedoffset)^,Offset-expectedoffset);
  318. expectedoffset:=Offset+fpc_Copy_internal(Src+Offset,Dest+Offset,PRecordElement(Temp)^.TypeInfo^);
  319. Inc(PRecordElement(Temp));
  320. end;
  321. { elements remaining? }
  322. if result>expectedoffset then
  323. move((Src+expectedoffset)^,(Dest+expectedoffset)^,Result-expectedoffset);
  324. end;
  325. end;
  326. {$ifdef FPC_HAS_FEATURE_DYNARRAYS}
  327. tkDynArray:
  328. fpc_dynarray_assign(PPointer(Dest)^,PPointer(Src)^,typeinfo);
  329. {$endif FPC_HAS_FEATURE_DYNARRAYS}
  330. {$ifdef FPC_HAS_FEATURE_CLASSES}
  331. tkInterface:
  332. fpc_intf_assign(PPointer(Dest)^,PPointer(Src)^);
  333. {$endif FPC_HAS_FEATURE_CLASSES}
  334. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  335. tkVariant:
  336. begin
  337. VarCopyProc(pvardata(dest)^,pvardata(src)^);
  338. result:=sizeof(tvardata);
  339. end;
  340. {$endif FPC_HAS_FEATURE_VARIANTS}
  341. end;
  342. end;
  343. { For internal use by the compiler, because otherwise $x- can cause trouble. }
  344. { Generally disabling extended syntax checking for all compilerprocs may }
  345. { have unintended side-effects }
  346. procedure fpc_Copy_proc (Src, Dest, TypeInfo : Pointer);compilerproc; inline;
  347. begin
  348. fpc_copy_internal(src,dest,typeinfo);
  349. end;
  350. procedure fpc_initialize_array(data,typeinfo : pointer;count : SizeInt); [public,alias:'FPC_INITIALIZE_ARRAY']; compilerproc;
  351. var
  352. i, size : SizeInt;
  353. begin
  354. if RTTIManagementAndSize(typeinfo, rotInitialize, size, manBuiltin)<>manNone then
  355. for i:=0 to count-1 do
  356. int_initialize(data+size*i,typeinfo);
  357. end;
  358. procedure fpc_finalize_array(data,typeinfo : pointer;count : SizeInt); [Public,Alias:'FPC_FINALIZE_ARRAY']; compilerproc;
  359. var
  360. i, size : SizeInt;
  361. begin
  362. if RTTIManagementAndSize(typeinfo, rotFinalize, size, manBuiltin)<>manNone then
  363. for i:=0 to count-1 do
  364. int_finalize(data+size*i,typeinfo);
  365. end;
  366. procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_ADDREF_ARRAY']; compilerproc;
  367. var
  368. i, size : SizeInt;
  369. begin
  370. if RTTIManagementAndSize(typeinfo, rotAddRef, size, manBuiltin)<>manNone then
  371. for i:=0 to count-1 do
  372. int_addref(data+size*i,typeinfo);
  373. end;
  374. { The following two procedures are now obsolete, needed only for bootstrapping }
  375. procedure fpc_decref (Data, TypeInfo : Pointer);[Public,alias : 'FPC_DECREF']; compilerproc;
  376. begin
  377. int_finalize(Data,TypeInfo);
  378. end;
  379. procedure fpc_decref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_DECREF_ARRAY']; compilerproc;
  380. begin
  381. int_finalizeArray(data,typeinfo,count);
  382. end;
  383. procedure InitializeArray(p, typeInfo: Pointer; count: SizeInt);
  384. external name 'FPC_INITIALIZE_ARRAY';
  385. procedure FinalizeArray(p, typeInfo: Pointer; count: SizeInt);
  386. external name 'FPC_FINALIZE_ARRAY';
  387. procedure CopyArray(dest, source, typeInfo: Pointer; count: SizeInt);
  388. var
  389. i, size: SizeInt;
  390. begin
  391. if RTTIManagementAndSize(typeinfo, rotCopy, size, manBuiltin)<>manNone then
  392. for i:=0 to count-1 do
  393. fpc_Copy_internal(source+size*i, dest+size*i, typeInfo);
  394. end;