diff options
Diffstat (limited to 'closures/compiler/nobj.pas')
| -rw-r--r-- | closures/compiler/nobj.pas | 1593 |
1 files changed, 1593 insertions, 0 deletions
diff --git a/closures/compiler/nobj.pas b/closures/compiler/nobj.pas new file mode 100644 index 0000000000..7ce974f2f7 --- /dev/null +++ b/closures/compiler/nobj.pas @@ -0,0 +1,1593 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Routines for the code generation of data structures + like VMT, Messages, VTables, Interfaces descs + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit nobj; + +{$i fpcdefs.inc} + +interface + + uses + cutils,cclasses, + globtype, + symdef,symsym, + aasmbase,aasmtai,aasmdata + ; + + type + TVMTBuilder=class + private + _Class : tobjectdef; + handledprotocols: tfpobjectlist; + function is_new_vmt_entry(pd:tprocdef; out overridesclasshelper: boolean):boolean; + procedure add_new_vmt_entry(pd:tprocdef; allowoverridingmethod: boolean); + function check_msg_str(vmtpd, pd: tprocdef):boolean; + function intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef; + procedure intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef); + procedure intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef); + procedure prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef); + procedure intf_optimize_vtbls; + procedure intf_allocate_vtbls; + public + constructor create(c:tobjectdef); + destructor destroy;override; + procedure generate_vmt; + procedure build_interface_mappings; + end; + + type + pprocdeftree = ^tprocdeftree; + tprocdeftree = record + data : tprocdef; + nl : tasmlabel; + l,r : pprocdeftree; + end; + + TVMTWriter=class + private + _Class : tobjectdef; + { message tables } + root : pprocdeftree; + procedure disposeprocdeftree(p : pprocdeftree); + procedure insertmsgint(p:TObject;arg:pointer); + procedure insertmsgstr(p:TObject;arg:pointer); + procedure insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint); + procedure insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint); + procedure writenames(p : pprocdeftree); + procedure writeintentry(p : pprocdeftree); + procedure writestrentry(p : pprocdeftree); +{$ifdef WITHDMT} + { dmt } + procedure insertdmtentry(p:TObject;arg:pointer); + procedure writedmtindexentry(p : pprocdeftree); + procedure writedmtaddressentry(p : pprocdeftree); +{$endif} + { published methods } + procedure do_count_published_methods(p:TObject;arg:pointer); + procedure do_gen_published_methods(p:TObject;arg:pointer); + { virtual methods } + procedure writevirtualmethods(List:TAsmList); + { interface tables } + function intf_get_vtbl_name(AImplIntf:TImplementedInterface): string; + procedure intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface); + procedure intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface); + function intf_write_table:TAsmLabel; + { generates the message tables for a class } + function genstrmsgtab : tasmlabel; + function genintmsgtab : tasmlabel; + function genpublishedmethodstable : tasmlabel; + function generate_field_table : tasmlabel; +{$ifdef WITHDMT} + { generates a DMT for _class } + function gendmt : tasmlabel; +{$endif WITHDMT} + public + constructor create(c:tobjectdef); + destructor destroy;override; + { write the VMT to al_globals } + procedure writevmt; + procedure writeinterfaceids; + end; + +implementation + + uses + SysUtils, + globals,verbose,systems, + node, + symbase,symtable,symconst,symtype,defcmp, + dbgbase, + ncgrtti, + wpobase + ; + + +{***************************************************************************** + TVMTBuilder +*****************************************************************************} + + constructor TVMTBuilder.create(c:tobjectdef); + begin + inherited Create; + _Class:=c; + end; + + + destructor TVMTBuilder.destroy; + begin + end; + + + procedure TVMTBuilder.add_new_vmt_entry(pd:tprocdef; allowoverridingmethod: boolean); + var + i : longint; + vmtentry : pvmtentry; + vmtpd : tprocdef; + begin + { new entry is needed, override was not possible } + { Allowed when overriding a category method for a parent class in a + descendent Objective-C class } + if not allowoverridingmethod and + (po_overridingmethod in pd.procoptions) then + MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false)); + + { check that all methods have overload directive } + if not(m_fpc in current_settings.modeswitches) then + begin + for i:=0 to _class.vmtentries.count-1 do + begin + vmtentry:=pvmtentry(_class.vmtentries[i]); + vmtpd:=tprocdef(vmtentry^.procdef); + if (vmtpd.procsym=pd.procsym) and + (not(po_overload in pd.procoptions) or + not(po_overload in vmtpd.procoptions)) then + begin + MessagePos1(pd.fileinfo,parser_e_no_overload_for_all_procs,pd.procsym.realname); + { recover } + include(vmtpd.procoptions,po_overload); + include(pd.procoptions,po_overload); + end; + end; + end; + + { Register virtual method and give it a number } + if (po_virtualmethod in pd.procoptions) then + begin + { store vmt entry number in procdef } + if (pd.extnumber<>$ffff) and + (pd.extnumber<>_class.VMTEntries.Count) then + internalerror(200810283); + pd.extnumber:=_class.VMTEntries.Count; + new(vmtentry); + vmtentry^.procdef:=pd; + vmtentry^.procdefderef.reset; + vmtentry^.visibility:=pd.visibility; + _class.VMTEntries.Add(vmtentry); + end; + end; + + + function TVMTBuilder.check_msg_str(vmtpd, pd: tprocdef): boolean; + begin + result:=true; + if not(is_objc_class_or_protocol(_class)) then + begin + { the only requirement for normal methods is that both either + have a message string or not (the value is irrelevant) } + if ((pd.procoptions * [po_msgstr]) <> (vmtpd.procoptions * [po_msgstr])) then + begin + MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false)); + tprocsym(vmtpd.procsym).write_parameter_lists(pd); + result:=false; + end + end + else + begin + { the compiler should have ensured that the protocol or parent + class method has a message name specified } + if not(po_msgstr in vmtpd.procoptions) then + internalerror(2009070601); + if not(po_msgstr in pd.procoptions) then + begin + { copy the protocol's/parent class' message name to the one in + the class if none has been specified there } + include(pd.procoptions,po_msgstr); + pd.messageinf.str:=stringdup(vmtpd.messageinf.str^); + end + else + begin + { if both have a message name, make sure they are equal } + if (vmtpd.messageinf.str^<>pd.messageinf.str^) then + begin + MessagePos2(pd.fileinfo,parser_e_objc_message_name_changed,vmtpd.messageinf.str^,pd.messageinf.str^); + result:=false; + end; + end; + end; + end; + + + function TVMTBuilder.is_new_vmt_entry(pd:tprocdef; out overridesclasshelper: boolean):boolean; + const + po_comp = [po_classmethod,po_virtualmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgint, + po_exports,po_varargs,po_explicitparaloc,po_nostackframe]; + var + i : longint; + hasequalpara, + hasoverloads, + pdoverload : boolean; + srsym : tsym; + st : tsymtable; + + // returns true if we can stop checking, false if we have to continue + function found_entry(var vmtpd: tprocdef; var vmtentryvis: tvisibility; updatevalues: boolean): boolean; + begin + result:=false; + + { ignore hidden entries (e.g. virtual overridden by a static) that are not visible anymore } + if vmtentryvis=vis_hidden then + exit; + + { ignore different names } + if vmtpd.procsym.name<>pd.procsym.name then + exit; + + { hide private methods that are not visible anymore. For this check we + must override the visibility with the highest value in the override chain. + This is required for case (see tw3292) with protected-private-protected where the + same vmtentry is used (PFV) } + if not is_visible_for_object(vmtpd.owner,vmtentryvis,_class) then + exit; + + { inherit overload } + if (po_overload in vmtpd.procoptions) then + begin + include(pd.procoptions,po_overload); + pdoverload:=true; + end; + + { compare parameter types only, no specifiers yet } + hasequalpara:=(compare_paras(vmtpd.paras,pd.paras,cp_none,[cpo_ignoreuniv,cpo_ignorehidden])>=te_equal); + + { check that we are not trying to override a final method } + if (po_finalmethod in vmtpd.procoptions) and + hasequalpara and (po_overridingmethod in pd.procoptions) and + (is_class(_class) or is_objectpascal_helper(_class)) then + MessagePos1(pd.fileinfo,parser_e_final_can_no_be_overridden,pd.fullprocname(false)) + else + { old definition has virtual + new definition has no virtual or override } + if (po_virtualmethod in vmtpd.procoptions) and + ( + not(po_virtualmethod in pd.procoptions) or + ( + { new one does not have reintroduce in case of an objccategory } + (is_objccategory(_class) and not(po_reintroduce in pd.procoptions)) or + { new one does not have override in case of objpas/objc class/helper/intf/proto } + ( + (is_class_or_interface_or_objc(_class) or is_objectpascal_helper(_class)) and + not is_objccategory(_class) and not(po_overridingmethod in pd.procoptions) + ) + ) + ) then + begin + if ( + not(pdoverload or hasoverloads) or + hasequalpara + ) then + begin + if not(po_reintroduce in pd.procoptions) then + if not(is_objc_class_or_protocol(_class)) then + MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false)) + else + begin + { In Objective-C, you cannot create a new VMT entry to + start a new inheritance tree. We therefore give an + error when the class is implemented in Pascal, to + avoid confusion due to things working differently + with Object Pascal classes. + + In case of external classes, we only give a hint, + because requiring override everywhere may make + automated header translation tools too complex. } + if not(oo_is_external in _class.objectoptions) then + if not is_objccategory(_class) then + MessagePos1(pd.fileinfo,parser_e_must_use_override_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil)) + else + MessagePos1(pd.fileinfo,parser_e_must_use_reintroduce_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil)) + { there may be a lot of these in auto-translated + heaeders, so only calculate the fulltypename if + the hint will be shown } + else if CheckVerbosity(V_Hint) then + if not is_objccategory(_class) then + MessagePos1(pd.fileinfo,parser_h_should_use_override_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil)) + else + MessagePos1(pd.fileinfo,parser_h_should_use_reintroduce_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil)); + { no new entry, but copy the message name if any from + the procdef in the parent class } + check_msg_str(vmtpd,pd); + result:=true; + exit; + end; + { disable/hide old VMT entry } + if updatevalues then + vmtentryvis:=vis_hidden; + end; + end + { both are virtual? } + else if (po_virtualmethod in pd.procoptions) and + (po_virtualmethod in vmtpd.procoptions) then + begin + { same parameter and return types (parameter specifiers will be checked below) } + if hasequalpara and + compatible_childmethod_resultdef(vmtpd.returndef,pd.returndef) then + begin + { inherite calling convention when it was explicit and the + current definition has none explicit set } + if (po_hascallingconvention in vmtpd.procoptions) and + not(po_hascallingconvention in pd.procoptions) then + begin + pd.proccalloption:=vmtpd.proccalloption; + include(pd.procoptions,po_hascallingconvention); + end; + + { All parameter specifiers and some procedure the flags have to match + except abstract and override } + if (compare_paras(vmtpd.paras,pd.paras,cp_all,[cpo_ignoreuniv,cpo_ignorehidden])<te_equal) or + (vmtpd.proccalloption<>pd.proccalloption) or + (vmtpd.proctypeoption<>pd.proctypeoption) or + ((vmtpd.procoptions*po_comp)<>(pd.procoptions*po_comp)) then + begin + MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false)); + tprocsym(vmtpd.procsym).write_parameter_lists(pd); + end; + + check_msg_str(vmtpd,pd); + + { Give a note if the new visibility is lower. For a higher + visibility update the vmt info } + if vmtentryvis>pd.visibility then + MessagePos4(pd.fileinfo,parser_n_ignore_lower_visibility,pd.fullprocname(false), + visibilityname[pd.visibility],tobjectdef(vmtpd.owner.defowner).objrealname^,visibilityname[vmtentryvis]) + else if pd.visibility>vmtentryvis then + begin + if updatevalues then + vmtentryvis:=pd.visibility; + end; + + { override old virtual method in VMT } + if updatevalues then + begin + if (vmtpd.extnumber<>i) then + internalerror(200611084); + pd.extnumber:=vmtpd.extnumber; + vmtpd:=pd; + end; + result:=true; + exit; + end + { different parameters } + else + begin + { when we got an override directive then can search futher for + the procedure to override. + If we are starting a new virtual tree then hide the old tree } + if not(po_overridingmethod in pd.procoptions) and + not(pdoverload or hasoverloads) then + begin + if not(po_reintroduce in pd.procoptions) then + begin + if not is_object(_class) and + not is_objc_class_or_protocol(_class) then + MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false)) + else + { objects don't allow starting a new virtual tree + and neither does Objective-C } + MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,vmtpd.fullprocname(false)); + end; + { disable/hide old VMT entry } + if updatevalues then + vmtentryvis:=vis_hidden; + end; + end; + end; + end; + + function found_category_method(st: tsymtable): boolean; + var + entrycount: longint; + cat: tobjectdef; + vmtpd: tprocdef; + vmtvis: tvisibility; + begin + result:=false; + if is_objccategory(tdef(st.defowner)) then + begin + cat:=tobjectdef(st.defowner); + { go through all of the category's methods to find the + vmtentry corresponding to the procdef we are handling } + for entrycount:=0 to cat.vmtentries.Count-1 do + begin + vmtpd:=pvmtentry(cat.vmtentries[entrycount])^.procdef; + vmtvis:=pvmtentry(cat.vmtentries[entrycount])^.visibility; + { don't change the vmtentry of the category } + if found_entry(vmtpd,vmtvis,false) then + begin + result:=true; + exit; + end; + end; + end; + end; + + begin + result:=false; + overridesclasshelper:=false; + { Load other values for easier readability } + hasoverloads:=(tprocsym(pd.procsym).ProcdefList.Count>1); + pdoverload:=(po_overload in pd.procoptions); + + { compare with all stored definitions } + for i:=0 to _class.vmtentries.Count-1 do + begin + if found_entry(pvmtentry(_class.vmtentries[i])^.procdef, pvmtentry(_class.vmtentries[i])^.visibility,true) then + exit; + end; + + { in case of Objective-C, also check the categories that apply to this + class' *parent* for methods to override (don't allow class X to + "override" a method added by a category to class X itself, since in + that case the category method will in fact replace class X' + "overriding" method } + if is_objcclass(_class) and + assigned(_class.childof) and + search_objc_helper(_class.childof,pd.procsym.name,srsym,st) then + begin + overridesclasshelper:=found_category_method(st); + end; + + { No entry found, we need to create a new entry } + result:=true; + end; + + + function TVMTBuilder.intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef; + const + po_comp = [po_classmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgint, + po_exports,po_varargs,po_explicitparaloc,po_nostackframe]; + var + implprocdef : Tprocdef; + i: cardinal; + hclass : tobjectdef; + hashedid : THashedIDString; + srsym : tsym; + begin + result:=nil; + hashedid.id:=name; + hclass:=_class; + while assigned(hclass) do + begin + srsym:=tsym(hclass.symtable.FindWithHash(hashedid)); + if assigned(srsym) and + (srsym.typ=procsym) then + begin + for i:=0 to Tprocsym(srsym).ProcdefList.Count-1 do + begin + implprocdef:=tprocdef(tprocsym(srsym).ProcdefList[i]); + if (implprocdef.procsym=tprocsym(srsym)) and + (compare_paras(proc.paras,implprocdef.paras,cp_all,[cpo_ignorehidden,cpo_comparedefaultvalue,cpo_ignoreuniv])>=te_equal) and + (compare_defs(proc.returndef,implprocdef.returndef,nothingn)>=te_equal) and + (proc.proccalloption=implprocdef.proccalloption) and + (proc.proctypeoption=implprocdef.proctypeoption) and + ((proc.procoptions*po_comp)=((implprocdef.procoptions+[po_virtualmethod])*po_comp)) and + check_msg_str(proc,implprocdef) then + begin + result:=implprocdef; + exit; + end; + end; + end; + hclass:=hclass.childof; + end; + end; + + + procedure TVMTBuilder.intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef); + var + i : longint; + def : tdef; + hs, + prefix, + mappedname: string; + implprocdef: tprocdef; + begin + prefix:=ImplIntf.IntfDef.symtable.name^+'.'; + for i:=0 to IntfDef.symtable.DefList.Count-1 do + begin + def:=tdef(IntfDef.symtable.DefList[i]); + if assigned(def) and + (def.typ=procdef) then + begin + { Find implementing procdef + 1. Check for mapped name + 2. Use symbol name, but only if there's no mapping, + or we're processing ancestor of interface. + When modifying this code, ensure that webtbs/tw11862, webtbs/tw4950 + and webtbf/tw19591 stay correct. } + implprocdef:=nil; + hs:=prefix+tprocdef(def).procsym.name; + mappedname:=ImplIntf.GetMapping(hs); + if mappedname<>'' then + implprocdef:=intf_search_procdef_by_name(tprocdef(def),mappedname); + if not assigned(implprocdef) then + if (mappedname='') or (ImplIntf.IntfDef<>IntfDef) then + implprocdef:=intf_search_procdef_by_name(tprocdef(def),tprocdef(def).procsym.name); + + { Add procdef to the implemented interface } + if assigned(implprocdef) then + begin + if (tobjectdef(implprocdef.struct).objecttype<>odt_objcclass) then + ImplIntf.AddImplProc(implprocdef) + else + begin + { If no message name has been specified for the method + in the objcclass, copy it from the protocol + definition. } + if not(po_msgstr in tprocdef(def).procoptions) then + begin + include(tprocdef(def).procoptions,po_msgstr); + implprocdef.messageinf.str:=stringdup(tprocdef(def).messageinf.str^); + end + else + begin + { If a message name has been specified in the + objcclass, it has to match the message name in the + protocol definition. } + if (implprocdef.messageinf.str^<>tprocdef(def).messageinf.str^) then + MessagePos2(implprocdef.fileinfo,parser_e_objc_message_name_changed,tprocdef(def).messageinf.str^,implprocdef.messageinf.str^); + end; + end; + end + else + if (ImplIntf.IType=etStandard) and + not(po_optional in tprocdef(def).procoptions) then + MessagePos1(_Class.typesym.fileinfo,sym_e_no_matching_implementation_found,tprocdef(def).fullprocname(false)); + end; + end; + end; + + + procedure TVMTBuilder.intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef); + begin + if assigned(IntfDef.childof) then + intf_get_procdefs_recursive(ImplIntf,IntfDef.childof); + intf_get_procdefs(ImplIntf,IntfDef); + end; + + + procedure TVMTBuilder.prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef); + var + i: longint; + begin + { don't check the same protocol twice } + if handledprotocols.IndexOf(ProtDef)<>-1 then + exit; + handledprotocols.add(ProtDef); + for i:=0 to ProtDef.ImplementedInterfaces.count-1 do + prot_get_procdefs_recursive(ImplProt,TImplementedInterface(ProtDef.ImplementedInterfaces[i]).intfdef); + intf_get_procdefs(ImplProt,ProtDef); + end; + + + procedure TVMTBuilder.intf_optimize_vtbls; + type + tcompintfentry = record + weight: longint; + compintf: longint; + end; + { Max 1000 interface in the class header interfaces it's enough imho } + tcompintfs = array[0..1000] of tcompintfentry; + pcompintfs = ^tcompintfs; + tequals = array[0..1000] of longint; + pequals = ^tequals; + timpls = array[0..1000] of longint; + pimpls = ^timpls; + var + aequals: pequals; + compats: pcompintfs; + impls: pimpls; + ImplIntfCount, + w,i,j,k: longint; + ImplIntfI, + ImplIntfJ : TImplementedInterface; + cij: boolean; + cji: boolean; + begin + ImplIntfCount:=_class.ImplementedInterfaces.count; + if ImplIntfCount>=High(tequals) then + Internalerror(200006135); + getmem(compats,sizeof(tcompintfentry)*ImplIntfCount); + getmem(aequals,sizeof(longint)*ImplIntfCount); + getmem(impls,sizeof(longint)*ImplIntfCount); + filldword(compats^,(sizeof(tcompintfentry) div sizeof(dword))*ImplIntfCount,dword(-1)); + filldword(aequals^,ImplIntfCount,dword(-1)); + filldword(impls^,ImplIntfCount,dword(-1)); + { ismergepossible is a containing relation + meaning of ismergepossible(a,b,w) = + if implementorfunction map of a is contained implementorfunction map of b + imp(a,b) and imp(b,c) => imp(a,c) ; imp(a,b) and imp(b,a) => a == b + } + { the order is very important for correct allocation } + for i:=0 to ImplIntfCount-1 do + begin + for j:=i+1 to ImplIntfCount-1 do + begin + ImplIntfI:=TImplementedInterface(_class.ImplementedInterfaces[i]); + ImplIntfJ:=TImplementedInterface(_class.ImplementedInterfaces[j]); + cij:=ImplIntfI.IsImplMergePossible(ImplIntfJ,w); + cji:=ImplIntfJ.IsImplMergePossible(ImplIntfI,w); + if cij and cji then { i equal j } + begin + { get minimum index of equal } + if aequals^[j]=-1 then + aequals^[j]:=i; + end + else if cij then + begin + { get minimum index of maximum weight } + if compats^[i].weight<w then + begin + compats^[i].weight:=w; + compats^[i].compintf:=j; + end; + end + else if cji then + begin + { get minimum index of maximum weight } + if (compats^[j].weight<w) then + begin + compats^[j].weight:=w; + compats^[j].compintf:=i; + end; + end; + end; + end; + { Reset, no replacements by default } + for i:=0 to ImplIntfCount-1 do + impls^[i]:=i; + { Replace vtbls when equal or compat, repeat + until there are no replacements possible anymore. This is + needed for the cases like: + First loop: 2->3, 3->1 + Second loop: 2->1 (because 3 was replaced with 1) + } + repeat + k:=0; + for i:=0 to ImplIntfCount-1 do + begin + if compats^[impls^[i]].compintf<>-1 then + impls^[i]:=compats^[impls^[i]].compintf + else if aequals^[impls^[i]]<>-1 then + impls^[i]:=aequals^[impls^[i]] + else + inc(k); + end; + until k=ImplIntfCount; + { Update the VtblImplIntf } + for i:=0 to ImplIntfCount-1 do + begin + ImplIntfI:=TImplementedInterface(_class.ImplementedInterfaces[i]); + ImplIntfI.VtblImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[impls^[i]]); + end; + freemem(compats); + freemem(aequals); + freemem(impls); + end; + + + procedure TVMTBuilder.intf_allocate_vtbls; + var + i : longint; + ImplIntf : TImplementedInterface; + begin + { Allocation vtbl space } + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + { if it implements itself and if it's not implemented by delegation } + if (ImplIntf.VtblImplIntf=ImplIntf) and (ImplIntf.IType=etStandard) then + begin + { allocate a pointer in the object memory } + with tObjectSymtable(_class.symtable) do + begin + datasize:=align(datasize,sizeof(pint)); + ImplIntf.Ioffset:=datasize; + datasize:=datasize+sizeof(pint); + end; + end; + end; + { Update ioffset of current interface with the ioffset from + the interface that is reused to implements this interface } + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + if ImplIntf.VtblImplIntf<>ImplIntf then + ImplIntf.IOffset:=ImplIntf.VtblImplIntf.IOffset; + end; + end; + + + procedure TVMTBuilder.generate_vmt; + var + i : longint; + def : tdef; + old_current_structdef : tabstractrecorddef; + overridesclasshelper : boolean; + begin + old_current_structdef:=current_structdef; + current_structdef:=_class; + + _class.resetvmtentries; + + { inherit (copy) VMT from parent object } + if assigned(_class.childof) then + begin + if not assigned(_class.childof.vmtentries) then + internalerror(200810281); + _class.copyvmtentries(_class.childof); + end; + + { process all procdefs, we must process the defs to + keep the same order as that is written in the source + to be compatible with the indexes in the interface vtable (PFV) } + for i:=0 to _class.symtable.DefList.Count-1 do + begin + def:=tdef(_class.symtable.DefList[i]); + if def.typ=procdef then + begin + { VMT entry } + if is_new_vmt_entry(tprocdef(def),overridesclasshelper) then + add_new_vmt_entry(tprocdef(def),overridesclasshelper); + end; + end; + build_interface_mappings; + if assigned(_class.ImplementedInterfaces) and + not(is_objc_class_or_protocol(_class)) then + begin + { Optimize interface tables to reuse wrappers } + intf_optimize_vtbls; + { Allocate interface tables } + intf_allocate_vtbls; + end; + + current_structdef:=old_current_structdef; + end; + + + procedure TVMTBuilder.build_interface_mappings; + var + ImplIntf : TImplementedInterface; + i: longint; + begin + { Find Procdefs implementing the interfaces } + if assigned(_class.ImplementedInterfaces) and + (_class.objecttype<>odt_objcprotocol) then + begin + { Collect implementor functions into the tImplementedInterface.procdefs } + case _class.objecttype of + odt_class: + begin + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + intf_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef) + end; + end; + odt_objcclass: + begin + { Object Pascal interfaces are afterwards optimized via the + intf_optimize_vtbls() method, but we can't do this for + protocols -> check for duplicates here already. } + handledprotocols:=tfpobjectlist.create(false); + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + prot_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef); + end; + handledprotocols.free; + end + else + internalerror(2009091801); + end + end; + end; + + +{***************************************************************************** + TVMTWriter +*****************************************************************************} + + constructor TVMTWriter.create(c:tobjectdef); + begin + inherited Create; + _Class:=c; + end; + + + destructor TVMTWriter.destroy; + begin + end; + + +{************************************** + Message Tables +**************************************} + + procedure TVMTWriter.disposeprocdeftree(p : pprocdeftree); + begin + if assigned(p^.l) then + disposeprocdeftree(p^.l); + if assigned(p^.r) then + disposeprocdeftree(p^.r); + dispose(p); + end; + + + procedure TVMTWriter.insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint); + begin + if at=nil then + begin + at:=p; + inc(count); + end + else + begin + if p^.data.messageinf.i<at^.data.messageinf.i then + insertint(p,at^.l,count) + else if p^.data.messageinf.i>at^.data.messageinf.i then + insertint(p,at^.r,count) + else + Message1(parser_e_duplicate_message_label,tostr(p^.data.messageinf.i)); + end; + end; + + + procedure TVMTWriter.insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint); + var + i : integer; + begin + if at=nil then + begin + at:=p; + inc(count); + end + else + begin + i:=CompareStr(p^.data.messageinf.str^,at^.data.messageinf.str^); + if i<0 then + insertstr(p,at^.l,count) + else if i>0 then + insertstr(p,at^.r,count) + else + Message1(parser_e_duplicate_message_label,p^.data.messageinf.str^); + end; + end; + + + procedure TVMTWriter.insertmsgint(p:TObject;arg:pointer); + var + i : longint; + pd : Tprocdef; + pt : pprocdeftree; + begin + if tsym(p).typ<>procsym then + exit; + for i:=0 to Tprocsym(p).ProcdefList.Count-1 do + begin + pd:=tprocdef(Tprocsym(p).ProcdefList[i]); + if po_msgint in pd.procoptions then + begin + new(pt); + pt^.data:=pd; + pt^.l:=nil; + pt^.r:=nil; + insertint(pt,root,plongint(arg)^); + end; + end; + end; + + + procedure TVMTWriter.insertmsgstr(p:TObject;arg:pointer); + var + i : longint; + pd : Tprocdef; + pt : pprocdeftree; + begin + if tsym(p).typ<>procsym then + exit; + for i:=0 to Tprocsym(p).ProcdefList.Count-1 do + begin + pd:=tprocdef(Tprocsym(p).ProcdefList[i]); + if po_msgstr in pd.procoptions then + begin + new(pt); + pt^.data:=pd; + pt^.l:=nil; + pt^.r:=nil; + insertstr(pt,root,plongint(arg)^); + end; + end; + end; + + + procedure TVMTWriter.writenames(p : pprocdeftree); + var + ca : pchar; + len : byte; + begin + current_asmdata.getdatalabel(p^.nl); + if assigned(p^.l) then + writenames(p^.l); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(p^.nl)); + len:=length(p^.data.messageinf.str^); + current_asmdata.asmlists[al_globals].concat(tai_const.create_8bit(len)); + getmem(ca,len+1); + move(p^.data.messageinf.str^[1],ca^,len); + ca[len]:=#0; + current_asmdata.asmlists[al_globals].concat(Tai_string.Create_pchar(ca,len)); + if assigned(p^.r) then + writenames(p^.r); + end; + + procedure TVMTWriter.writestrentry(p : pprocdeftree); + + begin + if assigned(p^.l) then + writestrentry(p^.l); + + { write name label } + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(p^.nl)); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0)); + + if assigned(p^.r) then + writestrentry(p^.r); + end; + + + function TVMTWriter.genstrmsgtab : tasmlabel; + var + count : longint; + begin + root:=nil; + count:=0; + { insert all message handlers into a tree, sorted by name } + _class.symtable.SymList.ForEachCall(@insertmsgstr,@count); + + { write all names } + if assigned(root) then + writenames(root); + + { now start writing of the message string table } + current_asmdata.getdatalabel(result); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(result)); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(longint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count)); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + if assigned(root) then + begin + writestrentry(root); + disposeprocdeftree(root); + end; + end; + + + procedure TVMTWriter.writeintentry(p : pprocdeftree); + begin + if assigned(p^.l) then + writeintentry(p^.l); + + { write name label } + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(longint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(p^.data.messageinf.i)); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0)); + + if assigned(p^.r) then + writeintentry(p^.r); + end; + + + function TVMTWriter.genintmsgtab : tasmlabel; + var + r : tasmlabel; + count : longint; + begin + root:=nil; + count:=0; + { insert all message handlers into a tree, sorted by name } + _class.symtable.SymList.ForEachCall(@insertmsgint,@count); + + { now start writing of the message string table } + current_asmdata.getdatalabel(r); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(r)); + genintmsgtab:=r; + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(longint)))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count)); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + if assigned(root) then + begin + writeintentry(root); + disposeprocdeftree(root); + end; + end; + +{$ifdef WITHDMT} + +{************************************** + DMT +**************************************} + + procedure TVMTWriter.insertdmtentry(p:TObject;arg:pointer); + + var + hp : tprocdef; + pt : pprocdeftree; + + begin + if tsym(p).typ=procsym then + begin + hp:=tprocsym(p).definition; + while assigned(hp) do + begin + if (po_msgint in hp.procoptions) then + begin + new(pt); + pt^.p:=hp; + pt^.l:=nil; + pt^.r:=nil; + insertint(pt,root); + end; + hp:=hp.nextoverloaded; + end; + end; + end; + + procedure TVMTWriter.writedmtindexentry(p : pprocdeftree); + + begin + if assigned(p^.l) then + writedmtindexentry(p^.l); + al_globals.concat(Tai_const.Create_32bit(p^.data.messageinf.i)); + if assigned(p^.r) then + writedmtindexentry(p^.r); + end; + + procedure TVMTWriter.writedmtaddressentry(p : pprocdeftree); + + begin + if assigned(p^.l) then + writedmtaddressentry(p^.l); + al_globals.concat(Tai_const_symbol.Createname(p^.data.mangledname,0)); + if assigned(p^.r) then + writedmtaddressentry(p^.r); + end; + + function TVMTWriter.gendmt : tasmlabel; + + var + r : tasmlabel; + + begin + root:=nil; + count:=0; + gendmt:=nil; + { insert all message handlers into a tree, sorted by number } + _class.symtable.SymList.ForEachCall(insertdmtentry); + + if count>0 then + begin + current_asmdata.getdatalabel(r); + gendmt:=r; + al_globals.concat(cai_align.create(const_align(sizeof(pint)))); + al_globals.concat(Tai_label.Create(r)); + { entries for caching } + al_globals.concat(Tai_const.Create_ptr(0)); + al_globals.concat(Tai_const.Create_ptr(0)); + + al_globals.concat(Tai_const.Create_32bit(count)); + if assigned(root) then + begin + writedmtindexentry(root); + writedmtaddressentry(root); + disposeprocdeftree(root); + end; + end; + end; + +{$endif WITHDMT} + +{************************************** + Published Methods +**************************************} + + procedure TVMTWriter.do_count_published_methods(p:TObject;arg:pointer); + var + i : longint; + pd : tprocdef; + begin + if (tsym(p).typ<>procsym) then + exit; + for i:=0 to Tprocsym(p).ProcdefList.Count-1 do + begin + pd:=tprocdef(Tprocsym(p).ProcdefList[i]); + if (pd.procsym=tsym(p)) and + (pd.visibility=vis_published) then + inc(plongint(arg)^); + end; + end; + + + procedure TVMTWriter.do_gen_published_methods(p:TObject;arg:pointer); + var + i : longint; + l : tasmlabel; + pd : tprocdef; + begin + if (tsym(p).typ<>procsym) then + exit; + for i:=0 to Tprocsym(p).ProcdefList.Count-1 do + begin + pd:=tprocdef(Tprocsym(p).ProcdefList[i]); + if (pd.procsym=tsym(p)) and + (pd.visibility=vis_published) then + begin + current_asmdata.getdatalabel(l); + new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,l.name,const_align(sizeof(pint))); + current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l)); + current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_8bit(length(tsym(p).realname))); + current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create(tsym(p).realname)); + + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(l)); + if po_abstractmethod in pd.procoptions then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(pd.mangledname,0)); + end; + end; + end; + + + function TVMTWriter.genpublishedmethodstable : tasmlabel; + + var + l : tasmlabel; + count : longint; + + begin + count:=0; + _class.symtable.SymList.ForEachCall(@do_count_published_methods,@count); + if count>0 then + begin + current_asmdata.getdatalabel(l); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(l)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count)); + _class.symtable.SymList.ForEachCall(@do_gen_published_methods,nil); + genpublishedmethodstable:=l; + end + else + genpublishedmethodstable:=nil; + end; + + + function TVMTWriter.generate_field_table : tasmlabel; + var + i : longint; + sym : tsym; + fieldtable, + classtable : tasmlabel; + classindex, + fieldcount : longint; + classtablelist : TFPList; + begin + classtablelist:=TFPList.Create; + current_asmdata.getdatalabel(fieldtable); + current_asmdata.getdatalabel(classtable); + maybe_new_object_file(current_asmdata.asmlists[al_rtti]); + new_section(current_asmdata.asmlists[al_rtti],sec_rodata,classtable.name,const_align(sizeof(pint))); + + { retrieve field info fields } + fieldcount:=0; + for i:=0 to _class.symtable.SymList.Count-1 do + begin + sym:=tsym(_class.symtable.SymList[i]); + if (sym.typ=fieldvarsym) and + (sym.visibility=vis_published) then + begin + if tfieldvarsym(sym).vardef.typ<>objectdef then + internalerror(200611032); + classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef); + if classindex=-1 then + classtablelist.Add(tfieldvarsym(sym).vardef); + inc(fieldcount); + end; + end; + + { write fields } + current_asmdata.asmlists[al_rtti].concat(Tai_label.Create(fieldtable)); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(fieldcount)); + if (tf_requires_proper_alignment in target_info.flags) then + current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_sym(classtable)); + for i:=0 to _class.symtable.SymList.Count-1 do + begin + sym:=tsym(_class.symtable.SymList[i]); + if (sym.typ=fieldvarsym) and + (sym.visibility=vis_published) then + begin + if (tf_requires_proper_alignment in target_info.flags) then + current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(pint))); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_pint(tfieldvarsym(sym).fieldoffset)); + classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef); + if classindex=-1 then + internalerror(200611033); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(classindex+1)); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(length(tfieldvarsym(sym).realname))); + current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(tfieldvarsym(sym).realname)); + end; + end; + + { generate the class table } + current_asmdata.asmlists[al_rtti].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_rtti].concat(Tai_label.Create(classtable)); + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(classtablelist.count)); + if (tf_requires_proper_alignment in target_info.flags) then + current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); + for i:=0 to classtablelist.Count-1 do + current_asmdata.asmlists[al_rtti].concat(Tai_const.Createname(tobjectdef(classtablelist[i]).vmt_mangledname,0)); + + classtablelist.free; + result:=fieldtable; + end; + + +{************************************** + Interface tables +**************************************} + + function TVMTWriter.intf_get_vtbl_name(AImplIntf:TImplementedInterface): string; + begin + result:=make_mangledname('VTBL',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^); + end; + + + procedure TVMTWriter.intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface); + var + pd : tprocdef; + vtblstr, + hs : string; + i : longint; + begin + vtblstr:=intf_get_vtbl_name(AImplIntf); + section_symbol_start(rawdata,vtblstr,AT_DATA,true,sec_data,const_align(sizeof(pint))); + if assigned(AImplIntf.procdefs) then + begin + for i:=0 to AImplIntf.procdefs.count-1 do + begin + pd:=tprocdef(AImplIntf.procdefs[i]); + hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+ + tostr(i)+'_$_'+pd.mangledname); + { create reference } + rawdata.concat(Tai_const.Createname(hs,0)); + end; + end; + section_symbol_end(rawdata,vtblstr); + end; + + + procedure TVMTWriter.intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface); + var + iidlabel, + guidlabel : tasmlabel; + i: longint; + pd: tprocdef; + begin + { GUID } + if AImplIntf.IntfDef.objecttype in [odt_interfacecom] then + begin + { label for GUID } + current_asmdata.getdatalabel(guidlabel); + rawdata.concat(cai_align.create(const_align(sizeof(pint)))); + rawdata.concat(Tai_label.Create(guidlabel)); + with AImplIntf.IntfDef.iidguid^ do + begin + rawdata.concat(Tai_const.Create_32bit(longint(D1))); + rawdata.concat(Tai_const.Create_16bit(D2)); + rawdata.concat(Tai_const.Create_16bit(D3)); + for i:=Low(D4) to High(D4) do + rawdata.concat(Tai_const.Create_8bit(D4[i])); + end; + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(guidlabel)); + end + else + begin + { nil for Corba interfaces } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + end; + { VTable } + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(intf_get_vtbl_name(AImplIntf.VtblImplIntf),0)); + { IOffset field } + case AImplIntf.VtblImplIntf.IType of + etFieldValue, etFieldValueClass, + etStandard: + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(AImplIntf.VtblImplIntf.IOffset)); + etStaticMethodResult, etStaticMethodClass: + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname( + tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef).mangledname, + 0 + )); + etVirtualMethodResult, etVirtualMethodClass: + begin + pd := tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(tobjectdef(pd.struct).vmtmethodoffset(pd.extnumber))); + end; + else + internalerror(200802162); + end; + + { IIDStr } + current_asmdata.getdatalabel(iidlabel); + rawdata.concat(cai_align.create(const_align(sizeof(pint)))); + rawdata.concat(Tai_label.Create(iidlabel)); + rawdata.concat(Tai_const.Create_8bit(length(AImplIntf.IntfDef.iidstr^))); + if AImplIntf.IntfDef.objecttype=odt_interfacecom then + rawdata.concat(Tai_string.Create(upper(AImplIntf.IntfDef.iidstr^))) + else + rawdata.concat(Tai_string.Create(AImplIntf.IntfDef.iidstr^)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(iidlabel)); + { IType } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(aint(AImplIntf.VtblImplIntf.IType))); + end; + + + function TVMTWriter.intf_write_table:TAsmLabel; + var + rawdata : TAsmList; + i : longint; + ImplIntf : TImplementedInterface; + intftablelab : tasmlabel; + begin + current_asmdata.getdatalabel(intftablelab); + current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(pint)))); + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(intftablelab)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(_class.ImplementedInterfaces.count)); + rawdata:=TAsmList.Create; + { Write vtbls } + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + if ImplIntf.VtblImplIntf=ImplIntf then + intf_create_vtbl(rawdata,ImplIntf); + end; + { Write vtbl references } + for i:=0 to _class.ImplementedInterfaces.count-1 do + begin + ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); + intf_gen_intf_ref(rawdata,ImplIntf); + end; + { Write interface table } + current_asmdata.asmlists[al_globals].concatlist(rawdata); + rawdata.free; + result:=intftablelab; + end; + + + { Write interface identifiers to the data section } + procedure TVMTWriter.writeinterfaceids; + var + i : longint; + s : string; + begin + if assigned(_class.iidguid) then + begin + s:=make_mangledname('IID',_class.owner,_class.objname^); + maybe_new_object_file(current_asmdata.asmlists[al_globals]); + new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,const_align(sizeof(pint))); + current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(longint(_class.iidguid^.D1))); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D2)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D3)); + for i:=Low(_class.iidguid^.D4) to High(_class.iidguid^.D4) do + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(_class.iidguid^.D4[i])); + end; + maybe_new_object_file(current_asmdata.asmlists[al_globals]); + s:=make_mangledname('IIDSTR',_class.owner,_class.objname^); + new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,0); + current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.iidstr^))); + current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.iidstr^)); + end; + + + procedure TVMTWriter.writevirtualmethods(List:TAsmList); + var + vmtpd : tprocdef; + vmtentry : pvmtentry; + i : longint; + procname : string; +{$ifdef vtentry} + hs : string; +{$endif vtentry} + begin + if not assigned(_class.VMTEntries) then + exit; + for i:=0 to _class.VMTEntries.Count-1 do + begin + vmtentry:=pvmtentry(_class.vmtentries[i]); + vmtpd:=vmtentry^.procdef; + { safety checks } + if not(po_virtualmethod in vmtpd.procoptions) then + internalerror(200611082); + if vmtpd.extnumber<>i then + internalerror(200611083); + if (po_abstractmethod in vmtpd.procoptions) then + procname:='FPC_ABSTRACTERROR' + else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then + procname:=vmtpd.mangledname; + List.concat(Tai_const.createname(procname,0)); +{$ifdef vtentry} + hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(pint)); + current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0)); +{$endif vtentry} + end; + end; + + + procedure TVMTWriter.writevmt; + var + methodnametable,intmessagetable, + strmessagetable,classnamelabel, + fieldtablelabel : tasmlabel; + hs: string; +{$ifdef WITHDMT} + dmtlabel : tasmlabel; +{$endif WITHDMT} + interfacetable : tasmlabel; + begin +{$ifdef WITHDMT} + dmtlabel:=gendmt; +{$endif WITHDMT} + + { write tables for classes, this must be done before the actual + class is written, because we need the labels defined } + if is_class(_class) then + begin + current_asmdata.getdatalabel(classnamelabel); + maybe_new_object_file(current_asmdata.asmlists[al_globals]); + new_section(current_asmdata.asmlists[al_globals],sec_rodata,classnamelabel.name,const_align(sizeof(pint))); + + { interface table } + if _class.ImplementedInterfaces.count>0 then + interfacetable:=intf_write_table; + + methodnametable:=genpublishedmethodstable; + fieldtablelabel:=generate_field_table; + { write class name } + current_asmdata.asmlists[al_globals].concat(Tai_label.Create(classnamelabel)); + hs:=_class.RttiName; + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(hs))); + current_asmdata.asmlists[al_globals].concat(Tai_string.Create(hs)); + + { generate message and dynamic tables } + if (oo_has_msgstr in _class.objectoptions) then + strmessagetable:=genstrmsgtab; + if (oo_has_msgint in _class.objectoptions) then + intmessagetable:=genintmsgtab; + end; + + { write debug info } + maybe_new_object_file(current_asmdata.asmlists[al_globals]); + new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(pint))); + current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0)); + + { determine the size with symtable.datasize, because } + { size gives back 4 for classes } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tObjectSymtable(_class.symtable).datasize)); + current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tObjectSymtable(_class.symtable).datasize))); +{$ifdef WITHDMT} + if _class.classtype=ct_object then + begin + if assigned(dmtlabel) then + current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel))) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0)); + end; +{$endif WITHDMT} + { write pointer to parent VMT, this isn't implemented in TP } + { but this is not used in FPC ? (PM) } + { it's not used yet, but the delphi-operators as and is need it (FK) } + { it is not written for parents that don't have any vmt !! } + if assigned(_class.childof) and + (oo_has_vmt in _class.childof.objectoptions) then + current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,0)) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + + { write extended info for classes, for the order see rtl/inc/objpash.inc } + if is_class(_class) then + begin + { pointer to class name string } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel)); + { pointer to dynamic table or nil } + if (oo_has_msgint in _class.objectoptions) then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable)) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + { pointer to method table or nil } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable)); + { pointer to field table } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel)); + { pointer to type info of published section } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,fullrtti))); + { inittable for con-/destruction } + if _class.members_need_inittable then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,initrtti))) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + { auto table } + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + { interface table } + if _class.ImplementedInterfaces.count>0 then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable)) + else if _class.implements_any_interfaces then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(current_asmdata.RefAsmSymbol('FPC_EMPTYINTF'))); + { table for string messages } + if (oo_has_msgstr in _class.objectoptions) then + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable)) + else + current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil)); + end; + { write virtual methods } + writevirtualmethods(current_asmdata.asmlists[al_globals]); + current_asmdata.asmlists[al_globals].concat(Tai_const.create(aitconst_ptr,0)); + { write the size of the VMT } + current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname)); +{$ifdef vtentry} + { write vtinherit symbol to notify the linker of the class inheritance tree } + hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$'; + if assigned(_class.childof) then + hs:=hs+_class.childof.vmt_mangledname + else + hs:=hs+_class.vmt_mangledname; + current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0)); +{$endif vtentry} + end; + + +end. |
