njvmcal.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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,ncgcal;
  24. type
  25. tjvmcallparanode = class(tcgcallparanode)
  26. protected
  27. outcopybasereg: tregister;
  28. procedure push_formal_para; override;
  29. procedure push_copyout_para; override;
  30. procedure handleformalcopyoutpara(orgparadef: tdef); override;
  31. procedure load_arrayref_para(useparadef: tdef);
  32. end;
  33. { tjvmcallnode }
  34. tjvmcallnode = class(tcgcallnode)
  35. protected
  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. public
  43. function pass_1: tnode; override;
  44. end;
  45. implementation
  46. uses
  47. verbose,globtype,constexp,cutils,
  48. symconst,symtable,symsym,defutil,
  49. ncal,
  50. cgutils,tgobj,procinfo,
  51. cpubase,aasmdata,aasmcpu,
  52. hlcgobj,hlcgcpu,
  53. pass_1,nutils,nbas,ncnv,ncon,ninl,nld,nmem,
  54. jvmdef;
  55. {*****************************************************************************
  56. TJVMCALLPARANODE
  57. *****************************************************************************}
  58. procedure tjvmcallparanode.load_arrayref_para(useparadef: tdef);
  59. var
  60. arrayloc: tlocation;
  61. arrayref: treference;
  62. begin
  63. { cannot be a regular array or record, because those are passed by
  64. plain reference (since they are reference types at the Java level,
  65. but not at the Pascal level) -> no special initialisation necessary }
  66. outcopybasereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  67. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,java_jlobject,outcopybasereg);
  68. reference_reset_base(arrayref,outcopybasereg,0,4);
  69. arrayref.arrayreftype:=art_indexconst;
  70. arrayref.indexoffset:=0;
  71. { load the current parameter value into the array in case it's not an
  72. out-parameter; if it's an out-parameter the contents must be nil
  73. but that's already ok, since the anewarray opcode takes care of that }
  74. if (parasym.varspez<>vs_out) then
  75. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,useparadef,useparadef,left.location,arrayref);
  76. { store the array reference into the parameter location (don't change
  77. left.location, we may need it for copy-back after the call) }
  78. location_reset(arrayloc,LOC_REGISTER,OS_ADDR);
  79. arrayloc.register:=outcopybasereg;
  80. hlcg.gen_load_loc_cgpara(current_asmdata.CurrAsmList,java_jlobject,arrayloc,tempcgpara)
  81. end;
  82. procedure tjvmcallparanode.push_formal_para;
  83. begin
  84. { primitive values are boxed, so in all cases this is a pointer to
  85. something and since it cannot be changed (or is not supposed to be
  86. changed anyway), we don't have to create a temporary array to hold a
  87. pointer to this value and can just pass the pointer to this value
  88. directly.
  89. In case the value can be changed (formal var/out), then we have
  90. already created a temporary array of one element that holds the boxed
  91. (or in case of a non-primitive type: original) value. The reason is
  92. that copying it back out may be a complex operation which we don't
  93. want to handle at the code generator level.
  94. -> always push a value parameter (which is either an array of one
  95. element, or an object) }
  96. push_value_para
  97. end;
  98. procedure tjvmcallparanode.push_copyout_para;
  99. var
  100. mangledname: string;
  101. primitivetype: boolean;
  102. opc: tasmop;
  103. begin
  104. { create an array with one element of the parameter type }
  105. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
  106. mangledname:=jvmarrtype(left.resultdef,primitivetype);
  107. if primitivetype then
  108. opc:=a_newarray
  109. else
  110. opc:=a_anewarray;
  111. { doesn't change stack height: one int replaced by one reference }
  112. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
  113. load_arrayref_para(left.resultdef);
  114. end;
  115. procedure getparabasenodes(p: tnode; out basenode: tnode; out parent: tunarynode);
  116. begin
  117. parent:=nil;
  118. while assigned(p) do
  119. begin
  120. case p.nodetype of
  121. inlinen:
  122. begin
  123. if tinlinenode(p).inlinenumber=in_box_x then
  124. begin
  125. parent:=tunarynode(p);
  126. p:=parent.left;
  127. end
  128. else
  129. break;
  130. end;
  131. subscriptn,
  132. vecn:
  133. begin
  134. break;
  135. end;
  136. typeconvn:
  137. begin
  138. parent:=tunarynode(p);
  139. { skip typeconversions that don't change the node type }
  140. p:=p.actualtargetnode;
  141. end;
  142. derefn:
  143. begin
  144. parent:=tunarynode(p);
  145. p:=tunarynode(p).left;
  146. end
  147. else
  148. break;
  149. end;
  150. end;
  151. basenode:=p;
  152. end;
  153. function replacewithtemps(var orgnode, copiednode: tnode): ttempcreatenode;
  154. begin
  155. result:=ctempcreatenode.create_value(
  156. orgnode.resultdef,orgnode.resultdef.size,
  157. tt_persistent,true,orgnode);
  158. { this right is reused while constructing the temp }
  159. orgnode:=ctemprefnode.create(result);
  160. typecheckpass(orgnode);
  161. { this right is not reused }
  162. copiednode.free;
  163. copiednode:=ctemprefnode.create(result);
  164. typecheckpass(copiednode);
  165. end;
  166. procedure tjvmcallparanode.handleformalcopyoutpara(orgparadef: tdef);
  167. var
  168. paravaltemp,
  169. arraytemp,
  170. indextemp: ttempcreatenode;
  171. arrdef: tarraydef;
  172. initstat,
  173. finistat: tstatementnode;
  174. leftcopy: tnode;
  175. realpara, copyrealpara, tempn, assignmenttempn: tnode;
  176. realparaparent,copyrealparaparent: tunarynode;
  177. derefbasedef: tdef;
  178. deref: boolean;
  179. begin
  180. fparainit:=internalstatements(initstat);
  181. { In general, we now create a temp array of one element, assign left
  182. (or its address in case of a jvmimplicitpointertype) to it, replace
  183. the parameter with this array, and add code to paracopyback that
  184. extracts the value from the array again and assigns it to the original
  185. variable.
  186. Complications
  187. a) in case the parameter involves calling a function, it must not
  188. be called twice, so take the address of the location (since this
  189. is a var/out parameter, taking the address is conceptually
  190. always possible)
  191. b) in case this is an element of a string, we can't take the address
  192. in JVM code, so we then have to take the address of the string
  193. (which conceptually may not be possible since it can be a
  194. property or so) and store the index value into a temp, and
  195. reconstruct the vecn in te paracopyback code from this data
  196. (it's similar for normal var/out parameters)
  197. }
  198. { we'll replace a bunch of stuff in the parameter with temprefnodes,
  199. but we can't take a getcopy for the assignment afterwards of this
  200. result since a getcopy will always assume that we are copying the
  201. init/deletenodes too and that the temprefnodes have to point to the
  202. new temps -> get a copy of the parameter in advance, and then replace
  203. the nodes in the copy with temps just like in the original para }
  204. leftcopy:=left.getcopy;
  205. { get the real parameter source in case of type conversions. This is
  206. the same logic as for set_unique(). The parent is where we have to
  207. replace realpara with the temp that replaces it. }
  208. getparabasenodes(left,realpara,realparaparent);
  209. getparabasenodes(leftcopy,copyrealpara,copyrealparaparent);
  210. { assign either the parameter's address (in case it's an implicit
  211. pointer type) or the parameter itself (in case it's a primitive or
  212. actual pointer/object type) to the temp }
  213. deref:=false;
  214. if jvmimplicitpointertype(realpara.resultdef) then
  215. begin
  216. derefbasedef:=realpara.resultdef;
  217. realpara:=caddrnode.create_internal(realpara);
  218. include(realpara.flags,nf_typedaddr);
  219. typecheckpass(realpara);
  220. { we'll have to reference the parameter again in the expression }
  221. deref:=true;
  222. end;
  223. paravaltemp:=nil;
  224. { make sure we don't replace simple loadnodes with a temp, because
  225. in case of passing e.g. stringvar[3] to a formal var/out parameter,
  226. we add "stringvar[3]:=<result>" afterwards. Because Java strings are
  227. immutable, this is translated into "stringvar:=stringvar.setChar(3,
  228. <result>)". So if we replace stringvar with a temp, this will change
  229. the temp rather than stringvar. }
  230. indextemp:=nil;
  231. if (realpara.nodetype=vecn) then
  232. begin
  233. if node_complexity(tvecnode(realpara).left)>1 then
  234. begin
  235. paravaltemp:=replacewithtemps(tvecnode(realpara).left,
  236. tvecnode(copyrealpara).left);
  237. addstatement(initstat,paravaltemp);
  238. end;
  239. { in case of an array index, also replace the index with a temp if
  240. necessary/useful }
  241. if (node_complexity(tvecnode(realpara).right)>1) then
  242. begin
  243. indextemp:=replacewithtemps(tvecnode(realpara).right,
  244. tvecnode(copyrealpara).right);
  245. addstatement(initstat,indextemp);
  246. end;
  247. end
  248. else
  249. begin
  250. paravaltemp:=ctempcreatenode.create_value(
  251. realpara.resultdef,java_jlobject.size,tt_persistent,true,realpara);
  252. addstatement(initstat,paravaltemp);
  253. { replace the parameter in the parameter expression with this temp }
  254. tempn:=ctemprefnode.create(paravaltemp);
  255. assignmenttempn:=ctemprefnode.create(paravaltemp);
  256. { will be spliced in the middle of a tree that has already been
  257. typecheckpassed }
  258. typecheckpass(tempn);
  259. typecheckpass(assignmenttempn);
  260. if assigned(realparaparent) then
  261. begin
  262. { left has been reused in paravaltemp (it's realpara itself) ->
  263. don't free }
  264. realparaparent.left:=tempn;
  265. { the left's copy is not reused }
  266. copyrealparaparent.left.free;
  267. copyrealparaparent.left:=assignmenttempn;
  268. end
  269. else
  270. begin
  271. { left has been reused in paravaltemp (it's realpara itself) ->
  272. don't free }
  273. left:=tempn;
  274. { leftcopy can remain the same }
  275. assignmenttempn.free;
  276. end;
  277. end;
  278. { create the array temp that that will serve as the paramter }
  279. arrdef:=tarraydef.create(0,1,s32inttype);
  280. if parasym.vardef.typ=formaldef then
  281. arrdef.elementdef:=java_jlobject
  282. else
  283. arrdef.elementdef:=parasym.vardef;
  284. arraytemp:=ctempcreatenode.create(arrdef,java_jlobject.size,
  285. tt_persistent,true);
  286. addstatement(initstat,arraytemp);
  287. { in case of a non-out parameter, pass in the original value }
  288. if parasym.varspez<>vs_out then
  289. begin
  290. { wrap the primitive type in an object container
  291. if required }
  292. if parasym.vardef.typ=formaldef then
  293. begin
  294. if (left.resultdef.typ in [orddef,floatdef]) then
  295. begin
  296. left:=cinlinenode.create(in_box_x,false,ccallparanode.create(left,nil));
  297. typecheckpass(left);
  298. end;
  299. left:=ctypeconvnode.create_explicit(left,java_jlobject);
  300. end;
  301. addstatement(initstat,cassignmentnode.create(
  302. cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0)),
  303. left));
  304. end
  305. else
  306. left.free;
  307. { replace the parameter with the array }
  308. left:=ctemprefnode.create(arraytemp);
  309. { add the extraction of the parameter and assign it back to the
  310. original location }
  311. fparacopyback:=internalstatements(finistat);
  312. tempn:=cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0));
  313. { unbox if necessary }
  314. if parasym.vardef.typ=formaldef then
  315. begin
  316. if orgparadef.typ in [orddef,floatdef] then
  317. tempn:=cinlinenode.create(in_unbox_x_y,false,ccallparanode.create(
  318. ctypenode.create(orgparadef),ccallparanode.create(tempn,nil)));
  319. end;
  320. if (deref) then
  321. begin
  322. inserttypeconv_explicit(tempn,getpointerdef(derefbasedef));
  323. tempn:=cderefnode.create(tempn);
  324. end;
  325. addstatement(finistat,cassignmentnode.create(leftcopy,
  326. ctypeconvnode.create_explicit(tempn,orgparadef)));
  327. if assigned(indextemp) then
  328. addstatement(finistat,ctempdeletenode.create(indextemp));
  329. addstatement(finistat,ctempdeletenode.create(arraytemp));
  330. if assigned(paravaltemp) then
  331. addstatement(finistat,ctempdeletenode.create(paravaltemp));
  332. typecheckpass(fparainit);
  333. typecheckpass(left);
  334. typecheckpass(fparacopyback);
  335. end;
  336. {*****************************************************************************
  337. TJVMCALLNODE
  338. *****************************************************************************}
  339. procedure tjvmcallnode.extra_pre_call_code;
  340. begin
  341. { when calling a constructor, first create a new instance, except
  342. when calling it from another constructor (because then this has
  343. already been done before calling the current constructor) }
  344. if procdefinition.typ<>procdef then
  345. exit;
  346. if tabstractprocdef(procdefinition).proctypeoption<>potype_constructor then
  347. exit;
  348. if not(methodpointer.resultdef.typ in [classrefdef,recorddef]) then
  349. exit;
  350. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(tabstractprocdef(procdefinition).owner.defowner).jvm_full_typename(true))));
  351. { the constructor doesn't return anything, so put a duplicate of the
  352. self pointer on the evaluation stack for use as function result
  353. after the constructor has run }
  354. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  355. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  356. end;
  357. procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
  358. begin
  359. location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
  360. { in case of jvmimplicitpointertype(), the function will have allocated
  361. it already and we don't have to allocate it again here }
  362. if not jvmimplicitpointertype(realresdef) then
  363. tg.gethltemp(current_asmdata.CurrAsmList,realresdef,realresdef.size,tt_normal,location.reference)
  364. else
  365. tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,java_jlobject.size,tt_normal,location.reference);
  366. end;
  367. procedure tjvmcallnode.do_release_unused_return_value;
  368. begin
  369. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  370. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  371. exit;
  372. if (location.loc=LOC_REFERENCE) then
  373. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  374. if assigned(funcretnode) then
  375. exit;
  376. case resultdef.size of
  377. 0:
  378. ;
  379. 1..4:
  380. begin
  381. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
  382. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  383. end;
  384. 8:
  385. begin
  386. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop2));
  387. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  388. end
  389. else
  390. internalerror(2011010305);
  391. end;
  392. end;
  393. procedure tjvmcallnode.extra_post_call_code;
  394. var
  395. totalremovesize: longint;
  396. realresdef: tdef;
  397. ppn: tjvmcallparanode;
  398. pararef: treference;
  399. begin
  400. if not assigned(typedef) then
  401. realresdef:=tstoreddef(resultdef)
  402. else
  403. realresdef:=tstoreddef(typedef);
  404. { a constructor doesn't actually return a value in the jvm }
  405. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
  406. totalremovesize:=pushedparasize
  407. else
  408. { even a byte takes up a full stackslot -> align size to multiple of 4 }
  409. totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
  410. { remove parameters from internal evaluation stack counter (in case of
  411. e.g. no parameters and a result, it can also increase) }
  412. if totalremovesize>0 then
  413. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,totalremovesize)
  414. else if totalremovesize<0 then
  415. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,-totalremovesize);
  416. { if this was an inherited constructor call, initialise all fields that
  417. are wrapped types following it }
  418. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  419. (cnf_inherited in callnodeflags) then
  420. thlcgjvm(hlcg).gen_initialize_fields_code(current_asmdata.CurrAsmList);
  421. { copy back the copyout parameter values, if any }
  422. { Release temps from parameters }
  423. ppn:=tjvmcallparanode(left);
  424. while assigned(ppn) do
  425. begin
  426. if assigned(ppn.left) then
  427. begin
  428. { don't try to copy back vs_constref }
  429. if (ppn.parasym.varspez in [vs_var,vs_out]) and
  430. (ppn.outcopybasereg<>NR_NO) then
  431. begin
  432. reference_reset_base(pararef,NR_NO,0,4);
  433. pararef.arrayreftype:=art_indexconst;
  434. pararef.base:=ppn.outcopybasereg;
  435. pararef.indexoffset:=0;
  436. { the value has to be copied back into persistent storage }
  437. if (ppn.parasym.vardef.typ<>formaldef) then
  438. begin
  439. case ppn.left.location.loc of
  440. LOC_REFERENCE:
  441. hlcg.a_load_ref_ref(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.reference);
  442. LOC_CREGISTER:
  443. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.register);
  444. else
  445. internalerror(2011051201);
  446. end;
  447. end
  448. else
  449. begin
  450. { extracting values from foramldef parameters is done
  451. by the generic code }
  452. end;
  453. end;
  454. end;
  455. ppn:=tjvmcallparanode(ppn.right);
  456. end;
  457. end;
  458. procedure tjvmcallnode.remove_hidden_paras;
  459. var
  460. prevpara, para, nextpara: tcallparanode;
  461. begin
  462. prevpara:=nil;
  463. para:=tcallparanode(left);
  464. while assigned(para) do
  465. begin
  466. nextpara:=tcallparanode(para.right);
  467. if vo_is_hidden_para in para.parasym.varoptions then
  468. begin
  469. if assigned(prevpara) then
  470. prevpara.right:=nextpara
  471. else
  472. left:=nextpara;
  473. para.right:=nil;
  474. para.free;
  475. end
  476. else
  477. prevpara:=para;
  478. para:=nextpara;
  479. end;
  480. end;
  481. function tjvmcallnode.dispatch_procvar: tnode;
  482. var
  483. pdclass: tobjectdef;
  484. begin
  485. pdclass:=tprocvardef(right.resultdef).classdef;
  486. { convert procvar type into corresponding class }
  487. if not tprocvardef(right.resultdef).is_addressonly then
  488. begin
  489. right:=caddrnode.create_internal(right);
  490. include(right.flags,nf_typedaddr);
  491. end;
  492. right:=ctypeconvnode.create_explicit(right,pdclass);
  493. include(right.flags,nf_load_procvar);
  494. typecheckpass(right);
  495. { call the invoke method with these parameters. It will take care of the
  496. wrapping and typeconversions; first filter out the automatically added
  497. hidden parameters though }
  498. remove_hidden_paras;
  499. result:=ccallnode.createinternmethod(right,'INVOKE',left);
  500. { reused }
  501. left:=nil;
  502. right:=nil;
  503. end;
  504. function tjvmcallnode.pass_1: tnode;
  505. var
  506. sym: tsym;
  507. wrappername: shortstring;
  508. begin
  509. { transform procvar calls }
  510. if assigned(right) then
  511. result:=dispatch_procvar
  512. else
  513. begin
  514. { replace virtual class method and constructor calls in case they may
  515. be indirect; make sure we don't replace the callthrough to the
  516. original constructor with another call to the wrapper }
  517. if (procdefinition.typ=procdef) and
  518. (current_procinfo.procdef.synthetickind<>tsk_callthrough) and
  519. not(cnf_inherited in callnodeflags) and
  520. ((procdefinition.proctypeoption=potype_constructor) or
  521. (po_classmethod in procdefinition.procoptions)) and
  522. (po_virtualmethod in procdefinition.procoptions) and
  523. (methodpointer.nodetype<>loadvmtaddrn) then
  524. begin
  525. wrappername:=symtableprocentry.name+'__FPCVIRTUALCLASSMETHOD__';
  526. sym:=
  527. search_struct_member(tobjectdef(procdefinition.owner.defowner),
  528. wrappername);
  529. if not assigned(sym) or
  530. (sym.typ<>procsym) then
  531. internalerror(2011072801);
  532. { do not simply replace the procsym/procdef in case we could
  533. in theory do that, because the parameter nodes have already
  534. been bound to the current procdef's parasyms }
  535. remove_hidden_paras;
  536. result:=ccallnode.create(left,tprocsym(sym),symtableproc,methodpointer,callnodeflags);
  537. result.flags:=flags;
  538. left:=nil;
  539. methodpointer:=nil;
  540. exit;
  541. end;
  542. result:=inherited pass_1;
  543. if assigned(result) then
  544. exit;
  545. end;
  546. end;
  547. begin
  548. ccallnode:=tjvmcallnode;
  549. ccallparanode:=tjvmcallparanode;
  550. end.