objcgutl.pas 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927
  1. {
  2. Copyright (c) 2009 by Jonas Maebe
  3. This unit implements some Objective-C helper routines at the code generator
  4. level.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License,or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$i fpcdefs.inc}
  19. unit objcgutl;
  20. interface
  21. uses
  22. cclasses,
  23. aasmbase,aasmdata,
  24. symbase,symdef;
  25. procedure objcfinishstringrefpoolentry(entry: phashsetitem; stringpool: tconstpooltype; refsec, stringsec: tasmsectiontype);
  26. procedure objcfinishclassrefnfpoolentry(entry: phashsetitem; classdef: tobjectdef);
  27. procedure MaybeGenerateObjectiveCImageInfo(globalst, localst: tsymtable);
  28. implementation
  29. uses
  30. globtype,globals,fmodule,cutils,
  31. systems,
  32. aasmtai,
  33. cgbase,
  34. objcdef,objcutil,
  35. aasmcnst,
  36. symconst,symtype,symsym,symtable,
  37. ngenutil,
  38. verbose;
  39. type
  40. tobjcabi = (oa_fragile, oa_nonfragile);
  41. (* tivarlayouttype = (il_weak,il_strong); *)
  42. tobjcrttiwriter = class
  43. protected
  44. fabi: tobjcabi;
  45. classdefs,
  46. catdefs: tfpobjectlist;
  47. classrttidefs,
  48. catrttidefs: tfpobjectlist;
  49. classsyms,
  50. catsyms: tfpobjectlist;
  51. procedure gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmsymbol; classmethods, iscategory: Boolean);
  52. procedure gen_objc_protocol_elements(list: tasmlist; protocol: tobjectdef; out reqinstsym, optinstsym, reqclssym, optclssym: TAsmLabel);
  53. procedure gen_objc_protocol_list(list:TAsmList; protolist: TFPObjectList; out protolistsym: TAsmLabel);
  54. procedure gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;const sectname: string; out listsym: TAsmLabel);
  55. procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);virtual;abstract;
  56. procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol; out catlabeldef: tdef);virtual;abstract;
  57. procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol; out classlabeldef: tdef);virtual;abstract;
  58. procedure gen_objc_info_sections(list: tasmlist);virtual;abstract;
  59. public
  60. constructor create(_abi: tobjcabi);
  61. destructor destroy;override;
  62. procedure gen_objc_rtti_sections(list:TAsmList; st:TSymtable);
  63. property abi: tobjcabi read fabi;
  64. end;
  65. { Used by by PowerPC/32 and i386 }
  66. tobjcrttiwriter_fragile = class(tobjcrttiwriter)
  67. protected
  68. function gen_objc_protocol_ext(list: TAsmList; optinstsym, optclssym: TAsmLabel): TAsmLabel;
  69. procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
  70. procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
  71. procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol; out catlabeldef: tdef);override;
  72. procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol; out classlabeldef: tdef);override;
  73. procedure gen_objc_info_sections(list: tasmlist);override;
  74. public
  75. constructor create;
  76. end;
  77. { Used by PowerPC/64, ARM, x86_64 and AArch64 }
  78. tobjcrttiwriter_nonfragile = class(tobjcrttiwriter)
  79. protected
  80. ObjCEmptyCacheVar,
  81. ObjCEmptyVtableVar: TAsmSymbol;
  82. procedure gen_objc_class_ro_part(list: TAsmList; objclss: tobjectdef; protolistsym: TAsmSymbol; out classrolabel: TAsmSymbol; metaclass: boolean);
  83. procedure addclasslist(list: tasmlist; section: tasmsectiontype; const symname: string; classes: tfpobjectlist);
  84. procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
  85. procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
  86. procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol; out catlabeldef: tdef);override;
  87. procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol; out classlabeldef: tdef);override;
  88. procedure gen_objc_info_sections(list: tasmlist);override;
  89. public
  90. constructor create;
  91. end;
  92. {******************************************************************
  93. Protocol declaration helpers
  94. *******************************************************************}
  95. function objcfindprotocolentry(const p: shortstring): TAsmSymbol;
  96. var
  97. item : PHashSetItem;
  98. begin
  99. result:=nil;
  100. if not assigned(current_asmdata.ConstPools[sp_objcprotocolrefs]) then
  101. exit;
  102. item:=current_asmdata.constpools[sp_objcprotocolrefs].Find(@p[1], length(p));
  103. if not assigned(item) then
  104. exit;
  105. result:=TAsmSymbol(item^.Data);
  106. end;
  107. function objcaddprotocolentry(const p: shortstring; ref: TAsmSymbol): Boolean;
  108. var
  109. item : PHashSetItem;
  110. begin
  111. item:=current_asmdata.constpools[sp_objcprotocolrefs].FindOrAdd(@p[1], length(p));
  112. Result:=(item^.Data=nil);
  113. if Result then
  114. item^.Data:=ref;
  115. end;
  116. {******************************************************************
  117. Pool section helpers
  118. *******************************************************************}
  119. procedure objcreatestringpoolentryintern(p: pchar; len: longint; pooltype: tconstpooltype; stringsec: tasmsectiontype; out sym: TAsmLabel; out def: tdef);
  120. var
  121. entry : PHashSetItem;
  122. strlab : tasmlabel;
  123. pool : THashSet;
  124. tcb : ttai_typedconstbuilder;
  125. begin
  126. pool := current_asmdata.constpools[pooltype];
  127. entry:=pool.FindOrAdd(p,len);
  128. if not assigned(entry^.data) then
  129. begin
  130. { create new entry }
  131. current_asmdata.getlabel(strlab,alt_data);
  132. entry^.Data:=strlab;
  133. { Make sure strlab has a reference }
  134. strlab.increfs;
  135. { add the string to the approriate section }
  136. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section]);
  137. def:=tcb.emit_pchar_const(pchar(entry^.key),entry^.keylength);
  138. current_asmdata.asmlists[al_objc_pools].concatList(
  139. tcb.get_final_asmlist(strlab,def,stringsec,strlab.name,1)
  140. );
  141. tcb.free;
  142. def:=cpointerdef.getreusable(def);
  143. end
  144. else
  145. def:=cpointerdef.getreusable(carraydef.getreusable(cansichartype,len+1));
  146. sym:=TAsmLabel(Entry^.Data);
  147. end;
  148. procedure objcfinishstringrefpoolentry(entry: phashsetitem; stringpool: tconstpooltype; refsec, stringsec: tasmsectiontype);
  149. var
  150. reflab,
  151. strlab : tasmlabel;
  152. classname: string;
  153. tcb: ttai_typedconstbuilder;
  154. strdef: tdef;
  155. begin
  156. { have we already generated a reference for this string entry? }
  157. if not assigned(entry^.Data) then
  158. begin
  159. { no, add the string to the associated strings section }
  160. objcreatestringpoolentryintern(pchar(entry^.key),entry^.keylength,stringpool,stringsec,strlab,strdef);
  161. { and now finish the reference }
  162. current_asmdata.getlabel(reflab,alt_data);
  163. entry^.Data:=reflab;
  164. { add a pointer to the string in the string references section }
  165. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section,tcalo_no_dead_strip]);
  166. tcb.emit_tai(Tai_const.Create_sym(strlab),strdef);
  167. current_asmdata.asmlists[al_objc_pools].concatList(
  168. tcb.get_final_asmlist(reflab,strdef,refsec,reflab.name,sizeof(pint))
  169. );
  170. tcb.free;
  171. { in case of a class reference, also add a lazy symbol reference for
  172. the class (the linker requires this for the fragile ABI). }
  173. if (refsec=sec_objc_cls_refs) and
  174. not(target_info.system in systems_objc_nfabi) then
  175. begin
  176. classname:='';
  177. setlength(classname,entry^.keylength);
  178. move(entry^.key^,classname[1],entry^.keylength);
  179. { no way to express this in LLVM either, they also just emit
  180. module level assembly for it }
  181. current_asmdata.asmlists[al_pure_assembler].concat(tai_directive.Create(asd_lazy_reference,'.objc_class_name_'+classname));
  182. end;
  183. end;
  184. end;
  185. procedure objcreatestringpoolentry(const s: string; pooltype: tconstpooltype; stringsec: tasmsectiontype; out sym: TAsmLabel; out def: tdef);
  186. begin
  187. objcreatestringpoolentryintern(@s[1],length(s),pooltype,stringsec,sym,def);
  188. end;
  189. procedure objcfinishclassrefnfpoolentry(entry: phashsetitem; classdef: tobjectdef);
  190. var
  191. reflab: TAsmLabel;
  192. classym: TasmSymbol;
  193. tcb: ttai_typedconstbuilder;
  194. begin
  195. { have we already generated a reference for this class ref entry? }
  196. if not assigned(entry^.Data) then
  197. begin
  198. { no, add the classref to the sec_objc_cls_refs section }
  199. current_asmdata.getlabel(reflab,alt_data);
  200. entry^.Data:=reflab;
  201. { add a pointer to the class }
  202. classym:=current_asmdata.RefAsmSymbol(classdef.rtti_mangledname(objcclassrtti),AT_DATA);
  203. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section]);
  204. tcb.emit_tai(Tai_const.Create_sym(classym),voidpointertype);
  205. current_asmdata.asmlists[al_objc_pools].concatList(
  206. tcb.get_final_asmlist(reflab,voidpointertype,sec_objc_cls_refs,reflab.name,sizeof(pint))
  207. );
  208. tcb.free;
  209. end;
  210. end;
  211. {******************************************************************
  212. RTTI generation -- Helpers
  213. *******************************************************************}
  214. procedure ConcatSymOrNil(tcb: ttai_typedconstbuilder; sym: TAsmSymbol; def: tdef); inline;
  215. begin
  216. if Assigned(sym) then
  217. tcb.emit_tai(tai_const.Create_sym(sym),def)
  218. else
  219. tcb.emit_tai(tai_const.Create_nil_dataptr,def);
  220. end;
  221. {******************************************************************
  222. RTTI generation -- Common
  223. *******************************************************************}
  224. { generate a method list, either of class methods or of instance methods,
  225. and both for obj-c classes and categories. }
  226. procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmsymbol; classmethods, iscategory: Boolean);
  227. const
  228. {clas/cat inst/cls}
  229. SectType : array [Boolean, Boolean] of tasmsectiontype =
  230. ((sec_objc_inst_meth, sec_objc_cls_meth),
  231. (sec_objc_cat_inst_meth, sec_objc_cat_cls_meth));
  232. {clas/cat inst/cls}
  233. SectName : array [Boolean, Boolean] of string[20] =
  234. (('_OBJC_INST_METH','_OBJC_CLS_METH'),
  235. ('_OBJC_CAT_INST_METH','_OBJC_CAT_CLS_METH'));
  236. {frag/non-frag ABI}
  237. SectFlags : array [Boolean] of ttcasmlistoptions =
  238. ([tcalo_new_section],[tcalo_new_section,tcalo_no_dead_strip]);
  239. {inst/cls}
  240. instclsName : array [Boolean] of string = ('INSTANCE','CLASS');
  241. type
  242. method_data = record
  243. def : tprocdef;
  244. selsym : TAsmLabel;
  245. seldef : tdef;
  246. encsym : TAsmLabel;
  247. encdef : tdef;
  248. end;
  249. var
  250. i : Integer;
  251. def : tprocdef;
  252. defs : array of method_data;
  253. mcnt : integer;
  254. mtype : tdef;
  255. tcb : ttai_typedconstbuilder;
  256. mdef : tdef;
  257. begin
  258. methodslabel:=nil;
  259. mcnt:=0;
  260. defs:=nil;
  261. { collect all instance/class methods }
  262. SetLength(defs,objccls.vmtentries.count);
  263. for i:=0 to objccls.vmtentries.count-1 do
  264. begin
  265. def:=pvmtentry(objccls.vmtentries[i])^.procdef;
  266. if (def.owner.defowner=objccls) and
  267. (classmethods = (po_classmethod in def.procoptions)) then
  268. begin
  269. defs[mcnt].def:=def;
  270. objcreatestringpoolentry(def.messageinf.str^,sp_objcvarnames,sec_objc_meth_var_names,defs[mcnt].selsym,defs[mcnt].seldef);
  271. objcreatestringpoolentry(objcencodemethod(def),sp_objcvartypes,sec_objc_meth_var_types,defs[mcnt].encsym,defs[mcnt].encdef);
  272. inc(mcnt);
  273. end;
  274. end;
  275. if mcnt=0 then
  276. exit;
  277. tcb:=ctai_typedconstbuilder.create(SectFlags[target_info.system in systems_objc_nfabi]);
  278. tcb.begin_anonymous_record(internaltypeprefixName[itp_objc_method_list]+tostr(mcnt),
  279. C_alignment,1,
  280. targetinfos[target_info.system]^.alignment.recordalignmin);
  281. if (abi=oa_fragile) then
  282. { not used, always zero }
  283. tcb.emit_ord_const(0,u32inttype)
  284. else
  285. begin
  286. { size of each entry -- always 32 bit value }
  287. mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD',true).typedef;
  288. tcb.emit_ord_const(mtype.size,u32inttype);
  289. end;
  290. { number of objc_method entries in the method_list array -- always 32 bit}
  291. tcb.emit_ord_const(mcnt,u32inttype);
  292. for i:=0 to mcnt-1 do
  293. begin
  294. { reference to the selector name }
  295. tcb.queue_init(charpointertype);
  296. tcb.queue_emit_asmsym(defs[i].selsym,defs[i].seldef);
  297. { reference to the obj-c encoded function parameters (signature) }
  298. tcb.queue_init(charpointertype);
  299. tcb.queue_emit_asmsym(defs[i].encsym,defs[i].encdef);
  300. { mangled name of the method }
  301. tcb.queue_init(voidcodepointertype);
  302. tcb.queue_emit_proc(defs[i].def);
  303. end;
  304. mdef:=tcb.end_anonymous_record;
  305. if iscategory then
  306. begin
  307. methodslabel:=current_asmdata.DefineAsmSymbol('l_OBJC_$_CATEGORY_'+instclsName[classmethods]+'_METHODS_'+objccls.objextname^+'_$_'+objccls.childof.objextname^,AB_LOCAL,AT_DATA,mdef);
  308. end
  309. else
  310. begin
  311. methodslabel:=current_asmdata.DefineAsmSymbol('l_OBJC_$_'+instclsName[classmethods]+'_METHODS_'+objccls.objextname^,AB_LOCAL,AT_DATA,mdef);
  312. end;
  313. list.concatList(
  314. tcb.get_final_asmlist(methodslabel,mdef,
  315. SectType[iscategory,classmethods],
  316. SectName[iscategory,classmethods],sizeof(ptrint)
  317. )
  318. );
  319. tcb.free;
  320. end;
  321. { generate method (and in the future also property) info for protocols }
  322. procedure tobjcrttiwriter.gen_objc_protocol_elements(list: tasmlist; protocol: tobjectdef; out reqinstsym, optinstsym, reqclssym, optclssym: TAsmLabel);
  323. var
  324. proc : tprocdef;
  325. reqinstmlist,
  326. reqclsmlist,
  327. optinstmlist,
  328. optclsmlist : TFPObjectList;
  329. i : ptrint;
  330. begin
  331. reqinstmlist:=TFPObjectList.Create(false);
  332. reqclsmlist:=TFPObjectList.Create(false);
  333. optinstmlist:=TFPObjectList.Create(false);
  334. optclsmlist:=TFPObjectList.Create(false);
  335. for i:=0 to protocol.vmtentries.Count-1 do
  336. begin
  337. proc:=pvmtentry(protocol.vmtentries[i])^.procdef;
  338. if (po_classmethod in proc.procoptions) then
  339. if not(po_optional in proc.procoptions) then
  340. reqclsmlist.Add(proc)
  341. else
  342. optclsmlist.Add(proc)
  343. else if not(po_optional in proc.procoptions) then
  344. reqinstmlist.Add(proc)
  345. else
  346. optinstmlist.Add(proc);
  347. end;
  348. if reqinstmlist.Count > 0 then
  349. gen_objc_cat_methods(list,reqinstmlist,sec_objc_cat_inst_meth,'_OBJC_CAT_INST_METH',reqinstsym)
  350. else
  351. reqinstsym:=nil;
  352. if optinstmlist.Count > 0 then
  353. gen_objc_cat_methods(list,optinstmlist,sec_objc_cat_inst_meth,'_OBJC_CAT_INST_METH',optinstsym)
  354. else
  355. optinstsym:=nil;
  356. if reqclsmlist.Count>0 then
  357. gen_objc_cat_methods(list,reqclsmlist,sec_objc_cat_cls_meth,'_OBJC_CAT_CLS_METH',reqclssym)
  358. else
  359. reqclssym:=nil;
  360. if optclsmlist.Count>0 then
  361. gen_objc_cat_methods(list,optclsmlist,sec_objc_cat_cls_meth,'_OBJC_CAT_CLS_METH',optclssym)
  362. else
  363. optclssym:=nil;
  364. reqinstmlist.Free;
  365. reqclsmlist.Free;
  366. optinstmlist.Free;
  367. optclsmlist.Free;
  368. end;
  369. (*
  370. From CLang:
  371. struct objc_protocol_list
  372. {
  373. #ifdef FRAGILE_ABI
  374. struct objc_protocol_list *next;
  375. int count;
  376. #else
  377. long count;
  378. #endif
  379. Protocol *list[1];
  380. };
  381. *)
  382. procedure tobjcrttiwriter.gen_objc_protocol_list(list: tasmlist; protolist: tfpobjectlist; out protolistsym: tasmlabel);
  383. var
  384. i : Integer;
  385. protosym : TAsmSymbol;
  386. protodef : tobjectdef;
  387. tcb : ttai_typedconstbuilder;
  388. begin
  389. if not Assigned(protolist) or
  390. (protolist.Count=0) then
  391. begin
  392. protolistsym:=nil;
  393. Exit;
  394. end;
  395. for i:=0 to protolist.Count-1 do
  396. begin
  397. protodef:=TImplementedInterface(protolist[i]).IntfDef;
  398. protosym:=objcfindprotocolentry(protodef.objextname^);
  399. if not assigned(protosym) then
  400. begin
  401. gen_objc_protocol(list,protodef,protosym);
  402. objcaddprotocolentry(protodef.objextname^,protosym);
  403. end;
  404. end;
  405. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section]);
  406. tcb.begin_anonymous_record(internaltypeprefixName[itp_objc_proto_list]+tostr(protolist.Count),
  407. C_alignment,1,
  408. targetinfos[target_info.system]^.alignment.recordalignmin);
  409. { protocol lists are stored in .objc_cat_cls_meth section }
  410. current_asmdata.getlabel(protolistsym, alt_data);
  411. if (abi=oa_fragile) then
  412. { From Clang: next, always nil}
  413. tcb.emit_tai(tai_const.Create_nil_dataptr,ptruinttype);
  414. { From Clang: protocols count}
  415. tcb.emit_tai(Tai_const.Create_int_dataptr(protolist.Count),ptruinttype);
  416. for i:=0 to protolist.Count-1 do
  417. begin
  418. protodef:=(protolist[i] as TImplementedInterface).IntfDef;
  419. protosym:=objcfindprotocolentry(protodef.objextname^);
  420. if not Assigned(protosym) then
  421. begin
  422. { For some reason protosym is not declared, though must be!
  423. Probably gen_obcj1_protocol returned wrong protosym
  424. }
  425. InternalError(2009091602);
  426. end;
  427. tcb.emit_tai(tai_const.Create_sym(protosym),voidpointertype);
  428. end;
  429. list.concatList(
  430. tcb.get_final_asmlist(
  431. protolistsym,tcb.end_anonymous_record,
  432. sec_objc_cat_cls_meth,'_OBJC_PROTOCOLLIST',sizeof(pint)
  433. )
  434. );
  435. tcb.free;
  436. { the symbol will point to a record }
  437. end;
  438. { Generate rtti for an Objective-C methods (methods without implementation) }
  439. { items : TFPObjectList of Tprocdef }
  440. procedure tobjcrttiwriter.gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;
  441. const sectname: string; out listsym: TAsmLabel);
  442. var
  443. i : integer;
  444. m : tprocdef;
  445. lab : tasmlabel;
  446. ldef : tdef;
  447. mtype : tdef;
  448. tcb : ttai_typedconstbuilder;
  449. begin
  450. if not assigned(items) or
  451. (items.count=0) then
  452. exit;
  453. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section]);
  454. current_asmdata.getlabel(listsym,alt_data);
  455. tcb.begin_anonymous_record(
  456. internaltypeprefixName[itp_objc_cat_methods]+tostr(items.count),
  457. C_alignment,1,
  458. targetinfos[target_info.system]^.alignment.recordalignmin);
  459. if (abi=oa_nonfragile) then
  460. begin
  461. { size of each entry -- always 32 bit value }
  462. mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD',true).typedef;
  463. tcb.emit_ord_const(mtype.size,u32inttype);
  464. end;
  465. tcb.emit_ord_const(items.count,u32inttype);
  466. for i:=0 to items.Count-1 do
  467. begin
  468. m:=tprocdef(items[i]);
  469. objcreatestringpoolentry(m.messageinf.str^,sp_objcvarnames,sec_objc_meth_var_names,lab,ldef);
  470. tcb.emit_tai(Tai_const.Create_sym(lab),ldef);
  471. objcreatestringpoolentry(objcencodemethod(m),sp_objcvartypes,sec_objc_meth_var_types,lab,ldef);
  472. tcb.emit_tai(Tai_const.Create_sym(lab),ldef);
  473. { placeholder for address of implementation? }
  474. if (abi=oa_nonfragile) then
  475. tcb.emit_tai(Tai_const.Create_nil_codeptr,codeptruinttype);
  476. end;
  477. list.concatList(
  478. tcb.get_final_asmlist(
  479. listsym,tcb.end_anonymous_record,section,sectname,sizeof(pint))
  480. );
  481. tcb.free;
  482. end;
  483. { Generate the rtti sections for all obj-c classes defined in st, and return
  484. these classes in the classes list. }
  485. procedure tobjcrttiwriter.gen_objc_rtti_sections(list:TAsmList; st:TSymtable);
  486. var
  487. i: longint;
  488. def,
  489. rttidef: tdef;
  490. sym: TAsmSymbol;
  491. begin
  492. if not Assigned(st) then
  493. exit;
  494. for i:=0 to st.DefList.Count-1 do
  495. begin
  496. def:=tdef(st.DefList[i]);
  497. { check whether all types used in Objective-C class/protocol/category
  498. declarations can be used with the Objective-C run time (can only be
  499. done now, because at parse-time some of these types can still be
  500. forwarddefs) }
  501. if is_objc_class_or_protocol(def) then
  502. if not tobjectdef(def).check_objc_types then
  503. continue;
  504. if is_objcclass(def) and
  505. not(oo_is_external in tobjectdef(def).objectoptions) then
  506. begin
  507. if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
  508. begin
  509. gen_objc_classes_sections(list,tobjectdef(def),sym,rttidef);
  510. classsyms.add(sym);
  511. classrttidefs.add(rttidef);
  512. classdefs.add(def);
  513. end
  514. else
  515. begin
  516. gen_objc_category_sections(list,tobjectdef(def),sym,rttidef);
  517. catsyms.add(sym);
  518. catrttidefs.add(rttidef);
  519. catdefs.add(def);
  520. end
  521. end;
  522. end;
  523. end;
  524. constructor tobjcrttiwriter.create(_abi: tobjcabi);
  525. begin
  526. fabi:=_abi;
  527. classdefs:=tfpobjectlist.create(false);
  528. classsyms:=tfpobjectlist.create(false);
  529. classrttidefs:=tfpobjectlist.create(false);
  530. catrttidefs:=tfpobjectlist.create(false);
  531. catdefs:=tfpobjectlist.create(false);
  532. catsyms:=tfpobjectlist.create(false);
  533. end;
  534. destructor tobjcrttiwriter.destroy;
  535. begin
  536. classdefs.free;
  537. classsyms.free;
  538. classrttidefs.free;
  539. catrttidefs.free;
  540. catdefs.free;
  541. catsyms.free;
  542. inherited destroy;
  543. end;
  544. {******************************************************************
  545. RTTI generation -- Fragile ABI
  546. *******************************************************************}
  547. { generate an instance variables list for an obj-c class. }
  548. procedure tobjcrttiwriter_fragile.gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
  549. type
  550. ivar_data = record
  551. vf : tfieldvarsym;
  552. namesym : TAsmLabel;
  553. namedef : tdef;
  554. typesym : TAsmLabel;
  555. typedef : tdef;
  556. end;
  557. var
  558. i : integer;
  559. vf : tfieldvarsym;
  560. vars : array of ivar_data;
  561. vcnt : Integer;
  562. enctype : ansistring;
  563. encerr : tdef;
  564. begin
  565. ivarslabel:=nil;
  566. vcnt:=0;
  567. vars:=nil;
  568. setLength(vars,objccls.symtable.SymList.Count);
  569. for i:=0 to objccls.symtable.SymList.Count-1 do
  570. if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
  571. begin
  572. vf:=tfieldvarsym(objccls.symtable.SymList[i]);
  573. if objctryencodetype(vf.vardef,enctype,encerr) then
  574. begin
  575. vars[vcnt].vf:=vf;
  576. objcreatestringpoolentry(vf.RealName,sp_objcvarnames,sec_objc_meth_var_names,vars[vcnt].namesym,vars[vcnt].namedef);
  577. objcreatestringpoolentry(enctype,sp_objcvartypes,sec_objc_meth_var_types,vars[vcnt].typesym,vars[vcnt].typedef);
  578. inc(vcnt);
  579. end
  580. else
  581. { Should be caught during parsing }
  582. internalerror(2009090601);
  583. end;
  584. if vcnt=0 then
  585. exit;
  586. new_section(list,sec_objc_instance_vars,'_OBJC_INSTANCE_VARS',sizeof(pint));
  587. current_asmdata.getlabel(ivarslabel,alt_data);
  588. list.Concat(tai_label.Create(ivarslabel));
  589. { objc_ivar_list: first the number of elements }
  590. list.Concat(tai_const.Create_32bit(vcnt));
  591. for i:=0 to vcnt-1 do
  592. begin
  593. { reference to the instance variable name }
  594. list.Concat(tai_const.Create_sym(vars[i].namesym));
  595. { reference to the encoded type }
  596. list.Concat(tai_const.Create_sym(vars[i].typesym));
  597. { and the offset of the field }
  598. list.Concat(tai_const.Create_32bit(vars[i].vf.fieldoffset));
  599. end;
  600. end;
  601. (* From GCC:
  602. struct _objc_protocol_extension
  603. {
  604. uint32_t size; // sizeof (struct _objc_protocol_extension)
  605. struct objc_method_list *optional_instance_methods;
  606. struct objc_method_list *optional_class_methods;
  607. struct objc_prop_list *instance_properties;
  608. }
  609. *)
  610. function tobjcrttiwriter_fragile.gen_objc_protocol_ext(list: TAsmList; optinstsym, optclssym: TAsmLabel): TAsmLabel;
  611. var
  612. tcb: ttai_typedconstbuilder;
  613. begin
  614. if assigned(optinstsym) or
  615. assigned(optclssym) then
  616. begin
  617. current_asmdata.getlabel(Result,alt_data);
  618. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  619. tcb.begin_anonymous_record(
  620. internaltypeprefixName[itb_objc_fr_protocol_ext],
  621. C_alignment,1,
  622. targetinfos[target_info.system]^.alignment.recordalignmin);
  623. { size of this structure }
  624. tcb.emit_ord_const(16,u32inttype);
  625. { optional instance methods }
  626. ConcatSymOrNil(tcb,optinstsym,voidpointertype);
  627. { optional class methods }
  628. ConcatSymOrNil(tcb,optclssym,voidpointertype);
  629. { optional properties (todo) }
  630. ConcatSymOrNil(tcb,nil,voidpointertype);
  631. list.concatList(
  632. tcb.get_final_asmlist(
  633. result,tcb.end_anonymous_record,
  634. sec_objc_protocol_ext,'_OBJC_PROTOCOLEXT',sizeof(pint)
  635. )
  636. );
  637. tcb.free;
  638. end
  639. else
  640. Result:=nil;
  641. end;
  642. { Generate rtti for an Objective-C protocol }
  643. procedure tobjcrttiwriter_fragile.gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);
  644. var
  645. namesym : TAsmLabel;
  646. namedef : tdef;
  647. protolist : TAsmLabel;
  648. reqinstsym,
  649. optinstsym,
  650. reqclssym,
  651. optclssym,
  652. protoext,
  653. lbl : TAsmLabel;
  654. tcb : ttai_typedconstbuilder;
  655. begin
  656. gen_objc_protocol_list(list,protocol.ImplementedInterfaces,protolist);
  657. gen_objc_protocol_elements(list,protocol,reqinstsym,optinstsym,reqclssym,optclssym);
  658. protoext:=gen_objc_protocol_ext(list,optinstsym,optclssym);
  659. current_asmdata.getlabel(lbl,alt_data);
  660. protocollabel:=lbl;
  661. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  662. tcb.begin_anonymous_record(
  663. internaltypeprefixName[itb_objc_fr_protocol],
  664. C_alignment,1,
  665. targetinfos[target_info.system]^.alignment.recordalignmin);
  666. { protocol's isa - points to information about optional methods/properties }
  667. ConcatSymOrNil(tcb,protoext,voidpointertype);
  668. { name }
  669. objcreatestringpoolentry(protocol.objextname^,sp_objcclassnames,sec_objc_class_names,namesym,namedef);
  670. tcb.queue_init(voidpointertype);
  671. tcb.queue_emit_asmsym(namesym,namedef);
  672. { protocol's list }
  673. ConcatSymOrNil(tcb,protolist,voidpointertype);
  674. { instance methods, in __cat_inst_meth }
  675. ConcatSymOrNil(tcb,reqinstsym,voidpointertype);
  676. { class methods, in __cat_cls_meth }
  677. ConcatSymOrNil(tcb,reqclssym,voidpointertype);
  678. list.concatList(
  679. tcb.get_final_asmlist(
  680. lbl,tcb.end_anonymous_record,
  681. sec_objc_protocol,'_OBJC_PROTOCOL',sizeof(pint)
  682. )
  683. );
  684. tcb.free;
  685. end;
  686. (*
  687. From Clang:
  688. struct _objc_category {
  689. char *category_name;
  690. char *class_name;
  691. struct _objc_method_list *instance_methods;
  692. struct _objc_method_list *class_methods;
  693. struct _objc_protocol_list *protocols;
  694. uint32_t size; // <rdar://4585769>
  695. struct _objc_property_list *instance_properties;
  696. };
  697. *)
  698. { Generate rtti for an Objective-C class and its meta-class. }
  699. procedure tobjcrttiwriter_fragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol; out catlabeldef: tdef);
  700. var
  701. catstrsym,
  702. clsstrsym,
  703. protolistsym : TAsmLabel;
  704. instmthdlist,
  705. clsmthdlist,
  706. catsym : TAsmSymbol;
  707. catstrdef,
  708. clsstrdef,
  709. catdef : tdef;
  710. tcb : ttai_typedconstbuilder;
  711. begin
  712. { the category name }
  713. objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names,catstrsym,catstrdef);
  714. { the name of the class it extends }
  715. objcreatestringpoolentry(objccat.childof.objextname^,sp_objcclassnames,sec_objc_class_names,clsstrsym,clsstrdef);
  716. { generate the methods lists }
  717. gen_objc_methods(list,objccat,instmthdlist,false,true);
  718. gen_objc_methods(list,objccat,clsmthdlist,true,true);
  719. { generate implemented protocols list }
  720. gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
  721. { category declaration section }
  722. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  723. tcb.begin_anonymous_record(
  724. internaltypeprefixName[itb_objc_fr_category],
  725. C_alignment,1,
  726. targetinfos[target_info.system]^.alignment.recordalignmin);
  727. tcb.queue_init(voidpointertype);
  728. tcb.queue_emit_asmsym(catstrsym,catstrdef);
  729. tcb.queue_init(voidpointertype);
  730. tcb.queue_emit_asmsym(clsstrsym,clsstrdef);
  731. ConcatSymOrNil(tcb,instmthdlist,voidpointertype);
  732. ConcatSymOrNil(tcb,clsmthdlist,voidpointertype);
  733. ConcatSymOrNil(tcb,protolistsym,voidpointertype);
  734. { size of this structure }
  735. tcb.emit_ord_const(28,u32inttype);
  736. { properties, not yet supported }
  737. tcb.emit_ord_const(0,u32inttype);
  738. catdef:=tcb.end_anonymous_record;
  739. catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA,catdef);
  740. list.concatList(
  741. tcb.get_final_asmlist(
  742. catsym,catdef,
  743. sec_objc_category,'_OBJC_CATEGORY',sizeof(pint)
  744. )
  745. );
  746. tcb.free;
  747. catlabel:=catsym;
  748. catlabeldef:=catdef;
  749. end;
  750. (*
  751. From Clang:
  752. struct _objc_class {
  753. Class isa;
  754. Class super_class;
  755. const char *name;
  756. long version;
  757. long info;
  758. long instance_size;
  759. struct _objc_ivar_list *ivars;
  760. struct _objc_method_list *methods;
  761. struct _objc_cache *cache;
  762. struct _objc_protocol_list *protocols;
  763. // Objective-C 1.0 extensions (<rdr://4585769>) -- for garbage collection
  764. const char *ivar_layout;
  765. struct _objc_class_ext *ext;
  766. };
  767. *)
  768. { Generate rtti for an Objective-C class and its meta-class. }
  769. procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol; out classlabeldef: tdef);
  770. const
  771. CLS_CLASS = 1;
  772. CLS_META = 2;
  773. CLS_HIDDEN = $20000;
  774. META_INST_SIZE = 40+8; // sizeof(objc_class) + 8
  775. var
  776. root : tobjectdef;
  777. metasym,
  778. mthdlist,
  779. clssym : TAsmSymbol;
  780. superStrDef,
  781. classStrDef,
  782. metaisaStrDef,
  783. metaDef,
  784. clsDef : tdef;
  785. superStrSym,
  786. classStrSym,
  787. metaisaStrSym,
  788. ivarslist,
  789. protolistsym : TAsmLabel;
  790. hiddenflag : cardinal;
  791. tcb : ttai_typedconstbuilder;
  792. begin
  793. { generate the class methods list }
  794. gen_objc_methods(list,objclss,mthdlist,true,false);
  795. { generate implemented protocols list }
  796. gen_objc_protocol_list(list,objclss.ImplementedInterfaces,protolistsym);
  797. { register necessary names }
  798. { 1) the superclass }
  799. if assigned(objclss.childof) then
  800. objcreatestringpoolentry(objclss.childof.objextname^,sp_objcclassnames,sec_objc_class_names,superStrSym,superStrDef)
  801. else
  802. begin
  803. { not empty string, but nil! }
  804. superStrSym:=nil;
  805. superStrDef:=voidpointertype;
  806. end;
  807. { 2) the current class }
  808. objcreatestringpoolentry(objclss.objextname^,sp_objcclassnames,sec_objc_class_names,classStrSym,classStrDef);
  809. { 3) the isa }
  810. { From Clang: The isa for the meta-class is the root of the hierarchy. }
  811. root:=objclss;
  812. while assigned(root.childof) do
  813. root:=root.childof;
  814. objcreatestringpoolentry(root.objextname^,sp_objcclassnames,sec_objc_class_names,metaisaStrSym,metaisaStrDef);
  815. { 4) the flags }
  816. { consider every class declared in the implementation section of a unit
  817. as "hidden"
  818. }
  819. hiddenflag:=0;
  820. if (objclss.owner.symtabletype=staticsymtable) and
  821. current_module.is_unit then
  822. hiddenflag:=CLS_HIDDEN;
  823. { class declaration section }
  824. { 1) meta-class declaration }
  825. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  826. tcb.begin_anonymous_record(internaltypeprefixName[itb_objc_fr_meta_class],
  827. C_alignment,1,
  828. targetinfos[target_info.system]^.alignment.recordalignmin);
  829. tcb.queue_init(voidpointertype);
  830. tcb.queue_emit_asmsym(metaisaStrSym,metaisaStrDef);
  831. { pointer to the superclass name if any, otherwise nil }
  832. if assigned(superstrsym) then
  833. begin
  834. tcb.queue_init(voidpointertype);
  835. tcb.queue_emit_asmsym(superStrSym,superStrDef);
  836. end
  837. else
  838. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  839. { pointer to the class name }
  840. tcb.queue_init(voidpointertype);
  841. tcb.queue_emit_asmsym(classStrSym,classStrDef);
  842. { version is always 0 currently }
  843. tcb.emit_ord_const(0,u32inttype);
  844. { CLS_META for meta-classes }
  845. tcb.emit_ord_const(hiddenflag or CLS_META,u32inttype);
  846. { size of the meta-class instance: sizeof(objc_class) + 8 bytes }
  847. tcb.emit_ord_const(META_INST_SIZE,u32inttype);
  848. { meta-classes don't have ivars list (=0) }
  849. tcb.emit_ord_const(0,u32inttype);
  850. { class methods list (stored in "__cls_meth" section) }
  851. ConcatSymOrNil(tcb,mthdlist,voidpointertype);
  852. { From Clang: cache is always nil }
  853. tcb.emit_ord_const(0,u32inttype);
  854. { protocols }
  855. ConcatSymOrNil(tcb,protolistsym,voidpointertype);
  856. { From Clang: ivar_layout for meta-class is always NULL. }
  857. tcb.emit_ord_const(0,u32inttype);
  858. { From Clang: The class extension is always unused for meta-classes. }
  859. tcb.emit_ord_const(0,u32inttype);
  860. metaDef:=tcb.end_anonymous_record;
  861. metasym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcmetartti),AB_LOCAL,AT_DATA,metadef);
  862. list.concatList(
  863. tcb.get_final_asmlist(
  864. metasym,metaDef,
  865. sec_objc_meta_class,'_OBJC_META_CLASS',sizeof(pint)
  866. )
  867. );
  868. tcb.free;
  869. { 2) regular class declaration }
  870. { generate the instance methods list }
  871. gen_objc_methods(list,objclss,mthdlist,false,false);
  872. { generate the instance variables list }
  873. gen_objc_ivars(list,objclss,ivarslist);
  874. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  875. tcb.begin_anonymous_record(internaltypeprefixName[itb_objc_fr_class],
  876. C_alignment,1,
  877. targetinfos[target_info.system]^.alignment.recordalignmin);
  878. { for class declaration: the isa points to the meta-class declaration }
  879. tcb.emit_tai(Tai_const.Create_sym(metasym),cpointerdef.getreusable(metaDef));
  880. { pointer to the super_class name if any, nil otherwise }
  881. if assigned(superStrSym) then
  882. begin
  883. tcb.queue_init(voidcodepointertype);
  884. tcb.queue_emit_asmsym(superStrSym,superStrDef)
  885. end
  886. else
  887. tcb.emit_tai(Tai_const.Create_nil_dataptr,voidcodepointertype);
  888. { pointer to the class name }
  889. tcb.queue_init(voidcodepointertype);
  890. tcb.queue_emit_asmsym(classStrSym,classStrDef);
  891. { version is always 0 currently }
  892. tcb.emit_ord_const(0,u32inttype);
  893. { CLS_CLASS for classes }
  894. tcb.emit_ord_const(hiddenflag or CLS_CLASS,u32inttype);
  895. { size of instance: total size of instance variables }
  896. tcb.emit_ord_const(tobjectsymtable(objclss.symtable).datasize,u32inttype);
  897. { objc_ivar_list (stored in "__instance_vars" section) }
  898. ConcatSymOrNil(tcb,ivarslist,voidpointertype);
  899. { instance methods list (stored in "__inst_meth" section) }
  900. ConcatSymOrNil(tcb,mthdlist,voidpointertype);
  901. { From Clang: cache is always NULL }
  902. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  903. { protocols, protolistsym has been created for meta-class, no need to create another one}
  904. ConcatSymOrNil(tcb, protolistsym,voidpointertype);
  905. { From Clang: strong ivar_layout, necessary for garbage collection support }
  906. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  907. { TODO: From Clang: weak ivar_layout, necessary for garbage collection support }
  908. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  909. clsDef:=tcb.end_anonymous_record;
  910. clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA,clsDef);
  911. list.concatList(
  912. tcb.get_final_asmlist(
  913. clssym,clsDef,
  914. sec_objc_class,'_OBJC_CLASS',sizeof(pint)
  915. )
  916. );
  917. tcb.free;
  918. classlabel:=clssym;
  919. classlabeldef:=clsDef;
  920. end;
  921. { Generate the global information sections (objc_symbols and objc_module_info)
  922. for this module. }
  923. procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
  924. var
  925. i: longint;
  926. sym : TAsmSymbol;
  927. lab : TAsmLabel;
  928. symsdef,
  929. def : tdef;
  930. parent: tobjectdef;
  931. superclasses: tfpobjectlist;
  932. tcb: ttai_typedconstbuilder;
  933. begin
  934. if (classsyms.count<>0) or
  935. (catsyms.count<>0) then
  936. begin
  937. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  938. tcb.begin_anonymous_record('',
  939. C_alignment,1,
  940. targetinfos[target_info.system]^.alignment.recordalignmin);
  941. { ??? (always 0 in Clang) }
  942. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  943. { ??? (From Clang: always 0, pointer to some selector) }
  944. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  945. { From Clang: number of defined classes }
  946. tcb.emit_ord_const(classsyms.count,u16inttype);
  947. { From Clang: number of defined categories }
  948. tcb.emit_ord_const(catsyms.count,u16inttype);
  949. { first all classes }
  950. for i:=0 to classsyms.count-1 do
  951. tcb.emit_tai(Tai_const.Create_sym(tasmsymbol(classsyms[i])),tdef(classrttidefs[i]));
  952. { then all categories }
  953. for i:=0 to catsyms.count-1 do
  954. tcb.emit_tai(Tai_const.Create_sym(tasmsymbol(catsyms[i])),tdef(catrttidefs[i]));
  955. symsdef:=tcb.end_anonymous_record;
  956. sym := current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_SYMBOLS_$',AB_LOCAL,AT_DATA,symsdef);
  957. list.concatList(tcb.get_final_asmlist(sym,
  958. symsdef,
  959. sec_objc_symbols,'_OBJC_SYMBOLS',
  960. sizeof(pint)));
  961. end
  962. else
  963. begin
  964. sym:=nil;
  965. symsdef:=nil;
  966. end;
  967. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  968. tcb.begin_anonymous_record('',
  969. C_alignment,1,
  970. targetinfos[target_info.system]^.alignment.recordalignmin);
  971. { version number = 7 (always, both for gcc and clang) }
  972. tcb.emit_ord_const(7,ptruinttype);
  973. { sizeof(objc_module): 4 pointer-size entities }
  974. tcb.emit_ord_const(sizeof(pint)*4,ptruinttype);
  975. { used to be file name, now unused (points to empty string) }
  976. objcreatestringpoolentry('',sp_objcclassnames,sec_objc_class_names,lab,def);
  977. tcb.emit_tai(Tai_const.Create_sym(lab),def);
  978. { pointer to classes/categories list declared in this module }
  979. if assigned(sym) then
  980. tcb.emit_tai(tai_const.Create_sym(sym),symsdef)
  981. else
  982. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  983. current_asmdata.getlabel(lab,alt_data);
  984. list.concatList(tcb.get_final_asmlist(lab,
  985. tcb.end_anonymous_record,sec_objc_module_info,'_OBJC_MODULE_INFO',4));
  986. { Add lazy references to parent classes of all classes defined in this unit }
  987. superclasses:=tfpobjectlist.create(false);
  988. for i:=0 to classdefs.count-1 do
  989. begin
  990. parent:=tobjectdef(classdefs[i]).childof;
  991. { warning: linear search, performance hazard if large number of subclasses }
  992. if assigned(parent) and
  993. (superclasses.indexof(parent)=-1) then
  994. begin
  995. list.concat(tai_directive.create(asd_lazy_reference,'.objc_class_name_'+parent.objextname^));
  996. superclasses.add(parent);
  997. end;
  998. end;
  999. for i:=0 to catdefs.count-1 do
  1000. begin
  1001. parent:=tobjectdef(catdefs[i]).childof;
  1002. { warning: linear search, performance hazard if large number of subclasses }
  1003. if assigned(parent) and
  1004. (superclasses.indexof(parent)=-1) then
  1005. begin
  1006. list.concat(tai_directive.create(asd_lazy_reference,'.objc_class_name_'+parent.objextname^));
  1007. superclasses.add(parent);
  1008. end;
  1009. end;
  1010. superclasses.free;
  1011. { reference symbols for all classes and categories defined in this unit }
  1012. for i:=0 to classdefs.count-1 do
  1013. list.concat(tai_symbol.Createname_global_value('.objc_class_name_'+tobjectdef(classdefs[i]).objextname^,AT_DATA,0,0,voidpointertype));
  1014. for i:=0 to catdefs.count-1 do
  1015. list.concat(tai_symbol.Createname_global_value('.objc_category_name_'+
  1016. tobjectdef(catdefs[i]).childof.objextname^+'_'+
  1017. tobjectdef(catdefs[i]).objextname^,AT_DATA,0,0,voidpointertype));
  1018. end;
  1019. constructor tobjcrttiwriter_fragile.create;
  1020. begin
  1021. inherited create(oa_fragile);
  1022. end;
  1023. {******************************************************************
  1024. RTTI generation -- Non-Fragile ABI
  1025. *******************************************************************}
  1026. (*
  1027. From Clang:
  1028. /// EmitIvarList - Emit the ivar list for the given
  1029. /// implementation. The return value has type
  1030. /// IvarListnfABIPtrTy.
  1031. /// struct _ivar_t {
  1032. /// unsigned long int *offset; // pointer to ivar offset location
  1033. /// char *name;
  1034. /// char *type;
  1035. /// uint32_t alignment;
  1036. /// uint32_t size;
  1037. /// }
  1038. /// struct _ivar_list_t {
  1039. /// uint32 entsize; // sizeof(struct _ivar_t)
  1040. /// uint32 count;
  1041. /// struct _iver_t list[count];
  1042. /// }
  1043. ///
  1044. *)
  1045. procedure tobjcrttiwriter_nonfragile.gen_objc_ivars(list: tasmlist; objccls: tobjectdef; out ivarslabel: tasmlabel);
  1046. type
  1047. ivar_data = record
  1048. vf : tfieldvarsym;
  1049. namesym : TAsmLabel;
  1050. namedef : tdef;
  1051. typesym : TAsmLabel;
  1052. typedef : tdef;
  1053. offssym : TAsmSymbol;
  1054. end;
  1055. var
  1056. ivtype: tdef;
  1057. vf : tfieldvarsym;
  1058. vars : array of ivar_data;
  1059. i : integer;
  1060. vcnt : integer;
  1061. enctype : ansistring;
  1062. encerr : tdef;
  1063. prefix : shortstring;
  1064. vis : TAsmsymbind;
  1065. tcb : ttai_typedconstbuilder;
  1066. pptruinttype : tdef;
  1067. begin
  1068. ivarslabel:=nil;
  1069. prefix:='';
  1070. vcnt:=0;
  1071. vars:=nil;
  1072. setLength(vars,objccls.symtable.SymList.Count);
  1073. tcb:=nil;
  1074. prefix:='';
  1075. for i:=0 to objccls.symtable.SymList.Count-1 do
  1076. if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
  1077. begin
  1078. vf:=tfieldvarsym(objccls.symtable.SymList[i]);
  1079. if objctryencodetype(vf.vardef,enctype,encerr) then
  1080. begin
  1081. vars[vcnt].vf:=vf;
  1082. objcreatestringpoolentry(vf.RealName,sp_objcvarnames,sec_objc_meth_var_names,vars[vcnt].namesym,vars[vcnt].namedef);
  1083. objcreatestringpoolentry(enctype,sp_objcvartypes,sec_objc_meth_var_types,vars[vcnt].typesym,vars[vcnt].typedef);
  1084. if (vcnt=0) then
  1085. begin
  1086. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1087. prefix:=target_info.cprefix+'OBJC_IVAR_$_'+objccls.objextname^+'.';
  1088. end
  1089. else
  1090. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1091. { This matches gcc/Clang, but is strange: I would expect private
  1092. fields to be local symbols rather than private_extern (which
  1093. is "package-global") (JM)
  1094. }
  1095. if not(vf.visibility in [vis_public,vis_protected,vis_strictprotected]) then
  1096. vis:=AB_PRIVATE_EXTERN
  1097. else
  1098. vis:=AB_GLOBAL;
  1099. vars[vcnt].offssym:=current_asmdata.DefineAsmSymbol(prefix+vf.RealName,vis,AT_DATA,ptruinttype);
  1100. tcb.emit_tai(tai_const.Create_int_dataptr(vf.fieldoffset),ptruinttype);
  1101. list.concatList(
  1102. tcb.get_final_asmlist(
  1103. vars[vcnt].offssym,ptruinttype,
  1104. sec_objc_const,'_OBJC_IVAR_OFFSETS',sizeof(pint)
  1105. )
  1106. );
  1107. tcb.free;
  1108. inc(vcnt);
  1109. end
  1110. else
  1111. { must be caught during parsing }
  1112. internalerror(2009092301);
  1113. end;
  1114. if vcnt=0 then
  1115. exit;
  1116. tcb:=ctai_typedconstbuilder.create([tcalo_is_lab,tcalo_new_section,tcalo_no_dead_strip]);
  1117. current_asmdata.getlabel(ivarslabel,alt_data);
  1118. tcb.begin_anonymous_record(
  1119. internaltypeprefixName[itb_objc_nf_ivars]+tostr(vcnt),
  1120. C_alignment,1,
  1121. targetinfos[target_info.system]^.alignment.recordalignmin);
  1122. { size of each entry -- always 32 bit value }
  1123. ivtype:=search_named_unit_globaltype('OBJC','OBJC_IVAR',true).typedef;
  1124. tcb.emit_ord_const(ivtype.size,u32inttype);
  1125. { number of entries -- always 32 bit value }
  1126. tcb.emit_ord_const(vcnt,u32inttype);
  1127. { we use voidpointertype for all elements so that we can reuse the
  1128. recorddef for all ivar tables with the same number of elements }
  1129. pptruinttype:=cpointerdef.getreusable(ptruinttype);
  1130. for i:=0 to vcnt-1 do
  1131. begin
  1132. { reference to the offset }
  1133. tcb.emit_tai(tai_const.Create_sym(vars[i].offssym),pptruinttype);
  1134. { reference to the instance variable name (}
  1135. tcb.queue_init(voidpointertype);
  1136. tcb.queue_emit_asmsym(vars[i].namesym,vars[i].namedef);
  1137. { reference to the encoded type }
  1138. tcb.queue_init(voidpointertype);
  1139. tcb.queue_emit_asmsym(vars[i].typesym,vars[i].typedef);
  1140. { alignment -- always 32 bit value }
  1141. tcb.emit_ord_const(vars[i].vf.vardef.alignment,u32inttype);
  1142. { size -- always 32 bit value }
  1143. tcb.emit_ord_const(vars[i].vf.vardef.size,u32inttype);
  1144. end;
  1145. list.concatList(
  1146. tcb.get_final_asmlist(
  1147. ivarslabel,tcb.end_anonymous_record,
  1148. sec_objc_instance_vars,'_OBJC_INSTANCE_VARS',sizeof(pint)
  1149. )
  1150. );
  1151. tcb.free;
  1152. end;
  1153. (*
  1154. From Clang:
  1155. /// GetOrEmitProtocol - Generate the protocol meta-data:
  1156. /// @code
  1157. /// struct _protocol_t {
  1158. /// id isa; // NULL
  1159. /// const char * const protocol_name;
  1160. /// const struct _protocol_list_t * protocol_list; // super protocols
  1161. /// const struct method_list_t * const instance_methods;
  1162. /// const struct method_list_t * const class_methods;
  1163. /// const struct method_list_t *optionalInstanceMethods;
  1164. /// const struct method_list_t *optionalClassMethods;
  1165. /// const struct _prop_list_t * properties;
  1166. /// const uint32_t size; // sizeof(struct _protocol_t)
  1167. /// const uint32_t flags; // = 0
  1168. /// }
  1169. /// @endcode
  1170. *)
  1171. procedure tobjcrttiwriter_nonfragile.gen_objc_protocol(list: tasmlist; protocol: tobjectdef; out protocollabel: tasmsymbol);
  1172. var
  1173. lbl,
  1174. listsym : TAsmSymbol;
  1175. namedef : tdef;
  1176. namesym,
  1177. protolist : TAsmLabel;
  1178. reqinstsym,
  1179. reqclssym,
  1180. optinstsym,
  1181. optclssym : TAsmLabel;
  1182. prottype : tdef;
  1183. tcb : ttai_typedconstbuilder;
  1184. sec : TAsmSectiontype;
  1185. begin
  1186. gen_objc_protocol_list(list,protocol.ImplementedInterfaces,protolist);
  1187. gen_objc_protocol_elements(list,protocol,reqinstsym,optinstsym,reqclssym,optclssym);
  1188. { label for the protocol needs to be
  1189. a) in a coalesced section (so multiple definitions of the same protocol
  1190. can be merged by the linker)
  1191. b) private_extern (should only be merged within the same module)
  1192. c) weakly defined (so multiple definitions don't cause errors)
  1193. }
  1194. prottype:=search_named_unit_globaltype('OBJC','OBJC_PROTOCOL',true).typedef;
  1195. lbl:=current_asmdata.DefineAsmSymbol(protocol.rtti_mangledname(objcclassrtti),AB_PRIVATE_EXTERN,AT_DATA,prottype);
  1196. protocollabel:=lbl;
  1197. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_weak]);
  1198. tcb.maybe_begin_aggregate(prottype);
  1199. { protocol's isa - always nil }
  1200. tcb.emit_tai(Tai_const.Create_nil_dataptr,objc_idtype);
  1201. { name }
  1202. objcreatestringpoolentry(protocol.objextname^,sp_objcclassnames,sec_objc_class_names,namesym,namedef);
  1203. tcb.queue_init(charpointertype);
  1204. tcb.queue_emit_asmsym(namesym,namedef);
  1205. { parent protocols list }
  1206. ConcatSymOrNil(tcb,protolist,voidpointertype);
  1207. { required instance methods }
  1208. ConcatSymOrNil(tcb,reqinstsym,voidpointertype);
  1209. { required class methods }
  1210. ConcatSymOrNil(tcb,reqclssym,voidpointertype);
  1211. { optional instance methods }
  1212. ConcatSymOrNil(tcb,optinstsym,voidpointertype);
  1213. { optional class methods }
  1214. ConcatSymOrNil(tcb,optclssym,voidpointertype);
  1215. { TODO: properties }
  1216. tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
  1217. { size of this type }
  1218. tcb.emit_ord_const(prottype.size,u32inttype);
  1219. { flags }
  1220. tcb.emit_ord_const(0,u32inttype);
  1221. tcb.maybe_end_aggregate(prottype);
  1222. { coalesced sections are only required for ld-classic, because it does not
  1223. support "weak" bits on all symbols. They are deprecated in ld64 starting
  1224. from 2015: https://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20151012/305992.html
  1225. While targeting 10.6 or higher does not guarantee we are using ld64,
  1226. we don't have a better heuristic available.
  1227. }
  1228. if not MacOSXVersionMin.isvalid or
  1229. (MacOSXVersionMin.relationto(10,6,0)>=0) then
  1230. sec:=sec_data
  1231. else
  1232. sec:=sec_data_coalesced;
  1233. list.concatList(
  1234. tcb.get_final_asmlist(
  1235. lbl,prottype,
  1236. sec,'_OBJC_PROTOCOL',sizeof(pint)
  1237. )
  1238. );
  1239. tcb.free;
  1240. { also add an entry to the __DATA, __objc_protolist section, required to
  1241. register the protocol with the runtime }
  1242. listsym:=current_asmdata.DefineAsmSymbol(protocol.rtti_mangledname(objcmetartti),AB_PRIVATE_EXTERN,AT_DATA,cpointerdef.getreusable(prottype));
  1243. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_weak,tcalo_no_dead_strip]);
  1244. tcb.emit_tai(tai_const.Create_sym(lbl),cpointerdef.getreusable(prottype));
  1245. list.concatList(
  1246. tcb.get_final_asmlist(
  1247. listsym,cpointerdef.getreusable(prottype),
  1248. sec_objc_protolist,'_OBJC_PROTOLIST',sizeof(pint)
  1249. )
  1250. );
  1251. tcb.free;
  1252. end;
  1253. (*
  1254. From Clang:
  1255. /// struct _category_t {
  1256. /// const char * const name;
  1257. /// struct _class_t *const cls;
  1258. /// const struct _method_list_t * const instance_methods;
  1259. /// const struct _method_list_t * const class_methods;
  1260. /// const struct _protocol_list_t * const protocols;
  1261. /// const struct _prop_list_t * const properties;
  1262. /// }
  1263. *)
  1264. procedure tobjcrttiwriter_nonfragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol; out catlabeldef: tdef);
  1265. var
  1266. catstrsym,
  1267. protolistsym : TAsmLabel;
  1268. instmthdlist,
  1269. clsmthdlist,
  1270. clssym,
  1271. catsym : TAsmSymbol;
  1272. catstrdef,
  1273. catdef : tdef;
  1274. tcb : ttai_typedconstbuilder;
  1275. begin
  1276. { the category name }
  1277. objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names,catstrsym,catstrdef);
  1278. { the class it extends }
  1279. clssym:=current_asmdata.RefAsmSymbol(objccat.childof.rtti_mangledname(objcclassrtti),AT_DATA);
  1280. { generate the methods lists }
  1281. gen_objc_methods(list,objccat,instmthdlist,false,true);
  1282. gen_objc_methods(list,objccat,clsmthdlist,true,true);
  1283. { generate implemented protocols list }
  1284. gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
  1285. { category declaration section }
  1286. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1287. tcb.begin_anonymous_record(internaltypeprefixName[itb_objc_nf_category],
  1288. C_alignment,1,
  1289. targetinfos[target_info.system]^.alignment.recordalignmin);
  1290. tcb.queue_init(voidpointertype);
  1291. tcb.queue_emit_asmsym(catstrsym,catstrdef);
  1292. tcb.emit_tai(Tai_const.Create_sym(clssym),voidpointertype);
  1293. ConcatSymOrNil(tcb,instmthdlist,voidpointertype);
  1294. ConcatSymOrNil(tcb,clsmthdlist,voidpointertype);
  1295. ConcatSymOrNil(tcb,protolistsym,voidpointertype);
  1296. { properties, not yet supported }
  1297. tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
  1298. catdef:=tcb.end_anonymous_record;
  1299. catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA,catdef);
  1300. list.concatList(
  1301. tcb.get_final_asmlist(
  1302. catsym,catdef,
  1303. sec_objc_const,'_OBJC_CATEGORY',sizeof(pint)
  1304. )
  1305. );
  1306. tcb.free;
  1307. catlabel:=catsym;
  1308. catlabeldef:=catdef;
  1309. end;
  1310. (*
  1311. From Clang:
  1312. /// BuildIvarLayout - Builds ivar layout bitmap for the class
  1313. /// implementation for the __strong or __weak case.
  1314. /// The layout map displays which words in ivar list must be skipped
  1315. /// and which must be scanned by GC (see below). String is built of bytes.
  1316. /// Each byte is divided up in two nibbles (4-bit each). Left nibble is count
  1317. /// of words to skip and right nibble is count of words to scan. So, each
  1318. /// nibble represents up to 15 workds to skip or scan. Skipping the rest is
  1319. /// represented by a 0x00 byte which also ends the string.
  1320. /// 1. when ForStrongLayout is true, following ivars are scanned:
  1321. /// - id, Class
  1322. /// - object * // note: this "object" means "Objective-C object" (JM)
  1323. /// - __strong anything
  1324. ///
  1325. /// 2. When ForStrongLayout is false, following ivars are scanned:
  1326. /// - __weak anything
  1327. *)
  1328. (*
  1329. Only required when supporting garbage collection
  1330. procedure tobjcrttiwriter_nonfragile.gen_objc_ivargc_recursive(st: tabstractrecordsymtable; ptrbset: tbitset; startoffset: puint; il: tivarlayouttype);
  1331. var
  1332. i: longint;
  1333. fs: tfieldvarsym;
  1334. includelen: longint;
  1335. begin
  1336. for i:=0 to st.SymList.count-1 do
  1337. if (tsym(st.symlist[i]).typ=fieldvarsym) then
  1338. begin
  1339. fs:=tfieldvarsym(st.symlist[i]);
  1340. includelen:=0;
  1341. case fs.vardef.typ of
  1342. pointerdef,
  1343. classrefdef:
  1344. if (fs.vardef=objc_idtype) or
  1345. (fs.vardef=objc_metaclasstype) then
  1346. includelen:=1;
  1347. recorddef:
  1348. TODO: bitpacking -> offset differences
  1349. gen_objc_ivargc_recursive(tabstractrecordsymtable(trecorddef(fs.vardef).symtable),ptrbset,startoffset+fs.fieldoffset,il);
  1350. arraydef:
  1351. begin
  1352. if not is_special_
  1353. end;
  1354. objectdef :
  1355. begin
  1356. case tobjectdef(fs.vardef).objecttype of
  1357. odt_objcclass,
  1358. odt_objcprotocol:
  1359. includelen:=1;
  1360. odt_object:
  1361. gen_objc_ivargc_recursive(tabstractrecordsymtable(tobjectdef(fs.vardef).symtable),ptrbset,startoffset+fs.fieldoffset,il);
  1362. end;
  1363. end;
  1364. end;
  1365. end;
  1366. end;
  1367. function tobjcrttiwriter_nonfragile.gen_objc_ivargcstring(objclss: tobjectdef; il: tivarlayouttype): ansistring;
  1368. var
  1369. ptrbset: tbitset;
  1370. parent: tobjectdef;
  1371. size,
  1372. startoffset: puint;
  1373. i: longint;
  1374. begin
  1375. size:=tObjectSymtable(objclss.symtable).datasize;
  1376. if assigned(objclss.childof) then
  1377. startoffset:=tObjectSymtable(objclss.childof.symtable).datasize
  1378. else
  1379. startoffset:=0;
  1380. size:=size-startoffset;
  1381. ptrbset:=tbitset.create_bytesize((size+sizeof(ptruint)-1) div sizeof(ptruint));
  1382. { has to include info for this class' fields and those of all parent
  1383. classes as well
  1384. }
  1385. parent:=obclss;
  1386. repeat
  1387. gen_objc_ivargc_recursive(parent.symtable,ptrbset,0,il);
  1388. parent:=parent.childof;
  1389. until not assigned(parent);
  1390. { convert bits set to encoded string }
  1391. end;
  1392. *)
  1393. (*
  1394. From Clang:
  1395. /// struct _class_ro_t {
  1396. /// uint32_t const flags;
  1397. /// uint32_t const instanceStart;
  1398. /// uint32_t const instanceSize;
  1399. /// uint32_t const reserved; // only when building for 64bit targets
  1400. /// const uint8_t * const ivarLayout;
  1401. /// const char *const name;
  1402. /// const struct _method_list_t * const baseMethods;
  1403. /// const struct _protocol_list_t *const baseProtocols;
  1404. /// const struct _ivar_list_t *const ivars;
  1405. /// const uint8_t * const weakIvarLayout;
  1406. /// const struct _prop_list_t * const properties;
  1407. /// }
  1408. *)
  1409. procedure tobjcrttiwriter_nonfragile.gen_objc_class_ro_part(list: tasmlist; objclss: tobjectdef; protolistsym: TAsmSymbol; out classrolabel: tasmsymbol; metaclass: boolean);
  1410. const
  1411. CLS_CLASS = 0;
  1412. CLS_META = 1;
  1413. CLS_ROOT = 2;
  1414. OBJC2_CLS_HIDDEN = $10;
  1415. CLS_EXCEPTION = $20;
  1416. var
  1417. methodssym,
  1418. rosym : TAsmSymbol;
  1419. classStrDef : tdef;
  1420. classStrSym,
  1421. ivarslab : TAsmLabel;
  1422. rodef,
  1423. class_type : tdef;
  1424. start,
  1425. size,
  1426. flags : cardinal;
  1427. rttitype : trttitype;
  1428. firstfield : tfieldvarsym;
  1429. i : longint;
  1430. tcb : ttai_typedconstbuilder;
  1431. begin
  1432. { consider every class declared in the implementation section of a unit
  1433. as "hidden"
  1434. }
  1435. flags:=0;
  1436. if (objclss.owner.symtabletype=staticsymtable) and
  1437. current_module.is_unit then
  1438. flags:=OBJC2_CLS_HIDDEN;
  1439. if metaclass then
  1440. begin
  1441. flags:=flags or CLS_META;
  1442. rttitype:=objcmetarortti;
  1443. { metaclass size/start: always size of objc_object }
  1444. class_type:=search_named_unit_globaltype('OBJC','OBJC_OBJECT',true).typedef;
  1445. start:=class_type.size;
  1446. size:=start;
  1447. end
  1448. else
  1449. begin
  1450. flags:=flags or CLS_CLASS;
  1451. rttitype:=objcclassrortti;
  1452. size:=tObjectSymtable(objclss.symtable).datasize;
  1453. { can't simply use childof's datasize, because alignment may cause the
  1454. first field to skip a couple of bytes after the previous end }
  1455. firstfield:=nil;
  1456. for i:=0 to objclss.symtable.SymList.Count-1 do
  1457. if (tsym(objclss.symtable.SymList[i]).typ=fieldvarsym) then
  1458. begin
  1459. firstfield:=tfieldvarsym(objclss.symtable.SymList[i]);
  1460. break;
  1461. end;
  1462. if assigned(firstfield) then
  1463. start:=firstfield.fieldoffset
  1464. else
  1465. { no extra fields -> start = size }
  1466. start:=size;
  1467. end;
  1468. if not assigned(objclss.childof) then
  1469. flags:=flags or CLS_ROOT;
  1470. objcreatestringpoolentry(objclss.objextname^,sp_objcclassnames,sec_objc_class_names,classStrSym,classStrDef);
  1471. { generate methods list }
  1472. gen_objc_methods(list,objclss,methodssym,metaclass,false);
  1473. { generate ivars (nil for metaclass) }
  1474. if metaclass then
  1475. ivarslab:=nil
  1476. else
  1477. gen_objc_ivars(list,objclss,ivarslab);
  1478. { class declaration section }
  1479. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1480. tcb.begin_anonymous_record(
  1481. internaltypeprefixName[itb_objc_nf_class_ro_part],
  1482. C_alignment,1,
  1483. targetinfos[target_info.system]^.alignment.recordalignmin);
  1484. tcb.emit_ord_const(flags,u32inttype);
  1485. tcb.emit_ord_const(start,u32inttype);
  1486. tcb.emit_ord_const(size,u32inttype);
  1487. { strong ivar layout for garbage collection (deprecated) }
  1488. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1489. tcb.queue_init(voidpointertype);
  1490. tcb.queue_emit_asmsym(classStrSym,classStrDef);
  1491. ConcatSymOrNil(tcb,methodssym,voidpointertype);
  1492. ConcatSymOrNil(tcb,protolistsym,voidpointertype);
  1493. ConcatSymOrNil(tcb,ivarslab,voidpointertype);
  1494. { weak ivar layout for garbage collection (deprecated) }
  1495. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1496. { TODO: properties }
  1497. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1498. rodef:=tcb.end_anonymous_record;
  1499. rosym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(rttitype),AB_LOCAL,AT_DATA,rodef);
  1500. list.concatList(
  1501. tcb.get_final_asmlist(
  1502. rosym,rodef,
  1503. sec_objc_const,'_OBJC_META_CLASS',sizeof(pint)
  1504. )
  1505. );
  1506. tcb.free;
  1507. classrolabel:=rosym;
  1508. end;
  1509. (*
  1510. From Clang:
  1511. /// struct _class_t {
  1512. /// struct _class_t *isa;
  1513. /// struct _class_t * const superclass;
  1514. /// void *cache;
  1515. /// IMP *vtable;
  1516. /// struct class_ro_t *ro;
  1517. /// }
  1518. ///
  1519. *)
  1520. { Generate rtti for an Objective-C class and its meta-class. }
  1521. procedure tobjcrttiwriter_nonfragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol; out classlabeldef: tdef);
  1522. var
  1523. root : tobjectdef;
  1524. superSym,
  1525. superMetaSym,
  1526. metaisaSym,
  1527. metasym,
  1528. clssym,
  1529. metarosym,
  1530. rosym : TAsmSymbol;
  1531. protolistsym : TAsmLabel;
  1532. vis : TAsmsymbind;
  1533. isatcb,
  1534. metatcb : ttai_typedconstbuilder;
  1535. metadef,
  1536. classdef : tdef;
  1537. begin
  1538. { A) Register necessary names }
  1539. { 1) the current class and metaclass }
  1540. if (objclss.owner.symtabletype=globalsymtable) then
  1541. vis:=AB_GLOBAL
  1542. else
  1543. vis:=AB_PRIVATE_EXTERN;
  1544. { create the typed const builders so we can get the (provisional) types
  1545. for the class and metaclass symbols }
  1546. isatcb:=ctai_typedconstbuilder.create([]);
  1547. classdef:=isatcb.begin_anonymous_record(
  1548. internaltypeprefixName[itb_objc_nf_class],
  1549. C_alignment,1,
  1550. targetinfos[target_info.system]^.alignment.recordalignmin);
  1551. metatcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1552. metadef:=metatcb.begin_anonymous_record(
  1553. internaltypeprefixName[itb_objc_nf_meta_class],
  1554. C_alignment,1,
  1555. targetinfos[target_info.system]^.alignment.recordalignmin);
  1556. clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),vis,AT_DATA,classdef);
  1557. metasym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcmetartti),vis,AT_DATA,metadef);
  1558. { 2) the superclass and meta superclass }
  1559. if assigned(objclss.childof) then
  1560. begin
  1561. superSym:=current_asmdata.RefAsmSymbol(objclss.childof.rtti_mangledname(objcclassrtti),AT_DATA);
  1562. superMetaSym:=current_asmdata.RefAsmSymbol(objclss.childof.rtti_mangledname(objcmetartti),AT_DATA);
  1563. end
  1564. else
  1565. begin
  1566. superSym:=nil;
  1567. { the class itself }
  1568. superMetaSym:=clssym;
  1569. end;
  1570. { 3) the isa }
  1571. { From Clang: The isa for the meta-class is the root of the hierarchy. }
  1572. root:=objclss;
  1573. while assigned(root.childof) do
  1574. root:=root.childof;
  1575. metaisaSym:=current_asmdata.RefAsmSymbol(root.rtti_mangledname(objcmetartti),AT_DATA);
  1576. { 4) the implemented protocols (same for metaclass and regular class) }
  1577. gen_objc_protocol_list(list,objclss.ImplementedInterfaces,protolistsym);
  1578. { 5) the read-only parts of the class definitions }
  1579. gen_objc_class_ro_part(list,objclss,protolistsym,metarosym,true);
  1580. gen_objc_class_ro_part(list,objclss,protolistsym,rosym,false);
  1581. { B) Class declaration section }
  1582. { both class and metaclass are in the objc_data section for obj-c 2 }
  1583. { 1) meta-class declaration }
  1584. { the isa }
  1585. metatcb.emit_tai(Tai_const.Create_sym(metaisaSym),voidpointertype);
  1586. { the superclass }
  1587. metatcb.emit_tai(Tai_const.Create_sym(superMetaSym),voidpointertype);
  1588. { pointer to cache }
  1589. if not assigned(ObjCEmptyCacheVar) then
  1590. ObjCEmptyCacheVar:=current_asmdata.RefAsmSymbol(target_info.Cprefix+'_objc_empty_cache',AT_DATA);
  1591. metatcb.emit_tai(Tai_const.Create_sym(ObjCEmptyCacheVar),voidpointertype);
  1592. { pointer to vtable }
  1593. if not assigned(ObjCEmptyVtableVar) and
  1594. not(target_info.system in [system_arm_ios,system_aarch64_ios,system_aarch64_darwin,system_i386_iphonesim,system_x86_64_iphonesim,system_aarch64_iphonesim]) then
  1595. ObjCEmptyVtableVar:=current_asmdata.RefAsmSymbol(target_info.Cprefix+'_objc_empty_vtable',AT_DATA);
  1596. ConcatSymOrNil(metatcb,ObjCEmptyVtableVar,voidpointertype);
  1597. { the read-only part }
  1598. metatcb.emit_tai(Tai_const.Create_sym(metarosym),voidpointertype);
  1599. metatcb.end_anonymous_record;
  1600. list.concatList(
  1601. metatcb.get_final_asmlist(
  1602. metasym,metadef,
  1603. sec_objc_data,'_OBJC_CLASS',sizeof(pint)
  1604. )
  1605. );
  1606. metatcb.free;
  1607. { 2) regular class declaration }
  1608. { the isa }
  1609. isatcb.emit_tai(Tai_const.Create_sym(metasym),cpointerdef.getreusable(metadef));
  1610. { the superclass }
  1611. ConcatSymOrNil(isatcb,supersym,voidpointertype);
  1612. { pointer to cache }
  1613. isatcb.emit_tai(Tai_const.Create_sym(ObjCEmptyCacheVar),voidpointertype);
  1614. { pointer to vtable }
  1615. ConcatSymOrNil(isatcb,ObjCEmptyVtableVar,voidpointertype);
  1616. { the read-only part }
  1617. isatcb.emit_tai(Tai_const.Create_sym(rosym),voidpointertype);
  1618. isatcb.end_anonymous_record;
  1619. list.concatList(
  1620. isatcb.get_final_asmlist(
  1621. clssym,classdef,
  1622. sec_objc_data,'_OBJC_CLASS',sizeof(pint)
  1623. )
  1624. );
  1625. isatcb.free;
  1626. classlabel:=clssym;
  1627. classlabeldef:=classdef;
  1628. end;
  1629. procedure tobjcrttiwriter_nonfragile.addclasslist(list: tasmlist; section: tasmsectiontype; const symname: string; classes: tfpobjectlist);
  1630. var
  1631. i: longint;
  1632. sym: TAsmSymbol;
  1633. tcb: ttai_typedconstbuilder;
  1634. arrdef: tdef;
  1635. begin
  1636. if classes.count=0 then
  1637. exit;
  1638. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  1639. arrdef:=carraydef.getreusable(voidpointertype,classes.count);
  1640. sym:=current_asmdata.DefineAsmSymbol(symname,AB_LOCAL,AT_DATA,arrdef);
  1641. tcb.maybe_begin_aggregate(arrdef);
  1642. for i:=0 to classes.count-1 do
  1643. tcb.emit_tai(
  1644. tai_const.Create_sym(current_asmdata.RefAsmSymbol(tobjectdef(classes[i]).rtti_mangledname(objcclassrtti),AT_DATA)),
  1645. voidpointertype
  1646. );
  1647. tcb.maybe_end_aggregate(arrdef);
  1648. list.concatList(
  1649. tcb.get_final_asmlist(
  1650. sym,arrdef,
  1651. section,symname,sizeof(pint)
  1652. )
  1653. );
  1654. end;
  1655. procedure tobjcrttiwriter_nonfragile.gen_objc_info_sections(list: tasmlist);
  1656. function collectnonlazyclasses(classes: tfpobjectlist): tfpobjectlist;
  1657. var
  1658. symentry : tsym;
  1659. procdef : tprocdef;
  1660. i,j : longint;
  1661. begin
  1662. { non-lazy classes are all classes that define a class method with the
  1663. selector called "load" (simply inheriting this class method is not enough,
  1664. they have to implement it themselves)
  1665. -- TODO: this currently only works if the Pascal identifier is also 'load'! }
  1666. result:=tfpobjectlist.create(false);
  1667. for i:=0 to classes.count-1 do
  1668. begin
  1669. symentry:=tsym(tobjectsymtable(tobjectdef(classes[i]).symtable).find('LOAD'));
  1670. if assigned(symentry) and
  1671. (symentry.typ=procsym) then
  1672. begin
  1673. for j:=0 to tprocsym(symentry).ProcdefList.count do
  1674. begin
  1675. procdef:=tprocdef(tprocsym(symentry).ProcdefList[0]);
  1676. if ((po_classmethod in procdef.procoptions) and
  1677. (procdef.messageinf.str^='load')) then
  1678. begin
  1679. result.add(classes[i]);
  1680. break;
  1681. end;
  1682. end;
  1683. end;
  1684. end;
  1685. end;
  1686. var
  1687. nonlazyclasses,
  1688. nonlazycategories : tfpobjectlist;
  1689. begin
  1690. if (classdefs.count=0) and
  1691. (catdefs.count=0) then
  1692. exit;
  1693. nonlazyclasses:=collectnonlazyclasses(classdefs);
  1694. nonlazycategories:=collectnonlazyclasses(catdefs);
  1695. { this list has to include all classes, also the non-lazy ones }
  1696. addclasslist(list,sec_objc_classlist,target_asm.labelprefix+'_OBJC_LABEL_CLASS_$',classdefs);
  1697. addclasslist(list,sec_objc_nlclasslist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CLASS_$',nonlazyclasses);
  1698. { category and non-lazy category lists }
  1699. addclasslist(list,sec_objc_catlist,target_asm.labelprefix+'_OBJC_LABEL_CATEGORY_$',catdefs);
  1700. addclasslist(list,sec_objc_nlcatlist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CATEGORY_$',nonlazycategories);
  1701. nonlazyclasses.free;
  1702. nonlazycategories.free;
  1703. { the non-fragile abi doesn't have any module info, nor lazy references
  1704. to used classes or to parent classes }
  1705. end;
  1706. constructor tobjcrttiwriter_nonfragile.create;
  1707. begin
  1708. inherited create(oa_nonfragile);
  1709. end;
  1710. {******************************************************************
  1711. RTTI generation -- Main function
  1712. *******************************************************************}
  1713. procedure MaybeGenerateObjectiveCImageInfo(globalst, localst: tsymtable);
  1714. var
  1715. objcrttiwriter: tobjcrttiwriter;
  1716. begin
  1717. if (m_objectivec1 in current_settings.modeswitches) then
  1718. begin
  1719. { generate rtti for all obj-c classes, protocols and categories
  1720. defined in this module. }
  1721. if not(target_info.system in systems_objc_nfabi) then
  1722. objcrttiwriter:=tobjcrttiwriter_fragile.create
  1723. else
  1724. objcrttiwriter:=tobjcrttiwriter_nonfragile.create;
  1725. objcrttiwriter.gen_objc_rtti_sections(current_asmdata.asmlists[al_objc_data],globalst);
  1726. objcrttiwriter.gen_objc_rtti_sections(current_asmdata.asmlists[al_objc_data],localst);
  1727. objcrttiwriter.gen_objc_info_sections(current_asmdata.asmlists[al_objc_data]);
  1728. objcrttiwriter.free;
  1729. end;
  1730. end;
  1731. end.