ncal.pas 122 KB

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