njvmcal.pas 25 KB

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