objcgutl.pas 67 KB

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