cg386cal.pas 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 assembler for in call nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cg386cal;
  19. interface
  20. { $define AnsiStrRef}
  21. uses
  22. symtable,tree;
  23. procedure secondcallparan(var p : ptree;defcoll : pparaitem;
  24. push_from_left_to_right,inlined,dword_align : boolean;para_offset : longint);
  25. procedure secondcalln(var p : ptree);
  26. procedure secondprocinline(var p : ptree);
  27. implementation
  28. uses
  29. globtype,systems,
  30. cobjects,verbose,globals,
  31. symconst,aasm,types,
  32. {$ifdef GDB}
  33. gdb,
  34. {$endif GDB}
  35. hcodegen,temp_gen,pass_2,
  36. cpubase,cpuasm,
  37. cgai386,tgeni386,cg386ld;
  38. {*****************************************************************************
  39. SecondCallParaN
  40. *****************************************************************************}
  41. procedure secondcallparan(var p : ptree;defcoll : pparaitem;
  42. push_from_left_to_right,inlined,dword_align : boolean;para_offset : longint);
  43. procedure maybe_push_high;
  44. begin
  45. { open array ? }
  46. { defcoll^.data can be nil for read/write }
  47. if assigned(defcoll^.data) and
  48. push_high_param(defcoll^.data) then
  49. begin
  50. if assigned(p^.hightree) then
  51. begin
  52. secondpass(p^.hightree);
  53. { this is a longint anyway ! }
  54. push_value_para(p^.hightree,inlined,para_offset,4);
  55. end
  56. else
  57. internalerror(432645);
  58. end;
  59. end;
  60. var
  61. otlabel,oflabel : pasmlabel;
  62. align : longint;
  63. { temporary variables: }
  64. tempdeftype : tdeftype;
  65. r : preference;
  66. begin
  67. { push from left to right if specified }
  68. if push_from_left_to_right and assigned(p^.right) then
  69. secondcallparan(p^.right,pparaitem(defcoll^.next),push_from_left_to_right,
  70. inlined,dword_align,para_offset);
  71. otlabel:=truelabel;
  72. oflabel:=falselabel;
  73. getlabel(truelabel);
  74. getlabel(falselabel);
  75. secondpass(p^.left);
  76. { filter array constructor with c styled args }
  77. if is_array_constructor(p^.left^.resulttype) and p^.left^.cargs then
  78. begin
  79. { nothing, everything is already pushed }
  80. end
  81. { in codegen.handleread.. defcoll^.data is set to nil }
  82. else if assigned(defcoll^.data) and
  83. (defcoll^.data^.deftype=formaldef) then
  84. begin
  85. { allow @var }
  86. inc(pushedparasize,4);
  87. if p^.left^.treetype=addrn then
  88. begin
  89. { always a register }
  90. if inlined then
  91. begin
  92. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  93. emit_reg_ref(A_MOV,S_L,
  94. p^.left^.location.register,r);
  95. end
  96. else
  97. emit_reg(A_PUSH,S_L,p^.left^.location.register);
  98. ungetregister32(p^.left^.location.register);
  99. end
  100. else
  101. begin
  102. if not(p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  103. CGMessage(type_e_mismatch)
  104. else
  105. begin
  106. if inlined then
  107. begin
  108. emit_ref_reg(A_LEA,S_L,
  109. newreference(p^.left^.location.reference),R_EDI);
  110. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  111. emit_reg_ref(A_MOV,S_L,R_EDI,r);
  112. end
  113. else
  114. emitpushreferenceaddr(p^.left^.location.reference);
  115. del_reference(p^.left^.location.reference);
  116. end;
  117. end;
  118. end
  119. { handle call by reference parameter }
  120. else if (defcoll^.paratyp=vs_var) then
  121. begin
  122. if (p^.left^.location.loc<>LOC_REFERENCE) then
  123. CGMessage(cg_e_var_must_be_reference);
  124. maybe_push_high;
  125. inc(pushedparasize,4);
  126. if inlined then
  127. begin
  128. emit_ref_reg(A_LEA,S_L,
  129. newreference(p^.left^.location.reference),R_EDI);
  130. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  131. emit_reg_ref(A_MOV,S_L,R_EDI,r);
  132. end
  133. else
  134. emitpushreferenceaddr(p^.left^.location.reference);
  135. del_reference(p^.left^.location.reference);
  136. end
  137. else
  138. begin
  139. tempdeftype:=p^.resulttype^.deftype;
  140. if tempdeftype=filedef then
  141. CGMessage(cg_e_file_must_call_by_reference);
  142. { open array must always push the address, this is needed to
  143. also push addr of small arrays (PFV) }
  144. if (assigned(defcoll^.data) and
  145. is_open_array(defcoll^.data)) or
  146. push_addr_param(p^.resulttype) then
  147. begin
  148. maybe_push_high;
  149. inc(pushedparasize,4);
  150. if inlined then
  151. begin
  152. emit_ref_reg(A_LEA,S_L,
  153. newreference(p^.left^.location.reference),R_EDI);
  154. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  155. emit_reg_ref(A_MOV,S_L,
  156. R_EDI,r);
  157. end
  158. else
  159. emitpushreferenceaddr(p^.left^.location.reference);
  160. del_reference(p^.left^.location.reference);
  161. end
  162. else
  163. begin
  164. align:=target_os.stackalignment;
  165. if dword_align then
  166. align:=4;
  167. push_value_para(p^.left,inlined,para_offset,align);
  168. end;
  169. end;
  170. freelabel(truelabel);
  171. freelabel(falselabel);
  172. truelabel:=otlabel;
  173. falselabel:=oflabel;
  174. { push from right to left }
  175. if not push_from_left_to_right and assigned(p^.right) then
  176. secondcallparan(p^.right,pparaitem(defcoll^.next),push_from_left_to_right,
  177. inlined,dword_align,para_offset);
  178. end;
  179. {*****************************************************************************
  180. SecondCallN
  181. *****************************************************************************}
  182. procedure secondcalln(var p : ptree);
  183. var
  184. unusedregisters : tregisterset;
  185. usablecount : byte;
  186. pushed : tpushed;
  187. hr,funcretref : treference;
  188. hregister,hregister2 : tregister;
  189. oldpushedparasize : longint;
  190. { true if ESI must be loaded again after the subroutine }
  191. loadesi : boolean;
  192. { true if a virtual method must be called directly }
  193. no_virtual_call : boolean;
  194. { true if we produce a con- or destrutor in a call }
  195. is_con_or_destructor : boolean;
  196. { true if a constructor is called again }
  197. extended_new : boolean;
  198. { adress returned from an I/O-error }
  199. iolabel : pasmlabel;
  200. { lexlevel count }
  201. i : longint;
  202. { help reference pointer }
  203. r : preference;
  204. hp,
  205. pp,params : ptree;
  206. inlined : boolean;
  207. inlinecode : ptree;
  208. para_offset : longint;
  209. { instruction for alignement correction }
  210. { corr : paicpu;}
  211. { we must pop this size also after !! }
  212. { must_pop : boolean; }
  213. pop_size : longint;
  214. pop_allowed : boolean;
  215. label
  216. dont_call;
  217. begin
  218. reset_reference(p^.location.reference);
  219. extended_new:=false;
  220. iolabel:=nil;
  221. inlinecode:=nil;
  222. inlined:=false;
  223. loadesi:=true;
  224. no_virtual_call:=false;
  225. unusedregisters:=unused;
  226. usablecount:=usablereg32;
  227. if not assigned(p^.procdefinition) then
  228. exit;
  229. if (pocall_inline in p^.procdefinition^.proccalloptions) then
  230. begin
  231. inlined:=true;
  232. inlinecode:=p^.right;
  233. { set it to the same lexical level as the local symtable, becuase
  234. the para's are stored there }
  235. pprocdef(p^.procdefinition)^.parast^.symtablelevel:=aktprocsym^.definition^.localst^.symtablelevel;
  236. if assigned(p^.left) then
  237. inlinecode^.para_offset:=gettempofsizepersistant(inlinecode^.para_size);
  238. pprocdef(p^.procdefinition)^.parast^.address_fixup:=inlinecode^.para_offset;
  239. {$ifdef extdebug}
  240. Comment(V_debug,
  241. 'inlined parasymtable is at offset '
  242. +tostr(pprocdef(p^.procdefinition)^.parast^.address_fixup));
  243. exprasmlist^.concat(new(pai_asm_comment,init(
  244. strpnew('inlined parasymtable is at offset '
  245. +tostr(pprocdef(p^.procdefinition)^.parast^.address_fixup)))));
  246. {$endif extdebug}
  247. p^.right:=nil;
  248. { disable further inlining of the same proc
  249. in the args }
  250. {$ifdef INCLUDEOK}
  251. exclude(p^.procdefinition^.proccalloptions,pocall_inline);
  252. {$else}
  253. p^.procdefinition^.proccalloptions:=p^.procdefinition^.proccalloptions-[pocall_inline];
  254. {$endif}
  255. end;
  256. { only if no proc var }
  257. if not(assigned(p^.right)) then
  258. is_con_or_destructor:=(p^.procdefinition^.proctypeoption in [potype_constructor,potype_destructor]);
  259. { proc variables destroy all registers }
  260. if (p^.right=nil) and
  261. { virtual methods too }
  262. not(po_virtualmethod in p^.procdefinition^.procoptions) then
  263. begin
  264. if (cs_check_io in aktlocalswitches) and
  265. (po_iocheck in p^.procdefinition^.procoptions) and
  266. not(po_iocheck in aktprocsym^.definition^.procoptions) then
  267. begin
  268. getlabel(iolabel);
  269. emitlab(iolabel);
  270. end
  271. else
  272. iolabel:=nil;
  273. { save all used registers }
  274. pushusedregisters(pushed,pprocdef(p^.procdefinition)^.usedregisters);
  275. { give used registers through }
  276. usedinproc:=usedinproc or pprocdef(p^.procdefinition)^.usedregisters;
  277. end
  278. else
  279. begin
  280. pushusedregisters(pushed,$ff);
  281. usedinproc:=$ff;
  282. { no IO check for methods and procedure variables }
  283. iolabel:=nil;
  284. end;
  285. { generate the code for the parameter and push them }
  286. oldpushedparasize:=pushedparasize;
  287. pushedparasize:=0;
  288. pop_size:=0;
  289. { no inc esp for inlined procedure
  290. and for objects constructors PM }
  291. if inlined or
  292. ((p^.right=nil) and
  293. (p^.procdefinition^.proctypeoption=potype_constructor) and
  294. { quick'n'dirty check if it is a class or an object }
  295. (p^.resulttype^.deftype=orddef)) then
  296. pop_allowed:=false
  297. else
  298. pop_allowed:=true;
  299. if pop_allowed then
  300. begin
  301. { Old pushedsize aligned on 4 ? }
  302. i:=oldpushedparasize and 3;
  303. if i>0 then
  304. inc(pop_size,4-i);
  305. { This parasize aligned on 4 ? }
  306. i:=p^.procdefinition^.para_size and 3;
  307. if i>0 then
  308. inc(pop_size,4-i);
  309. { insert the opcode and update pushedparasize }
  310. { never push 4 or more !! }
  311. pop_size:=pop_size mod 4;
  312. if pop_size>0 then
  313. begin
  314. inc(pushedparasize,pop_size);
  315. emit_const_reg(A_SUB,S_L,pop_size,R_ESP);
  316. {$ifdef GDB}
  317. if (cs_debuginfo in aktmoduleswitches) and
  318. (exprasmlist^.first=exprasmlist^.last) then
  319. exprasmlist^.concat(new(pai_force_line,init));
  320. {$endif GDB}
  321. end;
  322. end;
  323. if (p^.resulttype<>pdef(voiddef)) and
  324. ret_in_param(p^.resulttype) then
  325. begin
  326. funcretref.symbol:=nil;
  327. {$ifdef test_dest_loc}
  328. if dest_loc_known and (dest_loc_tree=p) and
  329. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  330. begin
  331. funcretref:=dest_loc.reference;
  332. if assigned(dest_loc.reference.symbol) then
  333. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  334. in_dest_loc:=true;
  335. end
  336. else
  337. {$endif test_dest_loc}
  338. if inlined then
  339. begin
  340. reset_reference(funcretref);
  341. funcretref.offset:=gettempofsizepersistant(p^.procdefinition^.retdef^.size);
  342. funcretref.base:=procinfo^.framepointer;
  343. end
  344. else
  345. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  346. end;
  347. if assigned(p^.left) then
  348. begin
  349. { be found elsewhere }
  350. if inlined then
  351. para_offset:=pprocdef(p^.procdefinition)^.parast^.address_fixup+
  352. pprocdef(p^.procdefinition)^.parast^.datasize
  353. else
  354. para_offset:=0;
  355. if assigned(p^.right) then
  356. secondcallparan(p^.left,pparaitem(pabstractprocdef(p^.right^.resulttype)^.para^.first),
  357. (pocall_leftright in p^.procdefinition^.proccalloptions),
  358. inlined,
  359. (pocall_cdecl in p^.procdefinition^.proccalloptions) or
  360. (pocall_stdcall in p^.procdefinition^.proccalloptions),
  361. para_offset)
  362. else
  363. secondcallparan(p^.left,pparaitem(p^.procdefinition^.para^.first),
  364. (pocall_leftright in p^.procdefinition^.proccalloptions),
  365. inlined,
  366. (pocall_cdecl in p^.procdefinition^.proccalloptions) or
  367. (pocall_stdcall in p^.procdefinition^.proccalloptions),
  368. para_offset);
  369. end;
  370. params:=p^.left;
  371. p^.left:=nil;
  372. if inlined then
  373. inlinecode^.retoffset:=gettempofsizepersistant(4);
  374. if ret_in_param(p^.resulttype) then
  375. begin
  376. { This must not be counted for C code
  377. complex return address is removed from stack
  378. by function itself ! }
  379. {$ifdef OLD_C_STACK}
  380. inc(pushedparasize,4); { lets try without it PM }
  381. {$endif not OLD_C_STACK}
  382. if inlined then
  383. begin
  384. emit_ref_reg(A_LEA,S_L,
  385. newreference(funcretref),R_EDI);
  386. r:=new_reference(procinfo^.framepointer,inlinecode^.retoffset);
  387. emit_reg_ref(A_MOV,S_L,
  388. R_EDI,r);
  389. end
  390. else
  391. emitpushreferenceaddr(funcretref);
  392. end;
  393. { procedure variable ? }
  394. if (p^.right=nil) then
  395. begin
  396. { overloaded operator have no symtable }
  397. { push self }
  398. if assigned(p^.symtable) and
  399. (p^.symtable^.symtabletype=withsymtable) then
  400. begin
  401. { dirty trick to avoid the secondcall below }
  402. p^.methodpointer:=genzeronode(callparan);
  403. p^.methodpointer^.location.loc:=LOC_REGISTER;
  404. p^.methodpointer^.location.register:=R_ESI;
  405. { ARGHHH this is wrong !!!
  406. if we can init from base class for a child
  407. class that the wrong VMT will be
  408. transfered to constructor !! }
  409. p^.methodpointer^.resulttype:=
  410. ptree(pwithsymtable(p^.symtable)^.withnode)^.left^.resulttype;
  411. { change dispose type !! }
  412. p^.disposetyp:=dt_mbleft_and_method;
  413. { make a reference }
  414. new(r);
  415. reset_reference(r^);
  416. { if assigned(ptree(pwithsymtable(p^.symtable)^.withnode)^.pref) then
  417. begin
  418. r^:=ptree(pwithsymtable(p^.symtable)^.withnode)^.pref^;
  419. end
  420. else
  421. begin
  422. r^.offset:=p^.symtable^.datasize;
  423. r^.base:=procinfo^.framepointer;
  424. end; }
  425. r^:=ptree(pwithsymtable(p^.symtable)^.withnode)^.withreference^;
  426. if (not pwithsymtable(p^.symtable)^.direct_with) or
  427. pobjectdef(p^.methodpointer^.resulttype)^.is_class then
  428. emit_ref_reg(A_MOV,S_L,r,R_ESI)
  429. else
  430. emit_ref_reg(A_LEA,S_L,r,R_ESI);
  431. end;
  432. { push self }
  433. if assigned(p^.symtable) and
  434. ((p^.symtable^.symtabletype=objectsymtable) or
  435. (p^.symtable^.symtabletype=withsymtable)) then
  436. begin
  437. if assigned(p^.methodpointer) then
  438. begin
  439. {
  440. if p^.methodpointer^.resulttype=classrefdef then
  441. begin
  442. two possibilities:
  443. 1. constructor
  444. 2. class method
  445. end
  446. else }
  447. begin
  448. case p^.methodpointer^.treetype of
  449. typen:
  450. begin
  451. { direct call to inherited method }
  452. if (po_abstractmethod in p^.procdefinition^.procoptions) then
  453. begin
  454. CGMessage(cg_e_cant_call_abstract_method);
  455. goto dont_call;
  456. end;
  457. { generate no virtual call }
  458. no_virtual_call:=true;
  459. if (sp_static in p^.symtableprocentry^.symoptions) then
  460. begin
  461. { well lets put the VMT address directly into ESI }
  462. { it is kind of dirty but that is the simplest }
  463. { way to accept virtual static functions (PM) }
  464. loadesi:=true;
  465. { if no VMT just use $0 bug0214 PM }
  466. if not(oo_has_vmt in pobjectdef(p^.methodpointer^.resulttype)^.objectoptions) then
  467. emit_const_reg(A_MOV,S_L,0,R_ESI)
  468. else
  469. begin
  470. emit_sym_ofs_reg(A_MOV,S_L,
  471. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname),
  472. 0,R_ESI);
  473. end;
  474. { emit_reg(A_PUSH,S_L,R_ESI);
  475. this is done below !! }
  476. end
  477. else
  478. { this is a member call, so ESI isn't modfied }
  479. loadesi:=false;
  480. { a class destructor needs a flag }
  481. if pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  482. assigned(aktprocsym) and
  483. (aktprocsym^.definition^.proctypeoption=potype_destructor) then
  484. begin
  485. push_int(0);
  486. emit_reg(A_PUSH,S_L,R_ESI);
  487. end;
  488. if not(is_con_or_destructor and
  489. pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  490. assigned(aktprocsym) and
  491. (aktprocsym^.definition^.proctypeoption in [potype_constructor,potype_destructor])
  492. ) then
  493. emit_reg(A_PUSH,S_L,R_ESI);
  494. { if an inherited con- or destructor should be }
  495. { called in a con- or destructor then a warning }
  496. { will be made }
  497. { con- and destructors need a pointer to the vmt }
  498. if is_con_or_destructor and
  499. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class) and
  500. assigned(aktprocsym) then
  501. begin
  502. if not(aktprocsym^.definition^.proctypeoption in
  503. [potype_constructor,potype_destructor]) then
  504. CGMessage(cg_w_member_cd_call_from_method);
  505. end;
  506. { class destructors get there flag below }
  507. if is_con_or_destructor and
  508. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  509. assigned(aktprocsym) and
  510. (aktprocsym^.definition^.proctypeoption=potype_destructor)) then
  511. push_int(0);
  512. end;
  513. hnewn:
  514. begin
  515. { extended syntax of new }
  516. { ESI must be zero }
  517. emit_reg_reg(A_XOR,S_L,R_ESI,R_ESI);
  518. emit_reg(A_PUSH,S_L,R_ESI);
  519. { insert the vmt }
  520. emit_sym(A_PUSH,S_L,
  521. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname));
  522. extended_new:=true;
  523. end;
  524. hdisposen:
  525. begin
  526. secondpass(p^.methodpointer);
  527. { destructor with extended syntax called from dispose }
  528. { hdisposen always deliver LOC_REFERENCE }
  529. emit_ref_reg(A_LEA,S_L,
  530. newreference(p^.methodpointer^.location.reference),R_ESI);
  531. del_reference(p^.methodpointer^.location.reference);
  532. emit_reg(A_PUSH,S_L,R_ESI);
  533. emit_sym(A_PUSH,S_L,
  534. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname));
  535. end;
  536. else
  537. begin
  538. { call to an instance member }
  539. if (p^.symtable^.symtabletype<>withsymtable) then
  540. begin
  541. secondpass(p^.methodpointer);
  542. case p^.methodpointer^.location.loc of
  543. LOC_CREGISTER,
  544. LOC_REGISTER:
  545. begin
  546. emit_reg_reg(A_MOV,S_L,p^.methodpointer^.location.register,R_ESI);
  547. ungetregister32(p^.methodpointer^.location.register);
  548. end;
  549. else
  550. begin
  551. if (p^.methodpointer^.resulttype^.deftype=classrefdef) or
  552. ((p^.methodpointer^.resulttype^.deftype=objectdef) and
  553. pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  554. emit_ref_reg(A_MOV,S_L,
  555. newreference(p^.methodpointer^.location.reference),R_ESI)
  556. else
  557. emit_ref_reg(A_LEA,S_L,
  558. newreference(p^.methodpointer^.location.reference),R_ESI);
  559. del_reference(p^.methodpointer^.location.reference);
  560. end;
  561. end;
  562. end;
  563. { when calling a class method, we have to load ESI with the VMT !
  564. But, not for a class method via self }
  565. if not(po_containsself in p^.procdefinition^.procoptions) then
  566. begin
  567. if (po_classmethod in p^.procdefinition^.procoptions) and
  568. not(p^.methodpointer^.resulttype^.deftype=classrefdef) then
  569. begin
  570. { class method needs current VMT }
  571. new(r);
  572. reset_reference(r^);
  573. r^.base:=R_ESI;
  574. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  575. emit_ref_reg(A_MOV,S_L,r,R_ESI);
  576. end;
  577. { direct call to destructor: don't remove data! }
  578. if (p^.procdefinition^.proctypeoption=potype_destructor) and
  579. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  580. (pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  581. emit_const(A_PUSH,S_L,1);
  582. { direct call to class constructor, don't allocate memory }
  583. if (p^.procdefinition^.proctypeoption=potype_constructor) and
  584. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  585. (pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  586. emit_const(A_PUSH,S_L,0)
  587. else
  588. emit_reg(A_PUSH,S_L,R_ESI);
  589. end;
  590. if is_con_or_destructor then
  591. begin
  592. { classes don't get a VMT pointer pushed }
  593. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  594. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  595. begin
  596. if (p^.procdefinition^.proctypeoption=potype_constructor) then
  597. begin
  598. { it's no bad idea, to insert the VMT }
  599. emit_sym(A_PUSH,S_L,newasmsymbol(
  600. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname));
  601. end
  602. { destructors haven't to dispose the instance, if this is }
  603. { a direct call }
  604. else
  605. push_int(0);
  606. end;
  607. end;
  608. end;
  609. end;
  610. end;
  611. end
  612. else
  613. begin
  614. if (po_classmethod in p^.procdefinition^.procoptions) and
  615. not(
  616. assigned(aktprocsym) and
  617. (po_classmethod in aktprocsym^.definition^.procoptions)
  618. ) then
  619. begin
  620. { class method needs current VMT }
  621. new(r);
  622. reset_reference(r^);
  623. r^.base:=R_ESI;
  624. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  625. emit_ref_reg(A_MOV,S_L,r,R_ESI);
  626. end
  627. else
  628. begin
  629. { member call, ESI isn't modified }
  630. loadesi:=false;
  631. end;
  632. emit_reg(A_PUSH,S_L,R_ESI);
  633. { but a con- or destructor here would probably almost }
  634. { always be placed wrong }
  635. if is_con_or_destructor then
  636. begin
  637. CGMessage(cg_w_member_cd_call_from_method);
  638. push_int(0);
  639. end;
  640. end;
  641. end;
  642. { push base pointer ?}
  643. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  644. ((pprocdef(p^.procdefinition)^.parast^.symtablelevel)>normal_function_level) then
  645. begin
  646. { if we call a nested function in a method, we must }
  647. { push also SELF! }
  648. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  649. { access }
  650. {
  651. begin
  652. loadesi:=false;
  653. emit_reg(A_PUSH,S_L,R_ESI);
  654. end;
  655. }
  656. if lexlevel=(pprocdef(p^.procdefinition)^.parast^.symtablelevel) then
  657. begin
  658. new(r);
  659. reset_reference(r^);
  660. r^.offset:=procinfo^.framepointer_offset;
  661. r^.base:=procinfo^.framepointer;
  662. emit_ref(A_PUSH,S_L,r)
  663. end
  664. { this is only true if the difference is one !!
  665. but it cannot be more !! }
  666. else if (lexlevel=pprocdef(p^.procdefinition)^.parast^.symtablelevel-1) then
  667. begin
  668. emit_reg(A_PUSH,S_L,procinfo^.framepointer)
  669. end
  670. else if (lexlevel>pprocdef(p^.procdefinition)^.parast^.symtablelevel) then
  671. begin
  672. hregister:=getregister32;
  673. new(r);
  674. reset_reference(r^);
  675. r^.offset:=procinfo^.framepointer_offset;
  676. r^.base:=procinfo^.framepointer;
  677. emit_ref_reg(A_MOV,S_L,r,hregister);
  678. for i:=(pprocdef(p^.procdefinition)^.parast^.symtablelevel) to lexlevel-1 do
  679. begin
  680. new(r);
  681. reset_reference(r^);
  682. {we should get the correct frame_pointer_offset at each level
  683. how can we do this !!! }
  684. r^.offset:=procinfo^.framepointer_offset;
  685. r^.base:=hregister;
  686. emit_ref_reg(A_MOV,S_L,r,hregister);
  687. end;
  688. emit_reg(A_PUSH,S_L,hregister);
  689. ungetregister32(hregister);
  690. end
  691. else
  692. internalerror(25000);
  693. end;
  694. if (po_virtualmethod in p^.procdefinition^.procoptions) and
  695. not(no_virtual_call) then
  696. begin
  697. { static functions contain the vmt_address in ESI }
  698. { also class methods }
  699. { Here it is quite tricky because it also depends }
  700. { on the methodpointer PM }
  701. if assigned(aktprocsym) then
  702. begin
  703. if (((sp_static in aktprocsym^.symoptions) or
  704. (po_classmethod in aktprocsym^.definition^.procoptions)) and
  705. ((p^.methodpointer=nil) or (p^.methodpointer^.treetype=typen)))
  706. or
  707. (po_staticmethod in p^.procdefinition^.procoptions) or
  708. (p^.procdefinition^.proctypeoption=potype_constructor) or
  709. { ESI is loaded earlier }
  710. (po_classmethod in p^.procdefinition^.procoptions) then
  711. begin
  712. new(r);
  713. reset_reference(r^);
  714. r^.base:=R_ESI;
  715. end
  716. else
  717. begin
  718. new(r);
  719. reset_reference(r^);
  720. r^.base:=R_ESI;
  721. { this is one point where we need vmt_offset (PM) }
  722. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  723. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  724. new(r);
  725. reset_reference(r^);
  726. r^.base:=R_EDI;
  727. end;
  728. end
  729. else
  730. { aktprocsym should be assigned, also in main program }
  731. internalerror(12345);
  732. {
  733. begin
  734. new(r);
  735. reset_reference(r^);
  736. r^.base:=R_ESI;
  737. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  738. new(r);
  739. reset_reference(r^);
  740. r^.base:=R_EDI;
  741. end;
  742. }
  743. if pprocdef(p^.procdefinition)^.extnumber=-1 then
  744. internalerror(44584);
  745. r^.offset:=pprocdef(p^.procdefinition)^._class^.vmtmethodoffset(pprocdef(p^.procdefinition)^.extnumber);
  746. {$ifndef TESTOBJEXT}
  747. if (cs_check_range in aktlocalswitches) then
  748. begin
  749. emit_reg(A_PUSH,S_L,r^.base);
  750. emitcall('FPC_CHECK_OBJECT');
  751. end;
  752. {$else TESTOBJEXT}
  753. if (cs_check_range in aktlocalswitches) then
  754. begin
  755. emit_sym(A_PUSH,S_L,
  756. newasmsymbol(pprocdef(p^.procdefinition)^._class^.vmt_mangledname));
  757. emit_reg(A_PUSH,S_L,r^.base);
  758. emitcall('FPC_CHECK_OBJECT_EXT');
  759. end;
  760. {$endif TESTOBJEXT}
  761. emit_ref(A_CALL,S_NO,r);
  762. end
  763. else if not inlined then
  764. emitcall(pprocdef(p^.procdefinition)^.mangledname)
  765. else { inlined proc }
  766. { inlined code is in inlinecode }
  767. begin
  768. { set poinline again }
  769. {$ifdef INCLUDEOK}
  770. include(p^.procdefinition^.proccalloptions,pocall_inline);
  771. {$else}
  772. p^.procdefinition^.proccalloptions:=p^.procdefinition^.proccalloptions+[pocall_inline];
  773. {$endif}
  774. { process the inlinecode }
  775. secondpass(inlinecode);
  776. { free the args }
  777. ungetpersistanttemp(pprocdef(p^.procdefinition)^.parast^.address_fixup);
  778. end;
  779. end
  780. else
  781. { now procedure variable case }
  782. begin
  783. secondpass(p^.right);
  784. { procedure of object? }
  785. if (po_methodpointer in p^.procdefinition^.procoptions) then
  786. begin
  787. { method pointer can't be in a register }
  788. hregister:=R_NO;
  789. { do some hacking if we call a method pointer }
  790. { which is a class member }
  791. { else ESI is overwritten ! }
  792. if (p^.right^.location.reference.base=R_ESI) or
  793. (p^.right^.location.reference.index=R_ESI) then
  794. begin
  795. del_reference(p^.right^.location.reference);
  796. emit_ref_reg(A_MOV,S_L,
  797. newreference(p^.right^.location.reference),R_EDI);
  798. hregister:=R_EDI;
  799. end;
  800. { load self, but not if it's already explicitly pushed }
  801. if not(po_containsself in p^.procdefinition^.procoptions) then
  802. begin
  803. { load ESI }
  804. inc(p^.right^.location.reference.offset,4);
  805. emit_ref_reg(A_MOV,S_L,
  806. newreference(p^.right^.location.reference),R_ESI);
  807. dec(p^.right^.location.reference.offset,4);
  808. { push self pointer }
  809. emit_reg(A_PUSH,S_L,R_ESI);
  810. end;
  811. if hregister=R_NO then
  812. emit_ref(A_CALL,S_NO,newreference(p^.right^.location.reference))
  813. else
  814. emit_reg(A_CALL,S_NO,hregister);
  815. del_reference(p^.right^.location.reference);
  816. end
  817. else
  818. begin
  819. case p^.right^.location.loc of
  820. LOC_REGISTER,LOC_CREGISTER:
  821. begin
  822. emit_reg(A_CALL,S_NO,p^.right^.location.register);
  823. ungetregister32(p^.right^.location.register);
  824. end
  825. else
  826. emit_ref(A_CALL,S_NO,newreference(p^.right^.location.reference));
  827. del_reference(p^.right^.location.reference);
  828. end;
  829. end;
  830. end;
  831. { this was only for normal functions
  832. displaced here so we also get
  833. it to work for procvars PM }
  834. if (not inlined) and (pocall_clearstack in p^.procdefinition^.proccalloptions) then
  835. begin
  836. { consider the alignment with the rest (PM) }
  837. inc(pushedparasize,pop_size);
  838. pop_size:=0;
  839. { better than an add on all processors }
  840. if pushedparasize=4 then
  841. emit_reg(A_POP,S_L,R_EDI)
  842. { the pentium has two pipes and pop reg is pairable }
  843. { but the registers must be different! }
  844. else if (pushedparasize=8) and
  845. not(cs_littlesize in aktglobalswitches) and
  846. (aktoptprocessor=ClassP5) and
  847. (procinfo^._class=nil) then
  848. begin
  849. emit_reg(A_POP,S_L,R_EDI);
  850. emit_reg(A_POP,S_L,R_ESI);
  851. end
  852. else if pushedparasize<>0 then
  853. emit_const_reg(A_ADD,S_L,pushedparasize,R_ESP);
  854. end;
  855. dont_call:
  856. pushedparasize:=oldpushedparasize;
  857. unused:=unusedregisters;
  858. usablereg32:=usablecount;
  859. {$ifdef TEMPREGDEBUG}
  860. testregisters32;
  861. {$endif TEMPREGDEBUG}
  862. { a constructor could be a function with boolean result }
  863. { if calling constructor called fail we
  864. must jump directly to quickexitlabel PM
  865. but only if it is a call of an inherited constructor }
  866. if (p^.right=nil) and
  867. (p^.procdefinition^.proctypeoption=potype_constructor) and
  868. assigned(p^.methodpointer) and
  869. (p^.methodpointer^.treetype=typen) and
  870. (aktprocsym^.definition^.proctypeoption=potype_constructor) then
  871. begin
  872. emitjmp(C_Z,faillabel);
  873. end;
  874. { handle function results }
  875. { structured results are easy to handle.... }
  876. { needed also when result_no_used !! }
  877. if (p^.resulttype<>pdef(voiddef)) and ret_in_param(p^.resulttype) then
  878. begin
  879. p^.location.loc:=LOC_MEM;
  880. p^.location.reference.symbol:=nil;
  881. p^.location.reference:=funcretref;
  882. end;
  883. { we have only to handle the result if it is used, but }
  884. { ansi/widestrings must be registered, so we can dispose them }
  885. if (p^.resulttype<>pdef(voiddef)) and (p^.return_value_used or
  886. is_ansistring(p^.resulttype) or is_widestring(p^.resulttype)) then
  887. begin
  888. { a contructor could be a function with boolean result }
  889. if (p^.right=nil) and
  890. (p^.procdefinition^.proctypeoption=potype_constructor) and
  891. { quick'n'dirty check if it is a class or an object }
  892. (p^.resulttype^.deftype=orddef) then
  893. begin
  894. { this fails if popsize > 0 PM }
  895. p^.location.loc:=LOC_FLAGS;
  896. p^.location.resflags:=F_NE;
  897. if extended_new then
  898. begin
  899. {$ifdef test_dest_loc}
  900. if dest_loc_known and (dest_loc_tree=p) then
  901. mov_reg_to_dest(p,S_L,R_EAX)
  902. else
  903. {$endif test_dest_loc}
  904. begin
  905. hregister:=getexplicitregister32(R_EAX);
  906. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  907. p^.location.register:=hregister;
  908. end;
  909. end;
  910. end
  911. { structed results are easy to handle.... }
  912. else if ret_in_param(p^.resulttype) then
  913. begin
  914. {p^.location.loc:=LOC_MEM;
  915. stringdispose(p^.location.reference.symbol);
  916. p^.location.reference:=funcretref;
  917. already done above (PM) }
  918. end
  919. else
  920. begin
  921. if (p^.resulttype^.deftype in [orddef,enumdef]) then
  922. begin
  923. p^.location.loc:=LOC_REGISTER;
  924. case p^.resulttype^.size of
  925. 4 :
  926. begin
  927. {$ifdef test_dest_loc}
  928. if dest_loc_known and (dest_loc_tree=p) then
  929. mov_reg_to_dest(p,S_L,R_EAX)
  930. else
  931. {$endif test_dest_loc}
  932. begin
  933. hregister:=getexplicitregister32(R_EAX);
  934. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  935. p^.location.register:=hregister;
  936. end;
  937. end;
  938. 1 :
  939. begin
  940. {$ifdef test_dest_loc}
  941. if dest_loc_known and (dest_loc_tree=p) then
  942. mov_reg_to_dest(p,S_B,R_AL)
  943. else
  944. {$endif test_dest_loc}
  945. begin
  946. hregister:=getexplicitregister32(R_EAX);
  947. emit_reg_reg(A_MOV,S_B,R_AL,reg32toreg8(hregister));
  948. p^.location.register:=reg32toreg8(hregister);
  949. end;
  950. end;
  951. 2 :
  952. begin
  953. {$ifdef test_dest_loc}
  954. if dest_loc_known and (dest_loc_tree=p) then
  955. mov_reg_to_dest(p,S_W,R_AX)
  956. else
  957. {$endif test_dest_loc}
  958. begin
  959. hregister:=getexplicitregister32(R_EAX);
  960. emit_reg_reg(A_MOV,S_W,R_AX,reg32toreg16(hregister));
  961. p^.location.register:=reg32toreg16(hregister);
  962. end;
  963. end;
  964. 8 :
  965. begin
  966. {$ifdef test_dest_loc}
  967. {$error Don't know what to do here}
  968. {$endif test_dest_loc}
  969. hregister:=getexplicitregister32(R_EAX);
  970. hregister2:=getexplicitregister32(R_EDX);
  971. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  972. emit_reg_reg(A_MOV,S_L,R_EDX,hregister2);
  973. p^.location.registerlow:=hregister;
  974. p^.location.registerhigh:=hregister2;
  975. end;
  976. else internalerror(7);
  977. end
  978. end
  979. else if (p^.resulttype^.deftype=floatdef) then
  980. case pfloatdef(p^.resulttype)^.typ of
  981. f32bit:
  982. begin
  983. p^.location.loc:=LOC_REGISTER;
  984. {$ifdef test_dest_loc}
  985. if dest_loc_known and (dest_loc_tree=p) then
  986. mov_reg_to_dest(p,S_L,R_EAX)
  987. else
  988. {$endif test_dest_loc}
  989. begin
  990. hregister:=getexplicitregister32(R_EAX);
  991. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  992. p^.location.register:=hregister;
  993. end;
  994. end;
  995. else
  996. begin
  997. p^.location.loc:=LOC_FPU;
  998. inc(fpuvaroffset);
  999. end;
  1000. end
  1001. else if is_ansistring(p^.resulttype) or
  1002. is_widestring(p^.resulttype) then
  1003. begin
  1004. hregister:=getexplicitregister32(R_EAX);
  1005. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  1006. gettempansistringreference(hr);
  1007. decrstringref(p^.resulttype,hr);
  1008. emit_reg_ref(A_MOV,S_L,hregister,
  1009. newreference(hr));
  1010. ungetregister32(hregister);
  1011. p^.location.loc:=LOC_MEM;
  1012. p^.location.reference:=hr;
  1013. end
  1014. else
  1015. begin
  1016. p^.location.loc:=LOC_REGISTER;
  1017. {$ifdef test_dest_loc}
  1018. if dest_loc_known and (dest_loc_tree=p) then
  1019. mov_reg_to_dest(p,S_L,R_EAX)
  1020. else
  1021. {$endif test_dest_loc}
  1022. begin
  1023. hregister:=getexplicitregister32(R_EAX);
  1024. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  1025. p^.location.register:=hregister;
  1026. end;
  1027. end;
  1028. end;
  1029. end;
  1030. { perhaps i/o check ? }
  1031. if iolabel<>nil then
  1032. begin
  1033. emit_sym(A_PUSH,S_L,iolabel);
  1034. emitcall('FPC_IOCHECK');
  1035. end;
  1036. if pop_size>0 then
  1037. emit_const_reg(A_ADD,S_L,pop_size,R_ESP);
  1038. { restore registers }
  1039. popusedregisters(pushed);
  1040. { at last, restore instance pointer (SELF) }
  1041. if loadesi then
  1042. maybe_loadesi;
  1043. pp:=params;
  1044. while assigned(pp) do
  1045. begin
  1046. if assigned(pp^.left) then
  1047. begin
  1048. if (pp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM]) then
  1049. ungetiftemp(pp^.left^.location.reference);
  1050. { process also all nodes of an array of const }
  1051. if pp^.left^.treetype=arrayconstructn then
  1052. begin
  1053. if assigned(pp^.left^.left) then
  1054. begin
  1055. hp:=pp^.left;
  1056. while assigned(hp) do
  1057. begin
  1058. if (hp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM]) then
  1059. ungetiftemp(hp^.left^.location.reference);
  1060. hp:=hp^.right;
  1061. end;
  1062. end;
  1063. end;
  1064. end;
  1065. pp:=pp^.right;
  1066. end;
  1067. if inlined then
  1068. ungetpersistanttemp(inlinecode^.retoffset);
  1069. disposetree(params);
  1070. { from now on the result can be freed normally }
  1071. if inlined and ret_in_param(p^.resulttype) then
  1072. persistanttemptonormal(funcretref.offset);
  1073. { if return value is not used }
  1074. if (not p^.return_value_used) and (p^.resulttype<>pdef(voiddef)) then
  1075. begin
  1076. if p^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1077. begin
  1078. { data which must be finalized ? }
  1079. if (p^.resulttype^.needs_inittable) and
  1080. ( (p^.resulttype^.deftype<>objectdef) or
  1081. not(pobjectdef(p^.resulttype)^.is_class)) then
  1082. finalize(p^.resulttype,p^.location.reference,ret_in_param(p^.resulttype));
  1083. { release unused temp }
  1084. ungetiftemp(p^.location.reference)
  1085. end
  1086. else if p^.location.loc=LOC_FPU then
  1087. begin
  1088. { release FPU stack }
  1089. emit_reg(A_FSTP,S_NO,R_ST0);
  1090. {
  1091. dec(fpuvaroffset);
  1092. do NOT decrement as the increment before
  1093. is not called for unused results PM }
  1094. end;
  1095. end;
  1096. end;
  1097. {*****************************************************************************
  1098. SecondProcInlineN
  1099. *****************************************************************************}
  1100. procedure secondprocinline(var p : ptree);
  1101. var st : psymtable;
  1102. oldprocsym : pprocsym;
  1103. para_size : longint;
  1104. oldprocinfo : pprocinfo;
  1105. { just dummies for genentrycode }
  1106. nostackframe,make_global : boolean;
  1107. proc_names : tstringcontainer;
  1108. inlineentrycode,inlineexitcode : paasmoutput;
  1109. oldexitlabel,oldexit2label,oldquickexitlabel:Pasmlabel;
  1110. begin
  1111. oldexitlabel:=aktexitlabel;
  1112. oldexit2label:=aktexit2label;
  1113. oldquickexitlabel:=quickexitlabel;
  1114. getlabel(aktexitlabel);
  1115. getlabel(aktexit2label);
  1116. oldprocsym:=aktprocsym;
  1117. oldprocinfo:=procinfo;
  1118. { set the return value }
  1119. aktprocsym:=p^.inlineprocsym;
  1120. procinfo^.retdef:=aktprocsym^.definition^.retdef;
  1121. procinfo^.retoffset:=p^.retoffset;
  1122. { arg space has been filled by the parent secondcall }
  1123. st:=aktprocsym^.definition^.localst;
  1124. { set it to the same lexical level }
  1125. st^.symtablelevel:=oldprocsym^.definition^.localst^.symtablelevel;
  1126. if st^.datasize>0 then
  1127. begin
  1128. st^.address_fixup:=gettempofsizepersistant(st^.datasize);
  1129. {$ifdef extdebug}
  1130. Comment(V_debug,'local symtable is at offset '+tostr(st^.address_fixup));
  1131. exprasmlist^.concat(new(pai_asm_comment,init(strpnew(
  1132. 'local symtable is at offset '+tostr(st^.address_fixup)))));
  1133. {$endif extdebug}
  1134. end;
  1135. {$ifdef extdebug}
  1136. exprasmlist^.concat(new(pai_asm_comment,init('Start of inlined proc')));
  1137. {$endif extdebug}
  1138. { takes care of local data initialization }
  1139. inlineentrycode:=new(paasmoutput,init);
  1140. inlineexitcode:=new(paasmoutput,init);
  1141. proc_names.init;
  1142. para_size:=p^.para_size;
  1143. make_global:=false; { to avoid warning }
  1144. genentrycode(inlineentrycode,proc_names,make_global,0,para_size,nostackframe,true);
  1145. exprasmlist^.concatlist(inlineentrycode);
  1146. secondpass(p^.inlinetree);
  1147. genexitcode(inlineexitcode,0,false,true);
  1148. exprasmlist^.concatlist(inlineexitcode);
  1149. {$ifdef extdebug}
  1150. exprasmlist^.concat(new(pai_asm_comment,init('End of inlined proc')));
  1151. {$endif extdebug}
  1152. {we can free the local data now, reset also the fixup address }
  1153. if st^.datasize>0 then
  1154. begin
  1155. ungetpersistanttemp(st^.address_fixup);
  1156. st^.address_fixup:=0;
  1157. end;
  1158. aktprocsym:=oldprocsym;
  1159. freelabel(aktexitlabel);
  1160. freelabel(aktexit2label);
  1161. aktexitlabel:=oldexitlabel;
  1162. aktexit2label:=oldexit2label;
  1163. quickexitlabel:=oldquickexitlabel;
  1164. procinfo:=oldprocinfo;
  1165. end;
  1166. end.
  1167. {
  1168. $Log$
  1169. Revision 1.110 1999-11-06 14:34:17 peter
  1170. * truncated log to 20 revs
  1171. Revision 1.109 1999/11/04 00:23:58 pierre
  1172. * fix for fpuvaroffset for unused return value
  1173. Revision 1.108 1999/10/26 12:30:40 peter
  1174. * const parameter is now checked
  1175. * better and generic check if a node can be used for assigning
  1176. * export fixes
  1177. * procvar equal works now (it never had worked at least from 0.99.8)
  1178. * defcoll changed to linkedlist with pparaitem so it can easily be
  1179. walked both directions
  1180. Revision 1.107 1999/10/08 15:40:47 pierre
  1181. * use and remember that C functions with complex data results use ret $4
  1182. Revision 1.106 1999/09/27 23:44:46 peter
  1183. * procinfo is now a pointer
  1184. * support for result setting in sub procedure
  1185. Revision 1.105 1999/09/26 13:26:02 florian
  1186. * exception patch of Romio nevertheless the excpetion handling
  1187. needs some corections regarding register saving
  1188. * gettempansistring is again a procedure
  1189. Revision 1.104 1999/09/16 11:34:46 pierre
  1190. * typo correction
  1191. Revision 1.103 1999/09/07 07:54:23 peter
  1192. * small array push to open array fixed, open array always needs addr
  1193. pushing
  1194. Revision 1.102 1999/08/25 11:59:39 jonas
  1195. * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
  1196. Revision 1.101 1999/08/23 23:38:18 pierre
  1197. + TEMPREGDEBUG code added
  1198. Revision 1.100 1999/08/19 13:08:45 pierre
  1199. * emit_??? used
  1200. Revision 1.99 1999/08/09 22:19:47 peter
  1201. * classes vmt changed to only positive addresses
  1202. * sharedlib creation is working
  1203. Revision 1.98 1999/08/09 10:37:55 peter
  1204. * fixed pushing of self with methodpointer
  1205. Revision 1.97 1999/08/04 13:45:18 florian
  1206. + floating point register variables !!
  1207. * pairegalloc is now generated for register variables
  1208. Revision 1.96 1999/08/04 00:22:41 florian
  1209. * renamed i386asm and i386base to cpuasm and cpubase
  1210. Revision 1.95 1999/08/03 22:02:34 peter
  1211. * moved bitmask constants to sets
  1212. * some other type/const renamings
  1213. Revision 1.94 1999/07/06 21:48:09 florian
  1214. * a lot bug fixes:
  1215. - po_external isn't any longer necessary for procedure compatibility
  1216. - m_tp_procvar is in -Sd now available
  1217. - error messages of procedure variables improved
  1218. - return values with init./finalization fixed
  1219. - data types with init./finalization aren't any longer allowed in variant
  1220. record
  1221. Revision 1.93 1999/06/22 13:31:24 peter
  1222. * merged
  1223. Revision 1.92 1999/06/16 09:32:45 peter
  1224. * merged
  1225. Revision 1.91 1999/06/14 17:47:47 peter
  1226. * merged
  1227. Revision 1.90.2.3 1999/06/22 13:30:08 peter
  1228. * fixed return with packenum
  1229. }