123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523 |
- {
- $Id$
- Copyright (c) 1998-2002 by Florian Klaempfl
- This file implements the node for sub procedure calling.
- 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 ncal;
- {$i fpcdefs.inc}
- interface
- uses
- cutils,cclasses,
- globtype,cpuinfo,
- paramgr,parabase,
- node,nbas,nutils,
- {$ifdef state_tracking}
- nstate,
- {$endif state_tracking}
- symbase,symtype,symsym,symdef,symtable;
- type
- tcallnodeflag = (
- cnf_restypeset,
- cnf_return_value_used,
- cnf_inherited,
- cnf_anon_inherited,
- cnf_new_call,
- cnf_dispose_call,
- cnf_member_call { called with implicit methodpointer tree }
- );
- tcallnodeflags = set of tcallnodeflag;
- tcallnode = class(tbinarynode)
- private
- {$ifndef VER1_0}
- { info for inlining }
- inlinelocals: array of tnode;
- {$endif VER1_0}
- { number of parameters passed from the source, this does not include the hidden parameters }
- paralength : smallint;
- function gen_self_tree_methodpointer:tnode;
- function gen_self_tree:tnode;
- function gen_vmt_tree:tnode;
- procedure bind_parasym;
- { function return node, this is used to pass the data for a
- ret_in_param return value }
- _funcretnode : tnode;
- procedure setfuncretnode(const returnnode: tnode);
- procedure convert_carg_array_of_const;
- procedure order_parameters;
- procedure createinlineparas(var createstatement, deletestatement: tstatementnode);
- function replaceparaload(var n: tnode; arg: pointer): foreachnoderesult;
- {$ifndef VER1_0}
- procedure createlocaltemps(p:TNamedIndexItem;arg:pointer);
- {$endif VER1_0}
- protected
- pushedparasize : longint;
- public
- { the symbol containing the definition of the procedure }
- { to call }
- symtableprocentry : tprocsym;
- symtableprocentryderef : tderef;
- { symtable where the entry was found, needed for with support }
- symtableproc : tsymtable;
- { the definition of the procedure to call }
- procdefinition : tabstractprocdef;
- procdefinitionderef : tderef;
- { tree that contains the pointer to the object for this method }
- methodpointerinit,
- methodpointerdone : tblocknode;
- methodpointer : tnode;
- { inline function body }
- inlinecode : tnode;
- { varargs parasyms }
- varargsparas : tvarargsparalist;
- { node that specifies where the result should be put for calls }
- { that return their result in a parameter }
- property funcretnode: tnode read _funcretnode write setfuncretnode;
- { separately specified resulttype for some compilerprocs (e.g. }
- { you can't have a function with an "array of char" resulttype }
- { the RTL) (JM) }
- restype: ttype;
- callnodeflags : tcallnodeflags;
- { only the processor specific nodes need to override this }
- { constructor }
- constructor create(l:tnode; v : tprocsym;st : tsymtable; mp: tnode; callflags:tcallnodeflags);virtual;
- constructor create_procvar(l,r:tnode);
- constructor createintern(const name: string; params: tnode);
- constructor createinternres(const name: string; params: tnode; const res: ttype);
- constructor createinternreturn(const name: string; params: tnode; returnnode : tnode);
- destructor destroy;override;
- constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
- procedure ppuwrite(ppufile:tcompilerppufile);override;
- procedure buildderefimpl;override;
- procedure derefimpl;override;
- function getcopy : tnode;override;
- { Goes through all symbols in a class and subclasses and calls
- verify abstract for each .
- }
- procedure verifyabstractcalls;
- { called for each definition in a class and verifies if a method
- is abstract or not, if it is abstract, give out a warning
- }
- procedure verifyabstract(p : tnamedindexitem;arg:pointer);
- procedure insertintolist(l : tnodelist);override;
- function pass_1 : tnode;override;
- function det_resulttype:tnode;override;
- {$ifdef state_tracking}
- function track_state_pass(exec_known:boolean):boolean;override;
- {$endif state_tracking}
- function docompare(p: tnode): boolean; override;
- procedure printnodedata(var t:text);override;
- function para_count:longint;
- private
- AbstractMethodsList : TStringList;
- end;
- tcallnodeclass = class of tcallnode;
- tcallparaflag = (
- cpf_is_colon_para,
- cpf_varargs_para { belongs this para to varargs }
- );
- tcallparaflags = set of tcallparaflag;
- tcallparanode = class(tbinarynode)
- public
- callparaflags : tcallparaflags;
- parasym : tparavarsym;
- used_by_callnode : boolean;
- { only the processor specific nodes need to override this }
- { constructor }
- constructor create(expr,next : tnode);virtual;
- destructor destroy;override;
- constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
- procedure ppuwrite(ppufile:tcompilerppufile);override;
- function getcopy : tnode;override;
- procedure insertintolist(l : tnodelist);override;
- procedure get_paratype;
- procedure insert_typeconv(do_count : boolean);
- procedure det_registers;
- procedure firstcallparan;
- procedure secondcallparan;virtual;abstract;
- function docompare(p: tnode): boolean; override;
- procedure printnodetree(var t:text);override;
- end;
- tcallparanodeclass = class of tcallparanode;
- function reverseparameters(p: tcallparanode): tcallparanode;
- var
- ccallnode : tcallnodeclass;
- ccallparanode : tcallparanodeclass;
- { Current callnode, this is needed for having a link
- between the callparanodes and the callnode they belong to }
- aktcallnode : tcallnode;
- implementation
- uses
- systems,
- verbose,globals,
- symconst,defutil,defcmp,
- htypechk,pass_1,
- ncnv,nld,ninl,nadd,ncon,nmem,
- procinfo,
- cgbase
- ;
- type
- tobjectinfoitem = class(tlinkedlistitem)
- objinfo : tobjectdef;
- constructor create(def : tobjectdef);
- end;
- {****************************************************************************
- HELPERS
- ****************************************************************************}
- function reverseparameters(p: tcallparanode): tcallparanode;
- var
- hp1, hp2: tcallparanode;
- begin
- hp1:=nil;
- while assigned(p) do
- begin
- { pull out }
- hp2:=p;
- p:=tcallparanode(p.right);
- { pull in }
- hp2.right:=hp1;
- hp1:=hp2;
- end;
- reverseparameters:=hp1;
- end;
- procedure maybe_load_para_in_temp(var p:tnode);
- var
- hp : tnode;
- ptemp : ttempcreatenode;
- newinitstatement,
- newdonestatement : tstatementnode;
- begin
- if not assigned(aktcallnode) then
- internalerror(200410121);
- hp:=p;
- while assigned(hp) and
- (hp.nodetype=typeconvn) do
- hp:=tunarynode(hp).left;
- if assigned(hp) and
- (
- { call result must always be loaded in temp to prevent
- double creation }
- (hp.nodetype=calln)
- { Also optimize also complex loads }
- {$warning Complex loads can also be optimized}
- // or not(hp.nodetype in [typen,loadvmtaddrn,loadn])
- ) then
- begin
- if not assigned(aktcallnode.methodpointerinit) then
- begin
- aktcallnode.methodpointerinit:=internalstatements(newinitstatement);
- aktcallnode.methodpointerdone:=internalstatements(newdonestatement);
- end
- else
- begin
- newinitstatement:=laststatement(aktcallnode.methodpointerinit);
- newdonestatement:=laststatement(aktcallnode.methodpointerdone);
- end;
- { temp create }
- ptemp:=ctempcreatenode.create_reg(p.resulttype,p.resulttype.def.size,tt_persistent);
- addstatement(newinitstatement,ptemp);
- addstatement(newinitstatement,cassignmentnode.create(
- ctemprefnode.create(ptemp),
- p));
- resulttypepass(aktcallnode.methodpointerinit);
- { new tree is only a temp reference }
- p:=ctemprefnode.create(ptemp);
- resulttypepass(p);
- { temp release }
- addstatement(newdonestatement,ctempdeletenode.create(ptemp));
- resulttypepass(aktcallnode.methodpointerdone);
- end;
- end;
- function gen_high_tree(var p:tnode;paradef:tdef):tnode;
- var
- temp: tnode;
- len : integer;
- loadconst : boolean;
- hightree : tnode;
- begin
- len:=-1;
- loadconst:=true;
- hightree:=nil;
- case p.resulttype.def.deftype of
- arraydef :
- begin
- if (paradef.deftype<>arraydef) then
- internalerror(200405241);
- { handle special case of passing an single array to an array of array }
- if compare_defs(tarraydef(paradef).elementtype.def,p.resulttype.def,nothingn)>=te_equal then
- len:=0
- else
- begin
- maybe_load_para_in_temp(p);
- { handle via a normal inline in_high_x node }
- loadconst := false;
- hightree := geninlinenode(in_high_x,false,p.getcopy);
- resulttypepass(hightree);
- { only substract low(array) if it's <> 0 }
- temp := geninlinenode(in_low_x,false,p.getcopy);
- resulttypepass(temp);
- if (temp.nodetype <> ordconstn) or
- (tordconstnode(temp).value <> 0) then
- hightree := caddnode.create(subn,hightree,temp)
- else
- temp.free;
- end;
- end;
- stringdef :
- begin
- if is_open_string(paradef) then
- begin
- maybe_load_para_in_temp(p);
- { handle via a normal inline in_high_x node }
- loadconst := false;
- hightree := geninlinenode(in_high_x,false,p.getcopy);
- end
- else
- begin
- { passing a string to an array of char }
- if (p.nodetype=stringconstn) then
- begin
- len:=str_length(p);
- if len>0 then
- dec(len);
- end
- else
- begin
- maybe_load_para_in_temp(p);
- hightree:=caddnode.create(subn,geninlinenode(in_length_x,false,p.getcopy),
- cordconstnode.create(1,s32inttype,false));
- loadconst:=false;
- end;
- end;
- end;
- else
- len:=0;
- end;
- if loadconst then
- hightree:=cordconstnode.create(len,s32inttype,true)
- else
- begin
- if not assigned(hightree) then
- internalerror(200304071);
- { Need to use explicit, because it can also be a enum }
- hightree:=ctypeconvnode.create_internal(hightree,s32inttype);
- end;
- result:=hightree;
- end;
- {****************************************************************************
- TOBJECTINFOITEM
- ****************************************************************************}
- constructor tobjectinfoitem.create(def : tobjectdef);
- begin
- inherited create;
- objinfo := def;
- end;
- {****************************************************************************
- TCALLPARANODE
- ****************************************************************************}
- constructor tcallparanode.create(expr,next : tnode);
- begin
- inherited create(callparan,expr,next);
- if not assigned(expr) then
- internalerror(200305091);
- expr.set_file_line(self);
- callparaflags:=[];
- end;
- destructor tcallparanode.destroy;
- begin
- { When the node is used by callnode then
- we don't destroy left, the callnode takes care of it }
- if used_by_callnode then
- left:=nil;
- inherited destroy;
- end;
- constructor tcallparanode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
- begin
- inherited ppuload(t,ppufile);
- ppufile.getsmallset(callparaflags);
- end;
- procedure tcallparanode.ppuwrite(ppufile:tcompilerppufile);
- begin
- inherited ppuwrite(ppufile);
- ppufile.putsmallset(callparaflags);
- end;
- function tcallparanode.getcopy : tnode;
- var
- n : tcallparanode;
- begin
- n:=tcallparanode(inherited getcopy);
- n.callparaflags:=callparaflags;
- n.parasym:=parasym;
- result:=n;
- end;
- procedure tcallparanode.insertintolist(l : tnodelist);
- begin
- end;
- procedure tcallparanode.get_paratype;
- var
- old_array_constructor : boolean;
- begin
- inc(parsing_para_level);
- if assigned(right) then
- tcallparanode(right).get_paratype;
- old_array_constructor:=allow_array_constructor;
- allow_array_constructor:=true;
- resulttypepass(left);
- allow_array_constructor:=old_array_constructor;
- if codegenerror then
- resulttype:=generrortype
- else
- resulttype:=left.resulttype;
- dec(parsing_para_level);
- end;
- procedure tcallparanode.insert_typeconv(do_count : boolean);
- var
- oldtype : ttype;
- {$ifdef extdebug}
- store_count_ref : boolean;
- {$endif def extdebug}
- begin
- inc(parsing_para_level);
- {$ifdef extdebug}
- if do_count then
- begin
- store_count_ref:=count_ref;
- count_ref:=true;
- end;
- {$endif def extdebug}
- { Be sure to have the resulttype }
- if not assigned(left.resulttype.def) then
- resulttypepass(left);
- if (left.nodetype<>nothingn) then
- begin
- { Convert tp procvars, this is needs to be done
- here to make the change permanent. in the overload
- choosing the changes are only made temporary }
- if (left.resulttype.def.deftype=procvardef) and
- (parasym.vartype.def.deftype<>procvardef) then
- begin
- if maybe_call_procvar(left,true) then
- resulttype:=left.resulttype;
- end;
- { Handle varargs and hidden paras directly, no typeconvs or }
- { typechecking needed }
- if (cpf_varargs_para in callparaflags) then
- begin
- { convert pascal to C types }
- case left.resulttype.def.deftype of
- stringdef :
- inserttypeconv(left,charpointertype);
- floatdef :
- inserttypeconv(left,s64floattype);
- end;
- set_varstate(left,vs_used,true);
- resulttype:=left.resulttype;
- { also update parasym type to get the correct parameter location
- for the new types }
- parasym.vartype:=left.resulttype;
- end
- else
- if (vo_is_hidden_para in parasym.varoptions) then
- begin
- set_varstate(left,vs_used,true);
- resulttype:=left.resulttype;
- end
- else
- begin
- { Do we need arrayconstructor -> set conversion, then insert
- it here before the arrayconstructor node breaks the tree
- with its conversions of enum->ord }
- if (left.nodetype=arrayconstructorn) and
- (parasym.vartype.def.deftype=setdef) then
- inserttypeconv(left,parasym.vartype);
- { set some settings needed for arrayconstructor }
- if is_array_constructor(left.resulttype.def) then
- begin
- if is_array_of_const(parasym.vartype.def) then
- begin
- { force variant array }
- include(left.flags,nf_forcevaria);
- end
- else
- begin
- include(left.flags,nf_novariaallowed);
- { now that the resultting type is know we can insert the required
- typeconvs for the array constructor }
- if parasym.vartype.def.deftype=arraydef then
- tarrayconstructornode(left).force_type(tarraydef(parasym.vartype.def).elementtype);
- end;
- end;
- { check if local proc/func is assigned to procvar }
- if left.resulttype.def.deftype=procvardef then
- test_local_to_procvar(tprocvardef(left.resulttype.def),parasym.vartype.def);
- { test conversions }
- if not(is_shortstring(left.resulttype.def) and
- is_shortstring(parasym.vartype.def)) and
- (parasym.vartype.def.deftype<>formaldef) then
- begin
- { Process open parameters }
- if paramanager.push_high_param(parasym.varspez,parasym.vartype.def,aktcallnode.procdefinition.proccalloption) then
- begin
- { insert type conv but hold the ranges of the array }
- oldtype:=left.resulttype;
- inserttypeconv(left,parasym.vartype);
- left.resulttype:=oldtype;
- end
- else
- begin
- { for ordinals, floats and enums, verify if we might cause
- some range-check errors. }
- if (parasym.vartype.def.deftype in [enumdef,orddef,floatdef]) and
- (left.resulttype.def.deftype in [enumdef,orddef,floatdef]) and
- (left.nodetype in [vecn,loadn,calln]) then
- begin
- if (left.resulttype.def.size>parasym.vartype.def.size) then
- begin
- if (cs_check_range in aktlocalswitches) then
- Message(type_w_smaller_possible_range_check)
- else
- Message(type_h_smaller_possible_range_check);
- end;
- end;
- inserttypeconv(left,parasym.vartype);
- end;
- if codegenerror then
- begin
- dec(parsing_para_level);
- exit;
- end;
- end;
- { check var strings }
- if (cs_strict_var_strings in aktlocalswitches) and
- is_shortstring(left.resulttype.def) and
- is_shortstring(parasym.vartype.def) and
- (parasym.varspez in [vs_out,vs_var]) and
- not(is_open_string(parasym.vartype.def)) and
- not(equal_defs(left.resulttype.def,parasym.vartype.def)) then
- begin
- aktfilepos:=left.fileinfo;
- CGMessage(type_e_strict_var_string_violation);
- end;
- { Handle formal parameters separate }
- if (parasym.vartype.def.deftype=formaldef) then
- begin
- { load procvar if a procedure is passed }
- if (m_tp_procvar in aktmodeswitches) and
- (left.nodetype=calln) and
- (is_void(left.resulttype.def)) then
- load_procvar_from_calln(left);
- case parasym.varspez of
- vs_var,
- vs_out :
- begin
- if not valid_for_formal_var(left) then
- CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list);
- end;
- vs_const :
- begin
- if not valid_for_formal_const(left) then
- CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list);
- end;
- end;
- end
- else
- begin
- { check if the argument is allowed }
- if (parasym.varspez in [vs_out,vs_var]) then
- valid_for_var(left);
- end;
- if parasym.varspez = vs_var then
- set_unique(left);
- { When the address needs to be pushed then the register is
- not regable. Exception is when the location is also a var
- parameter and we can pass the address transparently }
- if (
- not(
- (vo_is_hidden_para in parasym.varoptions) and
- (left.resulttype.def.deftype in [pointerdef,classrefdef])
- ) and
- paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
- aktcallnode.procdefinition.proccalloption) and
- not(
- (left.nodetype=loadn) and
- (tloadnode(left).is_addr_param_load)
- )
- ) then
- make_not_regable(left);
- if do_count then
- begin
- if parasym.varspez in [vs_var,vs_out] then
- set_varstate(left,vs_used,false)
- else
- set_varstate(left,vs_used,true);
- end;
- { must only be done after typeconv PM }
- resulttype:=parasym.vartype;
- end;
- end;
- { process next node }
- if assigned(right) then
- tcallparanode(right).insert_typeconv(do_count);
- dec(parsing_para_level);
- {$ifdef extdebug}
- if do_count then
- count_ref:=store_count_ref;
- {$endif def extdebug}
- end;
- procedure tcallparanode.det_registers;
- begin
- if assigned(right) then
- begin
- tcallparanode(right).det_registers;
- registersint:=right.registersint;
- registersfpu:=right.registersfpu;
- {$ifdef SUPPORT_MMX}
- registersmmx:=right.registersmmx;
- {$endif}
- end;
- firstpass(left);
- if left.registersint>registersint then
- registersint:=left.registersint;
- if left.registersfpu>registersfpu then
- registersfpu:=left.registersfpu;
- {$ifdef SUPPORT_MMX}
- if left.registersmmx>registersmmx then
- registersmmx:=left.registersmmx;
- {$endif SUPPORT_MMX}
- end;
- procedure tcallparanode.firstcallparan;
- begin
- if not assigned(left.resulttype.def) then
- get_paratype;
- det_registers;
- end;
- function tcallparanode.docompare(p: tnode): boolean;
- begin
- docompare :=
- inherited docompare(p) and
- (callparaflags = tcallparanode(p).callparaflags)
- ;
- end;
- procedure tcallparanode.printnodetree(var t:text);
- begin
- printnodelist(t);
- end;
- {****************************************************************************
- TCALLNODE
- ****************************************************************************}
- constructor tcallnode.create(l:tnode;v : tprocsym;st : tsymtable; mp: tnode; callflags:tcallnodeflags);
- begin
- inherited create(calln,l,nil);
- symtableprocentry:=v;
- symtableproc:=st;
- callnodeflags:=callflags+[cnf_return_value_used];
- methodpointer:=mp;
- methodpointerinit:=nil;
- methodpointerdone:=nil;
- procdefinition:=nil;
- _funcretnode:=nil;
- inlinecode:=nil;
- paralength:=-1;
- varargsparas:=nil;
- end;
- constructor tcallnode.create_procvar(l,r:tnode);
- begin
- inherited create(calln,l,r);
- symtableprocentry:=nil;
- symtableproc:=nil;
- methodpointer:=nil;
- methodpointerinit:=nil;
- methodpointerdone:=nil;
- procdefinition:=nil;
- callnodeflags:=[cnf_return_value_used];
- _funcretnode:=nil;
- inlinecode:=nil;
- paralength:=-1;
- varargsparas:=nil;
- end;
- constructor tcallnode.createintern(const name: string; params: tnode);
- var
- srsym: tsym;
- symowner: tsymtable;
- begin
- if not (cs_compilesystem in aktmoduleswitches) then
- begin
- srsym := searchsymonlyin(systemunit,name);
- symowner := systemunit;
- end
- else
- begin
- searchsym(name,srsym,symowner);
- if not assigned(srsym) then
- searchsym(upper(name),srsym,symowner);
- end;
- if not assigned(srsym) or
- (srsym.typ <> procsym) then
- begin
- {$ifdef EXTDEBUG}
- Comment(V_Error,'unknown compilerproc '+name);
- {$endif EXTDEBUG}
- internalerror(200107271);
- end;
- self.create(params,tprocsym(srsym),symowner,nil,[]);
- end;
- constructor tcallnode.createinternres(const name: string; params: tnode; const res: ttype);
- begin
- self.createintern(name,params);
- restype := res;
- include(callnodeflags,cnf_restypeset);
- { both the normal and specified resulttype either have to be returned via a }
- { parameter or not, but no mixing (JM) }
- if paramanager.ret_in_param(restype.def,pocall_compilerproc) xor
- paramanager.ret_in_param(symtableprocentry.first_procdef.rettype.def,symtableprocentry.first_procdef.proccalloption) then
- internalerror(200108291);
- end;
- constructor tcallnode.createinternreturn(const name: string; params: tnode; returnnode : tnode);
- begin
- self.createintern(name,params);
- _funcretnode:=returnnode;
- if not paramanager.ret_in_param(symtableprocentry.first_procdef.rettype.def,symtableprocentry.first_procdef.proccalloption) then
- internalerror(200204247);
- end;
- procedure tcallnode.setfuncretnode(const returnnode: tnode);
- var
- para: tcallparanode;
- begin
- if assigned(_funcretnode) then
- _funcretnode.free;
- _funcretnode := returnnode;
- { if the resulttype pass hasn't occurred yet, that one will do }
- { everything }
- if assigned(resulttype.def) then
- begin
- { these are returned as values, but we can optimize their loading }
- { as well }
- if is_ansistring(resulttype.def) or
- is_widestring(resulttype.def) then
- exit;
- para := tcallparanode(left);
- while assigned(para) do
- begin
- if (vo_is_hidden_para in para.parasym.varoptions) and
- (vo_is_funcret in tparavarsym(para.parasym).varoptions) then
- begin
- para.left.free;
- para.left := _funcretnode.getcopy;
- exit;
- end;
- para := tcallparanode(para.right);
- end;
- { no hidden resultpara found, error! }
- if not(procdefinition.proccalloption = pocall_inline) then
- internalerror(200306087);
- end;
- end;
- destructor tcallnode.destroy;
- begin
- methodpointer.free;
- methodpointerinit.free;
- methodpointerdone.free;
- _funcretnode.free;
- inlinecode.free;
- if assigned(varargsparas) then
- varargsparas.free;
- inherited destroy;
- end;
- constructor tcallnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
- begin
- inherited ppuload(t,ppufile);
- ppufile.getderef(symtableprocentryderef);
- {$ifdef fpc}
- {$warning FIXME: No withsymtable support}
- {$endif}
- symtableproc:=nil;
- ppufile.getderef(procdefinitionderef);
- ppufile.getsmallset(callnodeflags);
- methodpointer:=ppuloadnode(ppufile);
- methodpointerinit:=tblocknode(ppuloadnode(ppufile));
- methodpointerdone:=tblocknode(ppuloadnode(ppufile));
- _funcretnode:=ppuloadnode(ppufile);
- inlinecode:=ppuloadnode(ppufile);
- end;
- procedure tcallnode.ppuwrite(ppufile:tcompilerppufile);
- begin
- inherited ppuwrite(ppufile);
- ppufile.putderef(symtableprocentryderef);
- ppufile.putderef(procdefinitionderef);
- ppufile.putsmallset(callnodeflags);
- ppuwritenode(ppufile,methodpointer);
- ppuwritenode(ppufile,methodpointerinit);
- ppuwritenode(ppufile,methodpointerdone);
- ppuwritenode(ppufile,_funcretnode);
- ppuwritenode(ppufile,inlinecode);
- end;
- procedure tcallnode.buildderefimpl;
- begin
- inherited buildderefimpl;
- symtableprocentryderef.build(symtableprocentry);
- procdefinitionderef.build(procdefinition);
- if assigned(methodpointer) then
- methodpointer.buildderefimpl;
- if assigned(methodpointerinit) then
- methodpointerinit.buildderefimpl;
- if assigned(methodpointerdone) then
- methodpointerdone.buildderefimpl;
- if assigned(_funcretnode) then
- _funcretnode.buildderefimpl;
- if assigned(inlinecode) then
- inlinecode.buildderefimpl;
- end;
- procedure tcallnode.derefimpl;
- var
- pt : tcallparanode;
- i : integer;
- begin
- inherited derefimpl;
- symtableprocentry:=tprocsym(symtableprocentryderef.resolve);
- symtableproc:=symtableprocentry.owner;
- procdefinition:=tprocdef(procdefinitionderef.resolve);
- if assigned(methodpointer) then
- methodpointer.derefimpl;
- if assigned(methodpointerinit) then
- methodpointerinit.derefimpl;
- if assigned(methodpointerdone) then
- methodpointerdone.derefimpl;
- if assigned(_funcretnode) then
- _funcretnode.derefimpl;
- if assigned(inlinecode) then
- inlinecode.derefimpl;
- { Connect parasyms }
- pt:=tcallparanode(left);
- while assigned(pt) and
- (cpf_varargs_para in pt.callparaflags) do
- pt:=tcallparanode(pt.right);
- for i:=procdefinition.paras.count-1 downto 0 do
- begin
- if not assigned(pt) then
- internalerror(200311077);
- pt.parasym:=tparavarsym(procdefinition.paras[i]);
- pt:=tcallparanode(pt.right);
- end;
- if assigned(pt) then
- internalerror(200311078);
- end;
- function tcallnode.getcopy : tnode;
- var
- n : tcallnode;
- i : integer;
- hp,hpn : tparavarsym;
- oldleft : tnode;
- begin
- { Need to use a hack here to prevent the parameters from being copied.
- The parameters must be copied between methodpointerinit/methodpointerdone because
- the can reference methodpointer }
- oldleft:=left;
- left:=nil;
- n:=tcallnode(inherited getcopy);
- left:=oldleft;
- n.symtableprocentry:=symtableprocentry;
- n.symtableproc:=symtableproc;
- n.procdefinition:=procdefinition;
- n.restype := restype;
- n.callnodeflags := callnodeflags;
- if assigned(methodpointerinit) then
- n.methodpointerinit:=tblocknode(methodpointerinit.getcopy)
- else
- n.methodpointerinit:=nil;
- { methodpointerinit is copied, now references to the temp will also be copied
- correctly. We can now copy the parameters and methodpointer }
- if assigned(left) then
- n.left:=left.getcopy
- else
- n.left:=nil;
- if assigned(methodpointer) then
- n.methodpointer:=methodpointer.getcopy
- else
- n.methodpointer:=nil;
- if assigned(methodpointerdone) then
- n.methodpointerdone:=tblocknode(methodpointerdone.getcopy)
- else
- n.methodpointerdone:=nil;
- if assigned(_funcretnode) then
- n._funcretnode:=_funcretnode.getcopy
- else
- n._funcretnode:=nil;
- if assigned(inlinecode) then
- n.inlinecode:=inlinecode.getcopy
- else
- n.inlinecode:=nil;
- if assigned(varargsparas) then
- begin
- n.varargsparas:=tvarargsparalist.create;
- for i:=0 to varargsparas.count-1 do
- begin
- hp:=tparavarsym(varargsparas[i]);
- hpn:=tparavarsym.create(hp.realname,0,hp.varspez,hp.vartype);
- n.varargsparas.add(hpn);
- end;
- end
- else
- n.varargsparas:=nil;
- result:=n;
- end;
- procedure tcallnode.insertintolist(l : tnodelist);
- begin
- end;
- procedure tcallnode.convert_carg_array_of_const;
- var
- hp : tarrayconstructornode;
- oldleft : tcallparanode;
- begin
- oldleft:=tcallparanode(left);
- if oldleft.left.nodetype<>arrayconstructorn then
- begin
- CGMessage1(type_e_wrong_type_in_array_constructor,oldleft.left.resulttype.def.typename);
- exit;
- end;
- { Get arrayconstructor node and insert typeconvs }
- hp:=tarrayconstructornode(oldleft.left);
- hp.insert_typeconvs;
- { Add c args parameters }
- { It could be an empty set }
- if assigned(hp) and
- assigned(hp.left) then
- begin
- while assigned(hp) do
- begin
- left:=ccallparanode.create(hp.left,left);
- { set callparanode resulttype and flags }
- left.resulttype:=hp.left.resulttype;
- include(tcallparanode(left).callparaflags,cpf_varargs_para);
- hp.left:=nil;
- hp:=tarrayconstructornode(hp.right);
- end;
- end;
- { Remove value of old array of const parameter, but keep it
- in the list because it is required for bind_parasym.
- Generate a nothign to keep callparanoed.left valid }
- oldleft.left.free;
- oldleft.left:=cnothingnode.create;
- end;
- procedure tcallnode.verifyabstract(p : tnamedindexitem;arg:pointer);
- var
- hp : tprocdef;
- j: integer;
- begin
- if (tsym(p).typ=procsym) then
- begin
- for j:=1 to tprocsym(p).procdef_count do
- begin
- { index starts at 1 }
- hp:=tprocsym(p).procdef[j];
- { If this is an abstract method insert into the list }
- if (po_abstractmethod in hp.procoptions) then
- AbstractMethodsList.Insert(hp.procsym.realname)
- else
- { If this symbol is a virtual (includes override) method,
- then remove it from the list }
- if po_virtualmethod in hp.procoptions then
- AbstractMethodsList.Remove(hp.procsym.realname);
- end;
- end;
- end;
- procedure tcallnode.verifyabstractcalls;
- var
- objectdf : tobjectdef;
- parents : tlinkedlist;
- objectinfo : tobjectinfoitem;
- stritem : tstringlistitem;
- begin
- objectdf := nil;
- { verify if trying to create an instance of a class which contains
- non-implemented abstract methods }
- { first verify this class type, no class than exit }
- { also, this checking can only be done if the constructor is directly
- called, indirect constructor calls cannot be checked.
- }
- if assigned(methodpointer) then
- begin
- if (methodpointer.resulttype.def.deftype = objectdef) then
- objectdf:=tobjectdef(methodpointer.resulttype.def)
- else
- if (methodpointer.resulttype.def.deftype = classrefdef) and
- (tclassrefdef(methodpointer.resulttype.def).pointertype.def.deftype = objectdef) and
- (methodpointer.nodetype in [typen,loadvmtaddrn]) then
- objectdf:=tobjectdef(tclassrefdef(methodpointer.resulttype.def).pointertype.def);
- end;
- if not assigned(objectdf) then
- exit;
- parents := tlinkedlist.create;
- AbstractMethodsList := tstringlist.create;
- { insert all parents in this class : the first item in the
- list will be the base parent of the class .
- }
- while assigned(objectdf) do
- begin
- objectinfo:=tobjectinfoitem.create(objectdf);
- parents.insert(objectinfo);
- objectdf := objectdf.childof;
- end;
- { now all parents are in the correct order
- insert all abstract methods in the list, and remove
- those which are overriden by parent classes.
- }
- objectinfo:=tobjectinfoitem(parents.first);
- while assigned(objectinfo) do
- begin
- objectdf := objectinfo.objinfo;
- if assigned(objectdf.symtable) then
- objectdf.symtable.foreach(@verifyabstract,nil);
- objectinfo:=tobjectinfoitem(objectinfo.next);
- end;
- if assigned(parents) then
- parents.free;
- { Finally give out a warning for each abstract method still in the list }
- stritem := tstringlistitem(AbstractMethodsList.first);
- if assigned(stritem) then
- Message1(type_w_instance_with_abstract,objectdf.objrealname^);
- while assigned(stritem) do
- begin
- if assigned(stritem.fpstr) then
- Message1(sym_h_param_list,stritem.str);
- stritem := tstringlistitem(stritem.next);
- end;
- if assigned(AbstractMethodsList) then
- AbstractMethodsList.Free;
- end;
- function tcallnode.gen_self_tree_methodpointer:tnode;
- var
- hsym : tfieldvarsym;
- begin
- { find self field in methodpointer record }
- hsym:=tfieldvarsym(trecorddef(methodpointertype.def).symtable.search('self'));
- if not assigned(hsym) then
- internalerror(200305251);
- { Load tmehodpointer(right).self }
- result:=csubscriptnode.create(
- hsym,
- ctypeconvnode.create_internal(right.getcopy,methodpointertype));
- end;
- function tcallnode.gen_self_tree:tnode;
- var
- selftree : tnode;
- begin
- selftree:=nil;
- { inherited }
- if (cnf_inherited in callnodeflags) then
- selftree:=load_self_node
- else
- { constructors }
- if (procdefinition.proctypeoption=potype_constructor) then
- begin
- { push 0 as self when allocation is needed }
- if (methodpointer.resulttype.def.deftype=classrefdef) or
- (cnf_new_call in callnodeflags) then
- selftree:=cpointerconstnode.create(0,voidpointertype)
- else
- begin
- if methodpointer.nodetype=typen then
- selftree:=load_self_node
- else
- selftree:=methodpointer.getcopy;
- end;
- end
- else
- { Calling a static/class method }
- if (po_classmethod in procdefinition.procoptions) or
- (po_staticmethod in procdefinition.procoptions) then
- begin
- if (procdefinition.deftype<>procdef) then
- internalerror(200305062);
- if (oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
- begin
- { we only need the vmt, loading self is not required and there is no
- need to check for typen, because that will always get the
- loadvmtaddrnode added }
- selftree:=methodpointer.getcopy;
- if methodpointer.resulttype.def.deftype<>classrefdef then
- selftree:=cloadvmtaddrnode.create(selftree);
- end
- else
- selftree:=cpointerconstnode.create(0,voidpointertype);
- end
- else
- begin
- if methodpointer.nodetype=typen then
- selftree:=load_self_node
- else
- selftree:=methodpointer.getcopy;
- end;
- result:=selftree;
- end;
- function tcallnode.gen_vmt_tree:tnode;
- var
- vmttree : tnode;
- begin
- vmttree:=nil;
- if not(procdefinition.proctypeoption in [potype_constructor,potype_destructor]) then
- internalerror(200305051);
- { inherited call, no create/destroy }
- if (cnf_inherited in callnodeflags) then
- vmttree:=cpointerconstnode.create(0,voidpointertype)
- else
- { do not create/destroy when called from member function
- without specifying self explicit }
- if (cnf_member_call in callnodeflags) then
- begin
- if (methodpointer.resulttype.def.deftype=classrefdef) and
- (procdefinition.proctypeoption=potype_constructor) then
- vmttree:=methodpointer.getcopy
- else
- vmttree:=cpointerconstnode.create(0,voidpointertype);
- end
- else
- { constructor with extended syntax called from new }
- if (cnf_new_call in callnodeflags) then
- vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resulttype))
- else
- { destructor with extended syntax called from dispose }
- if (cnf_dispose_call in callnodeflags) then
- vmttree:=cloadvmtaddrnode.create(methodpointer.getcopy)
- else
- if (methodpointer.resulttype.def.deftype=classrefdef) then
- begin
- { constructor call via classreference => allocate memory }
- if (procdefinition.proctypeoption=potype_constructor) and
- is_class(tclassrefdef(methodpointer.resulttype.def).pointertype.def) then
- begin
- vmttree:=methodpointer.getcopy;
- { Only a typenode can be passed when it is called with <class of xx>.create }
- if vmttree.nodetype=typen then
- vmttree:=cloadvmtaddrnode.create(vmttree);
- end
- else
- vmttree:=cpointerconstnode.create(0,voidpointertype);
- end
- else
- { class }
- if is_class(methodpointer.resulttype.def) then
- begin
- { destructor: release instance, flag(vmt)=1
- constructor: direct call, do nothing, leave vmt=0 }
- if (procdefinition.proctypeoption=potype_destructor) then
- vmttree:=cpointerconstnode.create(1,voidpointertype)
- else
- vmttree:=cpointerconstnode.create(0,voidpointertype);
- end
- else
- { object }
- begin
- { destructor: direct call, no dispose, vmt=0
- constructor: initialize object, load vmt }
- if (procdefinition.proctypeoption=potype_constructor) then
- { old styled inherited call? }
- if (methodpointer.nodetype=typen) then
- vmttree:=cpointerconstnode.create(0,voidpointertype)
- else
- vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resulttype))
- else
- vmttree:=cpointerconstnode.create(0,voidpointertype);
- end;
- result:=vmttree;
- end;
- procedure tcallnode.bind_parasym;
- var
- i : integer;
- pt : tcallparanode;
- oldppt : ^tcallparanode;
- varargspara,
- currpara : tparavarsym;
- used_by_callnode : boolean;
- hiddentree : tnode;
- newstatement : tstatementnode;
- temp : ttempcreatenode;
- begin
- pt:=tcallparanode(left);
- oldppt:=@left;
- { flag all callparanodes that belong to the varargs }
- i:=paralength;
- while (i>procdefinition.maxparacount) do
- begin
- include(pt.callparaflags,cpf_varargs_para);
- oldppt:[email protected];
- pt:=tcallparanode(pt.right);
- dec(i);
- end;
- { skip varargs that are inserted by array of const }
- while assigned(pt) and
- (cpf_varargs_para in pt.callparaflags) do
- pt:=tcallparanode(pt.right);
- { process normal parameters and insert hidden parameters }
- for i:=procdefinition.paras.count-1 downto 0 do
- begin
- currpara:=tparavarsym(procdefinition.paras[i]);
- if vo_is_hidden_para in currpara.varoptions then
- begin
- { generate hidden tree }
- used_by_callnode:=false;
- hiddentree:=nil;
- if (vo_is_funcret in currpara.varoptions) then
- begin
- { Generate funcretnode if not specified }
- if assigned(funcretnode) then
- begin
- hiddentree:=funcretnode.getcopy;
- end
- else
- begin
- hiddentree:=internalstatements(newstatement);
- { need to use resulttype instead of procdefinition.rettype,
- because they can be different }
- temp:=ctempcreatenode.create(resulttype,resulttype.def.size,tt_persistent);
- addstatement(newstatement,temp);
- addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
- addstatement(newstatement,ctemprefnode.create(temp));
- end;
- end
- else
- if vo_is_high_para in currpara.varoptions then
- begin
- if not assigned(pt) or
- (i=0) then
- internalerror(200304082);
- { we need the information of the previous parameter }
- hiddentree:=gen_high_tree(pt.left,tparavarsym(procdefinition.paras[i-1]).vartype.def);
- end
- else
- if vo_is_self in currpara.varoptions then
- begin
- if assigned(right) then
- hiddentree:=gen_self_tree_methodpointer
- else
- hiddentree:=gen_self_tree;
- end
- else
- if vo_is_vmt in currpara.varoptions then
- begin
- hiddentree:=gen_vmt_tree;
- end
- {$ifdef powerpc}
- else
- if vo_is_syscall_lib in currpara.varoptions then
- begin
- { lib parameter has no special type but proccalloptions must be a syscall }
- hiddentree:=cloadnode.create(tprocdef(procdefinition).libsym,tprocdef(procdefinition).libsym.owner);
- end
- {$endif powerpc}
- else
- if vo_is_parentfp in currpara.varoptions then
- begin
- if not(assigned(procdefinition.owner.defowner)) then
- internalerror(200309287);
- hiddentree:=cloadparentfpnode.create(tprocdef(procdefinition.owner.defowner));
- end;
- { add the hidden parameter }
- if not assigned(hiddentree) then
- internalerror(200304073);
- { Already insert para and let the previous node point to
- this new node }
- pt:=ccallparanode.create(hiddentree,oldppt^);
- pt.used_by_callnode:=used_by_callnode;
- oldppt^:=pt;
- end;
- if not assigned(pt) then
- internalerror(200310052);
- pt.parasym:=currpara;
- oldppt:[email protected];
- pt:=tcallparanode(pt.right);
- end;
- { Create parasyms for varargs }
- pt:=tcallparanode(left);
- i:=0;
- while assigned(pt) do
- begin
- if cpf_varargs_para in pt.callparaflags then
- begin
- if not assigned(varargsparas) then
- varargsparas:=tvarargsparalist.create;
- varargspara:=tparavarsym.create('va'+tostr(i),0,vs_value,pt.resulttype);
- { varargspara is left-right, use insert
- instead of concat }
- varargsparas.add(varargspara);
- pt.parasym:=varargspara;
- end;
- pt:=tcallparanode(pt.right);
- end;
- end;
- function tcallnode.det_resulttype:tnode;
- var
- candidates : tcallcandidates;
- oldcallnode : tcallnode;
- hpt : tnode;
- pt : tcallparanode;
- lastpara : longint;
- currpara : tparavarsym;
- paraidx,
- cand_cnt : integer;
- i : longint;
- method_must_be_valid,
- is_const : boolean;
- label
- errorexit;
- begin
- result:=nil;
- candidates:=nil;
- oldcallnode:=aktcallnode;
- aktcallnode:=self;
- { determine length of parameter list }
- pt:=tcallparanode(left);
- paralength:=0;
- while assigned(pt) do
- begin
- inc(paralength);
- pt:=tcallparanode(pt.right);
- end;
- { determine the type of the parameters }
- if assigned(left) then
- begin
- tcallparanode(left).get_paratype;
- if codegenerror then
- goto errorexit;
- end;
- if assigned(methodpointer) then
- begin
- resulttypepass(methodpointer);
- maybe_load_para_in_temp(methodpointer);
- end;
- { procedure variable ? }
- if assigned(right) then
- begin
- set_varstate(right,vs_used,true);
- resulttypepass(right);
- if codegenerror then
- exit;
- procdefinition:=tabstractprocdef(right.resulttype.def);
- { Compare parameters from right to left }
- paraidx:=procdefinition.Paras.count-1;
- { Skip default parameters }
- if not(po_varargs in procdefinition.procoptions) then
- begin
- { ignore hidden parameters }
- while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
- dec(paraidx);
- for i:=1 to procdefinition.maxparacount-paralength do
- begin
- if paraidx<0 then
- internalerror(200402261);
- if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
- begin
- CGMessage(parser_e_wrong_parameter_size);
- goto errorexit;
- end;
- dec(paraidx);
- end;
- end;
- while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
- dec(paraidx);
- pt:=tcallparanode(left);
- lastpara:=paralength;
- while (paraidx>=0) and assigned(pt) do
- begin
- { only goto next para if we're out of the varargs }
- if not(po_varargs in procdefinition.procoptions) or
- (lastpara<=procdefinition.maxparacount) then
- begin
- repeat
- dec(paraidx);
- until (paraidx<0) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions);
- end;
- pt:=tcallparanode(pt.right);
- dec(lastpara);
- end;
- if assigned(pt) or
- ((paraidx>=0) and
- not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)) then
- begin
- if assigned(pt) then
- aktfilepos:=pt.fileinfo;
- CGMessage(parser_e_wrong_parameter_size);
- goto errorexit;
- end;
- end
- else
- { not a procedure variable }
- begin
- { do we know the procedure to call ? }
- if not(assigned(procdefinition)) then
- begin
- candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,(nf_isproperty in flags));
- { no procedures found? then there is something wrong
- with the parameter size or the procedures are
- not accessible }
- if candidates.count=0 then
- begin
- { when it's an auto inherited call and there
- is no procedure found, but the procedures
- were defined with overload directive and at
- least two procedures are defined then we ignore
- this inherited by inserting a nothingn. Only
- do this ugly hack in Delphi mode as it looks more
- like a bug. It's also not documented }
- if (m_delphi in aktmodeswitches) and
- (cnf_anon_inherited in callnodeflags) and
- (symtableprocentry.owner.symtabletype=objectsymtable) and
- (po_overload in symtableprocentry.first_procdef.procoptions) and
- (symtableprocentry.procdef_count>=2) then
- result:=cnothingnode.create
- else
- begin
- { in tp mode we can try to convert to procvar if
- there are no parameters specified. Only try it
- when there is only one proc definition, else the
- loadnode will give a strange error }
- if not(assigned(left)) and
- not(cnf_inherited in callnodeflags) and
- (m_tp_procvar in aktmodeswitches) and
- (symtableprocentry.procdef_count=1) then
- begin
- hpt:=cloadnode.create(tprocsym(symtableprocentry),symtableproc);
- if assigned(methodpointer) then
- tloadnode(hpt).set_mp(methodpointer.getcopy);
- resulttypepass(hpt);
- result:=hpt;
- end
- else
- begin
- if assigned(left) then
- aktfilepos:=left.fileinfo;
- CGMessage(parser_e_wrong_parameter_size);
- symtableprocentry.write_parameter_lists(nil);
- end;
- end;
- goto errorexit;
- end;
- { Retrieve information about the candidates }
- candidates.get_information;
- {$ifdef EXTDEBUG}
- { Display info when multiple candidates are found }
- if candidates.count>1 then
- candidates.dump_info(V_Debug);
- {$endif EXTDEBUG}
- { Choose the best candidate and count the number of
- candidates left }
- cand_cnt:=candidates.choose_best(procdefinition);
- { All parameters are checked, check if there are any
- procedures left }
- if cand_cnt>0 then
- begin
- { Multiple candidates left? }
- if cand_cnt>1 then
- begin
- CGMessage(type_e_cant_choose_overload_function);
- {$ifdef EXTDEBUG}
- candidates.dump_info(V_Hint);
- {$else EXTDEBUG}
- candidates.list(false);
- {$endif EXTDEBUG}
- { we'll just use the first candidate to make the
- call }
- end;
- { assign procdefinition }
- if symtableproc=nil then
- symtableproc:=procdefinition.owner;
- { update browser information }
- if make_ref then
- begin
- tprocdef(procdefinition).lastref:=tref.create(tprocdef(procdefinition).lastref,@fileinfo);
- inc(tprocdef(procdefinition).refcount);
- if tprocdef(procdefinition).defref=nil then
- tprocdef(procdefinition).defref:=tprocdef(procdefinition).lastref;
- end;
- end
- else
- begin
- { No candidates left, this must be a type error,
- because wrong size is already checked. procdefinition
- is filled with the first (random) definition that is
- found. We use this definition to display a nice error
- message that the wrong type is passed }
- candidates.find_wrong_para;
- candidates.list(true);
- {$ifdef EXTDEBUG}
- candidates.dump_info(V_Hint);
- {$endif EXTDEBUG}
- { We can not proceed, release all procs and exit }
- candidates.free;
- goto errorexit;
- end;
- candidates.free;
- end; { end of procedure to call determination }
- end;
- { add needed default parameters }
- if assigned(procdefinition) and
- (paralength<procdefinition.maxparacount) then
- begin
- paraidx:=0;
- i:=0;
- while (i<paralength) do
- begin
- if paraidx>=procdefinition.Paras.count then
- internalerror(200306181);
- if not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) then
- inc(i);
- inc(paraidx);
- end;
- while (paraidx<procdefinition.paras.count) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
- inc(paraidx);
- while (paraidx<procdefinition.paras.count) do
- begin
- if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
- internalerror(200212142);
- left:=ccallparanode.create(genconstsymtree(
- tconstsym(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)),left);
- { Ignore vs_hidden parameters }
- repeat
- inc(paraidx);
- until (paraidx>=procdefinition.paras.count) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions);
- end;
- end;
- { handle predefined procedures }
- is_const:=(po_internconst in procdefinition.procoptions) and
- ((block_type in [bt_const,bt_type]) or
- (assigned(left) and (tcallparanode(left).left.nodetype in [realconstn,ordconstn])));
- if (procdefinition.proccalloption=pocall_internproc) or is_const then
- begin
- if assigned(left) then
- begin
- { ptr and settextbuf needs two args }
- if assigned(tcallparanode(left).right) then
- begin
- hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,left);
- left:=nil;
- end
- else
- begin
- hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,tcallparanode(left).left);
- tcallparanode(left).left:=nil;
- end;
- end
- else
- hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,nil);
- result:=hpt;
- goto errorexit;
- end;
- { ensure that the result type is set }
- if not(cnf_restypeset in callnodeflags) then
- begin
- { constructors return their current class type, not the type where the
- constructor is declared, this can be different because of inheritance }
- if (procdefinition.proctypeoption=potype_constructor) and
- assigned(methodpointer) and
- assigned(methodpointer.resulttype.def) and
- (methodpointer.resulttype.def.deftype=classrefdef) then
- resulttype:=tclassrefdef(methodpointer.resulttype.def).pointertype
- else
- resulttype:=procdefinition.rettype;
- end
- else
- resulttype:=restype;
- {if resulttype.def.needs_inittable then
- include(current_procinfo.flags,pi_needs_implicit_finally);}
- if assigned(methodpointer) then
- begin
- { when methodpointer is a callnode we must load it first into a
- temp to prevent the processing callnode twice }
- if (methodpointer.nodetype=calln) then
- internalerror(200405121);
- { direct call to inherited abstract method, then we
- can already give a error in the compiler instead
- of a runtime error }
- if (cnf_inherited in callnodeflags) and
- (po_abstractmethod in procdefinition.procoptions) then
- CGMessage(cg_e_cant_call_abstract_method);
- { if an inherited con- or destructor should be }
- { called in a con- or destructor then a warning }
- { will be made }
- { con- and destructors need a pointer to the vmt }
- if (cnf_inherited in callnodeflags) and
- (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) and
- is_object(methodpointer.resulttype.def) and
- not(current_procinfo.procdef.proctypeoption in [potype_constructor,potype_destructor]) then
- CGMessage(cg_w_member_cd_call_from_method);
- if methodpointer.nodetype<>typen then
- begin
- { Remove all postfix operators }
- hpt:=methodpointer;
- while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do
- hpt:=tunarynode(hpt).left;
- if (procdefinition.proctypeoption=potype_constructor) and
- assigned(symtableproc) and
- (symtableproc.symtabletype=withsymtable) and
- (tnode(twithsymtable(symtableproc).withrefnode).nodetype=temprefn) then
- CGmessage(cg_e_cannot_call_cons_dest_inside_with);
- { R.Init then R will be initialized by the constructor,
- Also allow it for simple loads }
- if (procdefinition.proctypeoption=potype_constructor) or
- ((hpt.nodetype=loadn) and
- (
- (methodpointer.resulttype.def.deftype=classrefdef) or
- (
- (methodpointer.resulttype.def.deftype=objectdef) and
- not(oo_has_virtual in tobjectdef(methodpointer.resulttype.def).objectoptions)
- )
- )
- ) then
- method_must_be_valid:=false
- else
- method_must_be_valid:=true;
- set_varstate(methodpointer,vs_used,method_must_be_valid);
- { The object is already used if it is called once }
- if (hpt.nodetype=loadn) and
- (tloadnode(hpt).symtableentry.typ in [localvarsym,paravarsym,globalvarsym]) then
- tabstractvarsym(tloadnode(hpt).symtableentry).varstate:=vs_used;
- end;
- { if we are calling the constructor check for abstract
- methods. Ignore inherited and member calls, because the
- class is then already created }
- if (procdefinition.proctypeoption=potype_constructor) and
- not(cnf_inherited in callnodeflags) and
- not(cnf_member_call in callnodeflags) then
- verifyabstractcalls;
- end
- else
- begin
- { When this is method the methodpointer must be available }
- if (right=nil) and
- (procdefinition.owner.symtabletype=objectsymtable) then
- internalerror(200305061);
- end;
- { Change loading of array of const to varargs }
- if assigned(left) and
- is_array_of_const(tparavarsym(procdefinition.paras[procdefinition.paras.count-1]).vartype.def) and
- (procdefinition.proccalloption in [pocall_cppdecl,pocall_cdecl]) then
- convert_carg_array_of_const;
- { bind parasyms to the callparanodes and insert hidden parameters }
- bind_parasym;
- { methodpointer is only needed for virtual calls, and
- it should then be loaded with the VMT }
- if (po_virtualmethod in procdefinition.procoptions) and
- not(assigned(methodpointer) and
- (methodpointer.nodetype=typen)) then
- begin
- if not assigned(methodpointer) then
- internalerror(200305063);
- if (methodpointer.resulttype.def.deftype<>classrefdef) then
- begin
- methodpointer:=cloadvmtaddrnode.create(methodpointer);
- resulttypepass(methodpointer);
- end;
- end
- else
- begin
- { not needed anymore }
- methodpointer.free;
- methodpointer:=nil;
- end;
- { insert type conversions for parameters }
- if assigned(left) then
- tcallparanode(left).insert_typeconv(true);
- errorexit:
- aktcallnode:=oldcallnode;
- end;
- procedure tcallnode.order_parameters;
- var
- hp,hpcurr,hpnext,hpfirst,hpprev : tcallparanode;
- currloc : tcgloc;
- begin
- hpfirst:=nil;
- hpcurr:=tcallparanode(left);
- while assigned(hpcurr) do
- begin
- { pull out }
- hpnext:=tcallparanode(hpcurr.right);
- { pull in at the correct place.
- Used order:
- 1. LOC_REFERENCE with smallest offset (x86 only)
- 2. LOC_REFERENCE with most registers
- 3. LOC_REGISTER with most registers
- For the moment we only look at the first parameter field. Combining it
- with multiple parameter fields will make things a lot complexer (PFV) }
- currloc:=hpcurr.parasym.paraloc[callerside].location^.loc;
- hpprev:=nil;
- hp:=hpfirst;
- while assigned(hp) do
- begin
- case currloc of
- LOC_REFERENCE :
- begin
- case hp.parasym.paraloc[callerside].location^.loc of
- LOC_REFERENCE :
- begin
- { Offset is calculated like:
- sub esp,12
- mov [esp+8],para3
- mov [esp+4],para2
- mov [esp],para1
- call function
- That means the for pushes the para with the
- highest offset (see para3) needs to be pushed first
- }
- if (hpcurr.registersint>hp.registersint)
- {$ifdef x86}
- or (hpcurr.parasym.paraloc[callerside].location^.reference.offset>hp.parasym.paraloc[callerside].location^.reference.offset)
- {$endif x86}
- then
- break;
- end;
- LOC_REGISTER,
- LOC_FPUREGISTER :
- break;
- end;
- end;
- LOC_FPUREGISTER,
- LOC_REGISTER :
- begin
- if (hp.parasym.paraloc[callerside].location^.loc=currloc) and
- (hpcurr.registersint>hp.registersint) then
- break;
- end;
- end;
- hpprev:=hp;
- hp:=tcallparanode(hp.right);
- end;
- hpcurr.right:=hp;
- if assigned(hpprev) then
- hpprev.right:=hpcurr
- else
- hpfirst:=hpcurr;
- { next }
- hpcurr:=hpnext;
- end;
- left:=hpfirst;
- end;
- function tcallnode.replaceparaload(var n: tnode; arg: pointer): foreachnoderesult;
- var
- paras: tcallparanode;
- temp: tnode;
- begin
- result := fen_false;
- n.fileinfo := pfileposinfo(arg)^;
- if (n.nodetype = loadn) then
- begin
- paras := tcallparanode(left);
- while assigned(paras) and
- (paras.parasym <> tloadnode(n).symtableentry) do
- paras := tcallparanode(paras.right);
- if assigned(paras) then
- begin
- n.free;
- n := paras.left.getcopy;
- resulttypepass(n);
- result := fen_true;
- end
- {$ifndef VER1_0}
- else
- begin
- { local? }
- if (tloadnode(n).symtableentry.typ <> localvarsym) then
- exit;
- if (tloadnode(n).symtableentry.indexnr > high(inlinelocals)) or
- not assigned(inlinelocals[tloadnode(n).symtableentry.indexnr]) then
- internalerror(20040720);
- temp := inlinelocals[tloadnode(n).symtableentry.indexnr].getcopy;
- n.free;
- n := temp;
- resulttypepass(n);
- result := fen_true;
- end;
- {$endif ndef VER1_0}
- end;
- end;
- {$ifndef VER1_0}
- type
- ptempnodes = ^ttempnodes;
- ttempnodes = record
- createstatement, deletestatement: tstatementnode;
- end;
- procedure tcallnode.createlocaltemps(p:TNamedIndexItem;arg:pointer);
- var
- tempinfo: ptempnodes absolute ptempnodes(arg);
- tempnode: ttempcreatenode;
- begin
- if (tsymentry(p).typ <> localvarsym) then
- exit;
- if (p.indexnr > high(inlinelocals)) then
- setlength(inlinelocals,p.indexnr+10);
- {$ifndef VER1_0}
- if (vo_is_funcret in tabstractvarsym(p).varoptions) and
- assigned(funcretnode) then
- begin
- if node_complexity(funcretnode) > 1 then
- begin
- { can this happen? }
- { we may have to replace the funcretnode with the address of funcretnode }
- { loaded in a temp in this case, because the expression may e.g. contain }
- { a global variable that gets changed inside the function }
- internalerror(2004072101);
- end;
- inlinelocals[tabstractvarsym(p).indexnr] := funcretnode.getcopy
- end
- else
- {$endif ndef VER1_0}
- begin
- if (cs_regvars in aktglobalswitches) and
- (tabstractvarsym(p).varregable<>vr_none) and
- (not tabstractvarsym(p).vartype.def.needs_inittable) then
- tempnode := ctempcreatenode.create_reg(tabstractvarsym(p).vartype,tabstractvarsym(p).vartype.def.size,tt_persistent)
- else
- tempnode := ctempcreatenode.create(tabstractvarsym(p).vartype,tabstractvarsym(p).vartype.def.size,tt_persistent);
- addstatement(tempinfo^.createstatement,tempnode);
- if assigned(tlocalvarsym(p).defaultconstsym) then
- begin
- { warning: duplicate from psub.pas:initializevars() -> must refactor }
- addstatement(tempinfo^.createstatement,cassignmentnode.create(
- ctemprefnode.create(tempnode),
- cloadnode.create(tlocalvarsym(p).defaultconstsym,tlocalvarsym(p).defaultconstsym.owner)));
- end;
- if (vo_is_funcret in tlocalvarsym(p).varoptions) then
- begin
- funcretnode := ctemprefnode.create(tempnode);
- addstatement(tempinfo^.deletestatement,ctempdeletenode.create_normal_temp(tempnode));
- end
- else
- addstatement(tempinfo^.deletestatement,ctempdeletenode.create(tempnode));
- inlinelocals[p.indexnr] := ctemprefnode.create(tempnode);
- end;
- end;
- {$endif ndef VER1_0}
- procedure tcallnode.createinlineparas(var createstatement, deletestatement: tstatementnode);
- var
- para: tcallparanode;
- tempnode: ttempcreatenode;
- hp: tnode;
- {$ifndef VER1_0}
- tempnodes: ttempnodes;
- {$endif ndef VER1_0}
- begin
- { parameters }
- para := tcallparanode(left);
- while assigned(para) do
- begin
- if (para.parasym.typ = paravarsym) and
- { para.left will already be the same as funcretnode in the following case, so don't change }
- (not(vo_is_funcret in tparavarsym(para.parasym).varoptions) or
- (not assigned(funcretnode))) then
- begin
- { create temps for value parameters, function result and also for }
- { const parameters which are passed by value instead of by reference }
- if (vo_is_funcret in tparavarsym(para.parasym).varoptions) or
- (para.parasym.varspez = vs_value) or
- ((para.parasym.varspez = vs_const) and
- (not paramanager.push_addr_param(vs_const,para.left.resulttype.def,procdefinition.proccalloption) or
- { the problem is that we can't take the address of a function result :( }
- (node_complexity(para.left) >= NODE_COMPLEXITY_INF))) then
- begin
- if (cs_regvars in aktglobalswitches) and
- (tparavarsym(para.parasym).varregable<>vr_none) and
- (not tparavarsym(para.parasym).vartype.def.needs_inittable) then
- tempnode := ctempcreatenode.create_reg(para.left.resulttype,para.left.resulttype.def.size,tt_persistent)
- else
- tempnode := ctempcreatenode.create(para.left.resulttype,para.left.resulttype.def.size,tt_persistent);
- addstatement(createstatement,tempnode);
- { assign the value of the parameter to the temp, except in case of the function result }
- { (in that case, para.left is a block containing the creation of a new temp, while we }
- { only need a temprefnode, so delete the old stuff) }
- if not(vo_is_funcret in tparavarsym(para.parasym).varoptions) then
- begin
- addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
- para.left));
- para.left := ctemprefnode.create(tempnode);
- addstatement(deletestatement,ctempdeletenode.create(tempnode));
- end
- else
- begin
- if not(assigned(funcretnode)) then
- funcretnode := ctemprefnode.create(tempnode);
- para.left.free;
- para.left := ctemprefnode.create(tempnode);
- addstatement(deletestatement,ctempdeletenode.create_normal_temp(tempnode));
- end
- end
- else if node_complexity(para.left) > 1 then
- begin
- if (cs_regvars in aktglobalswitches) and
- not tparavarsym(para.parasym).vartype.def.needs_inittable then
- tempnode := ctempcreatenode.create_reg(voidpointertype,voidpointertype.def.size,tt_persistent)
- else
- tempnode := ctempcreatenode.create(voidpointertype,voidpointertype.def.size,tt_persistent);
- addstatement(createstatement,tempnode);
- addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
- caddrnode.create(para.left)));
- para.left := ctypeconvnode.create_internal(cderefnode.create(ctemprefnode.create(tempnode)),para.left.resulttype);
- addstatement(deletestatement,ctempdeletenode.create(tempnode));
- end;
- para := tcallparanode(para.right);
- end;
- end;
- {$ifndef VER1_0}
- { local variables }
- if not assigned(tprocdef(procdefinition).localst) or
- (tprocdef(procdefinition).localst.symindex.count = 0) then
- exit;
- tempnodes.createstatement := createstatement;
- tempnodes.deletestatement := deletestatement;
- setlength(inlinelocals,tprocdef(procdefinition).localst.symindex.count);
- tprocdef(procdefinition).localst.foreach(@createlocaltemps,@tempnodes);
- createstatement := tempnodes.createstatement;
- deletestatement := tempnodes.deletestatement;
- {$endif ndef VER1_0}
- end;
- function tcallnode.pass_1 : tnode;
- var
- createstatement,deletestatement: tstatementnode;
- createblock,deleteblock: tblocknode;
- i: longint;
- label
- errorexit;
- begin
- result:=nil;
- (*
- if (procdefinition.proccalloption=pocall_inline) and
- { can we inline this procedure at the node level? }
- (tprocdef(procdefinition).inlininginfo^.inlinenode) then
- begin
- { inherit flags }
- current_procinfo.flags := current_procinfo.flags + ((procdefinition as tprocdef).inlininginfo^.flags*inherited_inlining_flags);
- if assigned(methodpointer) then
- CGMessage(cg_e_unable_inline_object_methods);
- if assigned(right) then
- CGMessage(cg_e_unable_inline_procvar);
- if assigned(inlinecode) then
- internalerror(2004071110);
- if assigned(tprocdef(procdefinition).inlininginfo^.code) then
- result:=tprocdef(procdefinition).inlininginfo^.code.getcopy
- else
- CGMessage(cg_e_no_code_for_inline_stored);
- if assigned(result) then
- begin
- createblock := internalstatements(createstatement);
- deleteblock := internalstatements(deletestatement);
- { replace complex parameters with temps }
- createinlineparas(createstatement,deletestatement);
- { replace the parameter loads with the parameter values }
- foreachnode(result,replaceparaload,@fileinfo);
- { free the temps for the locals }
- for i := 0 to high(inlinelocals) do
- if assigned(inlinelocals[i]) then
- inlinelocals[i].free;
- setlength(inlinelocals,0);
- addstatement(createstatement,result);
- addstatement(createstatement,deleteblock);
- { set function result location if necessary }
- if assigned(funcretnode) and
- (cnf_return_value_used in callnodeflags) then
- addstatement(createstatement,funcretnode.getcopy);
- result := createblock;
- { consider it must not be inlined if called
- again inside the args or itself }
- procdefinition.proccalloption:=pocall_default;
- firstpass(result);
- procdefinition.proccalloption:=pocall_inline;
- exit;
- end;
- end;
- *)
- { calculate the parameter info for the procdef }
- if not procdefinition.has_paraloc_info then
- begin
- procdefinition.requiredargarea:=paramanager.create_paraloc_info(procdefinition,callerside);
- procdefinition.has_paraloc_info:=true;
- end;
- { calculate the parameter size needed for this call include varargs if they are available }
- if assigned(varargsparas) then
- pushedparasize:=paramanager.create_varargs_paraloc_info(procdefinition,varargsparas)
- else
- pushedparasize:=procdefinition.requiredargarea;
- { record maximum parameter size used in this proc }
- current_procinfo.allocate_push_parasize(pushedparasize);
- { work trough all parameters to get the register requirements }
- if assigned(left) then
- tcallparanode(left).det_registers;
- { order parameters }
- order_parameters;
- if assigned(methodpointerinit) then
- firstpass(methodpointerinit);
- if assigned(methodpointerdone) then
- firstpass(methodpointerdone);
- { function result node }
- if assigned(_funcretnode) then
- firstpass(_funcretnode);
- { procedure variable ? }
- if assigned(right) then
- begin
- firstpass(right);
- { procedure does a call }
- if not (block_type in [bt_const,bt_type]) then
- include(current_procinfo.flags,pi_do_call);
- end
- else
- { not a procedure variable }
- begin
- if procdefinition.deftype<>procdef then
- internalerror(200411071);
- { calc the correture value for the register }
- { handle predefined procedures }
- if (procdefinition.proccalloption=pocall_inline) then
- begin
- { inherit flags }
- current_procinfo.flags := current_procinfo.flags + (tprocdef(procdefinition).inlininginfo^.flags*inherited_inlining_flags);
- if assigned(methodpointer) then
- CGMessage(cg_e_unable_inline_object_methods);
- if assigned(right) then
- CGMessage(cg_e_unable_inline_procvar);
- if not assigned(inlinecode) then
- begin
- if assigned(tprocdef(procdefinition).inlininginfo^.code) then
- inlinecode:=tprocdef(procdefinition).inlininginfo^.code.getcopy
- else
- CGMessage(cg_e_no_code_for_inline_stored);
- if assigned(inlinecode) then
- begin
- { consider it has not inlined if called
- again inside the args }
- procdefinition.proccalloption:=pocall_default;
- firstpass(inlinecode);
- end;
- end;
- end
- else
- begin
- if not (block_type in [bt_const,bt_type]) then
- include(current_procinfo.flags,pi_do_call);
- end;
- end;
- { implicit finally needed ? }
- if resulttype.def.needs_inittable and
- not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
- not assigned(funcretnode) then
- include(current_procinfo.flags,pi_needs_implicit_finally);
- { get a register for the return value }
- if (not is_void(resulttype.def)) then
- begin
- if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
- begin
- expectloc:=LOC_REFERENCE;
- end
- else
- { for win32 records returned in EDX:EAX, we
- move them to memory after ... }
- if (resulttype.def.deftype=recorddef) then
- begin
- expectloc:=LOC_REFERENCE;
- end
- else
- { ansi/widestrings must be registered, so we can dispose them }
- if is_ansistring(resulttype.def) or
- is_widestring(resulttype.def) then
- begin
- expectloc:=LOC_REFERENCE;
- registersint:=1;
- end
- else
- { we have only to handle the result if it is used }
- if (cnf_return_value_used in callnodeflags) then
- begin
- case resulttype.def.deftype of
- enumdef,
- orddef :
- begin
- if (procdefinition.proctypeoption=potype_constructor) then
- begin
- expectloc:=LOC_REGISTER;
- registersint:=1;
- end
- else
- begin
- expectloc:=LOC_REGISTER;
- if is_64bit(resulttype.def) then
- registersint:=2
- else
- registersint:=1;
- end;
- end;
- floatdef :
- begin
- expectloc:=LOC_FPUREGISTER;
- {$ifdef cpufpemu}
- if (cs_fp_emulation in aktmoduleswitches) then
- registersint:=1
- else
- {$endif cpufpemu}
- {$ifdef m68k}
- if (tfloatdef(resulttype.def).typ=s32real) then
- registersint:=1
- else
- {$endif m68k}
- registersfpu:=1;
- end;
- else
- begin
- expectloc:=LOC_REGISTER;
- registersint:=1;
- end;
- end;
- end
- else
- expectloc:=LOC_VOID;
- end
- else
- expectloc:=LOC_VOID;
- {$ifdef m68k}
- { we need one more address register for virtual calls on m68k }
- if (po_virtualmethod in procdefinition.procoptions) then
- inc(registersint);
- {$endif m68k}
- { a fpu can be used in any procedure !! }
- {$ifdef i386}
- registersfpu:=procdefinition.fpu_used;
- {$endif i386}
- { if this is a call to a method calc the registers }
- if (methodpointer<>nil) then
- begin
- if methodpointer.nodetype<>typen then
- begin
- firstpass(methodpointer);
- registersfpu:=max(methodpointer.registersfpu,registersfpu);
- registersint:=max(methodpointer.registersint,registersint);
- {$ifdef SUPPORT_MMX }
- registersmmx:=max(methodpointer.registersmmx,registersmmx);
- {$endif SUPPORT_MMX}
- end;
- end;
- { determine the registers of the procedure variable }
- { is this OK for inlined procs also ?? (PM) }
- if assigned(inlinecode) then
- begin
- registersfpu:=max(inlinecode.registersfpu,registersfpu);
- registersint:=max(inlinecode.registersint,registersint);
- {$ifdef SUPPORT_MMX}
- registersmmx:=max(inlinecode.registersmmx,registersmmx);
- {$endif SUPPORT_MMX}
- end;
- { determine the registers of the procedure variable }
- { is this OK for inlined procs also ?? (PM) }
- if assigned(right) then
- begin
- registersfpu:=max(right.registersfpu,registersfpu);
- registersint:=max(right.registersint,registersint);
- {$ifdef SUPPORT_MMX}
- registersmmx:=max(right.registersmmx,registersmmx);
- {$endif SUPPORT_MMX}
- end;
- { determine the registers of the procedure }
- if assigned(left) then
- begin
- registersfpu:=max(left.registersfpu,registersfpu);
- registersint:=max(left.registersint,registersint);
- {$ifdef SUPPORT_MMX}
- registersmmx:=max(left.registersmmx,registersmmx);
- {$endif SUPPORT_MMX}
- end;
- errorexit:
- if assigned(inlinecode) then
- procdefinition.proccalloption:=pocall_inline;
- end;
- {$ifdef state_tracking}
- function Tcallnode.track_state_pass(exec_known:boolean):boolean;
- var hp:Tcallparanode;
- value:Tnode;
- begin
- track_state_pass:=false;
- hp:=Tcallparanode(left);
- while assigned(hp) do
- begin
- if left.track_state_pass(exec_known) then
- begin
- left.resulttype.def:=nil;
- do_resulttypepass(left);
- end;
- value:=aktstate.find_fact(hp.left);
- if value<>nil then
- begin
- track_state_pass:=true;
- hp.left.destroy;
- hp.left:=value.getcopy;
- do_resulttypepass(hp.left);
- end;
- hp:=Tcallparanode(hp.right);
- end;
- end;
- {$endif}
- function tcallnode.para_count:longint;
- var
- ppn : tcallparanode;
- begin
- result:=0;
- ppn:=tcallparanode(left);
- while assigned(ppn) do
- begin
- if not(assigned(ppn.parasym) and
- (vo_is_hidden_para in ppn.parasym.varoptions)) then
- inc(result);
- ppn:=tcallparanode(ppn.right);
- end;
- end;
- function tcallnode.docompare(p: tnode): boolean;
- begin
- docompare :=
- inherited docompare(p) and
- (symtableprocentry = tcallnode(p).symtableprocentry) and
- (procdefinition = tcallnode(p).procdefinition) and
- (methodpointer.isequal(tcallnode(p).methodpointer)) and
- (((cnf_restypeset in callnodeflags) and (cnf_restypeset in tcallnode(p).callnodeflags) and
- (equal_defs(restype.def,tcallnode(p).restype.def))) or
- (not(cnf_restypeset in callnodeflags) and not(cnf_restypeset in tcallnode(p).callnodeflags)));
- end;
- procedure tcallnode.printnodedata(var t:text);
- begin
- if assigned(procdefinition) and
- (procdefinition.deftype=procdef) then
- writeln(t,printnodeindention,'proc = ',tprocdef(procdefinition).fullprocname(true))
- else
- begin
- if assigned(symtableprocentry) then
- writeln(t,printnodeindention,'proc = ',symtableprocentry.name)
- else
- writeln(t,printnodeindention,'proc = <nil>');
- end;
- printnode(t,methodpointer);
- printnode(t,right);
- printnode(t,left);
- end;
- begin
- ccallnode:=tcallnode;
- ccallparanode:=tcallparanode;
- end.
- {
- $Log$
- Revision 1.260 2004-11-15 23:35:31 peter
- * tparaitem removed, use tparavarsym instead
- * parameter order is now calculated from paranr value in tparavarsym
- Revision 1.259 2004/11/09 17:26:47 peter
- * fixed wrong typecasts
- Revision 1.258 2004/11/08 22:09:58 peter
- * tvarsym splitted
- Revision 1.257 2004/11/02 12:55:16 peter
- * nf_internal flag for internal inserted typeconvs. This will
- supress the generation of warning/hints
- Revision 1.256 2004/11/01 18:16:48 peter
- * removed wrong check for symtableprocentry
- Revision 1.255 2004/11/01 16:58:57 peter
- * give IE instead of crash when no procsym is passed for calln
- Revision 1.254 2004/10/31 21:45:03 peter
- * generic tlocation
- * move tlocation to cgutils
- Revision 1.253 2004/10/25 15:38:41 peter
- * heap and heapsize removed
- * checkpointer fixes
- Revision 1.252 2004/10/15 09:14:16 mazen
- - remove $IFDEF DELPHI and related code
- - remove $IFDEF FPCPROCVAR and related code
- Revision 1.251 2004/10/12 14:36:38 peter
- * gen high tree makes copy in temp when there is a calln
- Revision 1.250 2004/10/10 20:22:53 peter
- * symtable allocation rewritten
- * loading of parameters to local temps/regs cleanup
- * regvar support for parameters
- * regvar support for staticsymtable (main body)
- Revision 1.249 2004/10/08 17:09:43 peter
- * tvarsym.varregable added, split vo_regable from varoptions
- Revision 1.248 2004/09/21 17:25:12 peter
- * paraloc branch merged
- Revision 1.247 2004/09/13 20:29:00 peter
- * use realname for abstract procs found
- Revision 1.246.4.1 2004/08/31 20:43:06 peter
- * paraloc patch
- Revision 1.246 2004/08/28 20:00:50 peter
- * use objrealname in Message1
- Revision 1.245 2004/08/22 10:17:13 peter
- * fixed crash when passing array constructor to formal parameter
- Revision 1.244 2004/08/14 14:50:42 florian
- * fixed several sparc alignment issues
- + Jonas' inline node patch; non functional yet
- Revision 1.243 2004/07/16 19:45:15 jonas
- + temps can now also hold fpu values in registers (take care with use,
- bacause of the x86 fpu stack)
- * fpu parameters to node-inlined procedures can now also be put in
- a register
- Revision 1.242 2004/07/15 21:02:05 jonas
- * the condition for when to use a temp in case of reference var/const
- parameters was inverse
- Revision 1.241 2004/07/15 19:55:39 jonas
- + (incomplete) node_complexity function to assess the complexity of a
- tree
- + support for inlining value and const parameters at the node level
- (all procedures without local variables and without formal parameters
- can now be inlined at the node level)
- Revision 1.240 2004/07/12 09:14:04 jonas
- * inline procedures at the node tree level, but only under some very
- limited circumstances for now (only procedures, and only if they have
- no or only vs_out/vs_var parameters).
- * fixed ppudump for inline procedures
- * fixed ppudump for ppc
- Revision 1.239 2004/06/20 08:55:29 florian
- * logs truncated
- Revision 1.238 2004/06/16 20:07:08 florian
- * dwarf branch merged
- Revision 1.237 2004/05/25 18:51:49 peter
- * fix tcallnode.getcopy. the parameters need to be copied after
- methodpointerinit is copied
- Revision 1.236 2004/05/24 17:31:51 peter
- * fix passing of array to open array of array (bug 3113)
- Revision 1.235 2004/05/23 18:28:41 peter
- * methodpointer is loaded into a temp when it was a calln
- Revision 1.234 2004/05/23 15:06:20 peter
- * implicit_finally flag must be set in pass1
- * add check whether the implicit frame is generated when expected
- }
|