| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273 | {    Copyright (c) 2011 by Jonas Maebe    This unit provides helpers for creating new syms/defs based on string    representations.    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. ****************************************************************************}{$i fpcdefs.inc}unit symcreat;interface  uses    finput,tokens,scanner,globtype,cclasses,    aasmdata,    symconst,symbase,symtype,symdef,symsym,    node;  type    tscannerstate = record      new_scanner: tscannerfile;      old_scanner: tscannerfile;      old_filepos: tfileposinfo;      old_token: ttoken;      old_c: char;      old_orgpattern: string;      old_modeswitches: tmodeswitches;      old_idtoken: ttoken;      valid: boolean;    end;  { save/restore the scanner state before/after injecting }  procedure replace_scanner(const tempname: string; out sstate: tscannerstate);  procedure restore_scanner(const sstate: tscannerstate);  { parses a (class or regular) method/constructor/destructor declaration from    str, as if it were declared in astruct's declaration body    WARNING: save the scanner state before calling this routine, and restore      when done. }  function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;  { parses a (class or regular)  method/constructor/destructor implementation    from str, as if it appeared in the current unit's implementation section      WARNINGS:        * save the scanner state before calling this routine, and restore when done.        * the code *must* be written in objfpc style  }  function str_parse_method_impl(const str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;  { parses a typed constant assignment to ssym      WARNINGS:        * save the scanner state before calling this routine, and restore when done.        * the code *must* be written in objfpc style  }  procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);  { in the JVM, constructors are not automatically inherited (so you can hide    them). To emulate the Pascal behaviour, we have to automatically add    all parent constructors to the current class as well. We also have to do    the same for the (emulated) virtual class methods }  procedure add_missing_parent_constructors_intf(obj: tobjectdef; addvirtclassmeth: boolean; forcevis: tvisibility);  { goes through all defs in st to add implementations for synthetic methods    added earlier }  procedure add_synthetic_method_implementations(st: tsymtable);  { create an alias for a procdef with Pascal name "newrealname",    mangledname "newmangledname", in symtable newparentst, part of the    record/class/.. "newstruct" (nil if none), and with synthetickind "sk" and    synthetic kind para "skpara" to create the implementation (tsk_none and nil    in case not necessary). Returns the new procdef; finish_copied_procdef() is    not required/must not be called for the result. }  function create_procdef_alias(pd: tprocdef; const newrealname: string; const newmangledname: TSymStr; newparentst: tsymtable; newstruct: tabstractrecorddef; sk: tsynthetickind; skpara: pointer): tprocdef;  { finalize a procdef that has been copied with    tprocdef.getcopyas(procdef,pc_bareproc) }  procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);  { checks whether sym (a local or para of pd) already has a counterpart in    pd's parentfpstruct, and if not adds a new field to the struct with type    "vardef" (can be different from sym's type in case it's a call-by-reference    parameter, which is indicated by addrparam). If it already has a field in    the parentfpstruct, this field is returned. }  function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;  { given a localvarsym or paravarsym of pd, returns the field of the    parentfpstruct corresponding to this sym }  function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;  { replaces all local and paravarsyms that have been mirrored in the    parentfpstruct with aliasvarsyms that redirect to these fields (used to    make sure that references to these syms in the owning procdef itself also    use the ones in the parentfpstructs) }  procedure redirect_parentfpstruct_local_syms(pd: tprocdef);  { finalises the parentfpstruct (alignment padding, ...) }  procedure finish_parentfpstruct(pd: tprocdef);  { turns a fieldvarsym into a class/static field definition, and returns the    created staticvarsym that is responsible for allocating the global storage }  function make_field_static(recst: tsymtable; fieldvs: tfieldvarsym): tstaticvarsym;  { create a new procdef with the signature of orgpd and (mangled) name    newname, and change the implementation of orgpd so that it calls through    to this new procedure }  procedure call_through_new_name(orgpd: tprocdef; const newname: TSymStr);  function generate_pkg_stub(pd:tprocdef):tnode;  procedure generate_attr_constrs(attrs:tfpobjectlist);  { Generate the hidden thunk class for interfaces,    so we can use them in TVirtualInterface on platforms that do not allow    generating executable code in memory at runtime.}  procedure add_synthetic_interface_classes_for_st(st : tsymtable; gen_intf, gen_impl : boolean);implementation  uses    cutils,globals,verbose,systems,comphook,fmodule,constexp,    symtable,defutil,symutil,procinfo,    pbase,pdecl, pdecobj,pdecsub,psub,ptconst,pparautl,{$ifdef jvm}    pjvm,jvmdef,{$endif jvm}    aasmcpu,symcpu,    nbas,nld,nmem,ncon,    defcmp,    paramgr;  procedure replace_scanner(const tempname: string; out sstate: tscannerstate);    var      old_block_type: tblock_type;    begin      { would require saving of cstringpattern, patternw }      if (token=_CSTRING) or         (token=_CWCHAR) or         (token=_CWSTRING) then        internalerror(2011032201);      sstate.old_scanner:=current_scanner;      sstate.old_filepos:=current_filepos;      sstate.old_token:=token;      sstate.old_c:=c;      sstate.old_orgpattern:=orgpattern;      sstate.old_modeswitches:=current_settings.modeswitches;      sstate.old_idtoken:=idtoken;      sstate.valid:=true;      { creating a new scanner resets the block type, while we want to continue        in the current one }      old_block_type:=block_type;      sstate.new_scanner:=tscannerfile.Create('_Macro_.'+tempname,true);      set_current_scanner(sstate.new_scanner);      block_type:=old_block_type;      { required for e.g. FpcDeepCopy record method (uses "out" parameter; field        names are escaped via &, so should not cause conflicts }      current_settings.modeswitches:=objfpcmodeswitches;    end;  procedure restore_scanner(const sstate: tscannerstate);    begin      if sstate.valid then        begin          sstate.new_scanner.free;          set_current_scanner(sstate.old_scanner);          current_filepos:=sstate.old_filepos;          token:=sstate.old_token;          current_settings.modeswitches:=sstate.old_modeswitches;          c:=sstate.old_c;          orgpattern:=sstate.old_orgpattern;          pattern:=upper(sstate.old_orgpattern);          idtoken:=sstate.old_idtoken;        end;    end;  function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;    var      oldparse_only: boolean;    begin      Message1(parser_d_internal_parser_string,str);      oldparse_only:=parse_only;      parse_only:=true;      result:=false;      { in case multiple strings are injected, make sure to always close the        previous macro inputfile to prevent memory leaks }      if assigned(current_scanner.inputfile) and         not(current_scanner.inputfile.closed) then        current_scanner.closeinputfile;      { inject the string in the scanner }      str:=str+'end;';      current_scanner.substitutemacro('meth_head_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);      current_scanner.readtoken(false);      { and parse it... }      case potype of        potype_class_constructor:          pd:=class_constructor_head(astruct);        potype_class_destructor:          pd:=class_destructor_head(astruct);        potype_constructor:          pd:=constructor_head;        potype_destructor:          pd:=destructor_head;        else if assigned(astruct) and           (astruct.typ=recorddef) then          pd:=parse_record_method_dec(astruct,is_classdef,false)        else          pd:=method_dec(astruct,is_classdef,false);      end;      if assigned(pd) then        result:=true;      parse_only:=oldparse_only;      { remove the temporary macro input file again }      current_scanner.closeinputfile;      current_scanner.nextfile;      current_scanner.tempopeninputfile;    end;  function str_parse_method_impl_with_fileinfo(str: ansistring; usefwpd: tprocdef; fileno, lineno: longint; is_classdef: boolean; out result_procdef: tprocdef):boolean;     var       oldparse_only: boolean;       tmpstr: ansistring;       flags : tread_proc_flags;     begin      if ((status.verbosity and v_debug)<>0) then        begin           if assigned(usefwpd) then             Message1(parser_d_internal_parser_string,usefwpd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker,pno_noleadingdollar])+str)           else             begin               if is_classdef then                 tmpstr:='class '               else                 tmpstr:='';               Message1(parser_d_internal_parser_string,tmpstr+str);             end;        end;      oldparse_only:=parse_only;      parse_only:=false;      result:=false;      { "const" starts a new kind of block and hence makes the scanner return }      str:=str+'const;';      { inject the string in the scanner }      current_scanner.substitutemacro('meth_impl_macro',@str[1],length(str),lineno,fileno,true);      current_scanner.readtoken(false);      { and parse it... }      flags:=[];      if is_classdef then        include(flags,rpf_classmethod);      result_procdef:=read_proc(flags,usefwpd);      parse_only:=oldparse_only;      { remove the temporary macro input file again }      current_scanner.closeinputfile;      current_scanner.nextfile;      current_scanner.tempopeninputfile;      result:=true;     end;  function str_parse_method_impl(const str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;    var      tmpproc: tprocdef;    begin      result:=str_parse_method_impl_with_fileinfo(str, usefwpd, current_scanner.inputfile.ref_index, current_scanner.line_no, is_classdef, tmpproc);    end;  function str_parse_method_impl(const str: ansistring; usefwpd: tprocdef; is_classdef: boolean; out result_procdef: tprocdef):boolean;    begin      result:=str_parse_method_impl_with_fileinfo(str, usefwpd, current_scanner.inputfile.ref_index, current_scanner.line_no, is_classdef, result_procdef);    end;  procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);    var      old_block_type: tblock_type;      old_parse_only: boolean;    begin      Message1(parser_d_internal_parser_string,str);      { a string that will be interpreted as the start of a new section ->        typed constant parsing will stop }      str:=str+'type ';      old_parse_only:=parse_only;      old_block_type:=block_type;      parse_only:=true;      block_type:=bt_const;      current_scanner.substitutemacro('typed_const_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);      current_scanner.readtoken(false);      read_typed_const(list,ssym,ssym.owner.symtabletype in [recordsymtable,objectsymtable]);      parse_only:=old_parse_only;      block_type:=old_block_type;      { remove the temporary macro input file again }      current_scanner.closeinputfile;      current_scanner.nextfile;      current_scanner.tempopeninputfile;    end;    function str_parse_objecttypedef(typename : shortstring;str: ansistring): tobjectdef;     var       b,oldparse_only: boolean;       i : integer;       tmpstr: ansistring;       flags : tread_proc_flags;       o : TObject;     begin      result:=nil;      Message1(parser_d_internal_parser_string,str);      oldparse_only:=parse_only;      parse_only:=true;      { "const" starts a new kind of block and hence makes the scanner return }      str:=str+'const;';      block_type:=bt_type;      { inject the string in the scanner }      current_scanner.substitutemacro('hidden_interface_class_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);      current_scanner.readtoken(false);      type_dec(b);      // In the interface part, the object def is not necessarily the last one, the methods also generate defs.      i:=current_module.DefList.count-1;      While (result=nil) and (i>=0) do        begin        O:=current_module.DefList[i];        if (o is tobjectdef) then           if (tobjectdef(o).GetTypeName=typename) then             result:=tobjectdef(o);        dec(i);        end;      if result=nil then        internalerror(2024050401);      parse_only:=oldparse_only;      { remove the temporary macro input file again }      current_scanner.closeinputfile;      current_scanner.nextfile;      current_scanner.tempopeninputfile;     end;  function def_unit_name_prefix_if_toplevel(def: tdef): TSymStr;    begin      result:='';      { if the routine is a global routine in a unit, explicitly use this unit        name to avoid accidentally calling other same-named routines that may be        in scope }      if not assigned(def.owner.defowner) and         assigned(def.owner.realname) and         (def.owner.moduleid<>0) then        result:=internal_macro_escape_unit_namespace_name+def.owner.realname^+'.';    end;  procedure add_missing_parent_constructors_intf(obj: tobjectdef; addvirtclassmeth: boolean; forcevis: tvisibility);    var      parent: tobjectdef;      def: tdef;      parentpd,      childpd: tprocdef;      i: longint;      srsym: tsym;      srsymtable: tsymtable;    begin      if (oo_is_external in obj.objectoptions) or         not assigned(obj.childof) then        exit;      parent:=obj.childof;      { find all constructor in the parent }      for i:=0 to tobjectsymtable(parent.symtable).deflist.count-1 do        begin          def:=tdef(tobjectsymtable(parent.symtable).deflist[i]);          if (def.typ<>procdef) or             ((tprocdef(def).proctypeoption<>potype_constructor) and              (not addvirtclassmeth or               not([po_classmethod,po_virtualmethod]<=tprocdef(def).procoptions))) or             not is_visible_for_object(tprocdef(def),obj) then            continue;          parentpd:=tprocdef(def);          { do we have this constructor too? (don't use            search_struct_member/searchsym_in_class, since those will            search parents too) }          if searchsym_in_record(obj,parentpd.procsym.name,srsym,srsymtable) then            begin              { there's a symbol with the same name, is it a routine of the                same type with the same parameters? }              if srsym.typ=procsym then                begin                  childpd:=tprocsym(srsym).find_procdef_bytype_and_para(                    tprocdef(def).proctypeoption,parentpd.paras,nil,                    [cpo_ignorehidden,cpo_ignoreuniv,cpo_openequalisexact]);                  if assigned(childpd) then                    continue;                end;            end;          { if we get here, we did not find it in the current objectdef ->            add }          childpd:=tprocdef(parentpd.getcopyas(procdef,pc_normal_no_hidden,'',true));          { get rid of the import name for inherited virtual class methods,            it has to be regenerated rather than amended }          if [po_classmethod,po_virtualmethod]<=childpd.procoptions then            begin              stringdispose(childpd.import_name);              exclude(childpd.procoptions,po_has_importname);            end;          if forcevis<>vis_none then            childpd.visibility:=forcevis;          if po_virtualmethod in childpd.procoptions then            include(childpd.procoptions,po_overridingmethod);          { ignore this artificially added procdef when looking for overloads }          include(childpd.procoptions,po_ignore_for_overload_resolution);          finish_copied_procdef(childpd,parentpd.procsym.realname,obj.symtable,obj);          exclude(childpd.procoptions,po_external);          childpd.synthetickind:=tsk_anon_inherited;          include(obj.objectoptions,oo_has_constructor);        end;    end;  procedure implement_anon_inherited(pd: tprocdef);    var      str: ansistring;      isclassmethod: boolean;    begin      isclassmethod:=        (po_classmethod in pd.procoptions) and        not(pd.proctypeoption in [potype_constructor,potype_destructor]);      str:='begin ';      if (pd.proctypeoption<>potype_constructor) and         not is_void(pd.returndef) then        str:=str+'result:=';      str:=str+'inherited end;';      str_parse_method_impl(str,pd,isclassmethod);    end;  procedure implement_jvm_clone(pd: tprocdef);    var      struct: tabstractrecorddef;      str: ansistring;      i: longint;      sym: tsym;      fsym: tfieldvarsym;    begin      if not(pd.struct.typ in [recorddef,objectdef]) then        internalerror(2011032802);      struct:=pd.struct;      { anonymous record types must get an artificial name, so we can generate        a typecast at the scanner level }      if (struct.typ=recorddef) and         not assigned(struct.typesym) then        internalerror(2011032812);      { We cannot easily use the inherited clone in case we have to create a        deep copy of certain fields. The reason is that e.g. sets are pointers        at the JVM level, but not in Pascal. So the JVM clone routine will copy        the pointer to the set from the old record (= class instance) to the new        one, but we have no way to change this pointer itself from inside Pascal        code.        We solve this by relying on the fact that the JVM is garbage collected:        we simply declare a temporary instance on the stack, which will be        allocated/initialized by the temp generator. We return its address as        the result of the clone routine, so it remains live. }      str:='var __fpc_newcopy:'+ struct.typesym.realname+'; begin clone:=JLObject(@__fpc_newcopy);';      { copy all field contents }      for i:=0 to struct.symtable.symlist.count-1 do        begin          sym:=tsym(struct.symtable.symlist[i]);          if (sym.typ=fieldvarsym) then            begin              fsym:=tfieldvarsym(sym);              str:=str+'__fpc_newcopy.&'+fsym.realname+':=&'+fsym.realname+';';            end;        end;      str:=str+'end;';      str_parse_method_impl(str,pd,false);    end;  procedure implement_record_deepcopy(pd: tprocdef);    var      struct: tabstractrecorddef;      str: ansistring;      i: longint;      sym: tsym;      fsym: tfieldvarsym;    begin      if not(pd.struct.typ in [recorddef,objectdef]) then        internalerror(2011032810);      struct:=pd.struct;      { anonymous record types must get an artificial name, so we can generate        a typecast at the scanner level }      if (struct.typ=recorddef) and         not assigned(struct.typesym) then        internalerror(2011032811);      { copy all fields }      str:='type _fpc_ptrt = ^'+struct.typesym.realname+'; var res: _fpc_ptrt; begin res:=_fpc_ptrt(result);';      for i:=0 to struct.symtable.symlist.count-1 do        begin          sym:=tsym(struct.symtable.symlist[i]);          if (sym.typ=fieldvarsym) then            begin              fsym:=tfieldvarsym(sym);              str:=str+'res^.&'+fsym.realname+':=&'+fsym.realname+';';            end;        end;      str:=str+'end;';      str_parse_method_impl(str,pd,false);    end;  procedure implement_record_initialize(pd: tprocdef);    var      struct: tabstractrecorddef;      str: ansistring;      i: longint;      sym: tsym;      fsym: tfieldvarsym;    begin      if not(pd.struct.typ in [recorddef,objectdef]) then        internalerror(2011071710);      struct:=pd.struct;      { anonymous record types must get an artificial name, so we can generate        a typecast at the scanner level }      if (struct.typ=recorddef) and         not assigned(struct.typesym) then        internalerror(2011032804);      { walk over all fields that need initialization }      str:='begin ';      for i:=0 to struct.symtable.symlist.count-1 do        begin          sym:=tsym(struct.symtable.symlist[i]);          if (sym.typ=fieldvarsym) then            begin              fsym:=tfieldvarsym(sym);              if fsym.vardef.needs_inittable then                str:=str+(internal_macro_escape_unit_namespace_name+'system.initialize(&')+fsym.realname+');';            end;        end;      str:=str+'end;';      str_parse_method_impl(str,pd,false);    end;  procedure implement_empty(pd: tprocdef);    var      str: ansistring;      isclassmethod: boolean;    begin      isclassmethod:=        (po_classmethod in pd.procoptions) and        not(pd.proctypeoption in [potype_constructor,potype_destructor]);      str:='begin end;';      str_parse_method_impl(str,pd,isclassmethod);    end;  procedure addvisibleparameters(var str: ansistring; pd: tprocdef);    var      currpara: tparavarsym;      i: longint;      firstpara: boolean;    begin      firstpara:=true;      for i:=0 to pd.paras.count-1 do        begin          currpara:=tparavarsym(pd.paras[i]);          if not(vo_is_hidden_para in currpara.varoptions) then            begin              if not firstpara then                str:=str+',';              firstpara:=false;              str:=str+'&'+currpara.realname;            end;        end;    end;  procedure implement_callthrough(pd: tprocdef);    var      str: ansistring;      callpd: tprocdef;      isclassmethod: boolean;    begin      isclassmethod:=        (po_classmethod in pd.procoptions) and        not(pd.proctypeoption in [potype_constructor,potype_destructor]);      callpd:=tprocdef(pd.skpara);      str:='begin ';      if pd.returndef<>voidtype then        str:=str+'result:=';      { if the routine is a global routine in a unit/program, explicitly        mnetion this program/unit name to avoid accidentally calling other        same-named routines that may be in scope }      str:=str+def_unit_name_prefix_if_toplevel(callpd)+callpd.procsym.realname+'(';      addvisibleparameters(str,pd);      str:=str+') end;';      str_parse_method_impl(str,pd,isclassmethod);    end;{$ifdef jvm}  procedure implement_jvm_enum_values(pd: tprocdef);    begin      str_parse_method_impl('begin result:=__fpc_FVALUES end;',pd,true);    end;  procedure implement_jvm_enum_valuof(pd: tprocdef);    begin      str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(inherited valueOf(JLClass(__FPC_TEnumClassAlias),__fpc_str)) end;',pd,true);    end;  procedure implement_jvm_enum_jumps_constr(pd: tprocdef);    begin      str_parse_method_impl('begin inherited create(__fpc_name,__fpc_ord); __fpc_fenumval:=__fpc_initenumval end;',pd,false);    end;  procedure implement_jvm_enum_fpcordinal(pd: tprocdef);    var      enumclass: tobjectdef;      enumdef: tenumdef;    begin      enumclass:=tobjectdef(pd.owner.defowner);      enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);      if not enumdef.has_jumps then        str_parse_method_impl('begin result:=ordinal end;',pd,false)      else        str_parse_method_impl('begin result:=__fpc_fenumval end;',pd,false);    end;  procedure implement_jvm_enum_fpcvalueof(pd: tprocdef);    var      enumclass: tobjectdef;      enumdef: tenumdef;      isclassmethod: boolean;    begin      isclassmethod:=        (po_classmethod in pd.procoptions) and        not(pd.proctypeoption in [potype_constructor,potype_destructor]);      enumclass:=tobjectdef(pd.owner.defowner);      enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);      { convert integer to corresponding enum instance: in case of no jumps        get it from the $VALUES array, otherwise from the __fpc_ord2enum        hashmap }      if not enumdef.has_jumps then        str_parse_method_impl('begin result:=__fpc_FVALUES[__fpc_int] end;',pd,isclassmethod)      else        str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(__fpc_ord2enum.get(JLInteger.valueOf(__fpc_int))) end;',pd,isclassmethod);    end;  function CompareEnumSyms(Item1, Item2: Pointer): Integer;    var      I1 : tenumsym absolute Item1;      I2 : tenumsym absolute Item2;    begin      Result:=I1.value-I2.value;    end;  procedure implement_jvm_enum_classconstr(pd: tprocdef);    var      enumclass: tobjectdef;      enumdef: tenumdef;      enumname,      str: ansistring;      i: longint;      enumsym: tenumsym;      orderedenums: tfpobjectlist;    begin      enumclass:=tobjectdef(pd.owner.defowner);      enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);      if not assigned(enumdef) then        internalerror(2011062305);      str:='begin ';      if enumdef.has_jumps then        { init hashmap for ordinal -> enum instance mapping; don't let it grow,          and set the capacity to the next prime following the total number of          enum elements to minimise the number of collisions }        str:=str+'__fpc_ord2enum:=JUHashMap.Create('+tostr(next_prime(enumdef.symtable.symlist.count))+',1.0);';      { iterate over all enum elements and initialise the class fields, and        store them in the values array. Since the java.lang.Enum doCompare        method is final and hardcoded to compare based on declaration order        (= java.lang.Enum.ordinal() value), we have to create them in order of        ascending FPC ordinal values (which may not be the same as the FPC        declaration order in case of jumps }      orderedenums:=tfpobjectlist.create(false);      for i:=0 to enumdef.symtable.symlist.count-1 do        orderedenums.add(enumdef.symtable.symlist[i]);      if enumdef.has_jumps then        orderedenums.sort(@CompareEnumSyms);      for i:=0 to orderedenums.count-1 do        begin          enumsym:=tenumsym(orderedenums[i]);          enumname:=enumsym.realname;          str:=str+enumsym.name+':=__FPC_TEnumClassAlias.Create('''+enumname+''','+tostr(i);          if enumdef.has_jumps then            str:=str+','+tostr(enumsym.value);          str:=str+');';          { alias for $VALUES array used internally by the JDK, and also by FPC            in case of no jumps }          str:=str+'__fpc_FVALUES['+tostr(i)+']:='+enumname+';';          if enumdef.has_jumps then            str:=str+'__fpc_ord2enum.put(JLInteger.valueOf('+tostr(enumsym.value)+'),'+enumname+');';        end;      orderedenums.free;      str:=str+' end;';      str_parse_method_impl(str,pd,true);    end;  procedure implement_jvm_enum_long2set(pd: tprocdef);    begin      str_parse_method_impl(        'var '+          'i, setval: jint;'+        'begin '+          'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+          'if __val<>0 then '+            'begin '+              '__setsize:=__setsize*8;'+              'for i:=0 to __setsize-1 do '+              // setsize-i because JVM = big endian              'if (__val and (jlong(1) shl (__setsize-i)))<>0 then '+                'result.add(fpcValueOf(i+__setbase));'+            'end '+          'end;',        pd,true);    end;  procedure implement_jvm_enum_bitset2set(pd: tprocdef);    begin      str_parse_method_impl(        'var '+          'i, setval: jint;'+        'begin '+          'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+          'i:=__val.nextSetBit(0);'+          'while i>=0 do '+            'begin '+              'setval:=-__fromsetbase;'+              'result.add(fpcValueOf(setval+__tosetbase));'+              'i:=__val.nextSetBit(i+1);'+            'end '+          'end;',        pd,true);    end;  procedure implement_jvm_enum_set2set(pd: tprocdef);    begin      str_parse_method_impl(        'var '+          'it: JUIterator;'+          'ele: FpcEnumValueObtainable;'+          'i: longint;'+        'begin '+          'result:=JUEnumSet.noneOf(JLClass(__FPC_TEnumClassAlias));'+          'it:=__val.iterator;'+          'while it.hasNext do '+            'begin '+              'ele:=FpcEnumValueObtainable(it.next);'+              'i:=ele.fpcOrdinal-__fromsetbase;'+              'result.add(fpcValueOf(i+__tosetbase));'+            'end '+          'end;',        pd,true);    end;  procedure implement_jvm_procvar_invoke(pd: tprocdef);    var      pvclass: tobjectdef;      procvar: tprocvardef;      paraname,str,endstr: ansistring;      pvs: tparavarsym;      paradef,boxdef,boxargdef: tdef;      i: longint;      firstpara: boolean;    begin      pvclass:=tobjectdef(pd.owner.defowner);      procvar:=tprocvardef(ttypesym(search_struct_member(pvclass,'__FPC_PROCVARALIAS')).typedef);      { the procvar wrapper class has a tmethod member called "method", whose        "code" field is a JLRMethod, and whose "data" field is the self pointer        if any (if none is required, it's ignored by the JVM, so there's no        problem with always passing it) }      { force extended syntax to allow calling invokeObjectFunc() without using        its result }      str:='';      endstr:='';      { create local pointer to result type for typecasting in case of an        implicit pointer type }      if jvmimplicitpointertype(procvar.returndef) then         str:=str+'type __FPC_returnptrtype = ^'+procvar.returndef.typename+';';      str:=str+'begin ';      { result handling (skip for generic definitions, we'll generate a new        version for the specialized definition) ) }      if not is_void(procvar.returndef) and         (procvar.returndef.typ<>undefineddef) then        begin          str:=str+'invoke:=';          if procvar.returndef.typ in [orddef,floatdef] then            begin              { primitivetype(boxtype(..).unboxmethod) }              jvmgetboxtype(procvar.returndef,boxdef,boxargdef,false);              str:=str+procvar.returndef.typename+'('+boxdef.typename+'(';              endstr:=').'+jvmgetunboxmethod(procvar.returndef)+')';            end          else if jvmimplicitpointertype(procvar.returndef) then            begin              str:=str+'__FPC_returnptrtype(';              { dereference }              endstr:=')^';            end          else            begin              str:=str+procvar.returndef.typename+'(';              endstr:=')';            end;        end;      str:=str+'invokeObjectFunc([';      { parameters are a constant array of jlobject }      firstpara:=true;      for i:=0 to procvar.paras.count-1 do        begin          { skip self/vmt/parentfp, passed separately }          pvs:=tparavarsym(procvar.paras[i]);          if ([vo_is_self,vo_is_vmt,vo_is_parentfp]*pvs.varoptions)<>[] then            continue;          if not firstpara then            str:=str+',';          firstpara:=false;          paraname:=pvs.realname;          paradef:=pvs.vardef;          { Pascalize hidden high parameter }          if vo_is_high_para in pvs.varoptions then            paraname:='high('+tparavarsym(procvar.paras[i-1]).realname+')'          else if vo_is_hidden_para in pvs.varoptions then            begin              if ([vo_is_range_check,vo_is_overflow_check]*pvs.varoptions)<>[] then                { ok, simple boolean parameters }              else                internalerror(2011072403);            end;          { var/out/constref parameters -> pass address through (same for            implicit pointer types) }          if paramanager.push_copyout_param(pvs.varspez,paradef,procvar.proccalloption) or             jvmimplicitpointertype(paradef) then            begin              paraname:='@'+paraname;              paradef:=java_jlobject;            end;          if paradef.typ in [orddef,floatdef] then            begin              { box primitive types; use valueOf() rather than create because it                can give better performance }              jvmgetboxtype(paradef,boxdef,boxargdef,false);              str:=str+boxdef.typename+'.valueOf('+boxargdef.typename+'('+paraname+'))'            end          else            str:=str+'JLObject('+paraname+')';        end;      str:=str+'])'+endstr+' end;';      str_parse_method_impl(str,pd,false)    end;  procedure implement_jvm_procvar_intconstr(pd: tprocdef);    var      pvdef: tprocvardef;    begin      { ideal, and most performant, would be to keep the interface instance        passed to the constructor around and always call its method directly        rather than working via reflection. Unfortunately, the procvar semantics        that allow directly modifying the procvar via typecasting it to a        tmethod make this very hard.        So for now we simply take the address of the interface instance's        method and assign it to the tmethod of this procvar }      pvdef:=tprocvardef(pd.skpara);      str_parse_method_impl('begin method:=System.TMethod(@__intf.'+pvdef.typesym.RealName+'Callback) end;',pd,false);    end;  procedure implement_jvm_virtual_clmethod(pd: tprocdef);    var      str: ansistring;      callpd: tprocdef;    begin      callpd:=tprocdef(pd.skpara);      str:='var pv: __fpc_virtualclassmethod_pv_t'+pd.unique_id_str+'; begin '        + 'pv:=@'+callpd.procsym.RealName+';';      if (pd.proctypeoption<>potype_constructor) and         not is_void(pd.returndef) then        str:=str+'result:=';      str:=str+'pv(';      addvisibleparameters(str,pd);      str:=str+') end;';      str_parse_method_impl(str,pd,true)    end;{$endif jvm}{$ifdef wasm}  procedure addvisibleparameterdeclarations(var str: ansistring; pd: tprocdef);    var      currpara: tparavarsym;      i: longint;      firstpara: boolean;    begin      firstpara:=true;      for i:=0 to pd.paras.count-1 do        begin          currpara:=tparavarsym(pd.paras[i]);          if not(vo_is_hidden_para in currpara.varoptions) then            begin              if not firstpara then                str:=str+';';              firstpara:=false;              case currpara.varspez of                vs_constref:                  str:=str+'constref ';                vs_out:                  str:=str+'out ';                vs_var:                  str:=str+'var ';                vs_const:                  str:=str+'const ';                vs_value:                  ;                else                  internalerror(2023061108);              end;              str:=str+currpara.realname;              if currpara.vardef.typ<>formaldef then                str:=str+':'+currpara.vardef.fulltypename;            end;        end;    end;  procedure implement_wasm_suspending(pd: tcpuprocdef; last: Boolean);    var      str: ansistring;      wrapper_name: ansistring;    begin      wrapper_name:=pd.suspending_wrapper_name;      if is_void(pd.returndef) then        str:='procedure '      else        str:='function ';      str:=str+wrapper_name+'(';      if last then        begin          addvisibleparameterdeclarations(str,pd);          if str[Length(str)]<>'(' then            str:=str+';';          str:=str+'__fpc_wasm_susp: WasmExternRef';        end      else        begin          str:=str+'__fpc_wasm_susp: WasmExternRef;';          addvisibleparameterdeclarations(str,pd);          if str[Length(str)]=';' then            delete(str,Length(str),1);        end;      str:=str+')';      if not is_void(pd.returndef) then        str:=str+': '+pd.returndef.fulltypename;      str:=str+'; external '''+pd.import_dll^+ ''' name '''+pd.import_name^+''';';      str_parse_method_impl(str,nil,false);      str:='var __fpc_wasm_suspender_copy:WasmExternRef; begin __fpc_wasm_suspender_copy:=__fpc_wasm_suspender; ';      if not is_void(pd.returndef) then        str:=str+' result:=';      str:=str+wrapper_name+'(__fpc_wasm_suspender_copy,';      addvisibleparameters(str,pd);      if str[Length(str)]=',' then        delete(str,Length(str),1);      str:=str+');';      str:=str+' __fpc_wasm_suspender:=__fpc_wasm_suspender_copy;';      str:=str+' end;';      str_parse_method_impl(str,pd,false);      exclude(pd.procoptions,po_external);    end;  function implement_wasm_promising_wrapper(pd: tcpuprocdef;last:boolean):tprocdef;    var      str: ansistring;      wrapper_name: ansistring;    begin      wrapper_name:=pd.promising_wrapper_name(last);      if is_void(pd.returndef) then        str:='procedure '      else        str:='function ';      str:=str+wrapper_name+'(';      if last then        begin          addvisibleparameterdeclarations(str,pd);          if str[Length(str)]<>'(' then            str:=str+';';          str:=str+'__fpc_wasm_susp: WasmExternRef';        end      else        begin          str:=str+'__fpc_wasm_susp: WasmExternRef;';          addvisibleparameterdeclarations(str,pd);          if str[Length(str)]=';' then            delete(str,Length(str),1);        end;      str:=str+')';      if not is_void(pd.returndef) then        str:=str+': '+pd.returndef.fulltypename;      str:=str+'; begin __fpc_wasm_suspender:=__fpc_wasm_susp;';      if not is_void(pd.returndef) then        str:=str+' result:=';      str:=str+pd.procsym.RealName+'(';      addvisibleparameters(str,pd);      if str[Length(str)]=',' then        delete(str,Length(str),1);      str:=str+'); end;';      str_parse_method_impl(str,nil,false,result);    end;  procedure implement_wasm_promising(pd: tcpuprocdef);    var      new_wrapper_pd: tprocdef;    begin      if pd.promising_first_export_name<>'' then        begin          new_wrapper_pd:=implement_wasm_promising_wrapper(pd,false);          current_asmdata.asmlists[al_exports].Concat(tai_export_name.create(pd.promising_first_export_name,new_wrapper_pd.mangledname,ie_Func));        end;      if pd.promising_last_export_name<>'' then        begin          new_wrapper_pd:=implement_wasm_promising_wrapper(pd,true);          current_asmdata.asmlists[al_exports].Concat(tai_export_name.create(pd.promising_last_export_name,new_wrapper_pd.mangledname,ie_Func));        end;    end;{$endif wasm}  procedure implement_field_getter(pd: tprocdef);    var      i: longint;      pvs: tparavarsym;      str: ansistring;      callthroughprop: tpropertysym;      propaccesslist: tpropaccesslist;      lastparanr: longint;      firstpara: boolean;    begin      callthroughprop:=tpropertysym(pd.skpara);      str:='begin result:='+callthroughprop.realname;      if ppo_hasparameters in callthroughprop.propoptions then        begin          if not callthroughprop.getpropaccesslist(palt_read,propaccesslist) then            internalerror(2012100701);          str:=str+'[';          firstpara:=true;          lastparanr:=tprocdef(propaccesslist.procdef).paras.count-1;          if ppo_indexed in callthroughprop.propoptions then            dec(lastparanr);          for i:=0 to lastparanr do            begin              { skip self/vmt/parentfp, passed implicitly }              pvs:=tparavarsym(tprocdef(propaccesslist.procdef).paras[i]);              if ([vo_is_self,vo_is_vmt,vo_is_parentfp]*pvs.varoptions)<>[] then                continue;              if not firstpara then                str:=str+',';              firstpara:=false;              str:=str+pvs.realname;            end;          str:=str+']';        end;      str:=str+'; end;';      str_parse_method_impl(str,pd,po_classmethod in pd.procoptions)    end;  procedure implement_field_setter(pd: tprocdef);    var      i, lastparaindex: longint;      pvs: tparavarsym;      paraname,  str: ansistring;      callthroughprop: tpropertysym;      propaccesslist: tpropaccesslist;      firstpara: boolean;    begin      callthroughprop:=tpropertysym(pd.skpara);      str:='begin '+callthroughprop.realname;      if not callthroughprop.getpropaccesslist(palt_write,propaccesslist) then        internalerror(2012100702);      if ppo_hasparameters in callthroughprop.propoptions then        begin          str:=str+'[';          firstpara:=true;          { last parameter is the value to be set, skip (only add index            parameters here) }          lastparaindex:=tprocdef(propaccesslist.procdef).paras.count-2;          if ppo_indexed in callthroughprop.propoptions then            dec(lastparaindex);          for i:=0 to lastparaindex do            begin              { skip self/vmt/parentfp/index, passed implicitly }              pvs:=tparavarsym(tprocdef(propaccesslist.procdef).paras[i]);              if ([vo_is_self,vo_is_vmt,vo_is_parentfp]*pvs.varoptions)<>[] then                continue;              if not firstpara then                str:=str+',';              firstpara:=false;              str:=str+pvs.realname;            end;          str:=str+']';        end;      { the value-to-be-set }      if assigned(propaccesslist.procdef) then        begin          pvs:=tparavarsym(tprocdef(propaccesslist.procdef).paras[tprocdef(propaccesslist.procdef).paras.count-1]);          paraname:=pvs.realname;        end      else        paraname:='__fpc_newval__';      str:=str+':='+paraname+'; end;';      str_parse_method_impl(str,pd,po_classmethod in pd.procoptions)    end;  procedure implement_block_invoke_procvar(pd: tprocdef);    var      str: ansistring;    begin      str:='';      str:='begin ';      if pd.returndef<>voidtype then        str:=str+'result:=';      str:=str+'__FPC_BLOCK_INVOKE_PV_TYPE(PFPC_Block_literal_complex_procvar(FPC_Block_Self)^.pv)(';      addvisibleparameters(str,pd);      str:=str+') end;';      str_parse_method_impl(str,pd,false);    end;  procedure implement_interface_wrapper(pd: tprocdef);    var      wrapperinfo: pskpara_interface_wrapper;      callthroughpd, tmpproc: tprocdef;      str: ansistring;      fileinfo: tfileposinfo;    begin      wrapperinfo:=pskpara_interface_wrapper(pd.skpara);      if not assigned(wrapperinfo) then        internalerror(2015090801);      callthroughpd:=tprocdef(wrapperinfo^.pd);      str:='begin ';      { self right now points to the VMT of interface inside the instance ->        adjust so it points to the start of the instance }      str:=str+'pointer(self):=pointer(self) - '+tostr(wrapperinfo^.offset)+';';      { now call through to the actual method }      if pd.returndef<>voidtype then        str:=str+'result:=';      str:=str+'&'+callthroughpd.procsym.realname+'(';      addvisibleparameters(str,pd);      str:=str+') end;';      { add dummy file info so we can step in/through it }      if pd.owner.iscurrentunit then        fileinfo:=pd.fileinfo      else        begin          fileinfo.moduleindex:=current_module.moduleid;          fileinfo.fileindex:=1;          fileinfo.line:=1;          fileinfo.column:=1;        end;      str_parse_method_impl_with_fileinfo(str,pd,fileinfo.fileindex,fileinfo.line,false,tmpproc);      dispose(wrapperinfo);      pd.skpara:=nil;    end;  procedure implement_call_no_parameters(pd: tprocdef);    var      callpd: tprocdef;      str: ansistring;      warningson,      isclassmethod: boolean;    begin      { avoid warnings about unset function results in these abstract wrappers }      warningson:=(status.verbosity and V_Warning)<>0;      setverbosity('W-');      str:='begin ';      callpd:=tprocdef(pd.skpara);      str:=str+def_unit_name_prefix_if_toplevel(callpd)+callpd.procsym.realname+'; end;';      isclassmethod:=        (po_classmethod in pd.procoptions) and        not(pd.proctypeoption in [potype_constructor,potype_destructor]);      str_parse_method_impl(str,pd,isclassmethod);      if warningson then        setverbosity('W+');    end;  function get_method_paramtype(vardef  : Tdef; asPointer : Boolean; out isAnonymousArrayDef : Boolean) : ansistring; forward;  function str_parse_method(str: ansistring; allowgenericid : boolean): tprocdef; forward;  function str_parse_method(str: ansistring): tprocdef;  begin     Result:=str_parse_method(str,false);  end;  procedure implement_invoke_helper(cn : string;pd: tprocdef; idx : integer);    var      sarg,str : ansistring;      pt, pn,d : shortstring;      sym : tsym;      aArg,argcount,i : integer;      isarray,haveresult : boolean;      para : tparavarsym;      hasopenarray, washigh: Boolean;    begin      str:='procedure __invoke_helper__';      pn:=pd.procsym.realname;      str:=str+cn+'__'+pn+'_'+tostr(idx);      for I:=1 to length(str) do        if str[i]='.' then          str[i]:='_';      str:=str+'(Instance : Pointer; Args : PPointer);'#10;      argCount:=0;      for i:=0 to pd.paras.Count-1 do        begin          para:=tparavarsym(pd.paras[i]);          if vo_is_hidden_para in para.varoptions then            continue;          inc(argCount);          if argCount=1 then            str:=str+'Type'#10;          pt:=get_method_paramtype(para.vardef,true,isArray);          if isArray then            begin            str:=str+'  tpa'+tostr(argcount)+' = '+pt+';'#10;            pt:='^tpa'+tostr(argcount);            end;          str:=str+'  tp'+tostr(argcount)+' = '+pt+';'#10;        end;      haveresult:=pd.returndef<>voidtype;      if haveresult then        begin        if argCount=0 then          str:=str+'Type'#10;        pt:=get_method_paramtype(pd.returndef ,true,isArray);        if isArray then          begin          str:=str+'  tra'+tostr(argcount)+' = '+pt+';'#10;          pt:='^tra';          end;        str:=str+'  tr = '+pt+';'#10;        end;      str:=str+'begin'#10'  ';      if haveResult then        str:=str+'TR(args[0])^:=';      str:=str+cn+'(Instance).'+pn+'(';      argCount:=0;      for i:=0 to pd.paras.Count-1 do        begin          para:=tparavarsym(pd.paras[i]);          if vo_is_hidden_para in para.varoptions then            continue;          inc(argCount);          sarg:=tostr(argcount);          if argCount>1 then            str:=str+',';          str:=str+'tp'+sarg+'(Args['+sarg+'])^';        end;      str:=str+');'#10;      str:=str+'end;'#10;      pd.invoke_helper:=str_parse_method(str,true);  end;  procedure add_synthetic_method_implementations_for_st(st: tsymtable);    var      i   : longint;      def : tdef;      pd  : tprocdef;      cn  : shortstring;    begin      for i:=0 to st.deflist.count-1 do        begin          def:=tdef(st.deflist[i]);          if (def.typ<>procdef) then            continue;          { skip methods when processing unit symtable }          if def.owner<>st then            continue;          pd:=tprocdef(def);          case pd.synthetickind of            tsk_none:              ;            tsk_anon_inherited:              implement_anon_inherited(pd);            tsk_jvm_clone:              implement_jvm_clone(pd);            tsk_record_deepcopy:              implement_record_deepcopy(pd);            tsk_record_initialize:              implement_record_initialize(pd);            tsk_empty,            { special handling for this one is done in tnodeutils.wrap_proc_body }            tsk_tcinit:              implement_empty(pd);            tsk_callthrough:              implement_callthrough(pd);            tsk_callthrough_nonabstract:              begin                if (pd.owner.defowner.typ<>objectdef) or                   (tobjectdef(pd.owner.defowner).abstractcnt=0) then                  implement_callthrough(pd)                else                  implement_empty(pd);              end;{$ifdef jvm}            tsk_jvm_enum_values:              implement_jvm_enum_values(pd);            tsk_jvm_enum_valueof:              implement_jvm_enum_valuof(pd);            tsk_jvm_enum_classconstr:              implement_jvm_enum_classconstr(pd);            tsk_jvm_enum_jumps_constr:              implement_jvm_enum_jumps_constr(pd);            tsk_jvm_enum_fpcordinal:              implement_jvm_enum_fpcordinal(pd);            tsk_jvm_enum_fpcvalueof:              implement_jvm_enum_fpcvalueof(pd);            tsk_jvm_enum_long2set:              implement_jvm_enum_long2set(pd);            tsk_jvm_enum_bitset2set:              implement_jvm_enum_bitset2set(pd);            tsk_jvm_enum_set2set:              implement_jvm_enum_set2set(pd);            tsk_jvm_procvar_invoke:              implement_jvm_procvar_invoke(pd);            tsk_jvm_procvar_intconstr:              implement_jvm_procvar_intconstr(pd);            tsk_jvm_virtual_clmethod:              implement_jvm_virtual_clmethod(pd);{$else}            tsk_jvm_enum_values,            tsk_jvm_enum_valueof,            tsk_jvm_enum_classconstr,            tsk_jvm_enum_jumps_constr,            tsk_jvm_enum_fpcordinal,            tsk_jvm_enum_fpcvalueof,            tsk_jvm_enum_long2set,            tsk_jvm_enum_bitset2set,            tsk_jvm_enum_set2set,            tsk_jvm_procvar_invoke,            tsk_jvm_procvar_intconstr,            tsk_jvm_virtual_clmethod:              internalerror(2011032801);{$endif jvm}{$ifdef wasm}            tsk_wasm_suspending_first:              implement_wasm_suspending(tcpuprocdef(pd),false);            tsk_wasm_suspending_last:              implement_wasm_suspending(tcpuprocdef(pd),true);            tsk_wasm_promising:              implement_wasm_promising(tcpuprocdef(pd));{$else wasm}            tsk_wasm_suspending_first,            tsk_wasm_suspending_last,            tsk_wasm_promising:              internalerror(2023061107);{$endif wasm}            tsk_field_getter:              implement_field_getter(pd);            tsk_field_setter:              implement_field_setter(pd);            tsk_block_invoke_procvar:              implement_block_invoke_procvar(pd);            tsk_interface_wrapper:              implement_interface_wrapper(pd);            tsk_call_no_parameters:              implement_call_no_parameters(pd);            tsk_invoke_helper:              begin                if (pd.owner.defowner) is tobjectdef  then                  cn:=tobjectdef(def.owner.defowner).GetTypeName                else                  internalerror(2023061107);                implement_invoke_helper(cn,pd,i);              end;          end;        end;    end;  function get_method_paramtype(vardef  : Tdef; asPointer : Boolean; out isAnonymousArrayDef : Boolean) : ansistring;  var    p : integer;    arrdef : tarraydef absolute vardef;  begin    {      None of the existing routines fulltypename,OwnerHierarchyName,FullOwnerHierarchyName,typename      results in a workable definition for open array parameters.    }    isAnonymousArrayDef:=false;    if asPointer and (vardef.typ=formaldef) then      exit('pointer');    if (vardef is tprocvardef) then      begin      result:=vardef.fullownerhierarchyname(false);      if Assigned(vardef.typesym) then        Result:=Result+(vardef.typesym.Name);      end    else if not (vardef is tarraydef) then      result:=vardef.fulltypename    else      begin      if (ado_isarrayofconst in arrdef.arrayoptions) then        begin          if asPointer then            Result:='Array of TVarRec'          else            result:='Array Of Const';          asPointer:=False;          isAnonymousArrayDef:=true;        end      else if (ado_OpenArray in arrdef.arrayoptions) then        begin        result:='Array of '+arrdef.elementdef.fulltypename;        asPointer:=False;        isAnonymousArrayDef:=true;        end      else        begin        result:=vardef.fulltypename;        end;      end;    // ansistring(0) -> ansistring    p:=pos('(',result);    if p=0 then      p:=pos('[',result);    if p>0 then      result:=copy(result,1,p-1);    if asPointer then      Result:='^'+Result;  end;  function get_method_paramtype(vardef  : Tdef; asPointer : Boolean) : ansistring;  var    ad : boolean;  begin    result:=get_method_paramtype(vardef,aspointer,ad);  end;  function create_intf_method_args(p : tprocdef; out argcount: integer) : ansistring;  const    varspezprefixes : array[tvarspez] of shortstring =      ('','const','var','out','constref','final');  var    i : integer;    s : string;    para : tparavarsym;  begin    result:='';    argCount:=0;    for i:=0 to p.paras.Count-1 do      begin      para:=tparavarsym(p.paras[i]);      if vo_is_hidden_para in para.varoptions then        continue;      if Result<>'' then        Result:=Result+';';      inc(argCount);      result:=result+varspezprefixes[para.varspez]+' p'+tostr(argcount);      if Assigned(para.vardef) and not (para.vardef is tformaldef) then        result:=Result+' : '+get_method_paramtype(para.vardef,false);      end;    if Result<>'' then      Result:='('+Result+')';  end;  function generate_thunkclass_name(acount: Integer; objdef : tobjectdef) : shortstring;  var    cn : shortstring;    i : integer;  begin    cn:=ObjDef.GetTypeName;    for i:=0 to Length(cn) do      begin      if cn[i]='.' then        cn[i]:='_'      else if (cn[i]='<') or (cn[i]='>') then        cn[i]:='_';      end;    result:='_t_hidden'+tostr(acount)+cn;  end;  function get_thunkclass_interface_vmtoffset(objdef : tobjectdef) : integer;  var    i,j,offs : integer;    sym : tsym;    proc : tprocsym absolute sym;    pd : tprocdef;  begin    offs:=maxint;    for I:=0 to objdef.symtable.symList.Count-1 do      begin      sym:=tsym(objdef.symtable.symList[i]);      if Not assigned(sym) then        continue;      if (Sym.typ<>procsym) then        continue;      for j:=0 to proc.ProcdefList.Count-1 do        begin        pd:=tprocdef(proc.ProcdefList[j]);        if pd.extnumber<offs then          offs:=pd.extnumber;        end;      end;      if offs=maxint then        offs:=0;      result:=offs;    end;  // return parent Interface def, but skip iunknown.  function getparent_interface_def(odef : tobjectdef) : tobjectdef;  begin    if (odef.getparentdef is tobjectdef) then      begin      result:=odef.getparentdef as tobjectdef;      if result=interface_iunknown then        result:=Nil;      end    else      result:=nil;  end;  procedure implement_interface_thunkclass_decl(cn : shortstring; objdef : tobjectdef);  var    parentname,str : ansistring;    sym : tsym;    proc : tprocsym absolute sym;    pd : tprocdef;    odef,def : tobjectdef;    offs,argcount,i,j : integer;    intfDef : tobjectdef;  begin    str:='type '#10;    odef:=getparent_interface_def(objdef);    if (oDef=Nil) or (oDef.hiddenclassdef=Nil) then      parentname:='TInterfaceThunk'    else      parentname:=odef.hiddenclassdef.GetTypeName;    str:=str+cn+' = class('+parentname+','+objdef.GetTypeName+')'#10;    str:=str+' protected '#10;    Intfdef:=objdef;    Repeat      if not IntfDef.is_generic then        for I:=0 to intfdef.symtable.symList.Count-1 do          begin          sym:=tsym(intfdef.symtable.symList[i]);          if Not assigned(sym) then            continue;          if (Sym.typ<>procsym) then            continue;          for j:=0 to proc.ProcdefList.Count-1 do            begin            pd:=tprocdef(proc.ProcdefList[j]);            if pd.returndef<>voidtype then              str:=str+'function '            else              str:=str+'procedure ';            str:=str+proc.RealName;            str:=str+create_intf_method_args(pd,argcount);            if pd.returndef<>voidtype then              str:=str+' : '+get_method_paramtype(pd.returndef,false);            str:=str+';'#10;            end;          end;      // Check parent class      intfdef:=getparent_interface_def(intfdef);      // If we already have a hidden class def for it, no need to continue      if (IntfDef<>nil) and (IntfDef.hiddenclassdef<>nil) then        IntfDef:=Nil;    until intfdef=nil;    offs:=get_thunkclass_interface_vmtoffset(objdef);    if offs>0 then      begin      str:=str+'public '#10;      str:=str+'  function InterfaceVMTOffset : word; override;'#10;      end;    str:=str+' end;'#10;    def:=str_parse_objecttypedef(cn,str);    if assigned(def) then      begin      def.created_in_current_module:=true;      if not def.typesym.is_registered then        def.typesym.register_sym;      def.buildderef;      include(def.objectoptions,oo_can_have_published);      end;    objdef.hiddenclassdef:=def;  end;  function str_parse_method(str: ansistring; allowgenericid : boolean): tprocdef;   var     oldparse_only: boolean;     tmpstr: ansistring;     flags : tread_proc_flags;     oldallow : boolean;   begin    Message1(parser_d_internal_parser_string,str);    oldparse_only:=parse_only;    parse_only:=false;    { "const" starts a new kind of block and hence makes the scanner return }    str:=str+'const;';    block_type:=bt_none;    { inject the string in the scanner }    oldallow:=current_scanner.allowgenericid;    current_scanner.allowgenericid:=allowgenericid;    current_scanner.substitutemacro('hidden_interface_method',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);    current_scanner.readtoken(false);    Result:=read_proc([],Nil);    parse_only:=oldparse_only;    { remove the temporary macro input file again }    current_scanner.closeinputfile;    current_scanner.nextfile;    current_scanner.tempopeninputfile;    current_scanner.allowgenericid:=oldallow;   end;  procedure implement_interface_thunkclass_impl_method(cn : shortstring; objdef : tobjectdef; proc : tprocsym; pd : tprocdef);  var    rest,str : ansistring;    pn,d : shortstring;    sym : tsym;    aArg,argcount,i : integer;    haveresult : boolean;    para : tparavarsym;    hasopenarray, washigh: Boolean;  begin    rest:='';    str:='';    if pd.returndef<>voidtype then      str:=str+'function '    else      str:=str+'procedure ';    pn:=proc.RealName;    str:=str+cn+'.'+pn;    str:=str+create_intf_method_args(pd,argcount);    haveresult:=pd.returndef<>voidtype;    if haveresult then      begin      rest:=get_method_paramtype(pd.returndef,false);      str:=str+' : '+rest;      end;    str:=str+';'#10;    str:=str+'var '#10;    str:=str+'  data : array[0..'+tostr(argcount)+'] of System.TInterfaceThunk.TArgData;'#10;    if haveresult then      str:=str+'  res : '+rest+';'#10;    str:=str+'begin'#10;    // initialize result.    if HaveResult then      begin      str:=Str+'  data[0].addr:=@Res;'#10;      str:=Str+'  data[0].info:=TypeInfo(Res);'#10;      end    else      begin      str:=Str+'  data[0].addr:=nil;'#10;      str:=Str+'  data[0].idx:=-1;'#10;      end;    str:=Str+'  data[0].idx:=-1;'#10;    str:=Str+'  data[0].ahigh:=-1;'#10;    // Fill rest of data    aArg:=0;    washigh:=false;    d:='0';    for i:=0 to pd.paras.Count-1 do      begin      para:=tparavarsym(pd.paras[i]);      // previous was open array. Record high      if (i>1) then        begin        WasHigh:=(vo_is_high_para in para.varoptions);        if Washigh then          // D is still value of previous (real) parameter          str:=str+'  data['+d+'].ahigh:=High(p'+d+');'#10        else          str:=str+'  data['+d+'].ahigh:=-1;'#10;        end;      if vo_is_hidden_para in para.varoptions then        continue;      inc(aArg);      d:=tostr(aArg);      Str:=Str+'  data['+d+'].addr:=@p'+d+';'#10;      Str:=Str+'  data['+d+'].idx:='+tostr(i)+';'#10;      if Assigned(para.vardef) and not (para.vardef is tformaldef) then        Str:=Str+'  data['+d+'].info:=TypeInfo(p'+d+');'#10      else        Str:=Str+'  data['+d+'].info:=Nil;'#10      end;    // if last was not high, set to sentinel.    if not WasHigh then      str:=str+'  data['+d+'].ahigh:=-1;'#10;    str:=str+'  Thunk('+tostr(pd.extnumber)+','+tostr(argcount)+',@Data);'#10;    if HaveResult then      str:=str+'  Result:=res;'#10;    str:=str+'end;'#10;    pd:=str_parse_method(str,true);  end;  procedure implement_thunkclass_interfacevmtoffset(cn : shortstring; objdef : tobjectdef; offs : integer);  var    str : ansistring;  begin    str:='function '+cn+'.InterfaceVMTOffset : word;'#10;    str:=str+'begin'#10;    str:=str+'  result:='+toStr(offs)+';'#10;    str:=str+'end;'#10;    str_parse_method(str);  end;  procedure implement_interface_thunkclass_impl(cn: shortstring; objdef : tobjectdef);  var    str : ansistring;    sym : tsym;    proc : tprocsym absolute sym;    pd : tprocdef;    offs,i,j : integer;    intfDef : tobjectdef;  begin    offs:=get_thunkclass_interface_vmtoffset(objdef);    if offs>0 then      implement_thunkclass_interfacevmtoffset(cn,objdef,offs);    intfDef:=objdef;    repeat      for I:=0 to intfdef.symtable.symList.Count-1 do        begin        sym:=tsym(intfdef.symtable.symList[i]);        if Not assigned(sym) then          continue;        if (Sym.typ<>procsym) then          continue;        for j:=0 to proc.ProcdefList.Count-1 do          begin          pd:=tprocdef(proc.ProcdefList[j]);          implement_interface_thunkclass_impl_method(cn,intfdef,proc,pd);          end;        end;      // Check parent class.      intfdef:=getparent_interface_def(intfdef);      // If we already have a hidden class def for it, no need to continue      if (intfdef<>Nil) and (IntfDef.hiddenclassdef<>nil) then        IntfDef:=Nil;    until (intfdef=Nil);  end;  procedure add_synthetic_interface_classes_for_st(st : tsymtable; gen_intf, gen_impl : boolean);  var    i   : longint;    def : tdef;    objdef : tobjectdef absolute def;    recdef : trecorddef absolute def;    sstate: tscannerstate;    cn : shortstring;    isDelphiMode : boolean;    oldsettings: tmodeswitches;  begin    { skip if any errors have occurred, since then this can only cause more      errors }    if ErrorCount<>0 then      exit;    isDelphiMode:=(m_delphi in current_settings.modeswitches);    replace_scanner('hiddenclass_impl',sstate);    sstate.new_scanner.allowgenericid:=true;    if isDelphiMode then      begin      oldsettings:=current_settings.modeswitches;      current_settings.modeswitches:=current_settings.modeswitches+[m_delphi]-[m_objfpc];      end;    for i:=0 to st.deflist.count-1 do      begin      def:=tdef(st.deflist[i]);      if (def.typ<>objectdef) then        continue;      if not (objdef.objecttype in objecttypes_with_thunk) then        continue;      if not (oo_can_have_published in objdef.objectoptions) then        continue;      // need to add here extended rtti check when it is available      cn:=generate_thunkclass_name(i,objdef);      if gen_intf then        implement_interface_thunkclass_decl(cn,objdef);      if gen_impl then        implement_interface_thunkclass_impl(cn,objdef);      end;    restore_scanner(sstate);    // Recurse for interfaces defined in a type section of a class/record.    for i:=0 to st.deflist.count-1 do      begin      def:=tdef(st.deflist[i]);      if (def.typ=objectdef) and (objdef.objecttype=odt_class) then        add_synthetic_interface_classes_for_st(objdef.symtable,gen_intf,gen_impl)      else if (def.typ=recorddef) and (m_advanced_records in current_settings.modeswitches) then        add_synthetic_interface_classes_for_st(recdef.symtable,gen_intf,gen_impl);      end;  end;  procedure add_synthetic_method_implementations(st: tsymtable);    var      i: longint;      def: tdef;      sstate: tscannerstate;    begin      { skip if any errors have occurred, since then this can only cause more        errors }      if ErrorCount<>0 then        exit;      replace_scanner('synthetic_impl',sstate);      add_synthetic_method_implementations_for_st(st);      for i:=0 to st.deflist.count-1 do        begin          def:=tdef(st.deflist[i]);          if (def.typ=procdef) and             assigned(tprocdef(def).localst) and             { not true for the "main" procedure, whose localsymtable is the staticsymtable }             (tprocdef(def).localst.symtabletype=localsymtable) then            add_synthetic_method_implementations(tprocdef(def).localst)          else if ((def.typ=objectdef) and                   not(oo_is_external in tobjectdef(def).objectoptions)) or                  (def.typ=recorddef) then           begin            { also complete nested types }            add_synthetic_method_implementations(tabstractrecorddef(def).symtable);           end;        end;      restore_scanner(sstate);    end;  function create_procdef_alias(pd: tprocdef; const newrealname: string; const newmangledname: TSymStr; newparentst: tsymtable; newstruct: tabstractrecorddef;      sk: tsynthetickind; skpara: pointer): tprocdef;    begin      { bare copy so we don't copy the aliasnames (specify prefix for        parameter names so we don't get issues in the body in case        we e.g. reference system.initialize and one of the parameters        is called "system") }      result:=tprocdef(pd.getcopyas(procdef,pc_bareproc,'__FPCW_',true));      { set the mangled name to the wrapper name }      result.setmangledname(newmangledname);      { finish creating the copy }      finish_copied_procdef(result,newrealname,newparentst,newstruct);      { insert hidden high parameters }      result.parast.SymList.ForEachCall(@insert_hidden_para,result);      { now insert self/vmt }      insert_self_and_vmt_para(result);      { and the function result }      insert_funcret_para(result);      { recalculate the parameters now that we've added the missing ones }      result.calcparas;      { set the info required to generate the implementation }      result.synthetickind:=sk;      result.skpara:=skpara;    end;  procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);    var      sym: tsym;      parasym: tparavarsym;      ps: tprocsym;      stname: string;      i: longint;    begin      { add generic flag if required }      if assigned(newstruct) and         (df_generic in newstruct.defoptions) then        include(pd.defoptions,df_generic);      { associate the procdef with a procsym in the owner }      if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then        stname:=upper(realname)      else        stname:=lower(realname);      sym:=tsym(newparentst.find(stname));      if assigned(sym) then        begin          if sym.typ<>procsym then            internalerror(2011040601);          ps:=tprocsym(sym);        end      else        begin          ps:=cprocsym.create(realname);          newparentst.insertsym(ps);        end;      pd.procsym:=ps;      pd.struct:=newstruct;      { in case of methods, replace the special parameter types with new ones }      if assigned(newstruct) then        begin          symtablestack.push(pd.parast);          { may not be assigned in case we converted a procvar into a procdef }          if assigned(pd.paras) then            begin              for i:=0 to pd.paras.count-1 do                begin                  parasym:=tparavarsym(pd.paras[i]);                  if vo_is_self in parasym.varoptions then                    begin                      if parasym.vardef.typ=classrefdef then                        parasym.vardef:=cclassrefdef.create(newstruct)                      else                        parasym.vardef:=newstruct;                    end                end;            end;          { also fix returndef in case of a constructor }          if pd.proctypeoption=potype_constructor then            pd.returndef:=newstruct;          symtablestack.pop(pd.parast);        end;      pd.calcparas;      proc_add_definition(pd);    end;  function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;    var      fieldvardef,      nestedvarsdef: tdef;      nestedvarsst: tsymtable;      initcode: tnode;      old_filepos: tfileposinfo;      symname,      symrealname: TSymStr;      highsym: tabstractvarsym;    begin      nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;      { redirect all aliases for the function result also to the function        result }      if vo_is_funcret in tabstractvarsym(sym).varoptions then        begin          symname:='result';          symrealname:='$result'        end      else        begin          symname:=sym.name;          symrealname:=sym.EscapedRealName;        end;      result:=search_struct_member(trecorddef(nestedvarsdef),symname);      if not assigned(result) then        begin          { mark that this symbol is mirrored in the parentfpstruct }          tabstractnormalvarsym(sym).inparentfpstruct:=true;          { add field to the struct holding all locals accessed            by nested routines }          nestedvarsst:=trecorddef(nestedvarsdef).symtable;          { indicate whether or not this is a var/out/constref/... parameter }          if addrparam then            fieldvardef:=cpointerdef.getreusable(vardef)          else            fieldvardef:=vardef;          result:=cfieldvarsym.create(symrealname,vs_value,fieldvardef,[]);          nestedvarsst.insertsym(result);          trecordsymtable(nestedvarsst).addfield(tfieldvarsym(result),vis_public);          { add initialization with original value if it's a parameter }          if (sym.typ=paravarsym) then            begin              old_filepos:=current_filepos;              fillchar(current_filepos,sizeof(current_filepos),0);              initcode:=cloadnode.create(sym,sym.owner);              { indicate that this load should not be transformed into a load                from the parentfpstruct, but instead should load the original                value }              include(initcode.flags,nf_internal);              { in case it's a var/out/constref parameter, store the address of the                parameter in the struct }              if addrparam then                begin                  initcode:=caddrnode.create_internal(initcode);                  include(taddrnode(initcode).addrnodeflags,anf_typedaddr);                end;              initcode:=cassignmentnode.create(                csubscriptnode.create(result,cloadnode.create(pd.parentfpstruct,pd.parentfpstruct.owner)),                initcode);              tblocknode(pd.parentfpinitblock).left:=cstatementnode.create                (initcode,tblocknode(pd.parentfpinitblock).left);              current_filepos:=old_filepos;              { also add the associated high para, if any. It may not be accessed                during code generation, and we need to catch 'em all (TM) during                the typecheck/firstpass }              highsym:=get_high_value_sym(tparavarsym(sym));              if assigned(highsym) then                maybe_add_sym_to_parentfpstruct(pd, highsym, highsym.vardef, false);            end;        end;    end;  procedure redirect_parentfpstruct_local_syms(pd: tprocdef);    var      nestedvarsdef: trecorddef;      sl: tpropaccesslist;      fsym,      lsym,      aliassym: tsym;      i: longint;    begin      nestedvarsdef:=trecorddef(tlocalvarsym(pd.parentfpstruct).vardef);      for i:=0 to nestedvarsdef.symtable.symlist.count-1 do        begin          fsym:=tsym(nestedvarsdef.symtable.symlist[i]);          if fsym.typ<>fieldvarsym then            continue;          lsym:=tsym(pd.localst.find(fsym.name));          if not assigned(lsym) then            lsym:=tsym(pd.parast.find(fsym.name));          if not assigned(lsym) then            internalerror(2011060408);          { add an absolute variable that redirects to the field }          sl:=tpropaccesslist.create;          sl.addsym(sl_load,pd.parentfpstruct);          sl.addsym(sl_subscript,tfieldvarsym(fsym));          aliassym:=cabsolutevarsym.create_ref(lsym.EscapedRealName,tfieldvarsym(fsym).vardef,sl);          { hide the original variable (can't delete, because there            may be other loadnodes that reference it)            -- only for locals; hiding parameters changes the            function signature }          if lsym.typ<>paravarsym then            hidesym(lsym);          { insert the absolute variable in the localst of the            routine; ignore duplicates, because this will also check the            parasymtable and we want to override parameters with our local            versions }          pd.localst.insertsym(aliassym,false);        end;    end;  function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;    var      nestedvarsdef: tdef;    begin      nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;      result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);    end;  procedure finish_parentfpstruct(pd: tprocdef);    begin      trecordsymtable(trecorddef(tlocalvarsym(pd.parentfpstruct).vardef).symtable).addalignmentpadding;    end;  function make_field_static(recst: tsymtable; fieldvs: tfieldvarsym): tstaticvarsym;    var      static_name: string;      hstaticvs: tstaticvarsym;      tmp: tabsolutevarsym;      sl: tpropaccesslist;    begin      include(fieldvs.symoptions,sp_static);      { generate the symbol which reserves the space }      static_name:=lower(generate_nested_name(recst,'_'))+'_'+fieldvs.name;      hstaticvs:=cstaticvarsym.create_from_fieldvar(static_name,fieldvs);{$ifdef jvm}      { for the JVM, static field accesses are name-based and        hence we have to keep the original name of the field.        Create a staticvarsym instead of a fieldvarsym so we can        nevertheless use a loadn instead of a subscriptn though,        since a subscriptn requires something to subscript and        there is nothing in this case (class+field name will be        encoded in the mangled symbol name) }      recst.insertsym(hstaticvs);      { only set the staticvarsym's basename (= field name, without any        mangling), because generating the fully mangled name right now can        result in a wrong string in case the field's type is a forward        declared class whose external name will change when the actual        definition is parsed }      if (vo_has_mangledname in fieldvs.varoptions) then        hstaticvs.set_mangledbasename(fieldvs.externalname^)      else        hstaticvs.set_mangledbasename(fieldvs.realname);      { for definition in class file }      hstaticvs.visibility:=fieldvs.visibility;{$else jvm}      include(hstaticvs.symoptions,sp_internal);      if df_generic in tdef(recst.defowner).defoptions then        tabstractrecordsymtable(recst).insertsym(hstaticvs)      else        tdef(tabstractrecordsymtable(recst).defowner).get_top_level_symtable(false).insertsym(hstaticvs);{$endif jvm}      { generate the symbol for the access }      sl:=tpropaccesslist.create;      sl.addsym(sl_load,hstaticvs);      { do *not* change the visibility of this absolutevarsym from vis_public        to anything else, because its visibility is used by visibility checks        after turning a class property referring to a class variable into a        load node (handle_staticfield_access -> searchsym_in_class ->        is_visible_for_object), which means that the load will fail if this        symbol is e.g. "strict private" while the property is public }      tmp:=cabsolutevarsym.create_ref('$'+static_name,fieldvs.vardef,sl);      recst.insertsym(tmp);      result:=hstaticvs;    end;  procedure call_through_new_name(orgpd: tprocdef; const newname: TSymStr);    var      newpd: tprocdef;    begin      { we have a forward declaration like         procedure test; (in the unit interface or "forward")        and then an implementation like         procedure test; external name 'something';        To solve this, we create a new external procdef for the        implementation, and then generate a procedure body for the original        one that calls through to the external procdef. This is necessary        because there may already be references to the mangled name for the        non-external "test".      }      { prefixing the parameters here is useless, because the new procdef will        just be an external declaration without a body }      newpd:=tprocdef(orgpd.getcopyas(procdef,pc_bareproc,'',true));      insert_funcret_para(newpd);      newpd.procoptions:=newpd.procoptions+orgpd.procoptions*[po_external,po_has_importname,po_has_importdll];      stringdispose(orgpd.import_name);      stringdispose(orgpd.import_dll);      orgpd.import_nr:=0;      newpd.setmangledname(newname);      finish_copied_procdef(newpd,'__FPC_IMPL_EXTERNAL_REDIRECT_'+newname,current_module.localsymtable,nil);      newpd.forwarddef:=false;      { ideally we would prefix the parameters of the original routine here, but since it        can be an interface definition, we cannot do that without risking to change the        interface crc }      orgpd.skpara:=newpd;      orgpd.synthetickind:=tsk_callthrough;      orgpd.procoptions:=orgpd.procoptions-[po_external,po_has_importname,po_has_importdll];      orgpd.forwarddef:=true;    end;  function generate_pkg_stub(pd:tprocdef):tnode;    begin      if target_info.system in systems_all_windows+systems_nativent then        begin          insert_funcret_local(pd);          result:=cassignmentnode.create(                      cloadnode.create(pd.funcretsym,pd.localst),                      cordconstnode.create(1,bool32type,false)                    );        end      else        result:=cnothingnode.create;    end;  procedure generate_attr_constrs(attrs:tfpobjectlist);    var      ps : tprocsym;      pd : tprocdef;      pi : tcgprocinfo;      i : sizeint;      attr : trtti_attribute;    begin      if attrs.count=0 then        exit;      { if this isn't set then this unit shouldn't have any attributes }      if not assigned(class_tcustomattribute) then        internalerror(2019071003);      for i:=0 to attrs.count-1 do        begin          attr:=trtti_attribute(attrs[i]);          {Generate a procsym for main}          ps:=cprocsym.create('$rttiattrconstr$'+tostr(i));          { always register the symbol }          ps.register_sym;          { the RTTI always references this symbol }          inc(ps.refs);          current_module.localsymtable.insertsym(ps);          pd:=cprocdef.create(normal_function_level,true);          { always register the def }          pd.register_def;          pd.procsym:=ps;          ps.ProcdefList.Add(pd);          { set procdef options }          pd.proctypeoption:=potype_function;          pd.proccalloption:=pocall_default;          include(pd.procoptions,po_hascallingconvention);          pd.returndef:=class_tcustomattribute;          insert_funcret_para(pd);          pd.calcparas;          pd.forwarddef:=false;          pd.aliasnames.insert(pd.mangledname);          handle_calling_convention(pd,hcc_default_actions_impl);          { set procinfo and current_procinfo.procdef }          pi:=tcgprocinfo(cprocinfo.create(nil));          pi.procdef:=pd;          { we always do a call, namely to the constructor }          include(pi.flags,pi_do_call);          insert_funcret_local(pd);          pi.code:=cassignmentnode.create(                      cloadnode.create(pd.funcretsym,pd.localst),                      attr.constructorcall.getcopy                    );          pi.generate_code;          attr.constructorpd:=pd;        end;    end;end.
 |