njvmcal.pas 25 KB

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