ncal.pas 130 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273
  1. {
  2. This file implements the node for sub procedure calling.
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncal;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cutils,cclasses,
  22. globtype,
  23. paramgr,parabase,
  24. node,nbas,nutils,
  25. {$ifdef state_tracking}
  26. nstate,
  27. {$endif state_tracking}
  28. symbase,symtype,symsym,symdef,symtable;
  29. type
  30. tcallnodeflag = (
  31. cnf_typedefset,
  32. cnf_return_value_used,
  33. cnf_do_inline,
  34. cnf_inherited,
  35. cnf_anon_inherited,
  36. cnf_new_call,
  37. cnf_dispose_call,
  38. cnf_member_call, { called with implicit methodpointer tree }
  39. cnf_uses_varargs, { varargs are used in the declaration }
  40. cnf_create_failed { exception thrown in constructor -> don't call beforedestruction }
  41. );
  42. tcallnodeflags = set of tcallnodeflag;
  43. tcallnode = class(tbinarynode)
  44. private
  45. { info for inlining }
  46. inlinelocals: TFPObjectList;
  47. { number of parameters passed from the source, this does not include the hidden parameters }
  48. paralength : smallint;
  49. function gen_self_tree_methodpointer:tnode;
  50. function gen_self_tree:tnode;
  51. function gen_vmt_tree:tnode;
  52. procedure bind_parasym;
  53. { function return node, this is used to pass the data for a
  54. ret_in_param return value }
  55. _funcretnode : tnode;
  56. procedure setfuncretnode(const returnnode: tnode);
  57. procedure convert_carg_array_of_const;
  58. procedure order_parameters;
  59. procedure createinlineparas(var createstatement, deletestatement: tstatementnode);
  60. function replaceparaload(var n: tnode; arg: pointer): foreachnoderesult;
  61. procedure createlocaltemps(p:TObject;arg:pointer);
  62. procedure check_inlining;
  63. function pass1_inline:tnode;
  64. function getfuncretassignment(inlineblock: tblocknode): tnode;
  65. protected
  66. pushedparasize : longint;
  67. public
  68. { the symbol containing the definition of the procedure }
  69. { to call }
  70. symtableprocentry : tprocsym;
  71. symtableprocentryderef : tderef;
  72. { symtable where the entry was found, needed for with support }
  73. symtableproc : TSymtable;
  74. { the definition of the procedure to call }
  75. procdefinition : tabstractprocdef;
  76. procdefinitionderef : tderef;
  77. methodpointerinit,
  78. methodpointerdone : tblocknode;
  79. { tree that contains the pointer to the object for this method }
  80. methodpointer : tnode;
  81. { varargs parasyms }
  82. varargsparas : tvarargsparalist;
  83. { node that specifies where the result should be put for calls }
  84. { that return their result in a parameter }
  85. property funcretnode: tnode read _funcretnode write setfuncretnode;
  86. { separately specified resultdef for some compilerprocs (e.g. }
  87. { you can't have a function with an "array of char" resultdef }
  88. { the RTL) (JM) }
  89. typedef: tdef;
  90. callnodeflags : tcallnodeflags;
  91. { only the processor specific nodes need to override this }
  92. { constructor }
  93. constructor create(l:tnode; v : tprocsym;st : TSymtable; mp: tnode; callflags:tcallnodeflags);virtual;
  94. constructor create_procvar(l,r:tnode);
  95. constructor createintern(const name: string; params: tnode);
  96. constructor createinternres(const name: string; params: tnode; res:tdef);
  97. constructor createinternreturn(const name: string; params: tnode; returnnode : tnode);
  98. destructor destroy;override;
  99. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  100. procedure ppuwrite(ppufile:tcompilerppufile);override;
  101. procedure derefnode;override;
  102. procedure buildderefimpl;override;
  103. procedure derefimpl;override;
  104. function dogetcopy : tnode;override;
  105. { Goes through all symbols in a class and subclasses and calls
  106. verify abstract for each .
  107. }
  108. procedure verifyabstractcalls;
  109. { called for each definition in a class and verifies if a method
  110. is abstract or not, if it is abstract, give out a warning
  111. }
  112. procedure verifyabstract(sym:TObject;arg:pointer);
  113. procedure insertintolist(l : tnodelist);override;
  114. function pass_1 : tnode;override;
  115. function pass_typecheck:tnode;override;
  116. {$ifdef state_tracking}
  117. function track_state_pass(exec_known:boolean):boolean;override;
  118. {$endif state_tracking}
  119. function docompare(p: tnode): boolean; override;
  120. procedure printnodedata(var t:text);override;
  121. function para_count:longint;
  122. function get_load_methodpointer:tnode;
  123. { checks if there are any parameters which end up at the stack, i.e.
  124. which have LOC_REFERENCE and set pi_has_stackparameter if this applies }
  125. procedure check_stack_parameters;
  126. property parameters : tnode read left write left;
  127. private
  128. AbstractMethodsList : TFPHashList;
  129. end;
  130. tcallnodeclass = class of tcallnode;
  131. tcallparaflag = (
  132. cpf_is_colon_para,
  133. cpf_varargs_para { belongs this para to varargs }
  134. );
  135. tcallparaflags = set of tcallparaflag;
  136. tcallparanode = class(ttertiarynode)
  137. public
  138. callparaflags : tcallparaflags;
  139. parasym : tparavarsym;
  140. used_by_callnode : boolean;
  141. { only the processor specific nodes need to override this }
  142. { constructor }
  143. constructor create(expr,next : tnode);virtual;
  144. destructor destroy;override;
  145. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  146. procedure ppuwrite(ppufile:tcompilerppufile);override;
  147. function dogetcopy : tnode;override;
  148. procedure insertintolist(l : tnodelist);override;
  149. procedure get_paratype;
  150. procedure insert_typeconv(do_count : boolean);
  151. procedure det_registers;
  152. procedure firstcallparan;
  153. procedure secondcallparan;virtual;abstract;
  154. function docompare(p: tnode): boolean; override;
  155. procedure printnodetree(var t:text);override;
  156. { returns whether a parameter contains a type conversion from }
  157. { a refcounted into a non-refcounted type }
  158. function can_be_inlined: boolean;
  159. property value : tnode read left write left;
  160. property nextpara : tnode read right write right;
  161. property parametername : tnode read third write third;
  162. end;
  163. tcallparanodeclass = class of tcallparanode;
  164. function reverseparameters(p: tcallparanode): tcallparanode;
  165. function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring = '';dispid : longint = 0;useresult : boolean = false) : tnode;
  166. var
  167. ccallnode : tcallnodeclass;
  168. ccallparanode : tcallparanodeclass;
  169. { Current callnode, this is needed for having a link
  170. between the callparanodes and the callnode they belong to }
  171. aktcallnode : tcallnode;
  172. implementation
  173. uses
  174. systems,
  175. verbose,globals,
  176. symconst,defutil,defcmp,
  177. htypechk,pass_1,
  178. ncnv,nld,ninl,nadd,ncon,nmem,nset,
  179. procinfo,
  180. cgbase
  181. ;
  182. type
  183. tobjectinfoitem = class(tlinkedlistitem)
  184. objinfo : tobjectdef;
  185. constructor create(def : tobjectdef);
  186. end;
  187. {****************************************************************************
  188. HELPERS
  189. ****************************************************************************}
  190. function reverseparameters(p: tcallparanode): tcallparanode;
  191. var
  192. hp1, hp2: tcallparanode;
  193. begin
  194. hp1:=nil;
  195. while assigned(p) do
  196. begin
  197. { pull out }
  198. hp2:=p;
  199. p:=tcallparanode(p.right);
  200. { pull in }
  201. hp2.right:=hp1;
  202. hp1:=hp2;
  203. end;
  204. reverseparameters:=hp1;
  205. end;
  206. function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring = '';dispid : longint = 0;useresult : boolean = false) : tnode;
  207. const
  208. DISPATCH_METHOD = $1;
  209. DISPATCH_PROPERTYGET = $2;
  210. DISPATCH_PROPERTYPUT = $4;
  211. DISPATCH_PROPERTYPUTREF = $8;
  212. DISPATCH_CONSTRUCT = $4000;
  213. var
  214. statements : tstatementnode;
  215. result_data,
  216. params : ttempcreatenode;
  217. paramssize : longint;
  218. calldescnode : tdataconstnode;
  219. resultvalue : tnode;
  220. para : tcallparanode;
  221. currargpos,
  222. namedparacount,
  223. paracount : longint;
  224. assignmenttype,
  225. vardatadef,
  226. pvardatadef : tdef;
  227. dispatchbyref : boolean;
  228. calldesc : packed record
  229. calltype,argcount,namedargcount : byte;
  230. { size of argtypes is unknown at compile time
  231. so this is basically a dummy }
  232. argtypes : array[0..255] of byte;
  233. { argtypes is followed by method name
  234. names of named parameters, each being
  235. a zero terminated string
  236. }
  237. end;
  238. names : ansistring;
  239. dispintfinvoke,
  240. variantdispatch : boolean;
  241. procedure increase_paramssize;
  242. begin
  243. { for now we pass everything by reference
  244. case para.value.resultdef.typ of
  245. variantdef:
  246. inc(paramssize,para.value.resultdef.size);
  247. else
  248. }
  249. inc(paramssize,sizeof(voidpointertype.size ));
  250. {
  251. end;
  252. }
  253. end;
  254. begin
  255. variantdispatch:=selfnode.resultdef.typ=variantdef;
  256. dispintfinvoke:=not(variantdispatch);
  257. result:=internalstatements(statements);
  258. fillchar(calldesc,sizeof(calldesc),0);
  259. if useresult then
  260. begin
  261. { get temp for the result }
  262. result_data:=ctempcreatenode.create(colevarianttype,colevarianttype.size,tt_persistent,true);
  263. addstatement(statements,result_data);
  264. end;
  265. { build parameters }
  266. { first, count and check parameters }
  267. // p2:=reverseparameters(tcallparanode(p2));
  268. para:=tcallparanode(parametersnode);
  269. paracount:=0;
  270. namedparacount:=0;
  271. paramssize:=0;
  272. while assigned(para) do
  273. begin
  274. inc(paracount);
  275. typecheckpass(para.value);
  276. { insert some extra casts }
  277. if is_constintnode(para.value) and not(is_64bitint(para.value.resultdef)) then
  278. begin
  279. para.value:=ctypeconvnode.create_internal(para.value,s32inttype);
  280. typecheckpass(para.value);
  281. end
  282. else if para.value.nodetype=stringconstn then
  283. begin
  284. para.value:=ctypeconvnode.create_internal(para.value,cwidestringtype);
  285. typecheckpass(para.value);
  286. end
  287. { force automatable boolean type }
  288. else if is_boolean(para.value.resultdef) then
  289. begin
  290. para.value:=ctypeconvnode.create_internal(para.value,bool16type);
  291. typecheckpass(para.value);
  292. end
  293. { force automatable float type }
  294. else if is_extended(para.value.resultdef) then
  295. begin
  296. para.value:=ctypeconvnode.create_internal(para.value,s64floattype);
  297. typecheckpass(para.value);
  298. end;
  299. if assigned(para.parametername) then
  300. begin
  301. typecheckpass(para.value);
  302. inc(namedparacount);
  303. end;
  304. if para.value.nodetype<>nothingn then
  305. if not is_automatable(para.value.resultdef) then
  306. CGMessagePos1(para.value.fileinfo,type_e_not_automatable,para.value.resultdef.typename);
  307. { we've to know the parameter size to allocate the temp. space }
  308. increase_paramssize;
  309. para:=tcallparanode(para.nextpara);
  310. end;
  311. if assigned(putvalue) then
  312. calldesc.calltype:=DISPATCH_PROPERTYPUT
  313. else
  314. calldesc.calltype:=DISPATCH_METHOD;
  315. calldesc.argcount:=paracount;
  316. { allocate space }
  317. params:=ctempcreatenode.create(voidtype,paramssize,tt_persistent,true);
  318. addstatement(statements,params);
  319. calldescnode:=cdataconstnode.create;
  320. if dispintfinvoke then
  321. calldescnode.append(dispid,sizeof(dispid));
  322. { build up parameters and description }
  323. para:=tcallparanode(parametersnode);
  324. currargpos:=0;
  325. paramssize:=0;
  326. names := '';
  327. while assigned(para) do
  328. begin
  329. if assigned(para.parametername) then
  330. begin
  331. if para.parametername.nodetype=stringconstn then
  332. names:=names+tstringconstnode(para.parametername).value_str+#0
  333. else
  334. internalerror(200611041);
  335. end;
  336. dispatchbyref:=para.value.resultdef.typ in [variantdef];
  337. { assign the argument/parameter to the temporary location }
  338. if para.value.nodetype<>nothingn then
  339. if dispatchbyref then
  340. addstatement(statements,cassignmentnode.create(
  341. ctypeconvnode.create_internal(cderefnode.create(caddnode.create(addn,
  342. caddrnode.create(ctemprefnode.create(params)),
  343. cordconstnode.create(paramssize,ptruinttype,false)
  344. )),voidpointertype),
  345. ctypeconvnode.create_internal(caddrnode.create_internal(para.value),voidpointertype)))
  346. else
  347. begin
  348. case para.value.resultdef.size of
  349. 1..4:
  350. assignmenttype:=u32inttype;
  351. 8:
  352. assignmenttype:=u64inttype;
  353. else
  354. internalerror(2007042801);
  355. end;
  356. addstatement(statements,cassignmentnode.create(
  357. ctypeconvnode.create_internal(cderefnode.create(caddnode.create(addn,
  358. caddrnode.create(ctemprefnode.create(params)),
  359. cordconstnode.create(paramssize,ptruinttype,false)
  360. )),assignmenttype),
  361. ctypeconvnode.create_internal(para.value,assignmenttype)));
  362. end;
  363. if is_ansistring(para.value.resultdef) then
  364. calldesc.argtypes[currargpos]:=varStrArg
  365. else
  366. calldesc.argtypes[currargpos]:=para.value.resultdef.getvardef;
  367. if dispatchbyref then
  368. calldesc.argtypes[currargpos]:=calldesc.argtypes[currargpos] or $80;
  369. increase_paramssize;
  370. para.value:=nil;
  371. inc(currargpos);
  372. para:=tcallparanode(para.nextpara);
  373. end;
  374. // typecheckpass(statements);
  375. // printnode(output,statements);
  376. { old argument list skeleton isn't needed anymore }
  377. parametersnode.free;
  378. calldescnode.append(calldesc,3+calldesc.argcount);
  379. pvardatadef:=tpointerdef(search_system_type('PVARDATA').typedef);
  380. if useresult then
  381. resultvalue:=caddrnode.create(ctemprefnode.create(result_data))
  382. else
  383. resultvalue:=cpointerconstnode.create(0,voidpointertype);
  384. if variantdispatch then
  385. begin
  386. methodname:=methodname+#0;
  387. calldescnode.append(pointer(methodname)^,length(methodname));
  388. calldescnode.append(pointer(names)^,length(names));
  389. { actual call }
  390. vardatadef:=trecorddef(search_system_type('TVARDATA').typedef);
  391. addstatement(statements,ccallnode.createintern('fpc_dispinvoke_variant',
  392. { parameters are passed always reverted, i.e. the last comes first }
  393. ccallparanode.create(caddrnode.create(ctemprefnode.create(params)),
  394. ccallparanode.create(caddrnode.create(calldescnode),
  395. ccallparanode.create(ctypeconvnode.create_internal(selfnode,vardatadef),
  396. ccallparanode.create(ctypeconvnode.create_internal(resultvalue,pvardatadef),nil)))))
  397. );
  398. end
  399. else
  400. begin
  401. addstatement(statements,ccallnode.createintern('fpc_dispatch_by_id',
  402. { parameters are passed always reverted, i.e. the last comes first }
  403. ccallparanode.create(caddrnode.create(ctemprefnode.create(params)),
  404. ccallparanode.create(caddrnode.create(calldescnode),
  405. ccallparanode.create(ctypeconvnode.create_internal(selfnode,voidpointertype),
  406. ccallparanode.create(ctypeconvnode.create_internal(resultvalue,pvardatadef),nil)))))
  407. );
  408. end;
  409. if useresult then
  410. begin
  411. { clean up }
  412. addstatement(statements,ctempdeletenode.create_normal_temp(result_data));
  413. addstatement(statements,ctemprefnode.create(result_data));
  414. end;
  415. end;
  416. procedure maybe_load_para_in_temp(var p:tnode);
  417. function is_simple_node(hp:tnode):boolean;
  418. begin
  419. is_simple_node:=(hp.nodetype in [typen,loadvmtaddrn,loadn,arrayconstructorn]);
  420. end;
  421. var
  422. hp,
  423. loadp,
  424. refp : tnode;
  425. hdef : tdef;
  426. ptemp : ttempcreatenode;
  427. usederef : boolean;
  428. usevoidpointer : boolean;
  429. newinitstatement,
  430. newdonestatement : tstatementnode;
  431. begin
  432. if not assigned(aktcallnode) then
  433. internalerror(200410121);
  434. { Load all complex loads into a temp to prevent
  435. double calls to a function. We can't simply check for a hp.nodetype=calln
  436. }
  437. hp:=p;
  438. while assigned(hp) and
  439. (hp.nodetype=typeconvn) and
  440. (ttypeconvnode(hp).convtype=tc_equal) do
  441. hp:=tunarynode(hp).left;
  442. if assigned(hp) and
  443. not is_simple_node(hp) then
  444. begin
  445. if not assigned(aktcallnode.methodpointerinit) then
  446. begin
  447. aktcallnode.methodpointerinit:=internalstatements(newinitstatement);
  448. aktcallnode.methodpointerdone:=internalstatements(newdonestatement);
  449. end
  450. else
  451. begin
  452. newinitstatement:=laststatement(aktcallnode.methodpointerinit);
  453. newdonestatement:=laststatement(aktcallnode.methodpointerdone);
  454. end;
  455. { temp create }
  456. usederef:=(p.resultdef.typ in [arraydef,recorddef]) or
  457. is_shortstring(p.resultdef) or
  458. is_object(p.resultdef);
  459. { avoid refcount increase }
  460. usevoidpointer:=is_interface(p.resultdef);
  461. if usederef then
  462. hdef:=tpointerdef.create(p.resultdef)
  463. else
  464. hdef:=p.resultdef;
  465. if usevoidpointer then
  466. begin
  467. ptemp:=ctempcreatenode.create(voidpointertype,voidpointertype.size,tt_persistent,true);
  468. loadp := ctypeconvnode.create_internal(p,voidpointertype);
  469. refp:=ctypeconvnode.create_internal(ctemprefnode.create(ptemp),hdef);
  470. end
  471. else
  472. begin
  473. ptemp:=ctempcreatenode.create(hdef,hdef.size,tt_persistent,true);
  474. if usederef then
  475. begin
  476. loadp:=caddrnode.create_internal(p);
  477. refp:=cderefnode.create(ctemprefnode.create(ptemp));
  478. end
  479. else
  480. begin
  481. loadp:=p;
  482. refp:=ctemprefnode.create(ptemp)
  483. end
  484. end;
  485. addstatement(newinitstatement,ptemp);
  486. addstatement(newinitstatement,cassignmentnode.create(
  487. ctemprefnode.create(ptemp),
  488. loadp));
  489. { new tree is only a temp reference }
  490. p:=refp;
  491. { temp release. We need to return a reference to the methodpointer
  492. otherwise the conversion from callnode to loadnode can't be done
  493. for the methodpointer unless the loadnode will also get a methodpointerinit and
  494. methodpointerdone node. For the moment we use register as temp and therefor
  495. don't create a temp-leak in the stackframe (PFV) }
  496. { the last statement should return the value as
  497. location and type, this is done be referencing the
  498. temp and converting it first from a persistent temp to
  499. normal temp }
  500. addstatement(newdonestatement,ctempdeletenode.create_normal_temp(ptemp));
  501. if usevoidpointer then
  502. addstatement(newdonestatement,ctypeconvnode.create_internal(
  503. ctemprefnode.create(ptemp),hdef))
  504. else
  505. addstatement(newdonestatement,ctemprefnode.create(ptemp));
  506. { call typecheckpass for new nodes }
  507. typecheckpass(p);
  508. typecheckpass(aktcallnode.methodpointerinit);
  509. typecheckpass(aktcallnode.methodpointerdone);
  510. end;
  511. end;
  512. function gen_high_tree(var p:tnode;paradef:tdef):tnode;
  513. {When passing an array to an open array, or a string to an open string,
  514. some code is needed that generates the high bound of the array. This
  515. function returns a tree containing the nodes for it.}
  516. var
  517. temp: tnode;
  518. len : integer;
  519. loadconst : boolean;
  520. hightree,l,r : tnode;
  521. begin
  522. len:=-1;
  523. loadconst:=true;
  524. hightree:=nil;
  525. case p.resultdef.typ of
  526. arraydef :
  527. begin
  528. if (paradef.typ<>arraydef) then
  529. internalerror(200405241);
  530. { passing a string to an array of char }
  531. if (p.nodetype=stringconstn) and
  532. is_char(tarraydef(paradef).elementdef) then
  533. begin
  534. len:=tstringconstnode(p).len;
  535. if len>0 then
  536. dec(len);
  537. end
  538. else
  539. { handle special case of passing an single array to an array of array }
  540. if compare_defs(tarraydef(paradef).elementdef,p.resultdef,nothingn)>=te_equal then
  541. len:=0
  542. else
  543. begin
  544. { handle via a normal inline in_high_x node }
  545. loadconst:=false;
  546. { slice? }
  547. if (p.nodetype=inlinen) and (tinlinenode(p).inlinenumber=in_slice_x) then
  548. with Tcallparanode(Tinlinenode(p).left) do
  549. begin
  550. {Array slice using slice builtin function.}
  551. l:=Tcallparanode(right).left;
  552. hightree:=caddnode.create(subn,l,genintconstnode(1));
  553. Tcallparanode(right).left:=nil;
  554. {Remove the inline node.}
  555. temp:=p;
  556. p:=left;
  557. Tcallparanode(tinlinenode(temp).left).left:=nil;
  558. temp.free;
  559. typecheckpass(hightree);
  560. end
  561. else if (p.nodetype=vecn) and (Tvecnode(p).right.nodetype=rangen) then
  562. begin
  563. {Array slice using .. operator.}
  564. with Trangenode(Tvecnode(p).right) do
  565. begin
  566. l:=left; {Get lower bound.}
  567. r:=right; {Get upper bound.}
  568. end;
  569. {In the procedure the array range is 0..(upper_bound-lower_bound).}
  570. hightree:=caddnode.create(subn,r,l);
  571. {Replace the rangnode in the tree by its lower_bound, and
  572. dispose the rangenode.}
  573. temp:=Tvecnode(p).right;
  574. Tvecnode(p).right:=l.getcopy;
  575. {Typecheckpass can only be performed *after* the l.getcopy since it
  576. can modify the tree, and l is in the hightree.}
  577. typecheckpass(hightree);
  578. with Trangenode(temp) do
  579. begin
  580. left:=nil;
  581. right:=nil;
  582. end;
  583. temp.free;
  584. {Tree changed from p[l..h] to p[l], recalculate resultdef.}
  585. p.resultdef:=nil;
  586. typecheckpass(p);
  587. end
  588. else
  589. begin
  590. maybe_load_para_in_temp(p);
  591. hightree:=geninlinenode(in_high_x,false,p.getcopy);
  592. typecheckpass(hightree);
  593. { only substract low(array) if it's <> 0 }
  594. temp:=geninlinenode(in_low_x,false,p.getcopy);
  595. typecheckpass(temp);
  596. if (temp.nodetype <> ordconstn) or
  597. (tordconstnode(temp).value <> 0) then
  598. hightree := caddnode.create(subn,hightree,temp)
  599. else
  600. temp.free;
  601. end;
  602. end;
  603. end;
  604. stringdef :
  605. begin
  606. if is_open_string(paradef) then
  607. begin
  608. maybe_load_para_in_temp(p);
  609. { handle via a normal inline in_high_x node }
  610. loadconst := false;
  611. hightree := geninlinenode(in_high_x,false,p.getcopy);
  612. end
  613. else
  614. { handle special case of passing an single string to an array of string }
  615. if compare_defs(tarraydef(paradef).elementdef,p.resultdef,nothingn)>=te_equal then
  616. len:=0
  617. else
  618. { passing a string to an array of char }
  619. if (p.nodetype=stringconstn) and
  620. is_char(tarraydef(paradef).elementdef) then
  621. begin
  622. len:=tstringconstnode(p).len;
  623. if len>0 then
  624. dec(len);
  625. end
  626. else
  627. begin
  628. maybe_load_para_in_temp(p);
  629. hightree:=caddnode.create(subn,geninlinenode(in_length_x,false,p.getcopy),
  630. cordconstnode.create(1,sinttype,false));
  631. loadconst:=false;
  632. end;
  633. end;
  634. else
  635. len:=0;
  636. end;
  637. if loadconst then
  638. hightree:=cordconstnode.create(len,sinttype,true)
  639. else
  640. begin
  641. if not assigned(hightree) then
  642. internalerror(200304071);
  643. { Need to use explicit, because it can also be a enum }
  644. hightree:=ctypeconvnode.create_internal(hightree,sinttype);
  645. end;
  646. result:=hightree;
  647. end;
  648. {****************************************************************************
  649. TOBJECTINFOITEM
  650. ****************************************************************************}
  651. constructor tobjectinfoitem.create(def : tobjectdef);
  652. begin
  653. inherited create;
  654. objinfo := def;
  655. end;
  656. {****************************************************************************
  657. TCALLPARANODE
  658. ****************************************************************************}
  659. constructor tcallparanode.create(expr,next : tnode);
  660. begin
  661. inherited create(callparan,expr,next,nil);
  662. if not assigned(expr) then
  663. internalerror(200305091);
  664. expr.fileinfo:=fileinfo;
  665. callparaflags:=[];
  666. end;
  667. destructor tcallparanode.destroy;
  668. begin
  669. { When the node is used by callnode then
  670. we don't destroy left, the callnode takes care of it }
  671. if used_by_callnode then
  672. left:=nil;
  673. inherited destroy;
  674. end;
  675. constructor tcallparanode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  676. begin
  677. inherited ppuload(t,ppufile);
  678. ppufile.getsmallset(callparaflags);
  679. end;
  680. procedure tcallparanode.ppuwrite(ppufile:tcompilerppufile);
  681. begin
  682. inherited ppuwrite(ppufile);
  683. ppufile.putsmallset(callparaflags);
  684. end;
  685. function tcallparanode.dogetcopy : tnode;
  686. var
  687. n : tcallparanode;
  688. begin
  689. n:=tcallparanode(inherited dogetcopy);
  690. n.callparaflags:=callparaflags;
  691. n.parasym:=parasym;
  692. result:=n;
  693. end;
  694. procedure tcallparanode.insertintolist(l : tnodelist);
  695. begin
  696. end;
  697. procedure tcallparanode.get_paratype;
  698. var
  699. old_array_constructor : boolean;
  700. begin
  701. inc(parsing_para_level);
  702. if assigned(right) then
  703. tcallparanode(right).get_paratype;
  704. old_array_constructor:=allow_array_constructor;
  705. allow_array_constructor:=true;
  706. typecheckpass(left);
  707. allow_array_constructor:=old_array_constructor;
  708. if codegenerror then
  709. resultdef:=generrordef
  710. else
  711. resultdef:=left.resultdef;
  712. dec(parsing_para_level);
  713. end;
  714. procedure tcallparanode.insert_typeconv(do_count : boolean);
  715. var
  716. olddef : tdef;
  717. hp : tnode;
  718. block : tblocknode;
  719. statements : tstatementnode;
  720. temp : ttempcreatenode;
  721. {$ifdef extdebug}
  722. store_count_ref : boolean;
  723. {$endif def extdebug}
  724. begin
  725. inc(parsing_para_level);
  726. {$ifdef extdebug}
  727. if do_count then
  728. begin
  729. store_count_ref:=count_ref;
  730. count_ref:=true;
  731. end;
  732. {$endif def extdebug}
  733. { Be sure to have the resultdef }
  734. if not assigned(left.resultdef) then
  735. typecheckpass(left);
  736. if (left.nodetype<>nothingn) then
  737. begin
  738. { Convert tp procvars, this is needs to be done
  739. here to make the change permanent. in the overload
  740. choosing the changes are only made temporary }
  741. if (left.resultdef.typ=procvardef) and
  742. (parasym.vardef.typ<>procvardef) then
  743. begin
  744. if maybe_call_procvar(left,true) then
  745. resultdef:=left.resultdef;
  746. end;
  747. { Remove implicitly inserted typecast to pointer for
  748. @procvar in macpas }
  749. if (m_mac_procvar in current_settings.modeswitches) and
  750. (parasym.vardef.typ=procvardef) and
  751. (left.nodetype=typeconvn) and
  752. is_voidpointer(left.resultdef) and
  753. (ttypeconvnode(left).left.nodetype=typeconvn) and
  754. (ttypeconvnode(ttypeconvnode(left).left).convtype=tc_proc_2_procvar) then
  755. begin
  756. hp:=left;
  757. left:=ttypeconvnode(left).left;
  758. ttypeconvnode(hp).left:=nil;
  759. hp.free;
  760. end;
  761. { Handle varargs and hidden paras directly, no typeconvs or }
  762. { pass_typechecking needed }
  763. if (cpf_varargs_para in callparaflags) then
  764. begin
  765. { this should only happen vor C varargs }
  766. { the necessary conversions have already been performed in }
  767. { tarrayconstructornode.insert_typeconvs }
  768. set_varstate(left,vs_read,[vsf_must_be_valid]);
  769. insert_varargstypeconv(left,true);
  770. resultdef:=left.resultdef;
  771. { also update parasym type to get the correct parameter location
  772. for the new types }
  773. parasym.vardef:=left.resultdef;
  774. end
  775. else
  776. if (vo_is_hidden_para in parasym.varoptions) then
  777. begin
  778. set_varstate(left,vs_read,[vsf_must_be_valid]);
  779. resultdef:=left.resultdef;
  780. end
  781. else
  782. begin
  783. { Do we need arrayconstructor -> set conversion, then insert
  784. it here before the arrayconstructor node breaks the tree
  785. with its conversions of enum->ord }
  786. if (left.nodetype=arrayconstructorn) and
  787. (parasym.vardef.typ=setdef) then
  788. inserttypeconv(left,parasym.vardef);
  789. { set some settings needed for arrayconstructor }
  790. if is_array_constructor(left.resultdef) then
  791. begin
  792. if left.nodetype<>arrayconstructorn then
  793. internalerror(200504041);
  794. if is_array_of_const(parasym.vardef) then
  795. begin
  796. { force variant array }
  797. include(left.flags,nf_forcevaria);
  798. end
  799. else
  800. begin
  801. include(left.flags,nf_novariaallowed);
  802. { now that the resultting type is know we can insert the required
  803. typeconvs for the array constructor }
  804. if parasym.vardef.typ=arraydef then
  805. tarrayconstructornode(left).force_type(tarraydef(parasym.vardef).elementdef);
  806. end;
  807. end;
  808. { check if local proc/func is assigned to procvar }
  809. if left.resultdef.typ=procvardef then
  810. test_local_to_procvar(tprocvardef(left.resultdef),parasym.vardef);
  811. { test conversions }
  812. if not(is_shortstring(left.resultdef) and
  813. is_shortstring(parasym.vardef)) and
  814. (parasym.vardef.typ<>formaldef) then
  815. begin
  816. { Process open parameters }
  817. if paramanager.push_high_param(parasym.varspez,parasym.vardef,aktcallnode.procdefinition.proccalloption) then
  818. begin
  819. { insert type conv but hold the ranges of the array }
  820. olddef:=left.resultdef;
  821. inserttypeconv(left,parasym.vardef);
  822. left.resultdef:=olddef;
  823. end
  824. else
  825. begin
  826. check_ranges(left.fileinfo,left,parasym.vardef);
  827. inserttypeconv(left,parasym.vardef);
  828. end;
  829. if codegenerror then
  830. begin
  831. dec(parsing_para_level);
  832. exit;
  833. end;
  834. end;
  835. { truncate shortstring value parameters at the caller side if }
  836. { they are passed by value (if passed by reference, then the }
  837. { callee will truncate when copying in the string) }
  838. { This happens e.g. on x86_64 for small strings }
  839. if is_shortstring(left.resultdef) and
  840. is_shortstring(parasym.vardef) and
  841. (parasym.varspez=vs_value) and
  842. not paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  843. aktcallnode.procdefinition.proccalloption) and
  844. ((is_open_string(left.resultdef) and
  845. (tstringdef(parasym.vardef).len < 255)) or
  846. (not is_open_string(left.resultdef) and
  847. { when a stringconstn is typeconverted, then only its }
  848. { def is modified, not the contents (needed because in }
  849. { Delphi/TP, if you pass a longer string to a const }
  850. { parameter, then the callee has to see this longer }
  851. { string) }
  852. (((left.nodetype<>stringconstn) and
  853. (tstringdef(parasym.vardef).len<tstringdef(left.resultdef).len)) or
  854. ((left.nodetype=stringconstn) and
  855. (tstringdef(parasym.vardef).len<tstringconstnode(left).len))))) then
  856. begin
  857. block:=internalstatements(statements);
  858. { temp for the new string }
  859. temp:=ctempcreatenode.create(parasym.vardef,parasym.vardef.size,
  860. tt_persistent,true);
  861. addstatement(statements,temp);
  862. { assign parameter to temp }
  863. addstatement(statements,cassignmentnode.create(ctemprefnode.create(temp),left));
  864. left:=nil;
  865. { release temp after next use }
  866. addstatement(statements,ctempdeletenode.create_normal_temp(temp));
  867. addstatement(statements,ctemprefnode.create(temp));
  868. typecheckpass(block);
  869. left:=block;
  870. end;
  871. { check var strings }
  872. if (cs_strict_var_strings in current_settings.localswitches) and
  873. is_shortstring(left.resultdef) and
  874. is_shortstring(parasym.vardef) and
  875. (parasym.varspez in [vs_out,vs_var]) and
  876. not(is_open_string(parasym.vardef)) and
  877. not(equal_defs(left.resultdef,parasym.vardef)) then
  878. begin
  879. current_filepos:=left.fileinfo;
  880. CGMessage(type_e_strict_var_string_violation);
  881. end;
  882. { Handle formal parameters separate }
  883. if (parasym.vardef.typ=formaldef) then
  884. begin
  885. { load procvar if a procedure is passed }
  886. if ((m_tp_procvar in current_settings.modeswitches) or
  887. (m_mac_procvar in current_settings.modeswitches)) and
  888. (left.nodetype=calln) and
  889. (is_void(left.resultdef)) then
  890. load_procvar_from_calln(left);
  891. case parasym.varspez of
  892. vs_var,
  893. vs_out :
  894. begin
  895. if not valid_for_formal_var(left,true) then
  896. CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list);
  897. end;
  898. vs_const :
  899. begin
  900. if not valid_for_formal_const(left,true) then
  901. CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list);
  902. end;
  903. end;
  904. end
  905. else
  906. begin
  907. { check if the argument is allowed }
  908. if (parasym.varspez in [vs_out,vs_var]) then
  909. valid_for_var(left,true);
  910. end;
  911. if parasym.varspez in [vs_var,vs_out] then
  912. set_unique(left);
  913. { When the address needs to be pushed then the register is
  914. not regable. Exception is when the location is also a var
  915. parameter and we can pass the address transparently (but
  916. that is handled by make_not_regable if ra_addr_regable is
  917. passed, and make_not_regable always needs to called for
  918. the ra_addr_taken info for non-invisble parameters }
  919. if (
  920. not(
  921. (vo_is_hidden_para in parasym.varoptions) and
  922. (left.resultdef.typ in [pointerdef,classrefdef])
  923. ) and
  924. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  925. aktcallnode.procdefinition.proccalloption)
  926. ) then
  927. { pushing the address of a variable to take the place of a temp }
  928. { as the complex function result of a function does not make its }
  929. { address escape the current block, as the "address of the }
  930. { function result" is not something which can be stored }
  931. { persistently by the callee (it becomes invalid when the callee }
  932. { returns) }
  933. if not(vo_is_funcret in parasym.varoptions) then
  934. make_not_regable(left,[ra_addr_regable,ra_addr_taken])
  935. else
  936. make_not_regable(left,[ra_addr_regable]);
  937. if do_count then
  938. begin
  939. case parasym.varspez of
  940. vs_out :
  941. begin
  942. { first set written separately to avoid false }
  943. { uninitialized warnings (tbs/tb0542) }
  944. set_varstate(left,vs_written,[]);
  945. set_varstate(left,vs_readwritten,[]);
  946. end;
  947. vs_var :
  948. set_varstate(left,vs_readwritten,[vsf_must_be_valid,vsf_use_hints]);
  949. else
  950. set_varstate(left,vs_read,[vsf_must_be_valid]);
  951. end;
  952. end;
  953. { must only be done after typeconv PM }
  954. resultdef:=parasym.vardef;
  955. end;
  956. end;
  957. { process next node }
  958. if assigned(right) then
  959. tcallparanode(right).insert_typeconv(do_count);
  960. dec(parsing_para_level);
  961. {$ifdef extdebug}
  962. if do_count then
  963. count_ref:=store_count_ref;
  964. {$endif def extdebug}
  965. end;
  966. procedure tcallparanode.det_registers;
  967. begin
  968. if assigned(right) then
  969. begin
  970. tcallparanode(right).det_registers;
  971. registersint:=right.registersint;
  972. registersfpu:=right.registersfpu;
  973. {$ifdef SUPPORT_MMX}
  974. registersmmx:=right.registersmmx;
  975. {$endif}
  976. end;
  977. firstpass(left);
  978. if left.registersint>registersint then
  979. registersint:=left.registersint;
  980. if left.registersfpu>registersfpu then
  981. registersfpu:=left.registersfpu;
  982. {$ifdef SUPPORT_MMX}
  983. if left.registersmmx>registersmmx then
  984. registersmmx:=left.registersmmx;
  985. {$endif SUPPORT_MMX}
  986. end;
  987. function tcallparanode.can_be_inlined: boolean;
  988. var
  989. n: tnode;
  990. begin
  991. n:=left;
  992. result:=false;
  993. while assigned(n) and
  994. (n.nodetype=typeconvn) do
  995. begin
  996. { look for type conversion nodes which convert a }
  997. { refcounted type into a non-refcounted type }
  998. if (not n.resultdef.needs_inittable or
  999. is_class(n.resultdef)) and
  1000. (ttypeconvnode(n).left.resultdef.needs_inittable and
  1001. not is_class(ttypeconvnode(n).left.resultdef)) then
  1002. exit;
  1003. n:=ttypeconvnode(n).left;
  1004. end;
  1005. { also check for dereferencing constant pointers, like }
  1006. { tsomerecord(nil^) passed to a const r: tsomerecord }
  1007. { parameter }
  1008. if (n.nodetype=derefn) then
  1009. begin
  1010. repeat
  1011. n:=tunarynode(n).left;
  1012. until (n.nodetype<>typeconvn);
  1013. if (n.nodetype in [niln,pointerconstn]) then
  1014. exit
  1015. end;
  1016. result:=true;
  1017. end;
  1018. procedure tcallparanode.firstcallparan;
  1019. begin
  1020. if not assigned(left.resultdef) then
  1021. get_paratype;
  1022. det_registers;
  1023. end;
  1024. function tcallparanode.docompare(p: tnode): boolean;
  1025. begin
  1026. docompare :=
  1027. inherited docompare(p) and
  1028. (callparaflags = tcallparanode(p).callparaflags)
  1029. ;
  1030. end;
  1031. procedure tcallparanode.printnodetree(var t:text);
  1032. begin
  1033. printnodelist(t);
  1034. end;
  1035. {****************************************************************************
  1036. TCALLNODE
  1037. ****************************************************************************}
  1038. constructor tcallnode.create(l:tnode;v : tprocsym;st : TSymtable; mp: tnode; callflags:tcallnodeflags);
  1039. begin
  1040. inherited create(calln,l,nil);
  1041. symtableprocentry:=v;
  1042. symtableproc:=st;
  1043. callnodeflags:=callflags+[cnf_return_value_used];
  1044. methodpointer:=mp;
  1045. methodpointerinit:=nil;
  1046. methodpointerdone:=nil;
  1047. procdefinition:=nil;
  1048. _funcretnode:=nil;
  1049. paralength:=-1;
  1050. varargsparas:=nil;
  1051. end;
  1052. constructor tcallnode.create_procvar(l,r:tnode);
  1053. begin
  1054. inherited create(calln,l,r);
  1055. symtableprocentry:=nil;
  1056. symtableproc:=nil;
  1057. methodpointer:=nil;
  1058. methodpointerinit:=nil;
  1059. methodpointerdone:=nil;
  1060. procdefinition:=nil;
  1061. callnodeflags:=[cnf_return_value_used];
  1062. _funcretnode:=nil;
  1063. paralength:=-1;
  1064. varargsparas:=nil;
  1065. end;
  1066. constructor tcallnode.createintern(const name: string; params: tnode);
  1067. var
  1068. srsym: tsym;
  1069. begin
  1070. srsym := tsym(systemunit.Find(name));
  1071. if not assigned(srsym) and
  1072. (cs_compilesystem in current_settings.moduleswitches) then
  1073. srsym := tsym(systemunit.Find(upper(name)));
  1074. if not assigned(srsym) or
  1075. (srsym.typ<>procsym) then
  1076. Message1(cg_f_unknown_compilerproc,name);
  1077. create(params,tprocsym(srsym),srsym.owner,nil,[]);
  1078. end;
  1079. constructor tcallnode.createinternres(const name: string; params: tnode; res:tdef);
  1080. var
  1081. pd : tprocdef;
  1082. begin
  1083. createintern(name,params);
  1084. typedef := res;
  1085. include(callnodeflags,cnf_typedefset);
  1086. pd:=tprocdef(symtableprocentry.ProcdefList[0]);
  1087. { both the normal and specified resultdef either have to be returned via a }
  1088. { parameter or not, but no mixing (JM) }
  1089. if paramanager.ret_in_param(typedef,pd.proccalloption) xor
  1090. paramanager.ret_in_param(pd.returndef,pd.proccalloption) then
  1091. internalerror(200108291);
  1092. end;
  1093. constructor tcallnode.createinternreturn(const name: string; params: tnode; returnnode : tnode);
  1094. var
  1095. pd : tprocdef;
  1096. begin
  1097. createintern(name,params);
  1098. _funcretnode:=returnnode;
  1099. pd:=tprocdef(symtableprocentry.ProcdefList[0]);
  1100. if not paramanager.ret_in_param(pd.returndef,pd.proccalloption) then
  1101. internalerror(200204247);
  1102. end;
  1103. procedure tcallnode.setfuncretnode(const returnnode: tnode);
  1104. var
  1105. para: tcallparanode;
  1106. begin
  1107. if assigned(_funcretnode) then
  1108. _funcretnode.free;
  1109. _funcretnode := returnnode;
  1110. { if the resultdef pass hasn't occurred yet, that one will do }
  1111. { everything }
  1112. if assigned(resultdef) then
  1113. begin
  1114. { these are returned as values, but we can optimize their loading }
  1115. { as well }
  1116. if is_ansistring(resultdef) or
  1117. is_widestring(resultdef) then
  1118. exit;
  1119. para := tcallparanode(left);
  1120. while assigned(para) do
  1121. begin
  1122. if (vo_is_hidden_para in para.parasym.varoptions) and
  1123. (vo_is_funcret in tparavarsym(para.parasym).varoptions) then
  1124. begin
  1125. para.left.free;
  1126. para.left := _funcretnode.getcopy;
  1127. exit;
  1128. end;
  1129. para := tcallparanode(para.right);
  1130. end;
  1131. { no hidden resultpara found, error! }
  1132. if not(po_inline in procdefinition.procoptions) then
  1133. internalerror(200306087);
  1134. end;
  1135. end;
  1136. destructor tcallnode.destroy;
  1137. begin
  1138. methodpointer.free;
  1139. methodpointerinit.free;
  1140. methodpointerdone.free;
  1141. _funcretnode.free;
  1142. if assigned(varargsparas) then
  1143. varargsparas.free;
  1144. inherited destroy;
  1145. end;
  1146. constructor tcallnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  1147. begin
  1148. methodpointerinit:=tblocknode(ppuloadnode(ppufile));
  1149. methodpointer:=ppuloadnode(ppufile);
  1150. methodpointerdone:=tblocknode(ppuloadnode(ppufile));
  1151. _funcretnode:=ppuloadnode(ppufile);
  1152. inherited ppuload(t,ppufile);
  1153. ppufile.getderef(symtableprocentryderef);
  1154. {$warning FIXME: No withsymtable support}
  1155. symtableproc:=nil;
  1156. ppufile.getderef(procdefinitionderef);
  1157. ppufile.getsmallset(callnodeflags);
  1158. end;
  1159. procedure tcallnode.ppuwrite(ppufile:tcompilerppufile);
  1160. begin
  1161. ppuwritenode(ppufile,methodpointerinit);
  1162. ppuwritenode(ppufile,methodpointer);
  1163. ppuwritenode(ppufile,methodpointerdone);
  1164. ppuwritenode(ppufile,_funcretnode);
  1165. inherited ppuwrite(ppufile);
  1166. ppufile.putderef(symtableprocentryderef);
  1167. ppufile.putderef(procdefinitionderef);
  1168. ppufile.putsmallset(callnodeflags);
  1169. end;
  1170. procedure tcallnode.derefnode;
  1171. begin
  1172. if assigned(methodpointerinit) then
  1173. methodpointerinit.derefnode;
  1174. if assigned(methodpointer) then
  1175. methodpointer.derefnode;
  1176. if assigned(methodpointerdone) then
  1177. methodpointerdone.derefnode;
  1178. if assigned(_funcretnode) then
  1179. _funcretnode.derefnode;
  1180. inherited derefnode;
  1181. end;
  1182. procedure tcallnode.buildderefimpl;
  1183. begin
  1184. inherited buildderefimpl;
  1185. symtableprocentryderef.build(symtableprocentry);
  1186. procdefinitionderef.build(procdefinition);
  1187. if assigned(methodpointer) then
  1188. methodpointer.buildderefimpl;
  1189. if assigned(methodpointerinit) then
  1190. methodpointerinit.buildderefimpl;
  1191. if assigned(methodpointerdone) then
  1192. methodpointerdone.buildderefimpl;
  1193. if assigned(_funcretnode) then
  1194. _funcretnode.buildderefimpl;
  1195. end;
  1196. procedure tcallnode.derefimpl;
  1197. var
  1198. pt : tcallparanode;
  1199. i : integer;
  1200. begin
  1201. inherited derefimpl;
  1202. symtableprocentry:=tprocsym(symtableprocentryderef.resolve);
  1203. if assigned(symtableprocentry) then
  1204. symtableproc:=symtableprocentry.owner;
  1205. procdefinition:=tabstractprocdef(procdefinitionderef.resolve);
  1206. if assigned(methodpointer) then
  1207. methodpointer.derefimpl;
  1208. if assigned(methodpointerinit) then
  1209. methodpointerinit.derefimpl;
  1210. if assigned(methodpointerdone) then
  1211. methodpointerdone.derefimpl;
  1212. if assigned(_funcretnode) then
  1213. _funcretnode.derefimpl;
  1214. { Connect parasyms }
  1215. pt:=tcallparanode(left);
  1216. while assigned(pt) and
  1217. (cpf_varargs_para in pt.callparaflags) do
  1218. pt:=tcallparanode(pt.right);
  1219. for i:=procdefinition.paras.count-1 downto 0 do
  1220. begin
  1221. if not assigned(pt) then
  1222. internalerror(200311077);
  1223. pt.parasym:=tparavarsym(procdefinition.paras[i]);
  1224. pt:=tcallparanode(pt.right);
  1225. end;
  1226. if assigned(pt) then
  1227. internalerror(200311078);
  1228. end;
  1229. function tcallnode.dogetcopy : tnode;
  1230. var
  1231. n : tcallnode;
  1232. i : integer;
  1233. hp,hpn : tparavarsym;
  1234. oldleft : tnode;
  1235. begin
  1236. { Need to use a hack here to prevent the parameters from being copied.
  1237. The parameters must be copied between methodpointerinit/methodpointerdone because
  1238. the can reference methodpointer }
  1239. oldleft:=left;
  1240. left:=nil;
  1241. n:=tcallnode(inherited dogetcopy);
  1242. left:=oldleft;
  1243. n.symtableprocentry:=symtableprocentry;
  1244. n.symtableproc:=symtableproc;
  1245. n.procdefinition:=procdefinition;
  1246. n.typedef := typedef;
  1247. n.callnodeflags := callnodeflags;
  1248. if assigned(methodpointerinit) then
  1249. n.methodpointerinit:=tblocknode(methodpointerinit.dogetcopy)
  1250. else
  1251. n.methodpointerinit:=nil;
  1252. { methodpointerinit is copied, now references to the temp will also be copied
  1253. correctly. We can now copy the parameters and methodpointer }
  1254. if assigned(left) then
  1255. n.left:=left.dogetcopy
  1256. else
  1257. n.left:=nil;
  1258. if assigned(methodpointer) then
  1259. n.methodpointer:=methodpointer.dogetcopy
  1260. else
  1261. n.methodpointer:=nil;
  1262. if assigned(methodpointerdone) then
  1263. n.methodpointerdone:=tblocknode(methodpointerdone.dogetcopy)
  1264. else
  1265. n.methodpointerdone:=nil;
  1266. if assigned(_funcretnode) then
  1267. n._funcretnode:=_funcretnode.dogetcopy
  1268. else
  1269. n._funcretnode:=nil;
  1270. if assigned(varargsparas) then
  1271. begin
  1272. n.varargsparas:=tvarargsparalist.create(true);
  1273. for i:=0 to varargsparas.count-1 do
  1274. begin
  1275. hp:=tparavarsym(varargsparas[i]);
  1276. hpn:=tparavarsym.create(hp.realname,hp.paranr,hp.varspez,hp.vardef,[]);
  1277. n.varargsparas.add(hpn);
  1278. end;
  1279. end
  1280. else
  1281. n.varargsparas:=nil;
  1282. result:=n;
  1283. end;
  1284. procedure tcallnode.insertintolist(l : tnodelist);
  1285. begin
  1286. end;
  1287. procedure tcallnode.convert_carg_array_of_const;
  1288. var
  1289. hp : tarrayconstructornode;
  1290. oldleft : tcallparanode;
  1291. begin
  1292. oldleft:=tcallparanode(left);
  1293. if oldleft.left.nodetype<>arrayconstructorn then
  1294. begin
  1295. CGMessage1(type_e_wrong_type_in_array_constructor,oldleft.left.resultdef.typename);
  1296. exit;
  1297. end;
  1298. include(callnodeflags,cnf_uses_varargs);
  1299. { Get arrayconstructor node and insert typeconvs }
  1300. hp:=tarrayconstructornode(oldleft.left);
  1301. { Add c args parameters }
  1302. { It could be an empty set }
  1303. if assigned(hp) and
  1304. assigned(hp.left) then
  1305. begin
  1306. while assigned(hp) do
  1307. begin
  1308. left:=ccallparanode.create(hp.left,left);
  1309. { set callparanode resultdef and flags }
  1310. left.resultdef:=hp.left.resultdef;
  1311. include(tcallparanode(left).callparaflags,cpf_varargs_para);
  1312. hp.left:=nil;
  1313. hp:=tarrayconstructornode(hp.right);
  1314. end;
  1315. end;
  1316. { Remove value of old array of const parameter, but keep it
  1317. in the list because it is required for bind_parasym.
  1318. Generate a nothign to keep callparanoed.left valid }
  1319. oldleft.left.free;
  1320. oldleft.left:=cnothingnode.create;
  1321. end;
  1322. procedure tcallnode.verifyabstract(sym:TObject;arg:pointer);
  1323. var
  1324. pd : tprocdef;
  1325. i : longint;
  1326. j : integer;
  1327. hs : string;
  1328. begin
  1329. if (tsym(sym).typ<>procsym) then
  1330. exit;
  1331. for i:=0 to tprocsym(sym).ProcdefList.Count-1 do
  1332. begin
  1333. pd:=tprocdef(tprocsym(sym).ProcdefList[i]);
  1334. hs:=pd.procsym.name+pd.typename_paras(false);
  1335. j:=AbstractMethodsList.FindIndexOf(hs);
  1336. if j<>-1 then
  1337. AbstractMethodsList[j]:=pd
  1338. else
  1339. AbstractMethodsList.Add(hs,pd);
  1340. end;
  1341. end;
  1342. procedure tcallnode.verifyabstractcalls;
  1343. var
  1344. objectdf : tobjectdef;
  1345. parents : tlinkedlist;
  1346. objectinfo : tobjectinfoitem;
  1347. pd : tprocdef;
  1348. i : integer;
  1349. first : boolean;
  1350. begin
  1351. objectdf := nil;
  1352. { verify if trying to create an instance of a class which contains
  1353. non-implemented abstract methods }
  1354. { first verify this class type, no class than exit }
  1355. { also, this checking can only be done if the constructor is directly
  1356. called, indirect constructor calls cannot be checked.
  1357. }
  1358. if assigned(methodpointer) and
  1359. not (nf_is_self in methodpointer.flags) then
  1360. begin
  1361. if (methodpointer.resultdef.typ = objectdef) then
  1362. objectdf:=tobjectdef(methodpointer.resultdef)
  1363. else
  1364. if (methodpointer.resultdef.typ = classrefdef) and
  1365. (tclassrefdef(methodpointer.resultdef).pointeddef.typ = objectdef) and
  1366. (methodpointer.nodetype in [typen,loadvmtaddrn]) then
  1367. objectdf:=tobjectdef(tclassrefdef(methodpointer.resultdef).pointeddef);
  1368. end;
  1369. if not assigned(objectdf) then
  1370. exit;
  1371. parents := tlinkedlist.create;
  1372. AbstractMethodsList := TFPHashList.create;
  1373. { insert all parents in this class : the first item in the
  1374. list will be the base parent of the class .
  1375. }
  1376. while assigned(objectdf) do
  1377. begin
  1378. objectinfo:=tobjectinfoitem.create(objectdf);
  1379. parents.insert(objectinfo);
  1380. objectdf := objectdf.childof;
  1381. end;
  1382. { now all parents are in the correct order
  1383. insert all abstract methods in the list, and remove
  1384. those which are overriden by parent classes.
  1385. }
  1386. objectinfo:=tobjectinfoitem(parents.first);
  1387. while assigned(objectinfo) do
  1388. begin
  1389. objectdf := objectinfo.objinfo;
  1390. if assigned(objectdf.symtable) then
  1391. objectdf.symtable.SymList.ForEachCall(@verifyabstract,nil);
  1392. objectinfo:=tobjectinfoitem(objectinfo.next);
  1393. end;
  1394. if assigned(parents) then
  1395. parents.free;
  1396. { Finally give out a warning for each abstract method still in the list }
  1397. first:=true;
  1398. for i:=0 to AbstractMethodsList.Count-1 do
  1399. begin
  1400. pd:=tprocdef(AbstractMethodsList[i]);
  1401. if po_abstractmethod in pd.procoptions then
  1402. begin
  1403. if first then
  1404. begin
  1405. Message1(type_w_instance_with_abstract,objectdf.objrealname^);
  1406. first:=false;
  1407. end;
  1408. MessagePos1(pd.fileinfo,sym_h_abstract_method_list,pd.fullprocname(true));
  1409. end;
  1410. end;
  1411. if assigned(AbstractMethodsList) then
  1412. AbstractMethodsList.Free;
  1413. end;
  1414. function tcallnode.gen_self_tree_methodpointer:tnode;
  1415. var
  1416. hsym : tfieldvarsym;
  1417. begin
  1418. { find self field in methodpointer record }
  1419. hsym:=tfieldvarsym(trecorddef(methodpointertype).symtable.Find('self'));
  1420. if not assigned(hsym) then
  1421. internalerror(200305251);
  1422. { Load tmehodpointer(right).self }
  1423. result:=csubscriptnode.create(
  1424. hsym,
  1425. ctypeconvnode.create_internal(right.getcopy,methodpointertype));
  1426. end;
  1427. function tcallnode.gen_self_tree:tnode;
  1428. var
  1429. selftree : tnode;
  1430. begin
  1431. selftree:=nil;
  1432. { inherited }
  1433. if (cnf_inherited in callnodeflags) then
  1434. selftree:=load_self_node
  1435. else
  1436. { constructors }
  1437. if (procdefinition.proctypeoption=potype_constructor) then
  1438. begin
  1439. { push 0 as self when allocation is needed }
  1440. if (methodpointer.resultdef.typ=classrefdef) or
  1441. (cnf_new_call in callnodeflags) then
  1442. selftree:=cpointerconstnode.create(0,voidpointertype)
  1443. else
  1444. begin
  1445. if methodpointer.nodetype=typen then
  1446. selftree:=load_self_node
  1447. else
  1448. selftree:=methodpointer.getcopy;
  1449. end;
  1450. end
  1451. else
  1452. { Calling a static/class method }
  1453. if (po_classmethod in procdefinition.procoptions) or
  1454. (po_staticmethod in procdefinition.procoptions) then
  1455. begin
  1456. if (procdefinition.typ<>procdef) then
  1457. internalerror(200305062);
  1458. if (oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
  1459. begin
  1460. { we only need the vmt, loading self is not required and there is no
  1461. need to check for typen, because that will always get the
  1462. loadvmtaddrnode added }
  1463. selftree:=methodpointer.getcopy;
  1464. if (methodpointer.resultdef.typ<>classrefdef) or
  1465. (methodpointer.nodetype = typen) then
  1466. selftree:=cloadvmtaddrnode.create(selftree);
  1467. end
  1468. else
  1469. selftree:=cpointerconstnode.create(0,voidpointertype);
  1470. end
  1471. else
  1472. begin
  1473. if methodpointer.nodetype=typen then
  1474. selftree:=load_self_node
  1475. else
  1476. selftree:=methodpointer.getcopy;
  1477. end;
  1478. result:=selftree;
  1479. end;
  1480. function tcallnode.gen_vmt_tree:tnode;
  1481. var
  1482. vmttree : tnode;
  1483. begin
  1484. vmttree:=nil;
  1485. if not(procdefinition.proctypeoption in [potype_constructor,potype_destructor]) then
  1486. internalerror(200305051);
  1487. { Handle classes and legacy objects separate to make it
  1488. more maintainable }
  1489. if (methodpointer.resultdef.typ=classrefdef) then
  1490. begin
  1491. if not is_class(tclassrefdef(methodpointer.resultdef).pointeddef) then
  1492. internalerror(200501041);
  1493. { constructor call via classreference => allocate memory }
  1494. if (procdefinition.proctypeoption=potype_constructor) then
  1495. begin
  1496. vmttree:=methodpointer.getcopy;
  1497. { Only a typenode can be passed when it is called with <class of xx>.create }
  1498. if vmttree.nodetype=typen then
  1499. vmttree:=cloadvmtaddrnode.create(vmttree);
  1500. end
  1501. else
  1502. begin
  1503. { Call afterconstruction }
  1504. vmttree:=cpointerconstnode.create(1,voidpointertype);
  1505. end;
  1506. end
  1507. else
  1508. { Class style objects }
  1509. if is_class(methodpointer.resultdef) then
  1510. begin
  1511. { inherited call, no create/destroy }
  1512. if (cnf_inherited in callnodeflags) then
  1513. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1514. else
  1515. { do not create/destroy when called from member function
  1516. without specifying self explicit }
  1517. if (cnf_member_call in callnodeflags) then
  1518. begin
  1519. { destructor: don't release instance, vmt=0
  1520. constructor:
  1521. if called from a constructor in the same class then
  1522. don't call afterconstruction, vmt=0
  1523. else
  1524. call afterconstrution, vmt=1 }
  1525. if (procdefinition.proctypeoption=potype_destructor) then
  1526. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1527. else if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  1528. (procdefinition.proctypeoption=potype_constructor) then
  1529. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1530. else
  1531. vmttree:=cpointerconstnode.create(1,voidpointertype);
  1532. end
  1533. else
  1534. { normal call to method like cl1.proc }
  1535. begin
  1536. { destructor:
  1537. if not called from exception block in constructor
  1538. call beforedestruction and release instance, vmt=1
  1539. else
  1540. don't call beforedestruction and release instance, vmt=-1
  1541. constructor:
  1542. if called from a constructor in the same class using self.create then
  1543. don't call afterconstruction, vmt=0
  1544. else
  1545. call afterconstrution, vmt=1 }
  1546. if (procdefinition.proctypeoption=potype_destructor) then
  1547. if not(cnf_create_failed in callnodeflags) then
  1548. vmttree:=cpointerconstnode.create(1,voidpointertype)
  1549. else
  1550. vmttree:=cpointerconstnode.create(TConstPtrUInt(-1),voidpointertype)
  1551. else
  1552. begin
  1553. if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  1554. (procdefinition.proctypeoption=potype_constructor) and
  1555. (nf_is_self in methodpointer.flags) then
  1556. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1557. else
  1558. vmttree:=cpointerconstnode.create(1,voidpointertype);
  1559. end;
  1560. end;
  1561. end
  1562. else
  1563. { Old style object }
  1564. begin
  1565. { constructor with extended syntax called from new }
  1566. if (cnf_new_call in callnodeflags) then
  1567. vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resultdef))
  1568. else
  1569. { destructor with extended syntax called from dispose }
  1570. if (cnf_dispose_call in callnodeflags) then
  1571. vmttree:=cloadvmtaddrnode.create(methodpointer.getcopy)
  1572. else
  1573. { inherited call, no create/destroy }
  1574. if (cnf_inherited in callnodeflags) then
  1575. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1576. else
  1577. { do not create/destroy when called from member function
  1578. without specifying self explicit }
  1579. if (cnf_member_call in callnodeflags) then
  1580. begin
  1581. { destructor: don't release instance, vmt=0
  1582. constructor: don't initialize instance, vmt=0 }
  1583. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1584. end
  1585. else
  1586. { normal object call like obj.proc }
  1587. begin
  1588. { destructor: direct call, no dispose, vmt=0
  1589. constructor: initialize object, load vmt }
  1590. if (procdefinition.proctypeoption=potype_constructor) then
  1591. begin
  1592. { old styled inherited call? }
  1593. if (methodpointer.nodetype=typen) then
  1594. vmttree:=cpointerconstnode.create(0,voidpointertype)
  1595. else
  1596. vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resultdef))
  1597. end
  1598. else
  1599. vmttree:=cpointerconstnode.create(0,voidpointertype);
  1600. end;
  1601. end;
  1602. result:=vmttree;
  1603. end;
  1604. type
  1605. pcallparanode = ^tcallparanode;
  1606. procedure tcallnode.bind_parasym;
  1607. var
  1608. i : integer;
  1609. pt : tcallparanode;
  1610. oldppt : pcallparanode;
  1611. varargspara,
  1612. currpara : tparavarsym;
  1613. used_by_callnode : boolean;
  1614. hiddentree : tnode;
  1615. newstatement : tstatementnode;
  1616. temp : ttempcreatenode;
  1617. begin
  1618. pt:=tcallparanode(left);
  1619. oldppt:=pcallparanode(@left);
  1620. { flag all callparanodes that belong to the varargs }
  1621. i:=paralength;
  1622. while (i>procdefinition.maxparacount) do
  1623. begin
  1624. include(pt.callparaflags,cpf_varargs_para);
  1625. oldppt:=pcallparanode(@pt.right);
  1626. pt:=tcallparanode(pt.right);
  1627. dec(i);
  1628. end;
  1629. { skip varargs that are inserted by array of const }
  1630. while assigned(pt) and
  1631. (cpf_varargs_para in pt.callparaflags) do
  1632. pt:=tcallparanode(pt.right);
  1633. { process normal parameters and insert hidden parameters }
  1634. for i:=procdefinition.paras.count-1 downto 0 do
  1635. begin
  1636. currpara:=tparavarsym(procdefinition.paras[i]);
  1637. if vo_is_hidden_para in currpara.varoptions then
  1638. begin
  1639. { generate hidden tree }
  1640. used_by_callnode:=false;
  1641. hiddentree:=nil;
  1642. if (vo_is_funcret in currpara.varoptions) then
  1643. begin
  1644. { Generate funcretnode if not specified }
  1645. if assigned(funcretnode) then
  1646. begin
  1647. hiddentree:=funcretnode.getcopy;
  1648. end
  1649. else
  1650. begin
  1651. hiddentree:=internalstatements(newstatement);
  1652. { need to use resultdef instead of procdefinition.returndef,
  1653. because they can be different }
  1654. temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,false);
  1655. addstatement(newstatement,temp);
  1656. addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
  1657. addstatement(newstatement,ctemprefnode.create(temp));
  1658. end;
  1659. end
  1660. else
  1661. if vo_is_high_para in currpara.varoptions then
  1662. begin
  1663. if not assigned(pt) or
  1664. (i=0) then
  1665. internalerror(200304082);
  1666. { we need the information of the previous parameter }
  1667. hiddentree:=gen_high_tree(pt.left,tparavarsym(procdefinition.paras[i-1]).vardef);
  1668. end
  1669. else
  1670. if vo_is_self in currpara.varoptions then
  1671. begin
  1672. if assigned(right) then
  1673. hiddentree:=gen_self_tree_methodpointer
  1674. else
  1675. hiddentree:=gen_self_tree;
  1676. end
  1677. else
  1678. if vo_is_vmt in currpara.varoptions then
  1679. begin
  1680. hiddentree:=gen_vmt_tree;
  1681. end
  1682. {$if defined(powerpc) or defined(m68k)}
  1683. else
  1684. if vo_is_syscall_lib in currpara.varoptions then
  1685. begin
  1686. { lib parameter has no special type but proccalloptions must be a syscall }
  1687. hiddentree:=cloadnode.create(tprocdef(procdefinition).libsym,tprocdef(procdefinition).libsym.owner);
  1688. end
  1689. {$endif powerpc or m68k}
  1690. else
  1691. if vo_is_parentfp in currpara.varoptions then
  1692. begin
  1693. if not(assigned(procdefinition.owner.defowner)) then
  1694. internalerror(200309287);
  1695. hiddentree:=cloadparentfpnode.create(tprocdef(procdefinition.owner.defowner));
  1696. end;
  1697. { add the hidden parameter }
  1698. if not assigned(hiddentree) then
  1699. internalerror(200304073);
  1700. { Already insert para and let the previous node point to
  1701. this new node }
  1702. pt:=ccallparanode.create(hiddentree,oldppt^);
  1703. pt.used_by_callnode:=used_by_callnode;
  1704. oldppt^:=pt;
  1705. end;
  1706. if not assigned(pt) then
  1707. internalerror(200310052);
  1708. pt.parasym:=currpara;
  1709. oldppt:=pcallparanode(@pt.right);
  1710. pt:=tcallparanode(pt.right);
  1711. end;
  1712. { Create parasyms for varargs, first count the number of varargs paras,
  1713. then insert the parameters with numbering in reverse order. The SortParas
  1714. will set the correct order at the end}
  1715. pt:=tcallparanode(left);
  1716. i:=0;
  1717. while assigned(pt) do
  1718. begin
  1719. if cpf_varargs_para in pt.callparaflags then
  1720. inc(i);
  1721. pt:=tcallparanode(pt.right);
  1722. end;
  1723. if (i>0) then
  1724. begin
  1725. varargsparas:=tvarargsparalist.create;
  1726. pt:=tcallparanode(left);
  1727. while assigned(pt) do
  1728. begin
  1729. if cpf_varargs_para in pt.callparaflags then
  1730. begin
  1731. varargspara:=tparavarsym.create('va'+tostr(i),i,vs_value,pt.resultdef,[]);
  1732. dec(i);
  1733. { varargspara is left-right, use insert
  1734. instead of concat }
  1735. varargsparas.add(varargspara);
  1736. pt.parasym:=varargspara;
  1737. end;
  1738. pt:=tcallparanode(pt.right);
  1739. end;
  1740. varargsparas.sortparas;
  1741. end;
  1742. end;
  1743. function tcallnode.pass_typecheck:tnode;
  1744. var
  1745. candidates : tcallcandidates;
  1746. oldcallnode : tcallnode;
  1747. hpt : tnode;
  1748. pt : tcallparanode;
  1749. lastpara : longint;
  1750. paraidx,
  1751. cand_cnt : integer;
  1752. i : longint;
  1753. is_const : boolean;
  1754. statements : tstatementnode;
  1755. converted_result_data : ttempcreatenode;
  1756. label
  1757. errorexit;
  1758. begin
  1759. result:=nil;
  1760. candidates:=nil;
  1761. oldcallnode:=aktcallnode;
  1762. aktcallnode:=self;
  1763. { determine length of parameter list }
  1764. pt:=tcallparanode(left);
  1765. paralength:=0;
  1766. while assigned(pt) do
  1767. begin
  1768. inc(paralength);
  1769. pt:=tcallparanode(pt.right);
  1770. end;
  1771. { determine the type of the parameters }
  1772. if assigned(left) then
  1773. begin
  1774. tcallparanode(left).get_paratype;
  1775. if codegenerror then
  1776. goto errorexit;
  1777. end;
  1778. if assigned(methodpointer) then
  1779. begin
  1780. typecheckpass(methodpointer);
  1781. maybe_load_para_in_temp(methodpointer);
  1782. end;
  1783. { procedure variable ? }
  1784. if assigned(right) then
  1785. begin
  1786. set_varstate(right,vs_read,[vsf_must_be_valid]);
  1787. typecheckpass(right);
  1788. if codegenerror then
  1789. exit;
  1790. procdefinition:=tabstractprocdef(right.resultdef);
  1791. { Compare parameters from right to left }
  1792. paraidx:=procdefinition.Paras.count-1;
  1793. { Skip default parameters }
  1794. if not(po_varargs in procdefinition.procoptions) then
  1795. begin
  1796. { ignore hidden parameters }
  1797. while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
  1798. dec(paraidx);
  1799. for i:=1 to procdefinition.maxparacount-paralength do
  1800. begin
  1801. if paraidx<0 then
  1802. internalerror(200402261);
  1803. if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
  1804. begin
  1805. CGMessage1(parser_e_wrong_parameter_size,'<Procedure Variable>');
  1806. goto errorexit;
  1807. end;
  1808. dec(paraidx);
  1809. end;
  1810. end;
  1811. while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
  1812. dec(paraidx);
  1813. pt:=tcallparanode(left);
  1814. lastpara:=paralength;
  1815. while (paraidx>=0) and assigned(pt) do
  1816. begin
  1817. { only goto next para if we're out of the varargs }
  1818. if not(po_varargs in procdefinition.procoptions) or
  1819. (lastpara<=procdefinition.maxparacount) then
  1820. begin
  1821. repeat
  1822. dec(paraidx);
  1823. until (paraidx<0) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions);
  1824. end;
  1825. pt:=tcallparanode(pt.right);
  1826. dec(lastpara);
  1827. end;
  1828. if assigned(pt) or
  1829. ((paraidx>=0) and
  1830. not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)) then
  1831. begin
  1832. if assigned(pt) then
  1833. current_filepos:=pt.fileinfo;
  1834. CGMessage1(parser_e_wrong_parameter_size,'<Procedure Variable>');
  1835. goto errorexit;
  1836. end;
  1837. end
  1838. else
  1839. { not a procedure variable }
  1840. begin
  1841. { do we know the procedure to call ? }
  1842. if not(assigned(procdefinition)) then
  1843. begin
  1844. candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,(nf_isproperty in flags),
  1845. { ignore possible private in delphi mode for anon. inherited (FK) }
  1846. (m_delphi in current_settings.modeswitches) and (cnf_anon_inherited in callnodeflags));
  1847. { no procedures found? then there is something wrong
  1848. with the parameter size or the procedures are
  1849. not accessible }
  1850. if candidates.count=0 then
  1851. begin
  1852. { when it's an auto inherited call and there
  1853. is no procedure found, but the procedures
  1854. were defined with overload directive and at
  1855. least two procedures are defined then we ignore
  1856. this inherited by inserting a nothingn. Only
  1857. do this ugly hack in Delphi mode as it looks more
  1858. like a bug. It's also not documented }
  1859. if (m_delphi in current_settings.modeswitches) and
  1860. (cnf_anon_inherited in callnodeflags) and
  1861. (symtableprocentry.owner.symtabletype=ObjectSymtable) and
  1862. (po_overload in tprocdef(symtableprocentry.ProcdefList[0]).procoptions) and
  1863. (symtableprocentry.ProcdefList.Count>=2) then
  1864. result:=cnothingnode.create
  1865. else
  1866. begin
  1867. { in tp mode we can try to convert to procvar if
  1868. there are no parameters specified }
  1869. if not(assigned(left)) and
  1870. not(cnf_inherited in callnodeflags) and
  1871. ((m_tp_procvar in current_settings.modeswitches) or
  1872. (m_mac_procvar in current_settings.modeswitches)) and
  1873. (not assigned(methodpointer) or
  1874. (methodpointer.nodetype <> typen)) then
  1875. begin
  1876. hpt:=cloadnode.create(tprocsym(symtableprocentry),symtableproc);
  1877. if assigned(methodpointer) then
  1878. tloadnode(hpt).set_mp(get_load_methodpointer);
  1879. typecheckpass(hpt);
  1880. result:=hpt;
  1881. end
  1882. else
  1883. begin
  1884. if assigned(left) then
  1885. current_filepos:=left.fileinfo;
  1886. CGMessage1(parser_e_wrong_parameter_size,symtableprocentry.realname);
  1887. symtableprocentry.write_parameter_lists(nil);
  1888. end;
  1889. end;
  1890. goto errorexit;
  1891. end;
  1892. { Retrieve information about the candidates }
  1893. candidates.get_information;
  1894. {$ifdef EXTDEBUG}
  1895. { Display info when multiple candidates are found }
  1896. if candidates.count>1 then
  1897. candidates.dump_info(V_Debug);
  1898. {$endif EXTDEBUG}
  1899. { Choose the best candidate and count the number of
  1900. candidates left }
  1901. cand_cnt:=candidates.choose_best(procdefinition,
  1902. assigned(left) and
  1903. not assigned(tcallparanode(left).right) and
  1904. (tcallparanode(left).left.resultdef.typ=variantdef));
  1905. { All parameters are checked, check if there are any
  1906. procedures left }
  1907. if cand_cnt>0 then
  1908. begin
  1909. { Multiple candidates left? }
  1910. if cand_cnt>1 then
  1911. begin
  1912. CGMessage(type_e_cant_choose_overload_function);
  1913. {$ifdef EXTDEBUG}
  1914. candidates.dump_info(V_Hint);
  1915. {$else EXTDEBUG}
  1916. candidates.list(false);
  1917. {$endif EXTDEBUG}
  1918. { we'll just use the first candidate to make the
  1919. call }
  1920. end;
  1921. { assign procdefinition }
  1922. if symtableproc=nil then
  1923. symtableproc:=procdefinition.owner;
  1924. end
  1925. else
  1926. begin
  1927. { No candidates left, this must be a type error,
  1928. because wrong size is already checked. procdefinition
  1929. is filled with the first (random) definition that is
  1930. found. We use this definition to display a nice error
  1931. message that the wrong type is passed }
  1932. candidates.find_wrong_para;
  1933. candidates.list(true);
  1934. {$ifdef EXTDEBUG}
  1935. candidates.dump_info(V_Hint);
  1936. {$endif EXTDEBUG}
  1937. { We can not proceed, release all procs and exit }
  1938. candidates.free;
  1939. goto errorexit;
  1940. end;
  1941. candidates.free;
  1942. end; { end of procedure to call determination }
  1943. end;
  1944. { check for hints (deprecated etc) }
  1945. if (procdefinition.typ = procdef) then
  1946. check_hints(tprocdef(procdefinition).procsym,tprocdef(procdefinition).symoptions);
  1947. { add needed default parameters }
  1948. if assigned(procdefinition) and
  1949. (paralength<procdefinition.maxparacount) then
  1950. begin
  1951. paraidx:=0;
  1952. i:=0;
  1953. while (i<paralength) do
  1954. begin
  1955. if paraidx>=procdefinition.Paras.count then
  1956. internalerror(200306181);
  1957. if not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) then
  1958. inc(i);
  1959. inc(paraidx);
  1960. end;
  1961. while (paraidx<procdefinition.paras.count) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
  1962. inc(paraidx);
  1963. while (paraidx<procdefinition.paras.count) do
  1964. begin
  1965. if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
  1966. internalerror(200212142);
  1967. left:=ccallparanode.create(genconstsymtree(
  1968. tconstsym(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)),left);
  1969. { Ignore vs_hidden parameters }
  1970. repeat
  1971. inc(paraidx);
  1972. until (paraidx>=procdefinition.paras.count) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions);
  1973. end;
  1974. end;
  1975. { recursive call? }
  1976. if assigned(current_procinfo) and
  1977. (procdefinition=current_procinfo.procdef) then
  1978. include(current_procinfo.flags,pi_is_recursive);
  1979. { handle predefined procedures }
  1980. is_const:=(po_internconst in procdefinition.procoptions) and
  1981. ((block_type in [bt_const,bt_type]) or
  1982. (assigned(left) and (tcallparanode(left).left.nodetype in [realconstn,ordconstn])));
  1983. if (procdefinition.proccalloption=pocall_internproc) or is_const then
  1984. begin
  1985. if assigned(left) then
  1986. begin
  1987. { ptr and settextbuf needs two args }
  1988. if assigned(tcallparanode(left).right) then
  1989. begin
  1990. hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,left);
  1991. left:=nil;
  1992. end
  1993. else
  1994. begin
  1995. hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,tcallparanode(left).left);
  1996. tcallparanode(left).left:=nil;
  1997. end;
  1998. end
  1999. else
  2000. hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,nil);
  2001. result:=hpt;
  2002. goto errorexit;
  2003. end;
  2004. { ensure that the result type is set }
  2005. if not(cnf_typedefset in callnodeflags) then
  2006. begin
  2007. { constructors return their current class type, not the type where the
  2008. constructor is declared, this can be different because of inheritance }
  2009. if (procdefinition.proctypeoption=potype_constructor) and
  2010. assigned(methodpointer) and
  2011. assigned(methodpointer.resultdef) and
  2012. (methodpointer.resultdef.typ=classrefdef) then
  2013. resultdef:=tclassrefdef(methodpointer.resultdef).pointeddef
  2014. else
  2015. { Member call to a (inherited) constructor from the class, the return
  2016. value is always self, so we change it to voidtype to generate an
  2017. error and to prevent users from generating non-working code
  2018. when they expect to clone the current instance, see bug 3662 (PFV) }
  2019. if (procdefinition.proctypeoption=potype_constructor) and
  2020. is_class(tprocdef(procdefinition)._class) and
  2021. assigned(methodpointer) and
  2022. (nf_is_self in methodpointer.flags) then
  2023. resultdef:=voidtype
  2024. else
  2025. resultdef:=procdefinition.returndef;
  2026. end
  2027. else
  2028. resultdef:=typedef;
  2029. {if resultdef.needs_inittable then
  2030. include(current_procinfo.flags,pi_needs_implicit_finally);}
  2031. if assigned(methodpointer) then
  2032. begin
  2033. { when methodpointer is a callnode we must load it first into a
  2034. temp to prevent the processing callnode twice }
  2035. if (methodpointer.nodetype=calln) then
  2036. internalerror(200405121);
  2037. { direct call to inherited abstract method, then we
  2038. can already give a error in the compiler instead
  2039. of a runtime error }
  2040. if (cnf_inherited in callnodeflags) and
  2041. (po_abstractmethod in procdefinition.procoptions) then
  2042. begin
  2043. if (m_delphi in current_settings.modeswitches) and
  2044. (cnf_anon_inherited in callnodeflags) then
  2045. begin
  2046. CGMessage(cg_h_inherited_ignored);
  2047. result:=cnothingnode.create;
  2048. exit;
  2049. end
  2050. else
  2051. CGMessage(cg_e_cant_call_abstract_method);
  2052. end;
  2053. { if an inherited con- or destructor should be }
  2054. { called in a con- or destructor then a warning }
  2055. { will be made }
  2056. { con- and destructors need a pointer to the vmt }
  2057. if (cnf_inherited in callnodeflags) and
  2058. (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) and
  2059. is_object(methodpointer.resultdef) and
  2060. not(current_procinfo.procdef.proctypeoption in [potype_constructor,potype_destructor]) then
  2061. CGMessage(cg_w_member_cd_call_from_method);
  2062. if methodpointer.nodetype<>typen then
  2063. begin
  2064. { Remove all postfix operators }
  2065. hpt:=methodpointer;
  2066. while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do
  2067. hpt:=tunarynode(hpt).left;
  2068. if (procdefinition.proctypeoption=potype_constructor) and
  2069. assigned(symtableproc) and
  2070. (symtableproc.symtabletype=withsymtable) and
  2071. (tnode(twithsymtable(symtableproc).withrefnode).nodetype=temprefn) then
  2072. CGmessage(cg_e_cannot_call_cons_dest_inside_with);
  2073. { R.Init then R will be initialized by the constructor,
  2074. Also allow it for simple loads }
  2075. if (procdefinition.proctypeoption=potype_constructor) or
  2076. ((hpt.nodetype=loadn) and
  2077. (methodpointer.resultdef.typ=objectdef) and
  2078. not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)
  2079. ) then
  2080. { a constructor will and a method may write something to }
  2081. { the fields }
  2082. set_varstate(methodpointer,vs_readwritten,[])
  2083. else if ((hpt.nodetype=loadn) and
  2084. (methodpointer.resultdef.typ=classrefdef)) then
  2085. set_varstate(methodpointer,vs_read,[])
  2086. else
  2087. set_varstate(methodpointer,vs_read,[vsf_must_be_valid]);
  2088. { The object is already used if it is called once }
  2089. if (hpt.nodetype=loadn) and
  2090. (tloadnode(hpt).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) then
  2091. set_varstate(hpt,vs_read,[]);
  2092. // tabstractvarsym(tloadnode(hpt).symtableentry).varstate:=vs_readwritten;
  2093. end;
  2094. { if we are calling the constructor check for abstract
  2095. methods. Ignore inherited and member calls, because the
  2096. class is then already created }
  2097. if (procdefinition.proctypeoption=potype_constructor) and
  2098. not(cnf_inherited in callnodeflags) and
  2099. not(cnf_member_call in callnodeflags) then
  2100. verifyabstractcalls;
  2101. end
  2102. else
  2103. begin
  2104. { When this is method the methodpointer must be available }
  2105. if (right=nil) and
  2106. (procdefinition.owner.symtabletype=ObjectSymtable) then
  2107. internalerror(200305061);
  2108. end;
  2109. { Set flag that the procedure uses varargs, also if they are not passed it is still
  2110. needed for x86_64 to pass the number of SSE registers used }
  2111. if po_varargs in procdefinition.procoptions then
  2112. include(callnodeflags,cnf_uses_varargs);
  2113. { Change loading of array of const to varargs }
  2114. if assigned(left) and
  2115. is_array_of_const(tparavarsym(procdefinition.paras[procdefinition.paras.count-1]).vardef) and
  2116. (procdefinition.proccalloption in [pocall_cppdecl,pocall_cdecl]) then
  2117. convert_carg_array_of_const;
  2118. { bind parasyms to the callparanodes and insert hidden parameters }
  2119. bind_parasym;
  2120. { insert type conversions for parameters }
  2121. if assigned(left) then
  2122. tcallparanode(left).insert_typeconv(true);
  2123. { dispinterface methode invoke? }
  2124. if assigned(methodpointer) and is_dispinterface(methodpointer.resultdef) then
  2125. begin
  2126. { if the result is used, we've to insert a call to convert the type to be on the "safe side" }
  2127. if cnf_return_value_used in callnodeflags then
  2128. begin
  2129. result:=internalstatements(statements);
  2130. converted_result_data:=ctempcreatenode.create(procdefinition.returndef,sizeof(procdefinition.returndef),tt_persistent,true);
  2131. addstatement(statements,converted_result_data);
  2132. addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data),
  2133. ctypeconvnode.create_internal(translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,true),
  2134. procdefinition.returndef)));
  2135. addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data));
  2136. addstatement(statements,ctemprefnode.create(converted_result_data));
  2137. end
  2138. else
  2139. result:=translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,false);
  2140. { don't free reused nodes }
  2141. methodpointer:=nil;
  2142. parameters:=nil;
  2143. end;
  2144. errorexit:
  2145. aktcallnode:=oldcallnode;
  2146. end;
  2147. procedure tcallnode.order_parameters;
  2148. var
  2149. hp,hpcurr,hpnext,hpfirst,hpprev : tcallparanode;
  2150. currloc : tcgloc;
  2151. begin
  2152. hpfirst:=nil;
  2153. hpcurr:=tcallparanode(left);
  2154. while assigned(hpcurr) do
  2155. begin
  2156. { pull out }
  2157. hpnext:=tcallparanode(hpcurr.right);
  2158. { pull in at the correct place.
  2159. Used order:
  2160. 1. LOC_REFERENCE with smallest offset (i386 only)
  2161. 2. LOC_REFERENCE with most registers and least complexity (non-i386 only)
  2162. 3. LOC_REFERENCE with least registers and most complexity (non-i386 only)
  2163. 4. LOC_REGISTER with most registers and most complexity
  2164. 5. LOC_REGISTER with least registers and least complexity
  2165. For the moment we only look at the first parameter field. Combining it
  2166. with multiple parameter fields will make things a lot complexer (PFV)
  2167. The reason for the difference regarding complexity ordering
  2168. between LOC_REFERENCE and LOC_REGISTER is mainly for calls:
  2169. we first want to treat the LOC_REFERENCE destinations whose
  2170. calculation does not require a call, because their location
  2171. may contain registers which might otherwise have to be saved
  2172. if a call has to be evaluated first. The calculated value is
  2173. stored on the stack and will thus no longer occupy any
  2174. register.
  2175. Similarly, for the register parameters we first want to
  2176. evaluate the calls, because otherwise the already loaded
  2177. register parameters will have to be saved so the intermediate
  2178. call can be evaluated (JM) }
  2179. if not assigned(hpcurr.parasym.paraloc[callerside].location) then
  2180. internalerror(200412152);
  2181. currloc:=hpcurr.parasym.paraloc[callerside].location^.loc;
  2182. hpprev:=nil;
  2183. hp:=hpfirst;
  2184. while assigned(hp) do
  2185. begin
  2186. case currloc of
  2187. LOC_REFERENCE :
  2188. begin
  2189. case hp.parasym.paraloc[callerside].location^.loc of
  2190. LOC_REFERENCE :
  2191. begin
  2192. { Offset is calculated like:
  2193. sub esp,12
  2194. mov [esp+8],para3
  2195. mov [esp+4],para2
  2196. mov [esp],para1
  2197. call function
  2198. That means the for pushes the para with the
  2199. highest offset (see para3) needs to be pushed first
  2200. }
  2201. {$ifdef i386}
  2202. { the i386 code generator expects all reference }
  2203. { parameter to be in this order so it can use }
  2204. { pushes }
  2205. if (hpcurr.parasym.paraloc[callerside].location^.reference.offset>hp.parasym.paraloc[callerside].location^.reference.offset) then
  2206. {$else i386}
  2207. if (hpcurr.registersint>hp.registersint) or
  2208. (node_complexity(hpcurr)<node_complexity(hp)) then
  2209. {$endif i386}
  2210. break;
  2211. end;
  2212. LOC_MMREGISTER,
  2213. LOC_REGISTER,
  2214. LOC_FPUREGISTER :
  2215. break;
  2216. end;
  2217. end;
  2218. LOC_MMREGISTER,
  2219. LOC_FPUREGISTER,
  2220. LOC_REGISTER :
  2221. begin
  2222. if (hp.parasym.paraloc[callerside].location^.loc<>LOC_REFERENCE) and
  2223. (node_complexity(hpcurr)>node_complexity(hp)) then
  2224. break;
  2225. end;
  2226. end;
  2227. hpprev:=hp;
  2228. hp:=tcallparanode(hp.right);
  2229. end;
  2230. hpcurr.right:=hp;
  2231. if assigned(hpprev) then
  2232. hpprev.right:=hpcurr
  2233. else
  2234. hpfirst:=hpcurr;
  2235. { next }
  2236. hpcurr:=hpnext;
  2237. end;
  2238. left:=hpfirst;
  2239. end;
  2240. function tcallnode.replaceparaload(var n: tnode; arg: pointer): foreachnoderesult;
  2241. var
  2242. paras: tcallparanode;
  2243. temp: tnode;
  2244. indexnr : integer;
  2245. begin
  2246. result := fen_false;
  2247. n.fileinfo := pfileposinfo(arg)^;
  2248. if (n.nodetype = loadn) then
  2249. begin
  2250. case tloadnode(n).symtableentry.typ of
  2251. paravarsym :
  2252. begin
  2253. paras := tcallparanode(left);
  2254. while assigned(paras) and
  2255. (paras.parasym <> tloadnode(n).symtableentry) do
  2256. paras := tcallparanode(paras.right);
  2257. if assigned(paras) then
  2258. begin
  2259. n.free;
  2260. n := paras.left.getcopy;
  2261. typecheckpass(n);
  2262. result := fen_true;
  2263. end;
  2264. end;
  2265. localvarsym :
  2266. begin
  2267. { local? }
  2268. if (tloadnode(n).symtableentry.owner <> tprocdef(procdefinition).localst) then
  2269. exit;
  2270. indexnr:=tloadnode(n).symtableentry.owner.SymList.IndexOf(tloadnode(n).symtableentry);
  2271. if (indexnr >= inlinelocals.count) or
  2272. not assigned(inlinelocals[indexnr]) then
  2273. internalerror(20040720);
  2274. temp := tnode(inlinelocals[indexnr]).getcopy;
  2275. n.free;
  2276. n := temp;
  2277. typecheckpass(n);
  2278. result := fen_true;
  2279. end;
  2280. end;
  2281. end;
  2282. end;
  2283. type
  2284. ptempnodes = ^ttempnodes;
  2285. ttempnodes = record
  2286. createstatement, deletestatement: tstatementnode;
  2287. end;
  2288. procedure tcallnode.createlocaltemps(p:TObject;arg:pointer);
  2289. var
  2290. tempinfo: ptempnodes absolute arg;
  2291. tempnode: ttempcreatenode;
  2292. indexnr : integer;
  2293. begin
  2294. if (TSym(p).typ <> localvarsym) then
  2295. exit;
  2296. indexnr:=TSym(p).Owner.SymList.IndexOf(p);
  2297. if (indexnr >= inlinelocals.count) then
  2298. inlinelocals.count:=indexnr+10;
  2299. if (vo_is_funcret in tabstractvarsym(p).varoptions) and
  2300. assigned(funcretnode) then
  2301. begin
  2302. if node_complexity(funcretnode) > 1 then
  2303. begin
  2304. { can this happen? }
  2305. { we may have to replace the funcretnode with the address of funcretnode }
  2306. { loaded in a temp in this case, because the expression may e.g. contain }
  2307. { a global variable that gets changed inside the function }
  2308. internalerror(2004072101);
  2309. end;
  2310. inlinelocals[indexnr] := funcretnode.getcopy
  2311. end
  2312. else
  2313. begin
  2314. if (vo_is_funcret in tlocalvarsym(p).varoptions) then
  2315. begin
  2316. tempnode := ctempcreatenode.create_inlined_result(tabstractvarsym(p).vardef,tabstractvarsym(p).vardef.size,tt_persistent,tabstractvarsym(p).is_regvar(false));
  2317. addstatement(tempinfo^.createstatement,tempnode);
  2318. funcretnode := ctemprefnode.create(tempnode);
  2319. addstatement(tempinfo^.deletestatement,ctempdeletenode.create_normal_temp(tempnode));
  2320. end
  2321. else
  2322. begin
  2323. tempnode := ctempcreatenode.create(tabstractvarsym(p).vardef,tabstractvarsym(p).vardef.size,tt_persistent,tabstractvarsym(p).is_regvar(false));
  2324. addstatement(tempinfo^.createstatement,tempnode);
  2325. addstatement(tempinfo^.deletestatement,ctempdeletenode.create(tempnode));
  2326. end;
  2327. { inherit addr_taken flag }
  2328. if (tabstractvarsym(p).addr_taken) then
  2329. include(tempnode.tempinfo^.flags,ti_addr_taken);
  2330. inlinelocals[indexnr] := ctemprefnode.create(tempnode);
  2331. end;
  2332. end;
  2333. function nonlocalvars(var n: tnode; arg: pointer): foreachnoderesult;
  2334. begin
  2335. result := fen_false;
  2336. { this is just to play it safe, there are more safe situations }
  2337. if (n.nodetype = derefn) or
  2338. ((n.nodetype = loadn) and
  2339. { globals and fields of (possibly global) objects could always be changed in the callee }
  2340. ((tloadnode(n).symtable.symtabletype in [globalsymtable,ObjectSymtable]) or
  2341. { statics can only be modified by functions in the same unit }
  2342. ((tloadnode(n).symtable.symtabletype = staticsymtable) and
  2343. (tloadnode(n).symtable = TSymtable(arg))))) or
  2344. ((n.nodetype = subscriptn) and
  2345. (tsubscriptnode(n).vs.owner.symtabletype = ObjectSymtable)) then
  2346. result := fen_norecurse_true;
  2347. end;
  2348. procedure tcallnode.createinlineparas(var createstatement, deletestatement: tstatementnode);
  2349. var
  2350. para: tcallparanode;
  2351. tempnode: ttempcreatenode;
  2352. tempnodes: ttempnodes;
  2353. n: tnode;
  2354. paracomplexity: longint;
  2355. begin
  2356. { parameters }
  2357. para := tcallparanode(left);
  2358. while assigned(para) do
  2359. begin
  2360. if (para.parasym.typ = paravarsym) and
  2361. { para.left will already be the same as funcretnode in the following case, so don't change }
  2362. (not(vo_is_funcret in tparavarsym(para.parasym).varoptions) or
  2363. (not assigned(funcretnode))) then
  2364. begin
  2365. { must take copy of para.left, because if it contains a }
  2366. { temprefn pointing to a copied temp (e.g. methodpointer), }
  2367. { then this parameter must be changed to point to the copy of }
  2368. { that temp (JM) }
  2369. n := para.left.getcopy;
  2370. para.left.free;
  2371. para.left := n;
  2372. firstpass(para.left);
  2373. { create temps for value parameters, function result and also for }
  2374. { const parameters which are passed by value instead of by reference }
  2375. { we need to take care that we use the type of the defined parameter and not of the
  2376. passed parameter, because these can be different in case of a formaldef (PFV) }
  2377. paracomplexity := node_complexity(para.left);
  2378. { check if we have to create a temp, assign the parameter's }
  2379. { contents to that temp and then substitute the paramter }
  2380. { with the temp everywhere in the function }
  2381. if
  2382. ((tparavarsym(para.parasym).varregable in [vr_none,vr_addr]) and
  2383. not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
  2384. { we can't assign to formaldef temps }
  2385. ((para.parasym.vardef.typ<>formaldef) and
  2386. (
  2387. { if paracomplexity > 1, we normally take the address of }
  2388. { the parameter expression, store it in a temp and }
  2389. { substitute the dereferenced temp in the inlined function }
  2390. { We can't do this if we can't take the address of the }
  2391. { parameter expression, so in that case assign to a temp }
  2392. not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CONSTANT]) or
  2393. ((paracomplexity > 1) and
  2394. (not valid_for_addr(para.left,false) or
  2395. (para.left.nodetype = calln) or
  2396. is_constnode(para.left))) or
  2397. { the problem is that we can't take the address of a function result :( }
  2398. (vo_is_funcret in tparavarsym(para.parasym).varoptions) or
  2399. { we do not need to create a temp for value parameters }
  2400. { which are not modified in the inlined function }
  2401. { const parameters can get vs_readwritten if their }
  2402. { address is taken }
  2403. ((((para.parasym.varspez = vs_value) and
  2404. (para.parasym.varstate in [vs_initialised,vs_declared,vs_read])) or
  2405. { in case of const, this is only necessary if the }
  2406. { variable would be passed by value normally, or if }
  2407. { there is such a variable somewhere in an expression }
  2408. ((para.parasym.varspez = vs_const) and
  2409. (not paramanager.push_addr_param(vs_const,para.parasym.vardef,procdefinition.proccalloption) or
  2410. (paracomplexity > 1)))) and
  2411. { however, if we pass a global variable, an object field or}
  2412. { an expression containing a pointer dereference as }
  2413. { parameter, this value could be modified in other ways as }
  2414. { well and in such cases create a temp to be on the safe }
  2415. { side }
  2416. foreachnodestatic(para.left,@nonlocalvars,pointer(symtableproc))) or
  2417. { value parameters of which we know they are modified by }
  2418. { definition have to be copied to a temp }
  2419. ((para.parasym.varspez = vs_value) and
  2420. not(para.parasym.varstate in [vs_initialised,vs_declared,vs_read])) or
  2421. { the compiler expects that it can take the address of parameters passed by reference in
  2422. the case of const so we can't replace the node simply by a constant node
  2423. When playing with this code, ensure that
  2424. function f(const a,b : longint) : longint;inline;
  2425. begin
  2426. result:=a*b;
  2427. end;
  2428. [...]
  2429. ...:=f(10,20));
  2430. [...]
  2431. is still folded. (FK)
  2432. }
  2433. ((para.parasym.varspez = vs_const) and
  2434. { const para's can get vs_readwritten if their address }
  2435. { is taken }
  2436. ((para.parasym.varstate = vs_readwritten) or
  2437. { call-by-reference const's may need to be passed by }
  2438. { reference to function called in the inlined code }
  2439. (paramanager.push_addr_param(vs_const,para.parasym.vardef,procdefinition.proccalloption) and
  2440. (not valid_for_addr(para.left,false) or
  2441. is_constnode(para.left)))))
  2442. )
  2443. ) then
  2444. begin
  2445. tempnode:=nil;
  2446. {$ifdef reuse_existing_para_temp}
  2447. { Try to reuse existing result tempnode from a parameter }
  2448. if para.left.nodetype=blockn then
  2449. begin
  2450. n:=tstatementnode(tblocknode(para.left).left);
  2451. while assigned(n) and assigned(tstatementnode(n).right) do
  2452. begin
  2453. if tstatementnode(n).left.nodetype=tempdeleten then
  2454. break;
  2455. n:=tstatementnode(tstatementnode(n).right);
  2456. end;
  2457. { We expect to find the following statements
  2458. tempdeletenode
  2459. tempref
  2460. nil }
  2461. if assigned(n) and
  2462. assigned(tstatementnode(n).right) and
  2463. (tstatementnode(tstatementnode(n).right).right=nil) and
  2464. (tstatementnode(tstatementnode(n).right).left.nodetype=temprefn) then
  2465. begin
  2466. tempnode:=ttempdeletenode(tstatementnode(n).left).tempinfo^.owner;
  2467. para.left:=tstatementnode(tstatementnode(n).right).left;
  2468. addstatement(deletestatement,tstatementnode(n).left);
  2469. { Replace tempdelete,tempref with dummy statement }
  2470. tstatementnode(n).left:=cnothingnode.create;
  2471. tstatementnode(tstatementnode(n).right).left:=cnothingnode.create;
  2472. end;
  2473. end;
  2474. {$endif reuse_existing_para_temp}
  2475. tempnode := ctempcreatenode.create(para.parasym.vardef,para.parasym.vardef.size,tt_persistent,tparavarsym(para.parasym).is_regvar(false));
  2476. addstatement(createstatement,tempnode);
  2477. { inherit addr_taken flag }
  2478. if (tabstractvarsym(para.parasym).addr_taken) then
  2479. include(tempnode.tempinfo^.flags,ti_addr_taken);
  2480. { assign the value of the parameter to the temp, except in case of the function result }
  2481. { (in that case, para.left is a block containing the creation of a new temp, while we }
  2482. { only need a temprefnode, so delete the old stuff) }
  2483. if not(vo_is_funcret in tparavarsym(para.parasym).varoptions) then
  2484. begin
  2485. addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
  2486. para.left));
  2487. para.left := ctemprefnode.create(tempnode);
  2488. addstatement(deletestatement,ctempdeletenode.create(tempnode));
  2489. end
  2490. else
  2491. begin
  2492. if not(assigned(funcretnode)) then
  2493. funcretnode := ctemprefnode.create(tempnode);
  2494. para.left.free;
  2495. para.left := ctemprefnode.create(tempnode);
  2496. addstatement(deletestatement,ctempdeletenode.create_normal_temp(tempnode));
  2497. end;
  2498. end
  2499. { otherwise if the parameter is "complex", take the address }
  2500. { of the parameter expression, store it in a temp and replace }
  2501. { occurrences of the parameter with dereferencings of this }
  2502. { temp }
  2503. else if (paracomplexity > 1) then
  2504. begin
  2505. tempnode := ctempcreatenode.create(voidpointertype,voidpointertype.size,tt_persistent,tparavarsym(para.parasym).is_regvar(true));
  2506. addstatement(createstatement,tempnode);
  2507. { inherit addr_taken flag }
  2508. if (tabstractvarsym(para.parasym).addr_taken) then
  2509. include(tempnode.tempinfo^.flags,ti_addr_taken);
  2510. addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
  2511. caddrnode.create_internal(para.left)));
  2512. para.left := ctypeconvnode.create_internal(cderefnode.create(ctemprefnode.create(tempnode)),para.left.resultdef);
  2513. addstatement(deletestatement,ctempdeletenode.create(tempnode));
  2514. end;
  2515. end;
  2516. para := tcallparanode(para.right);
  2517. end;
  2518. { local variables }
  2519. if not assigned(tprocdef(procdefinition).localst) or
  2520. (tprocdef(procdefinition).localst.SymList.count = 0) then
  2521. exit;
  2522. tempnodes.createstatement := createstatement;
  2523. tempnodes.deletestatement := deletestatement;
  2524. inlinelocals.count:=tprocdef(procdefinition).localst.SymList.count;
  2525. tprocdef(procdefinition).localst.SymList.ForEachCall(@createlocaltemps,@tempnodes);
  2526. createstatement := tempnodes.createstatement;
  2527. deletestatement := tempnodes.deletestatement;
  2528. end;
  2529. function tcallnode.getfuncretassignment(inlineblock: tblocknode): tnode;
  2530. var
  2531. hp: tstatementnode;
  2532. resassign: tnode;
  2533. begin
  2534. result:=nil;
  2535. if not assigned(funcretnode) or
  2536. not(cnf_return_value_used in callnodeflags) then
  2537. exit;
  2538. { tempcreatenode for the function result }
  2539. hp:=tstatementnode(inlineblock.left);
  2540. if not(assigned(hp)) or
  2541. (hp.left.nodetype <> tempcreaten) then
  2542. exit;
  2543. { assignment to the result }
  2544. hp:=tstatementnode(hp.right);
  2545. if not(assigned(hp)) or
  2546. (hp.left.nodetype<>assignn) or
  2547. { left must be function result }
  2548. (not(tassignmentnode(hp.left).left.isequal(funcretnode)) and
  2549. { can have extra type conversion due to absolute mapping }
  2550. { of <fucntionname> on function result var }
  2551. not((tassignmentnode(hp.left).left.nodetype = typeconvn) and
  2552. (ttypeconvnode(tassignmentnode(hp.left).left).convtype = tc_equal) and
  2553. (ttypeconvnode(tassignmentnode(hp.left).left).left.isequal(funcretnode)))) or
  2554. { right must be a constant (mainly to avoid trying to reuse }
  2555. { local temps which may already be freed afterwards once these }
  2556. { checks are made looser) }
  2557. not is_constnode(tassignmentnode(hp.left).right) then
  2558. exit
  2559. else
  2560. resassign:=hp.left;
  2561. { tempdelete to normal of the function result }
  2562. hp:=tstatementnode(hp.right);
  2563. if not(assigned(hp)) or
  2564. (hp.left.nodetype <> tempdeleten) then
  2565. exit;
  2566. { the function result once more }
  2567. hp:=tstatementnode(hp.right);
  2568. if not(assigned(hp)) or
  2569. not(hp.left.isequal(funcretnode)) then
  2570. exit;
  2571. { should be the end }
  2572. if assigned(hp.right) then
  2573. exit;
  2574. { we made it! }
  2575. result:=tassignmentnode(resassign).right.getcopy;
  2576. firstpass(result);
  2577. end;
  2578. function tcallnode.pass1_inline:tnode;
  2579. var
  2580. createstatement,deletestatement: tstatementnode;
  2581. createblock,deleteblock: tblocknode;
  2582. body : tnode;
  2583. begin
  2584. if not(assigned(tprocdef(procdefinition).inlininginfo) and
  2585. assigned(tprocdef(procdefinition).inlininginfo^.code)) then
  2586. internalerror(200412021);
  2587. { inherit flags }
  2588. current_procinfo.flags := current_procinfo.flags + ((procdefinition as tprocdef).inlininginfo^.flags*inherited_inlining_flags);
  2589. { create blocks for loading/deleting of local data }
  2590. createblock:=internalstatements(createstatement);
  2591. deleteblock:=internalstatements(deletestatement);
  2592. { add methodpointer init code to init statement }
  2593. { (fini must be done later, as it will delete the hookoncopy info) }
  2594. if assigned(methodpointerinit) then
  2595. addstatement(createstatement,methodpointerinit.getcopy);
  2596. inlinelocals:=TFPObjectList.create(true);
  2597. { get copy of the procedure body }
  2598. body:=tprocdef(procdefinition).inlininginfo^.code.getcopy;
  2599. { replace complex parameters with temps }
  2600. createinlineparas(createstatement,deletestatement);
  2601. { replace the parameter loads with the parameter values }
  2602. foreachnode(body,@replaceparaload,@fileinfo);
  2603. { copy methodpointer fini code }
  2604. if assigned(methodpointerdone) then
  2605. addstatement(deletestatement,methodpointerdone.getcopy);
  2606. { free the temps for the locals }
  2607. inlinelocals.free;
  2608. inlinelocals:=nil;
  2609. addstatement(createstatement,body);
  2610. addstatement(createstatement,deleteblock);
  2611. { set function result location if necessary }
  2612. if assigned(funcretnode) and
  2613. (cnf_return_value_used in callnodeflags) then
  2614. addstatement(createstatement,funcretnode.getcopy);
  2615. { consider it must not be inlined if called
  2616. again inside the args or itself }
  2617. exclude(procdefinition.procoptions,po_inline);
  2618. typecheckpass(createblock);
  2619. dosimplify(createblock);
  2620. firstpass(createblock);
  2621. include(procdefinition.procoptions,po_inline);
  2622. { if all that's left of the inlined function is an constant }
  2623. { assignment to the result, replace the whole block with what's }
  2624. { assigned to the result. There will also be a tempcreatenode for }
  2625. { the function result itself though, so ignore it. The statement/ }
  2626. { blocknode simplification code will have removed all nothingn- }
  2627. { statements empty nested blocks, so we don't have to care about }
  2628. { those }
  2629. result := getfuncretassignment(createblock);
  2630. if assigned(result) then
  2631. createblock.free
  2632. else
  2633. { return inlined block }
  2634. result := createblock;
  2635. {$ifdef DEBUGINLINE}
  2636. writeln;
  2637. writeln('**************************',tprocdef(procdefinition).mangledname);
  2638. printnode(output,result);
  2639. {$endif DEBUGINLINE}
  2640. end;
  2641. procedure tcallnode.check_stack_parameters;
  2642. var
  2643. hp : tcallparanode;
  2644. begin
  2645. hp:=tcallparanode(left);
  2646. while assigned(hp) do
  2647. begin
  2648. if assigned(hp.parasym) and
  2649. assigned(hp.parasym.paraloc[callerside].location) and
  2650. (hp.parasym.paraloc[callerside].location^.loc=LOC_REFERENCE) then
  2651. include(current_procinfo.flags,pi_has_stackparameter);
  2652. hp:=tcallparanode(hp.right);
  2653. end;
  2654. end;
  2655. procedure tcallnode.check_inlining;
  2656. var
  2657. st : tsymtable;
  2658. para : tcallparanode;
  2659. begin
  2660. { Can we inline the procedure? }
  2661. if ([po_inline,po_has_inlininginfo] <= procdefinition.procoptions) then
  2662. begin
  2663. include(callnodeflags,cnf_do_inline);
  2664. { Check if we can inline the procedure when it references proc/var that
  2665. are not in the globally available }
  2666. st:=procdefinition.owner;
  2667. if (st.symtabletype=ObjectSymtable) then
  2668. st:=st.defowner.owner;
  2669. if (pi_uses_static_symtable in tprocdef(procdefinition).inlininginfo^.flags) and
  2670. (st.symtabletype=globalsymtable) and
  2671. (not st.iscurrentunit) then
  2672. begin
  2673. Comment(V_lineinfo+V_Debug,'Not inlining "'+tprocdef(procdefinition).procsym.realname+'", references static symtable');
  2674. exclude(callnodeflags,cnf_do_inline);
  2675. end;
  2676. para:=tcallparanode(parameters);
  2677. while assigned(para) do
  2678. begin
  2679. if not para.can_be_inlined then
  2680. begin
  2681. Comment(V_lineinfo+V_Debug,'Not inlining "'+tprocdef(procdefinition).procsym.realname+'", invocation parameter contains an unsafe/unsupported construct');
  2682. exclude(callnodeflags,cnf_do_inline);
  2683. break;
  2684. end;
  2685. para:=tcallparanode(para.nextpara);
  2686. end;
  2687. end;
  2688. end;
  2689. function tcallnode.pass_1 : tnode;
  2690. var
  2691. st : TSymtable;
  2692. n: tcallparanode;
  2693. begin
  2694. result:=nil;
  2695. { Check if the call can be inlined, sets the cnf_do_inline flag }
  2696. check_inlining;
  2697. if cnf_do_inline in callnodeflags then
  2698. begin
  2699. result:=pass1_inline;
  2700. exit;
  2701. end;
  2702. { calculate the parameter info for the procdef }
  2703. if not procdefinition.has_paraloc_info then
  2704. begin
  2705. procdefinition.requiredargarea:=paramanager.create_paraloc_info(procdefinition,callerside);
  2706. procdefinition.has_paraloc_info:=true;
  2707. end;
  2708. { calculate the parameter size needed for this call include varargs if they are available }
  2709. if assigned(varargsparas) then
  2710. pushedparasize:=paramanager.create_varargs_paraloc_info(procdefinition,varargsparas)
  2711. else
  2712. pushedparasize:=procdefinition.requiredargarea;
  2713. { record maximum parameter size used in this proc }
  2714. current_procinfo.allocate_push_parasize(pushedparasize);
  2715. { work trough all parameters to get the register requirements }
  2716. if assigned(left) then
  2717. begin
  2718. tcallparanode(left).det_registers;
  2719. if (current_settings.optimizerswitches*[cs_opt_stackframe,cs_opt_level1]<>[]) then
  2720. begin
  2721. { check for stacked parameters }
  2722. check_stack_parameters;
  2723. end;
  2724. end;
  2725. { order parameters }
  2726. order_parameters;
  2727. if assigned(methodpointerinit) then
  2728. firstpass(methodpointerinit);
  2729. if assigned(methodpointerdone) then
  2730. firstpass(methodpointerdone);
  2731. { function result node }
  2732. if assigned(_funcretnode) then
  2733. firstpass(_funcretnode);
  2734. { procedure variable ? }
  2735. if assigned(right) then
  2736. firstpass(right);
  2737. if not (block_type in [bt_const,bt_type]) then
  2738. include(current_procinfo.flags,pi_do_call);
  2739. { implicit finally needed ? }
  2740. if resultdef.needs_inittable and
  2741. not paramanager.ret_in_param(resultdef,procdefinition.proccalloption) and
  2742. not assigned(funcretnode) then
  2743. include(current_procinfo.flags,pi_needs_implicit_finally);
  2744. { get a register for the return value }
  2745. if (not is_void(resultdef)) then
  2746. begin
  2747. if paramanager.ret_in_param(resultdef,procdefinition.proccalloption) then
  2748. begin
  2749. expectloc:=LOC_REFERENCE;
  2750. end
  2751. else
  2752. { ansi/widestrings must be registered, so we can dispose them }
  2753. if is_ansistring(resultdef) or
  2754. is_widestring(resultdef) then
  2755. begin
  2756. expectloc:=LOC_REFERENCE;
  2757. registersint:=1;
  2758. end
  2759. else
  2760. { we have only to handle the result if it is used }
  2761. if (cnf_return_value_used in callnodeflags) then
  2762. begin
  2763. case resultdef.typ of
  2764. enumdef,
  2765. orddef :
  2766. begin
  2767. if (procdefinition.proctypeoption=potype_constructor) then
  2768. begin
  2769. expectloc:=LOC_REGISTER;
  2770. registersint:=1;
  2771. end
  2772. else
  2773. begin
  2774. expectloc:=LOC_REGISTER;
  2775. if is_64bit(resultdef) then
  2776. registersint:=2
  2777. else
  2778. registersint:=1;
  2779. end;
  2780. end;
  2781. floatdef :
  2782. begin
  2783. expectloc:=LOC_FPUREGISTER;
  2784. {$ifdef cpufpemu}
  2785. if (cs_fp_emulation in current_settings.moduleswitches) then
  2786. registersint:=1
  2787. else
  2788. {$endif cpufpemu}
  2789. {$ifdef m68k}
  2790. if (tfloatdef(resultdef).floattype=s32real) then
  2791. registersint:=1
  2792. else
  2793. {$endif m68k}
  2794. registersfpu:=1;
  2795. end;
  2796. else
  2797. begin
  2798. expectloc:=procdefinition.funcretloc[callerside].loc;
  2799. if (expectloc = LOC_REGISTER) then
  2800. {$ifndef cpu64bit}
  2801. if (resultdef.size > sizeof(aint)) then
  2802. registersint:=2
  2803. else
  2804. {$endif cpu64bit}
  2805. registersint:=1
  2806. else
  2807. registersint:=0;
  2808. end;
  2809. end;
  2810. end
  2811. else
  2812. expectloc:=LOC_VOID;
  2813. end
  2814. else
  2815. expectloc:=LOC_VOID;
  2816. {$ifdef m68k}
  2817. { we need one more address register for virtual calls on m68k }
  2818. if (po_virtualmethod in procdefinition.procoptions) then
  2819. inc(registersint);
  2820. {$endif m68k}
  2821. { a fpu can be used in any procedure !! }
  2822. {$ifdef i386}
  2823. registersfpu:=procdefinition.fpu_used;
  2824. {$endif i386}
  2825. { if this is a call to a method calc the registers }
  2826. if (methodpointer<>nil) then
  2827. begin
  2828. if methodpointer.nodetype<>typen then
  2829. begin
  2830. firstpass(methodpointer);
  2831. registersfpu:=max(methodpointer.registersfpu,registersfpu);
  2832. registersint:=max(methodpointer.registersint,registersint);
  2833. {$ifdef SUPPORT_MMX }
  2834. registersmmx:=max(methodpointer.registersmmx,registersmmx);
  2835. {$endif SUPPORT_MMX}
  2836. end;
  2837. end;
  2838. { determine the registers of the procedure variable }
  2839. { is this OK for inlined procs also ?? (PM) }
  2840. if assigned(right) then
  2841. begin
  2842. registersfpu:=max(right.registersfpu,registersfpu);
  2843. registersint:=max(right.registersint,registersint);
  2844. {$ifdef SUPPORT_MMX}
  2845. registersmmx:=max(right.registersmmx,registersmmx);
  2846. {$endif SUPPORT_MMX}
  2847. end;
  2848. { determine the registers of the procedure }
  2849. if assigned(left) then
  2850. begin
  2851. registersfpu:=max(left.registersfpu,registersfpu);
  2852. registersint:=max(left.registersint,registersint);
  2853. {$ifdef SUPPORT_MMX}
  2854. registersmmx:=max(left.registersmmx,registersmmx);
  2855. {$endif SUPPORT_MMX}
  2856. end;
  2857. end;
  2858. {$ifdef state_tracking}
  2859. function Tcallnode.track_state_pass(exec_known:boolean):boolean;
  2860. var hp:Tcallparanode;
  2861. value:Tnode;
  2862. begin
  2863. track_state_pass:=false;
  2864. hp:=Tcallparanode(left);
  2865. while assigned(hp) do
  2866. begin
  2867. if left.track_state_pass(exec_known) then
  2868. begin
  2869. left.resultdef:=nil;
  2870. do_typecheckpass(left);
  2871. end;
  2872. value:=aktstate.find_fact(hp.left);
  2873. if value<>nil then
  2874. begin
  2875. track_state_pass:=true;
  2876. hp.left.destroy;
  2877. hp.left:=value.getcopy;
  2878. do_typecheckpass(hp.left);
  2879. end;
  2880. hp:=Tcallparanode(hp.right);
  2881. end;
  2882. end;
  2883. {$endif}
  2884. function tcallnode.para_count:longint;
  2885. var
  2886. ppn : tcallparanode;
  2887. begin
  2888. result:=0;
  2889. ppn:=tcallparanode(left);
  2890. while assigned(ppn) do
  2891. begin
  2892. if not(assigned(ppn.parasym) and
  2893. (vo_is_hidden_para in ppn.parasym.varoptions)) then
  2894. inc(result);
  2895. ppn:=tcallparanode(ppn.right);
  2896. end;
  2897. end;
  2898. function tcallnode.get_load_methodpointer:tnode;
  2899. var
  2900. newstatement : tstatementnode;
  2901. begin
  2902. if assigned(methodpointerinit) then
  2903. begin
  2904. result:=internalstatements(newstatement);
  2905. addstatement(newstatement,methodpointerinit);
  2906. addstatement(newstatement,methodpointer);
  2907. addstatement(newstatement,methodpointerdone);
  2908. methodpointerinit:=nil;
  2909. methodpointer:=nil;
  2910. methodpointerdone:=nil;
  2911. end
  2912. else
  2913. begin
  2914. result:=methodpointer;
  2915. methodpointer:=nil;
  2916. end;
  2917. end;
  2918. function tcallnode.docompare(p: tnode): boolean;
  2919. begin
  2920. docompare :=
  2921. inherited docompare(p) and
  2922. (symtableprocentry = tcallnode(p).symtableprocentry) and
  2923. (procdefinition = tcallnode(p).procdefinition) and
  2924. (methodpointer.isequal(tcallnode(p).methodpointer)) and
  2925. (((cnf_typedefset in callnodeflags) and (cnf_typedefset in tcallnode(p).callnodeflags) and
  2926. (equal_defs(typedef,tcallnode(p).typedef))) or
  2927. (not(cnf_typedefset in callnodeflags) and not(cnf_typedefset in tcallnode(p).callnodeflags)));
  2928. end;
  2929. procedure tcallnode.printnodedata(var t:text);
  2930. begin
  2931. if assigned(procdefinition) and
  2932. (procdefinition.typ=procdef) then
  2933. writeln(t,printnodeindention,'proc = ',tprocdef(procdefinition).fullprocname(true))
  2934. else
  2935. begin
  2936. if assigned(symtableprocentry) then
  2937. writeln(t,printnodeindention,'proc = ',symtableprocentry.name)
  2938. else
  2939. writeln(t,printnodeindention,'proc = <nil>');
  2940. end;
  2941. if assigned(methodpointer) then
  2942. begin
  2943. writeln(t,printnodeindention,'methodpointer =');
  2944. printnode(t,methodpointer);
  2945. end;
  2946. if assigned(methodpointerinit) then
  2947. begin
  2948. writeln(t,printnodeindention,'methodpointerinit =');
  2949. printnode(t,methodpointerinit);
  2950. end;
  2951. if assigned(methodpointerdone) then
  2952. begin
  2953. writeln(t,printnodeindention,'methodpointerdone =');
  2954. printnode(t,methodpointerdone);
  2955. end;
  2956. if assigned(right) then
  2957. begin
  2958. writeln(t,printnodeindention,'right =');
  2959. printnode(t,right);
  2960. end;
  2961. if assigned(left) then
  2962. begin
  2963. writeln(t,printnodeindention,'left =');
  2964. printnode(t,left);
  2965. end;
  2966. end;
  2967. begin
  2968. ccallnode:=tcallnode;
  2969. ccallparanode:=tcallparanode;
  2970. end.