njvmcal.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. JVM-specific code for call nodes
  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 njvmcal;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cgbase,
  22. symtype,symdef,
  23. node,ncal,ncgcal;
  24. type
  25. tjvmcallparanode = class(tcgcallparanode)
  26. protected
  27. procedure push_formal_para; override;
  28. procedure push_copyout_para; override;
  29. procedure handlemanagedbyrefpara(orgparadef: tdef); override;
  30. end;
  31. { tjvmcallnode }
  32. tjvmcallnode = class(tcgcallnode)
  33. protected
  34. procedure wrapcomplexinlinepara(para: tcallparanode); override;
  35. procedure extra_pre_call_code; override;
  36. procedure set_result_location(realresdef: tstoreddef); override;
  37. procedure do_release_unused_return_value;override;
  38. procedure extra_post_call_code; override;
  39. function dispatch_procvar: tnode;
  40. procedure remove_hidden_paras;
  41. public
  42. function pass_typecheck: tnode; override;
  43. function pass_1: tnode; override;
  44. end;
  45. implementation
  46. uses
  47. verbose,globals,globtype,constexp,cutils,
  48. symconst,symtable,symsym,symcpu,defutil,
  49. cgutils,tgobj,procinfo,htypechk,
  50. cpubase,aasmdata,aasmcpu,
  51. hlcgobj,hlcgcpu,
  52. pass_1,nutils,nadd,nbas,ncnv,ncon,nflw,ninl,nld,nmem,
  53. jvmdef;
  54. {*****************************************************************************
  55. TJVMCALLPARANODE
  56. *****************************************************************************}
  57. procedure tjvmcallparanode.push_formal_para;
  58. begin
  59. { primitive values are boxed, so in all cases this is a pointer to
  60. something and since it cannot be changed (or is not supposed to be
  61. changed anyway), we don't have to create a temporary array to hold a
  62. pointer to this value and can just pass the pointer to this value
  63. directly.
  64. In case the value can be changed (formal var/out), then we have
  65. already created a temporary array of one element that holds the boxed
  66. (or in case of a non-primitive type: original) value. The reason is
  67. that copying it back out may be a complex operation which we don't
  68. want to handle at the code generator level.
  69. -> always push a value parameter (which is either an array of one
  70. element, or an object) }
  71. push_value_para
  72. end;
  73. procedure tjvmcallparanode.push_copyout_para;
  74. begin
  75. { everything is wrapped and replaced by handlemanagedbyrefpara() in
  76. pass_1 }
  77. push_value_para;
  78. end;
  79. procedure getparabasenodes(p: tnode; out basenode: tnode; out parent: tunarynode);
  80. begin
  81. parent:=nil;
  82. while assigned(p) do
  83. begin
  84. case p.nodetype of
  85. inlinen:
  86. begin
  87. if tinlinenode(p).inlinenumber=in_box_x then
  88. begin
  89. parent:=tunarynode(p);
  90. p:=parent.left;
  91. end
  92. else
  93. break;
  94. end;
  95. subscriptn,
  96. vecn:
  97. begin
  98. break;
  99. end;
  100. typeconvn:
  101. begin
  102. parent:=tunarynode(p);
  103. { skip typeconversions that don't change the node type }
  104. p:=actualtargetnode(@p)^;
  105. end;
  106. derefn:
  107. begin
  108. parent:=tunarynode(p);
  109. p:=tunarynode(p).left;
  110. end
  111. else
  112. break;
  113. end;
  114. end;
  115. basenode:=p;
  116. end;
  117. function replacewithtemp(var orgnode:tnode): ttempcreatenode;
  118. begin
  119. if valid_for_var(orgnode,false) then
  120. result:=ctempcreatenode.create_reference(
  121. orgnode.resultdef,orgnode.resultdef.size,
  122. tt_persistent,true,orgnode,true)
  123. else
  124. result:=ctempcreatenode.create_value(
  125. orgnode.resultdef,orgnode.resultdef.size,
  126. tt_persistent,true,orgnode);
  127. { this node is reused while constructing the temp }
  128. orgnode:=ctemprefnode.create(result);
  129. typecheckpass(orgnode);
  130. end;
  131. procedure tjvmcallparanode.handlemanagedbyrefpara(orgparadef: tdef);
  132. var
  133. arrdef: tarraydef;
  134. arreledef: tdef;
  135. initstat,
  136. copybackstat,
  137. finistat: tstatementnode;
  138. finiblock: tblocknode;
  139. realpara, tempn, unwrappedele0, unwrappedele1: tnode;
  140. realparaparent: tunarynode;
  141. realparatemp, arraytemp: ttempcreatenode;
  142. leftcopy: tnode;
  143. implicitptrpara,
  144. verifyout: boolean;
  145. begin
  146. { implicit pointer types are already pointers -> no need to stuff them
  147. in an array to pass them by reference (except in case of a formal
  148. parameter, in which case everything is passed in an array since the
  149. callee can't know what was passed in) }
  150. if jvmimplicitpointertype(orgparadef) and
  151. (parasym.vardef.typ<>formaldef) then
  152. exit;
  153. fparainit:=internalstatements(initstat);
  154. fparacopyback:=internalstatements(copybackstat);
  155. finiblock:=internalstatements(finistat);
  156. getparabasenodes(left,realpara,realparaparent);
  157. { make sure we can get a copy of left safely, so we can use it both
  158. to load the original parameter value and to assign the result again
  159. afterwards (if required) }
  160. { special case for access to string character, because those are
  161. translated into function calls that differ depending on which side of
  162. an assignment they are on }
  163. if (realpara.nodetype=vecn) and
  164. (tvecnode(realpara).left.resultdef.typ=stringdef) then
  165. begin
  166. if node_complexity(tvecnode(realpara).left)>1 then
  167. begin
  168. realparatemp:=replacewithtemp(tvecnode(realpara).left);
  169. addstatement(initstat,realparatemp);
  170. addstatement(finistat,ctempdeletenode.create(realparatemp));
  171. end;
  172. if node_complexity(tvecnode(realpara).right)>1 then
  173. begin
  174. realparatemp:=replacewithtemp(tvecnode(realpara).right);
  175. addstatement(initstat,realparatemp);
  176. addstatement(finistat,ctempdeletenode.create(realparatemp));
  177. end;
  178. end
  179. else
  180. begin
  181. { general case: if it's possible that there's a function call
  182. involved, use a temp to prevent double evaluations }
  183. if assigned(realparaparent) then
  184. begin
  185. realparatemp:=replacewithtemp(realparaparent.left);
  186. addstatement(initstat,realparatemp);
  187. addstatement(finistat,ctempdeletenode.create(realparatemp));
  188. end;
  189. end;
  190. { create a copy of the original left (with temps already substituted),
  191. so we can use it if required to handle copying the return value back }
  192. leftcopy:=left.getcopy;
  193. implicitptrpara:=jvmimplicitpointertype(orgparadef);
  194. { create the array temp that that will serve as the paramter }
  195. if parasym.vardef.typ=formaldef then
  196. arreledef:=java_jlobject
  197. else if implicitptrpara then
  198. arreledef:=getpointerdef(orgparadef)
  199. else
  200. arreledef:=parasym.vardef;
  201. arrdef:=getarraydef(arreledef,1+ord(cs_check_var_copyout in current_settings.localswitches));
  202. { the -1 means "use the array's element count to determine the number
  203. of elements" in the JVM temp generator }
  204. arraytemp:=ctempcreatenode.create(arrdef,-1,tt_persistent,true);
  205. addstatement(initstat,arraytemp);
  206. addstatement(finistat,ctempdeletenode.create(arraytemp));
  207. { we can also check out-parameters if we are certain that they'll be
  208. valid according to the JVM. That's basically everything except for
  209. local variables (fields, arrays etc are all initialized on creation) }
  210. verifyout:=
  211. (cs_check_var_copyout in current_settings.localswitches) and
  212. ((actualtargetnode(@left)^.nodetype<>loadn) or
  213. (tloadnode(actualtargetnode(@left)^).symtableentry.typ<>localvarsym));
  214. { in case of a non-out parameter, pass in the original value (also
  215. always in case of implicitpointer type, since that pointer points to
  216. the data that will be changed by the callee) }
  217. if (parasym.varspez<>vs_out) or
  218. verifyout or
  219. ((parasym.vardef.typ<>formaldef) and
  220. implicitptrpara) then
  221. begin
  222. if implicitptrpara then
  223. begin
  224. { pass pointer to the struct }
  225. left:=caddrnode.create_internal(left);
  226. include(left.flags,nf_typedaddr);
  227. typecheckpass(left);
  228. end;
  229. { wrap the primitive type in an object container
  230. if required }
  231. if parasym.vardef.typ=formaldef then
  232. begin
  233. if (left.resultdef.typ in [orddef,floatdef]) then
  234. begin
  235. left:=cinlinenode.create(in_box_x,false,ccallparanode.create(left,nil));
  236. typecheckpass(left);
  237. end;
  238. left:=ctypeconvnode.create_explicit(left,java_jlobject);
  239. end;
  240. { put the parameter value in the array }
  241. addstatement(initstat,cassignmentnode.create(
  242. cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0)),
  243. left));
  244. { and the copy for checking }
  245. if (cs_check_var_copyout in current_settings.localswitches) then
  246. addstatement(initstat,cassignmentnode.create(
  247. cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(1)),
  248. cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0))));
  249. end
  250. else
  251. left.free;
  252. { replace the parameter with the temp array }
  253. left:=ctemprefnode.create(arraytemp);
  254. { generate the code to copy back the changed value into the original
  255. parameter in case of var/out.
  256. In case of a formaldef, changes to the parameter in the callee change
  257. the pointer inside the array -> we have to copy back the changes in
  258. all cases.
  259. In case of a regular parameter, we only have to copy things back in
  260. case it's not an implicit pointer type. The reason is that for
  261. implicit pointer types, any changes will have been directly applied
  262. to the original parameter via the implicit pointer that we passed in }
  263. if (parasym.varspez in [vs_var,vs_out]) and
  264. ((parasym.vardef.typ=formaldef) or
  265. not implicitptrpara) then
  266. begin
  267. { add the extraction of the parameter and assign it back to the
  268. original location }
  269. tempn:=ctemprefnode.create(arraytemp);
  270. tempn:=cvecnode.create(tempn,genintconstnode(0));
  271. { unbox if necessary }
  272. if parasym.vardef.typ=formaldef then
  273. begin
  274. if orgparadef.typ in [orddef,floatdef] then
  275. tempn:=cinlinenode.create(in_unbox_x_y,false,ccallparanode.create(
  276. ctypenode.create(orgparadef),ccallparanode.create(tempn,nil)))
  277. else if implicitptrpara then
  278. tempn:=ctypeconvnode.create_explicit(tempn,getpointerdef(orgparadef))
  279. end;
  280. if implicitptrpara then
  281. tempn:=cderefnode.create(tempn)
  282. else
  283. begin
  284. { add check to determine whether the location passed as
  285. var-parameter hasn't been modified directly to a different
  286. value than the returned var-parameter in the mean time }
  287. if ((parasym.varspez=vs_var) or
  288. verifyout) and
  289. (cs_check_var_copyout in current_settings.localswitches) then
  290. begin
  291. unwrappedele0:=cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0));
  292. unwrappedele1:=cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(1));
  293. if (parasym.vardef.typ=formaldef) and
  294. (orgparadef.typ in [orddef,floatdef]) then
  295. begin
  296. unwrappedele0:=cinlinenode.create(in_unbox_x_y,false,ccallparanode.create(
  297. ctypenode.create(orgparadef),ccallparanode.create(unwrappedele0,nil)));
  298. unwrappedele1:=cinlinenode.create(in_unbox_x_y,false,ccallparanode.create(
  299. ctypenode.create(orgparadef),ccallparanode.create(unwrappedele1,nil)))
  300. end;
  301. addstatement(copybackstat,cifnode.create(
  302. caddnode.create(andn,
  303. caddnode.create(unequaln,leftcopy.getcopy,ctypeconvnode.create_explicit(unwrappedele0,orgparadef)),
  304. caddnode.create(unequaln,leftcopy.getcopy,ctypeconvnode.create_explicit(unwrappedele1,orgparadef))),
  305. ccallnode.createintern('fpc_var_copyout_mismatch',
  306. ccallparanode.create(genintconstnode(fileinfo.column),
  307. ccallparanode.create(genintconstnode(fileinfo.line),nil))
  308. ),nil
  309. ));
  310. end;
  311. end;
  312. addstatement(copybackstat,cassignmentnode.create(leftcopy,
  313. ctypeconvnode.create_explicit(tempn,orgparadef)));
  314. end
  315. else
  316. leftcopy.free;
  317. addstatement(copybackstat,finiblock);
  318. firstpass(fparainit);
  319. firstpass(left);
  320. firstpass(fparacopyback);
  321. end;
  322. {*****************************************************************************
  323. TJVMCALLNODE
  324. *****************************************************************************}
  325. procedure tjvmcallnode.wrapcomplexinlinepara(para: tcallparanode);
  326. var
  327. tempnode: ttempcreatenode;
  328. begin
  329. { don't use caddrnodes for the JVM target, because we can't take the
  330. address of every kind of type (e.g., of ansistrings). A temp-reference
  331. node does work for any kind of memory reference (and the expectloc
  332. is LOC_(C)REFERENCE when this routine is called), but is not (yet)
  333. supported for other targets }
  334. tempnode:=ctempcreatenode.create_reference(para.parasym.vardef,para.parasym.vardef.size,
  335. tt_persistent,tparavarsym(para.parasym).is_regvar(false),para.left,false);
  336. addstatement(inlineinitstatement,tempnode);
  337. addstatement(inlinecleanupstatement,ctempdeletenode.create(tempnode));
  338. para.left:=ctemprefnode.create(tempnode);
  339. { inherit addr_taken flag }
  340. if (tabstractvarsym(para.parasym).addr_taken) then
  341. include(tempnode.tempinfo^.flags,ti_addr_taken);
  342. end;
  343. procedure tjvmcallnode.extra_pre_call_code;
  344. begin
  345. { when calling a constructor, first create a new instance, except
  346. when calling it from another constructor (because then this has
  347. already been done before calling the current constructor) }
  348. if procdefinition.proctypeoption<>potype_constructor then
  349. exit;
  350. if not(methodpointer.resultdef.typ in [classrefdef,recorddef]) then
  351. exit;
  352. { in case of an inherited constructor call in a class, the methodpointer
  353. is an objectdef rather than a classrefdef. That's not true in case
  354. of records though, so we need an extra check }
  355. if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  356. (cnf_inherited in callnodeflags) then
  357. exit;
  358. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(procdefinition.owner.defowner).jvm_full_typename(true))));
  359. { the constructor doesn't return anything, so put a duplicate of the
  360. self pointer on the evaluation stack for use as function result
  361. after the constructor has run }
  362. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  363. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  364. end;
  365. procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
  366. begin
  367. location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
  368. { in case of jvmimplicitpointertype(), the function will have allocated
  369. it already and we don't have to allocate it again here }
  370. if not jvmimplicitpointertype(realresdef) then
  371. tg.gethltemp(current_asmdata.CurrAsmList,realresdef,realresdef.size,tt_normal,location.reference)
  372. else
  373. tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,java_jlobject.size,tt_normal,location.reference);
  374. end;
  375. procedure tjvmcallnode.do_release_unused_return_value;
  376. begin
  377. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  378. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  379. exit;
  380. if is_void(resultdef) then
  381. exit;
  382. if (location.loc=LOC_REFERENCE) then
  383. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  384. if assigned(funcretnode) then
  385. exit;
  386. if jvmimplicitpointertype(resultdef) or
  387. (resultdef.size in [1..4]) then
  388. begin
  389. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
  390. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  391. end
  392. else if resultdef.size=8 then
  393. begin
  394. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop2));
  395. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  396. end
  397. else
  398. internalerror(2011010305);
  399. end;
  400. procedure tjvmcallnode.extra_post_call_code;
  401. var
  402. realresdef: tdef;
  403. begin
  404. thlcgjvm(hlcg).g_adjust_stack_after_call(current_asmdata.CurrAsmList,procdefinition,pushedparasize,typedef);
  405. { a constructor doesn't actually return a value in the jvm }
  406. if (tabstractprocdef(procdefinition).proctypeoption<>potype_constructor) then
  407. begin
  408. if cnf_return_value_used in callnodeflags then
  409. begin
  410. if not assigned(typedef) then
  411. realresdef:=tstoreddef(resultdef)
  412. else
  413. realresdef:=tstoreddef(typedef);
  414. thlcgjvm(hlcg).maybe_resize_stack_para_val(current_asmdata.CurrAsmList,realresdef,false);
  415. end;
  416. end;
  417. { if this was an inherited constructor call, initialise all fields that
  418. are wrapped types following it }
  419. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  420. (cnf_inherited in callnodeflags) then
  421. thlcgjvm(hlcg).gen_initialize_fields_code(current_asmdata.CurrAsmList);
  422. end;
  423. procedure tjvmcallnode.remove_hidden_paras;
  424. var
  425. prevpara, para, nextpara: tcallparanode;
  426. begin
  427. prevpara:=nil;
  428. para:=tcallparanode(left);
  429. while assigned(para) do
  430. begin
  431. nextpara:=tcallparanode(para.right);
  432. if vo_is_hidden_para in para.parasym.varoptions then
  433. begin
  434. if assigned(prevpara) then
  435. prevpara.right:=nextpara
  436. else
  437. left:=nextpara;
  438. para.right:=nil;
  439. para.free;
  440. end
  441. else
  442. prevpara:=para;
  443. para:=nextpara;
  444. end;
  445. end;
  446. function tjvmcallnode.pass_typecheck: tnode;
  447. begin
  448. result:=inherited pass_typecheck;
  449. if assigned(result) or
  450. codegenerror then
  451. exit;
  452. { unfortunately, we cannot handle a call to a virtual constructor for
  453. the current instance from inside another constructor. The reason is
  454. that these must be called via reflection, but before an instance has
  455. been fully initialized (which can only be done by calling either an
  456. inherited constructor or another constructor of this class) you can't
  457. perform reflection.
  458. Replacing virtual constructors with plain virtual methods that are
  459. called after the instance has been initialized causes problems if they
  460. in turn call plain constructors from inside the JDK (you cannot call
  461. constructors anymore once the instance has been constructed). It also
  462. causes problems regarding which other constructor to call then instead
  463. before to initialize the instance (we could add dummy constructors for
  464. that purpose to Pascal classes, but that scheme breaks when a class
  465. inherits from a JDK class other than JLObject).
  466. }
  467. if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  468. not(cnf_inherited in callnodeflags) and
  469. (procdefinition.proctypeoption=potype_constructor) and
  470. (po_virtualmethod in procdefinition.procoptions) and
  471. (cnf_member_call in callnodeflags) then
  472. CGMessage(parser_e_jvm_invalid_virtual_constructor_call);
  473. end;
  474. function tjvmcallnode.dispatch_procvar: tnode;
  475. var
  476. pdclass: tobjectdef;
  477. begin
  478. pdclass:=tcpuprocvardef(right.resultdef).classdef;
  479. { convert procvar type into corresponding class }
  480. if not tprocvardef(right.resultdef).is_addressonly then
  481. begin
  482. right:=caddrnode.create_internal(right);
  483. include(right.flags,nf_typedaddr);
  484. end;
  485. right:=ctypeconvnode.create_explicit(right,pdclass);
  486. include(right.flags,nf_load_procvar);
  487. typecheckpass(right);
  488. { call the invoke method with these parameters. It will take care of the
  489. wrapping and typeconversions; first filter out the automatically added
  490. hidden parameters though }
  491. remove_hidden_paras;
  492. result:=ccallnode.createinternmethod(right,'INVOKE',left);
  493. { reused }
  494. left:=nil;
  495. right:=nil;
  496. end;
  497. function tjvmcallnode.pass_1: tnode;
  498. var
  499. sym: tsym;
  500. wrappername: shortstring;
  501. begin
  502. { transform procvar calls }
  503. if assigned(right) then
  504. result:=dispatch_procvar
  505. else
  506. begin
  507. { replace virtual class method and constructor calls in case they may
  508. be indirect; make sure we don't replace the callthrough to the
  509. original constructor with another call to the wrapper }
  510. if (procdefinition.typ=procdef) and
  511. not(current_procinfo.procdef.synthetickind in [tsk_callthrough,tsk_callthrough_nonabstract]) and
  512. not(cnf_inherited in callnodeflags) and
  513. ((procdefinition.proctypeoption=potype_constructor) or
  514. (po_classmethod in procdefinition.procoptions)) and
  515. (po_virtualmethod in procdefinition.procoptions) and
  516. (methodpointer.nodetype<>loadvmtaddrn) then
  517. begin
  518. wrappername:=symtableprocentry.name+'__FPCVIRTUALCLASSMETHOD__';
  519. sym:=
  520. search_struct_member(tobjectdef(procdefinition.owner.defowner),
  521. wrappername);
  522. if not assigned(sym) or
  523. (sym.typ<>procsym) then
  524. internalerror(2011072801);
  525. { do not simply replace the procsym/procdef in case we could
  526. in theory do that, because the parameter nodes have already
  527. been bound to the current procdef's parasyms }
  528. remove_hidden_paras;
  529. result:=ccallnode.create(left,tprocsym(sym),symtableproc,methodpointer,callnodeflags);
  530. result.flags:=flags;
  531. left:=nil;
  532. methodpointer:=nil;
  533. exit;
  534. end;
  535. result:=inherited pass_1;
  536. if assigned(result) then
  537. exit;
  538. { set fforcedprocname so that even virtual method calls will be
  539. name-based (instead of based on VMT entry numbers) }
  540. if procdefinition.typ=procdef then
  541. fforcedprocname:=tprocdef(procdefinition).mangledname
  542. end;
  543. end;
  544. begin
  545. ccallnode:=tjvmcallnode;
  546. ccallparanode:=tjvmcallparanode;
  547. end.