njvmcal.pas 25 KB

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