cg386cal.pas 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  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 : pdefcoll;
  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. aasm,types,
  32. {$ifdef GDB}
  33. gdb,
  34. {$endif GDB}
  35. hcodegen,temp_gen,pass_2,
  36. {$ifndef OLDASM}
  37. i386base,i386asm,
  38. {$else}
  39. i386,
  40. {$endif}
  41. cgai386,tgeni386,cg386ld;
  42. {*****************************************************************************
  43. SecondCallParaN
  44. *****************************************************************************}
  45. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  46. push_from_left_to_right,inlined,dword_align : boolean;para_offset : longint);
  47. procedure maybe_push_high;
  48. begin
  49. { open array ? }
  50. { defcoll^.data can be nil for read/write }
  51. if assigned(defcoll^.data) and
  52. push_high_param(defcoll^.data) then
  53. begin
  54. if assigned(p^.hightree) then
  55. begin
  56. secondpass(p^.hightree);
  57. { this is a longint anyway ! }
  58. push_value_para(p^.hightree,inlined,para_offset,4);
  59. end
  60. else
  61. internalerror(432645);
  62. end;
  63. end;
  64. var
  65. otlabel,oflabel : plabel;
  66. align : longint;
  67. { temporary variables: }
  68. tempdeftype : tdeftype;
  69. r : preference;
  70. begin
  71. { push from left to right if specified }
  72. if push_from_left_to_right and assigned(p^.right) then
  73. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right,
  74. inlined,dword_align,para_offset);
  75. otlabel:=truelabel;
  76. oflabel:=falselabel;
  77. getlabel(truelabel);
  78. getlabel(falselabel);
  79. secondpass(p^.left);
  80. { filter array constructor with c styled args }
  81. if is_array_constructor(p^.left^.resulttype) and p^.left^.cargs then
  82. begin
  83. { nothing, everything is already pushed }
  84. end
  85. { in codegen.handleread.. defcoll^.data is set to nil }
  86. else if assigned(defcoll^.data) and
  87. (defcoll^.data^.deftype=formaldef) then
  88. begin
  89. { allow @var }
  90. inc(pushedparasize,4);
  91. if p^.left^.treetype=addrn then
  92. begin
  93. { always a register }
  94. if inlined then
  95. begin
  96. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  97. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  98. p^.left^.location.register,r)));
  99. end
  100. else
  101. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.left^.location.register)));
  102. ungetregister32(p^.left^.location.register);
  103. end
  104. else
  105. begin
  106. if not(p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  107. CGMessage(type_e_mismatch)
  108. else
  109. begin
  110. if inlined then
  111. begin
  112. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  113. newreference(p^.left^.location.reference),R_EDI)));
  114. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  115. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  116. end
  117. else
  118. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  119. del_reference(p^.left^.location.reference);
  120. end;
  121. end;
  122. end
  123. { handle call by reference parameter }
  124. else if (defcoll^.paratyp=vs_var) then
  125. begin
  126. if (p^.left^.location.loc<>LOC_REFERENCE) then
  127. CGMessage(cg_e_var_must_be_reference);
  128. maybe_push_high;
  129. inc(pushedparasize,4);
  130. if inlined then
  131. begin
  132. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  133. newreference(p^.left^.location.reference),R_EDI)));
  134. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  135. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  136. end
  137. else
  138. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  139. del_reference(p^.left^.location.reference);
  140. end
  141. else
  142. begin
  143. tempdeftype:=p^.resulttype^.deftype;
  144. if tempdeftype=filedef then
  145. CGMessage(cg_e_file_must_call_by_reference);
  146. if push_addr_param(p^.resulttype) then
  147. begin
  148. maybe_push_high;
  149. inc(pushedparasize,4);
  150. if inlined then
  151. begin
  152. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  153. newreference(p^.left^.location.reference),R_EDI)));
  154. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  155. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  156. R_EDI,r)));
  157. end
  158. else
  159. emitpushreferenceaddr(exprasmlist,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,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. pushed,pushedregs : tpushed;
  186. hr,funcretref : treference;
  187. hregister,hregister2 : tregister;
  188. oldpushedparasize : longint;
  189. { true if ESI must be loaded again after the subroutine }
  190. loadesi : boolean;
  191. { true if a virtual method must be called directly }
  192. no_virtual_call : boolean;
  193. { true if we produce a con- or destrutor in a call }
  194. is_con_or_destructor : boolean;
  195. { true if a constructor is called again }
  196. extended_new : boolean;
  197. { adress returned from an I/O-error }
  198. iolabel : plabel;
  199. { lexlevel count }
  200. i : longint;
  201. { help reference pointer }
  202. r : preference;
  203. hp,
  204. pp,params : ptree;
  205. inlined : boolean;
  206. inlinecode : ptree;
  207. para_offset : longint;
  208. { instruction for alignement correction }
  209. { corr : pai386;}
  210. { we must pop this size also after !! }
  211. { must_pop : boolean; }
  212. pop_size : longint;
  213. oldrl : plinkedlist;
  214. label
  215. dont_call;
  216. begin
  217. reset_reference(p^.location.reference);
  218. extended_new:=false;
  219. iolabel:=nil;
  220. inlinecode:=nil;
  221. inlined:=false;
  222. loadesi:=true;
  223. no_virtual_call:=false;
  224. unusedregisters:=unused;
  225. { save old ansi string release list }
  226. oldrl:=temptoremove;
  227. temptoremove:=new(plinkedlist,init);
  228. if not assigned(p^.procdefinition) then
  229. exit;
  230. if (p^.procdefinition^.options and poinline)<>0 then
  231. begin
  232. inlined:=true;
  233. inlinecode:=p^.right;
  234. { set it to the same lexical level as the local symtable, becuase
  235. the para's are stored there }
  236. p^.procdefinition^.parast^.symtablelevel:=aktprocsym^.definition^.localst^.symtablelevel;
  237. if assigned(p^.left) then
  238. inlinecode^.para_offset:=gettempofsizepersistant(inlinecode^.para_size);
  239. p^.procdefinition^.parast^.address_fixup:=inlinecode^.para_offset;
  240. {$ifdef extdebug}
  241. Comment(V_debug,
  242. 'inlined parasymtable is at offset '
  243. +tostr(p^.procdefinition^.parast^.address_fixup));
  244. exprasmlist^.concat(new(pai_asm_comment,init(
  245. strpnew('inlined parasymtable is at offset '
  246. +tostr(p^.procdefinition^.parast^.address_fixup)))));
  247. {$endif extdebug}
  248. p^.right:=nil;
  249. { disable further inlining of the same proc
  250. in the args }
  251. p^.procdefinition^.options:=p^.procdefinition^.options and (not poinline);
  252. end;
  253. { only if no proc var }
  254. if not(assigned(p^.right)) then
  255. is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
  256. or ((p^.procdefinition^.options and podestructor)<>0);
  257. { proc variables destroy all registers }
  258. if (p^.right=nil) and
  259. { virtual methods too }
  260. ((p^.procdefinition^.options and povirtualmethod)=0) then
  261. begin
  262. if ((p^.procdefinition^.options and poiocheck)<>0) and
  263. ((aktprocsym^.definition^.options and poiocheck)=0) and
  264. (cs_check_io in aktlocalswitches) then
  265. begin
  266. getlabel(iolabel);
  267. emitlab(iolabel);
  268. end
  269. else
  270. iolabel:=nil;
  271. { save all used registers }
  272. pushusedregisters(pushed,p^.procdefinition^.usedregisters);
  273. { give used registers through }
  274. usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
  275. end
  276. else
  277. begin
  278. pushusedregisters(pushed,$ff);
  279. usedinproc:=$ff;
  280. { no IO check for methods and procedure variables }
  281. iolabel:=nil;
  282. end;
  283. { generate the code for the parameter and push them }
  284. oldpushedparasize:=pushedparasize;
  285. pushedparasize:=0;
  286. pop_size:=0;
  287. if (not inlined) then
  288. begin
  289. { Old pushedsize aligned on 4 ? }
  290. i:=oldpushedparasize and 3;
  291. if i>0 then
  292. inc(pop_size,4-i);
  293. { This parasize aligned on 4 ? }
  294. i:=p^.procdefinition^.para_size and 3;
  295. if i>0 then
  296. inc(pop_size,4-i);
  297. { insert the opcode and update pushedparasize }
  298. if pop_size>0 then
  299. begin
  300. inc(pushedparasize,pop_size);
  301. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,S_L,pop_size,R_ESP)));
  302. {$ifdef GDB}
  303. if (cs_debuginfo in aktmoduleswitches) and
  304. (exprasmlist^.first=exprasmlist^.last) then
  305. exprasmlist^.concat(new(pai_force_line,init));
  306. {$endif GDB}
  307. end;
  308. end;
  309. if (p^.resulttype<>pdef(voiddef)) and
  310. ret_in_param(p^.resulttype) then
  311. begin
  312. funcretref.symbol:=nil;
  313. {$ifdef test_dest_loc}
  314. if dest_loc_known and (dest_loc_tree=p) and
  315. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  316. begin
  317. funcretref:=dest_loc.reference;
  318. if assigned(dest_loc.reference.symbol) then
  319. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  320. in_dest_loc:=true;
  321. end
  322. else
  323. {$endif test_dest_loc}
  324. if inlined then
  325. begin
  326. reset_reference(funcretref);
  327. funcretref.offset:=gettempofsizepersistant(p^.procdefinition^.retdef^.size);
  328. funcretref.base:=procinfo.framepointer;
  329. end
  330. else
  331. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  332. end;
  333. if assigned(p^.left) then
  334. begin
  335. { be found elsewhere }
  336. if inlined then
  337. para_offset:=p^.procdefinition^.parast^.address_fixup+
  338. p^.procdefinition^.parast^.datasize
  339. else
  340. para_offset:=0;
  341. if assigned(p^.right) then
  342. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  343. (p^.procdefinition^.options and poleftright)<>0,
  344. inlined,(p^.procdefinition^.options and (pocdecl or postdcall))<>0,para_offset)
  345. else
  346. secondcallparan(p^.left,p^.procdefinition^.para1,
  347. (p^.procdefinition^.options and poleftright)<>0,
  348. inlined,(p^.procdefinition^.options and (pocdecl or postdcall))<>0,para_offset);
  349. end;
  350. params:=p^.left;
  351. p^.left:=nil;
  352. if inlined then
  353. inlinecode^.retoffset:=gettempofsizepersistant(4);
  354. if ret_in_param(p^.resulttype) then
  355. begin
  356. inc(pushedparasize,4);
  357. if inlined then
  358. begin
  359. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  360. newreference(funcretref),R_EDI)));
  361. r:=new_reference(procinfo.framepointer,inlinecode^.retoffset);
  362. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  363. R_EDI,r)));
  364. end
  365. else
  366. emitpushreferenceaddr(exprasmlist,funcretref);
  367. end;
  368. { procedure variable ? }
  369. if (p^.right=nil) then
  370. begin
  371. { overloaded operator have no symtable }
  372. { push self }
  373. if assigned(p^.symtable) and
  374. (p^.symtable^.symtabletype=withsymtable) then
  375. begin
  376. { dirty trick to avoid the secondcall below }
  377. p^.methodpointer:=genzeronode(callparan);
  378. p^.methodpointer^.location.loc:=LOC_REGISTER;
  379. p^.methodpointer^.location.register:=R_ESI;
  380. { ARGHHH this is wrong !!!
  381. if we can init from base class for a child
  382. class that the wrong VMT will be
  383. transfered to constructor !! }
  384. {$ifdef NODIRECTWITH}
  385. p^.methodpointer^.resulttype:=p^.symtable^.defowner;
  386. {$else NODIRECTWITH}
  387. p^.methodpointer^.resulttype:=
  388. ptree(pwithsymtable(p^.symtable)^.withnode)^.left^.resulttype;
  389. {$endif def NODIRECTWITH}
  390. { change dispose type !! }
  391. p^.disposetyp:=dt_mbleft_and_method;
  392. { make a reference }
  393. new(r);
  394. reset_reference(r^);
  395. {$ifndef NODIRECTWITH}
  396. if assigned(ptree(pwithsymtable(p^.symtable)^.withnode)^.pref) then
  397. begin
  398. r^:=ptree(pwithsymtable(p^.symtable)^.withnode)^.pref^;
  399. {if assigned(r^.symbol) then
  400. r^.symbol:=stringdup(r^.symbol^);}
  401. end
  402. else
  403. {$endif def NODIRECTWITH}
  404. begin
  405. r^.offset:=p^.symtable^.datasize;
  406. r^.base:=procinfo.framepointer;
  407. end;
  408. {$ifndef NODIRECTWITH}
  409. if (not pwithsymtable(p^.symtable)^.direct_with) or
  410. pobjectdef(p^.methodpointer^.resulttype)^.isclass then
  411. {$endif def NODIRECTWITH}
  412. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)))
  413. {$ifndef NODIRECTWITH}
  414. else
  415. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,r,R_ESI)))
  416. {$endif def NODIRECTWITH}
  417. ;
  418. end;
  419. { push self }
  420. if assigned(p^.symtable) and
  421. ((p^.symtable^.symtabletype=objectsymtable) or
  422. (p^.symtable^.symtabletype=withsymtable)) then
  423. begin
  424. if assigned(p^.methodpointer) then
  425. begin
  426. {
  427. if p^.methodpointer^.resulttype=classrefdef then
  428. begin
  429. two possibilities:
  430. 1. constructor
  431. 2. class method
  432. end
  433. else }
  434. begin
  435. case p^.methodpointer^.treetype of
  436. typen:
  437. begin
  438. { direct call to inherited method }
  439. if (p^.procdefinition^.options and poabstractmethod)<>0 then
  440. begin
  441. CGMessage(cg_e_cant_call_abstract_method);
  442. goto dont_call;
  443. end;
  444. { generate no virtual call }
  445. no_virtual_call:=true;
  446. if (p^.symtableprocentry^.properties and sp_static)<>0 then
  447. begin
  448. { well lets put the VMT address directly into ESI }
  449. { it is kind of dirty but that is the simplest }
  450. { way to accept virtual static functions (PM) }
  451. loadesi:=true;
  452. { if no VMT just use $0 bug0214 PM }
  453. if (pobjectdef(p^.methodpointer^.resulttype)^.options and oo_hasvmt)=0 then
  454. exprasmlist^.concat(new(pai386,op_const_reg(A_MOV,S_L,0,R_ESI)))
  455. else
  456. begin
  457. exprasmlist^.concat(new(pai386,op_sym_ofs_reg(A_MOV,S_L,
  458. newasmsymbol(pobjectdef(
  459. p^.methodpointer^.resulttype)^.vmt_mangledname),0,R_ESI)));
  460. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  461. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  462. end;
  463. { exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  464. this is done below !! }
  465. end
  466. else
  467. { this is a member call, so ESI isn't modfied }
  468. loadesi:=false;
  469. { a class destructor needs a flag }
  470. if pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  471. assigned(aktprocsym) and
  472. ((aktprocsym^.definition^.options and
  473. (podestructor))<>0) then
  474. begin
  475. push_int(0);
  476. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  477. end;
  478. if not(is_con_or_destructor and
  479. pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  480. assigned(aktprocsym) and
  481. ((aktprocsym^.definition^.options and
  482. (poconstructor or podestructor))<>0)) then
  483. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  484. { if an inherited con- or destructor should be }
  485. { called in a con- or destructor then a warning }
  486. { will be made }
  487. { con- and destructors need a pointer to the vmt }
  488. if is_con_or_destructor and
  489. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) and
  490. assigned(aktprocsym) then
  491. begin
  492. if not ((aktprocsym^.definition^.options
  493. and (poconstructor or podestructor))<>0) then
  494. CGMessage(cg_w_member_cd_call_from_method);
  495. end;
  496. { class destructors get there flag below }
  497. if is_con_or_destructor and
  498. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  499. assigned(aktprocsym) and
  500. ((aktprocsym^.definition^.options and
  501. (podestructor))<>0)) then
  502. push_int(0);
  503. end;
  504. hnewn:
  505. begin
  506. { extended syntax of new }
  507. { ESI must be zero }
  508. exprasmlist^.concat(new(pai386,op_reg_reg(A_XOR,S_L,R_ESI,R_ESI)));
  509. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  510. { insert the vmt }
  511. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  512. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  513. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  514. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  515. extended_new:=true;
  516. end;
  517. hdisposen:
  518. begin
  519. secondpass(p^.methodpointer);
  520. { destructor with extended syntax called from dispose }
  521. { hdisposen always deliver LOC_REFERENCE }
  522. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  523. newreference(p^.methodpointer^.location.reference),R_ESI)));
  524. del_reference(p^.methodpointer^.location.reference);
  525. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  526. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  527. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  528. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  529. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  530. end;
  531. else
  532. begin
  533. { call to an instance member }
  534. if (p^.symtable^.symtabletype<>withsymtable) then
  535. begin
  536. secondpass(p^.methodpointer);
  537. case p^.methodpointer^.location.loc of
  538. LOC_CREGISTER,
  539. LOC_REGISTER:
  540. begin
  541. emit_reg_reg(A_MOV,S_L,p^.methodpointer^.location.register,R_ESI);
  542. ungetregister32(p^.methodpointer^.location.register);
  543. end;
  544. else
  545. begin
  546. if (p^.methodpointer^.resulttype^.deftype=classrefdef) or
  547. ((p^.methodpointer^.resulttype^.deftype=objectdef) and
  548. pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  549. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  550. newreference(p^.methodpointer^.location.reference),R_ESI)))
  551. else
  552. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  553. newreference(p^.methodpointer^.location.reference),R_ESI)));
  554. del_reference(p^.methodpointer^.location.reference);
  555. end;
  556. end;
  557. end;
  558. { when calling a class method, we have
  559. to load ESI with the VMT !
  560. But that's wrong, if we call a class method via self
  561. }
  562. if ((p^.procdefinition^.options and poclassmethod)<>0)
  563. and not(p^.methodpointer^.resulttype^.deftype=classrefdef) then
  564. begin
  565. { class method needs current VMT }
  566. new(r);
  567. reset_reference(r^);
  568. r^.base:=R_ESI;
  569. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  570. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)));
  571. end;
  572. { direct call to destructor: don't remove data! }
  573. if ((p^.procdefinition^.options and podestructor)<>0) and
  574. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  575. (pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  576. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,1)));
  577. { direct call to class constructor, don't allocate memory }
  578. if ((p^.procdefinition^.options and poconstructor)<>0) and
  579. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  580. (pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  581. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,0)))
  582. else
  583. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  584. if is_con_or_destructor then
  585. begin
  586. { classes don't get a VMT pointer pushed }
  587. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  588. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  589. begin
  590. if ((p^.procdefinition^.options and poconstructor)<>0) then
  591. begin
  592. { it's no bad idea, to insert the VMT }
  593. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,newasmsymbol(
  594. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  595. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  596. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  597. end
  598. { destructors haven't to dispose the instance, if this is }
  599. { a direct call }
  600. else
  601. push_int(0);
  602. end;
  603. end;
  604. end;
  605. end;
  606. end;
  607. end
  608. else
  609. begin
  610. if ((p^.procdefinition^.options and poclassmethod)<>0) and
  611. not(
  612. assigned(aktprocsym) and
  613. ((aktprocsym^.definition^.options and poclassmethod)<>0)
  614. ) then
  615. begin
  616. { class method needs current VMT }
  617. new(r);
  618. reset_reference(r^);
  619. r^.base:=R_ESI;
  620. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  621. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)));
  622. end
  623. else
  624. begin
  625. { member call, ESI isn't modified }
  626. loadesi:=false;
  627. end;
  628. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  629. { but a con- or destructor here would probably almost }
  630. { always be placed wrong }
  631. if is_con_or_destructor then
  632. begin
  633. CGMessage(cg_w_member_cd_call_from_method);
  634. push_int(0);
  635. end;
  636. end;
  637. end;
  638. { push base pointer ?}
  639. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  640. ((p^.procdefinition^.parast^.symtablelevel)>normal_function_level) then
  641. begin
  642. { if we call a nested function in a method, we must }
  643. { push also SELF! }
  644. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  645. { access }
  646. {
  647. begin
  648. loadesi:=false;
  649. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  650. end;
  651. }
  652. if lexlevel=(p^.procdefinition^.parast^.symtablelevel) then
  653. begin
  654. new(r);
  655. reset_reference(r^);
  656. r^.offset:=procinfo.framepointer_offset;
  657. r^.base:=procinfo.framepointer;
  658. exprasmlist^.concat(new(pai386,op_ref(A_PUSH,S_L,r)))
  659. end
  660. { this is only true if the difference is one !!
  661. but it cannot be more !! }
  662. else if (lexlevel=p^.procdefinition^.parast^.symtablelevel-1) then
  663. begin
  664. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,procinfo.framepointer)))
  665. end
  666. else if (lexlevel>p^.procdefinition^.parast^.symtablelevel) then
  667. begin
  668. hregister:=getregister32;
  669. new(r);
  670. reset_reference(r^);
  671. r^.offset:=procinfo.framepointer_offset;
  672. r^.base:=procinfo.framepointer;
  673. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,hregister)));
  674. for i:=(p^.procdefinition^.parast^.symtablelevel) to lexlevel-1 do
  675. begin
  676. new(r);
  677. reset_reference(r^);
  678. {we should get the correct frame_pointer_offset at each level
  679. how can we do this !!! }
  680. r^.offset:=procinfo.framepointer_offset;
  681. r^.base:=hregister;
  682. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,hregister)));
  683. end;
  684. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,hregister)));
  685. ungetregister32(hregister);
  686. end
  687. else
  688. internalerror(25000);
  689. end;
  690. if ((p^.procdefinition^.options and povirtualmethod)<>0) and
  691. not(no_virtual_call) then
  692. begin
  693. { static functions contain the vmt_address in ESI }
  694. { also class methods }
  695. { Here it is quite tricky because it also depends }
  696. { on the methodpointer PM }
  697. if assigned(aktprocsym) then
  698. begin
  699. if ((((aktprocsym^.properties and sp_static)<>0) or
  700. ((aktprocsym^.definition^.options and poclassmethod)<>0)) and
  701. ((p^.methodpointer=nil) or (p^.methodpointer^.treetype=typen)))
  702. or
  703. ((p^.procdefinition^.options and postaticmethod)<>0) or
  704. ((p^.procdefinition^.options and poconstructor)<>0) or
  705. { ESI is loaded earlier }
  706. ((p^.procdefinition^.options and poclassmethod)<>0)then
  707. begin
  708. new(r);
  709. reset_reference(r^);
  710. r^.base:=R_ESI;
  711. end
  712. else
  713. begin
  714. new(r);
  715. reset_reference(r^);
  716. r^.base:=R_ESI;
  717. { this is one point where we need vmt_offset (PM) }
  718. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  719. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  720. new(r);
  721. reset_reference(r^);
  722. r^.base:=R_EDI;
  723. end;
  724. end
  725. else
  726. { aktprocsym should be assigned, also in main program }
  727. internalerror(12345);
  728. {
  729. begin
  730. new(r);
  731. reset_reference(r^);
  732. r^.base:=R_ESI;
  733. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  734. new(r);
  735. reset_reference(r^);
  736. r^.base:=R_EDI;
  737. end;
  738. }
  739. if p^.procdefinition^.extnumber=-1 then
  740. internalerror($Da);
  741. r^.offset:=p^.procdefinition^.extnumber*4+12;
  742. {$ifndef TESTOBJEXT}
  743. if (cs_check_range in aktlocalswitches) then
  744. begin
  745. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,r^.base)));
  746. emitcall('FPC_CHECK_OBJECT',true);
  747. end;
  748. {$else TESTOBJEXT}
  749. if (cs_check_range in aktlocalswitches) then
  750. begin
  751. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  752. newasmsymbol(p^.procdefinition^._class^.vmt_mangledname))));
  753. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,r^.base)));
  754. emitcall('FPC_CHECK_OBJECT_EXT',true);
  755. end;
  756. {$endif TESTOBJEXT}
  757. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,r)));
  758. end
  759. else if not inlined then
  760. emitcall(p^.procdefinition^.mangledname,
  761. (p^.symtableproc^.symtabletype=unitsymtable) or
  762. ((p^.symtableproc^.symtabletype=objectsymtable) and
  763. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable))or
  764. ((p^.symtableproc^.symtabletype=withsymtable) and
  765. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable)))
  766. else { inlined proc }
  767. { inlined code is in inlinecode }
  768. begin
  769. { set poinline again }
  770. p^.procdefinition^.options:=p^.procdefinition^.options or poinline;
  771. { process the inlinecode }
  772. secondpass(inlinecode);
  773. { free the args }
  774. ungetpersistanttemp(p^.procdefinition^.parast^.address_fixup,
  775. p^.procdefinition^.parast^.datasize);
  776. end;
  777. end
  778. else
  779. { now procedure variable case }
  780. begin
  781. secondpass(p^.right);
  782. { method pointer ? }
  783. if (p^.procdefinition^.options and pomethodpointer)<>0 then
  784. begin
  785. { method pointer can't be in a register }
  786. hregister:=R_NO;
  787. { do some hacking if we call a method pointer }
  788. { which is a class member }
  789. { else ESI is overwritten ! }
  790. if (p^.right^.location.reference.base=R_ESI) or
  791. (p^.right^.location.reference.index=R_ESI) then
  792. begin
  793. del_reference(p^.right^.location.reference);
  794. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  795. newreference(p^.right^.location.reference),R_EDI)));
  796. hregister:=R_EDI;
  797. end;
  798. inc(p^.right^.location.reference.offset,4);
  799. { load ESI }
  800. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  801. newreference(p^.right^.location.reference),R_ESI)));
  802. { push self pointer }
  803. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  804. dec(p^.right^.location.reference.offset,4);
  805. if hregister=R_NO then
  806. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,newreference(p^.right^.location.reference))))
  807. else
  808. exprasmlist^.concat(new(pai386,op_reg(A_CALL,S_NO,hregister)));
  809. del_reference(p^.right^.location.reference);
  810. end
  811. else
  812. begin
  813. case p^.right^.location.loc of
  814. LOC_REGISTER,LOC_CREGISTER:
  815. begin
  816. exprasmlist^.concat(new(pai386,op_reg(A_CALL,S_NO,p^.right^.location.register)));
  817. ungetregister32(p^.right^.location.register);
  818. end
  819. else
  820. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,newreference(p^.right^.location.reference))));
  821. del_reference(p^.right^.location.reference);
  822. end;
  823. end;
  824. end;
  825. { this was only for normal functions
  826. displaced here so we also get
  827. it to work for procvars PM }
  828. if (not inlined) and ((p^.procdefinition^.options and poclearstack)<>0) then
  829. begin
  830. { consider the alignment with the rest (PM) }
  831. inc(pushedparasize,pop_size);
  832. pop_size:=0;
  833. { better than an add on all processors }
  834. if pushedparasize=4 then
  835. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDI)))
  836. { the pentium has two pipes and pop reg is pairable }
  837. { but the registers must be different! }
  838. else if (pushedparasize=8) and
  839. not(cs_littlesize in aktglobalswitches) and
  840. (aktoptprocessor=ClassP5) and
  841. (procinfo._class=nil) then
  842. begin
  843. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDI)));
  844. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ESI)));
  845. end
  846. else if pushedparasize<>0 then
  847. exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,pushedparasize,R_ESP)));
  848. end;
  849. dont_call:
  850. pushedparasize:=oldpushedparasize;
  851. unused:=unusedregisters;
  852. { handle function results }
  853. { structured results are easy to handle.... }
  854. { needed also when result_no_used !! }
  855. if (p^.resulttype<>pdef(voiddef)) and ret_in_param(p^.resulttype) then
  856. begin
  857. p^.location.loc:=LOC_MEM;
  858. p^.location.reference.symbol:=nil;
  859. p^.location.reference:=funcretref;
  860. end;
  861. { we have only to handle the result if it is used, but }
  862. { ansi/widestrings must be registered, so we can dispose them }
  863. if (p^.resulttype<>pdef(voiddef)) and (p^.return_value_used or
  864. is_ansistring(p^.resulttype) or is_widestring(p^.resulttype)) then
  865. begin
  866. { a contructor could be a function with boolean result }
  867. if (p^.right=nil) and
  868. ((p^.procdefinition^.options and poconstructor)<>0) and
  869. { quick'n'dirty check if it is a class or an object }
  870. (p^.resulttype^.deftype=orddef) then
  871. begin
  872. p^.location.loc:=LOC_FLAGS;
  873. p^.location.resflags:=F_NE;
  874. if extended_new then
  875. begin
  876. {$ifdef test_dest_loc}
  877. if dest_loc_known and (dest_loc_tree=p) then
  878. mov_reg_to_dest(p,S_L,R_EAX)
  879. else
  880. {$endif test_dest_loc}
  881. begin
  882. hregister:=getexplicitregister32(R_EAX);
  883. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  884. p^.location.register:=hregister;
  885. end;
  886. end;
  887. end
  888. { structed results are easy to handle.... }
  889. else if ret_in_param(p^.resulttype) then
  890. begin
  891. {p^.location.loc:=LOC_MEM;
  892. stringdispose(p^.location.reference.symbol);
  893. p^.location.reference:=funcretref;
  894. already done above (PM) }
  895. end
  896. else
  897. begin
  898. if (p^.resulttype^.deftype=orddef) then
  899. begin
  900. p^.location.loc:=LOC_REGISTER;
  901. case porddef(p^.resulttype)^.typ of
  902. s32bit,u32bit,bool32bit :
  903. begin
  904. {$ifdef test_dest_loc}
  905. if dest_loc_known and (dest_loc_tree=p) then
  906. mov_reg_to_dest(p,S_L,R_EAX)
  907. else
  908. {$endif test_dest_loc}
  909. begin
  910. hregister:=getexplicitregister32(R_EAX);
  911. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  912. p^.location.register:=hregister;
  913. end;
  914. end;
  915. uchar,u8bit,bool8bit,s8bit:
  916. begin
  917. {$ifdef test_dest_loc}
  918. if dest_loc_known and (dest_loc_tree=p) then
  919. mov_reg_to_dest(p,S_B,R_AL)
  920. else
  921. {$endif test_dest_loc}
  922. begin
  923. hregister:=getexplicitregister32(R_EAX);
  924. emit_reg_reg(A_MOV,S_B,R_AL,reg32toreg8(hregister));
  925. p^.location.register:=reg32toreg8(hregister);
  926. end;
  927. end;
  928. s16bit,u16bit,bool16bit :
  929. begin
  930. {$ifdef test_dest_loc}
  931. if dest_loc_known and (dest_loc_tree=p) then
  932. mov_reg_to_dest(p,S_W,R_AX)
  933. else
  934. {$endif test_dest_loc}
  935. begin
  936. hregister:=getexplicitregister32(R_EAX);
  937. emit_reg_reg(A_MOV,S_W,R_AX,reg32toreg16(hregister));
  938. p^.location.register:=reg32toreg16(hregister);
  939. end;
  940. end;
  941. s64bitint,u64bit:
  942. begin
  943. {$ifdef test_dest_loc}
  944. {$error Don't know what to do here}
  945. {$endif test_dest_loc}
  946. hregister:=getexplicitregister32(R_EAX);
  947. hregister2:=getexplicitregister32(R_EDX);
  948. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  949. emit_reg_reg(A_MOV,S_L,R_EDX,hregister2);
  950. p^.location.registerlow:=hregister;
  951. p^.location.registerhigh:=hregister2;
  952. end;
  953. else internalerror(7);
  954. end
  955. end
  956. else if (p^.resulttype^.deftype=floatdef) then
  957. case pfloatdef(p^.resulttype)^.typ of
  958. f32bit:
  959. begin
  960. p^.location.loc:=LOC_REGISTER;
  961. {$ifdef test_dest_loc}
  962. if dest_loc_known and (dest_loc_tree=p) then
  963. mov_reg_to_dest(p,S_L,R_EAX)
  964. else
  965. {$endif test_dest_loc}
  966. begin
  967. hregister:=getexplicitregister32(R_EAX);
  968. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  969. p^.location.register:=hregister;
  970. end;
  971. end;
  972. else
  973. p^.location.loc:=LOC_FPU;
  974. end
  975. else
  976. begin
  977. p^.location.loc:=LOC_REGISTER;
  978. {$ifdef test_dest_loc}
  979. if dest_loc_known and (dest_loc_tree=p) then
  980. mov_reg_to_dest(p,S_L,R_EAX)
  981. else
  982. {$endif test_dest_loc}
  983. begin
  984. hregister:=getexplicitregister32(R_EAX);
  985. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  986. p^.location.register:=hregister;
  987. if is_ansistring(p^.resulttype) or
  988. is_widestring(p^.resulttype) then
  989. begin
  990. gettempansistringreference(hr);
  991. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,p^.location.register,
  992. newreference(hr))));
  993. {$ifdef AnsiStrRef}
  994. ungetregister(hregister);
  995. p^.location.loc:=LOC_REFERENCE;
  996. p^.location.reference:=hr;
  997. {$endif}
  998. { unnessary ansi/wide strings are imm. disposed }
  999. if not(p^.return_value_used) then
  1000. begin
  1001. pushusedregisters(pushedregs,$ff);
  1002. emitpushreferenceaddr(exprasmlist,hr);
  1003. if is_ansistring(p^.resulttype) then
  1004. begin
  1005. exprasmlist^.concat(new(pai386,
  1006. op_sym(A_CALL,S_NO,newasmsymbol('FPC_ANSISTR_DECR_REF'))));
  1007. if not (cs_compilesystem in aktmoduleswitches) then
  1008. concat_external('FPC_ANSISTR_DECR_REF',EXT_NEAR);
  1009. end
  1010. else
  1011. begin
  1012. exprasmlist^.concat(new(pai386,
  1013. op_sym(A_CALL,S_NO,newasmsymbol('FPC_WIDESTR_DECR_REF'))));
  1014. if not (cs_compilesystem in aktmoduleswitches) then
  1015. concat_external('FPC_WIDESTR_DECR_REF',EXT_NEAR);
  1016. end;
  1017. ungetiftemp(hr);
  1018. popusedregisters(pushedregs);
  1019. end
  1020. else
  1021. oldrl^.concat(new(ptemptodestroy,init(hr,p^.resulttype)));
  1022. end;
  1023. end;
  1024. end;
  1025. end;
  1026. end;
  1027. { perhaps i/o check ? }
  1028. if iolabel<>nil then
  1029. begin
  1030. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,newasmsymbol(lab2str(iolabel)))));
  1031. emitcall('FPC_IOCHECK',true);
  1032. end;
  1033. if pop_size>0 then
  1034. exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,pop_size,R_ESP)));
  1035. { release temp. ansi strings }
  1036. removetemps(exprasmlist,temptoremove);
  1037. dispose(temptoremove,done);
  1038. temptoremove:=oldrl;
  1039. { restore registers }
  1040. popusedregisters(pushed);
  1041. { at last, restore instance pointer (SELF) }
  1042. if loadesi then
  1043. maybe_loadesi;
  1044. pp:=params;
  1045. while assigned(pp) do
  1046. begin
  1047. if assigned(pp^.left) then
  1048. begin
  1049. if (pp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM]) and
  1050. ungettempoftype(pp^.left^.resulttype) then
  1051. ungetiftemp(pp^.left^.location.reference);
  1052. { process also all nodes of an array of const }
  1053. if pp^.left^.treetype=arrayconstructn then
  1054. begin
  1055. if assigned(pp^.left^.left) then
  1056. begin
  1057. hp:=pp^.left;
  1058. while assigned(hp) do
  1059. begin
  1060. if (hp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM]) and
  1061. ungettempoftype(hp^.left^.resulttype) then
  1062. ungetiftemp(hp^.left^.location.reference);
  1063. hp:=hp^.right;
  1064. end;
  1065. end;
  1066. end;
  1067. end;
  1068. pp:=pp^.right;
  1069. end;
  1070. if inlined then
  1071. ungetpersistanttemp(inlinecode^.retoffset,4);
  1072. disposetree(params);
  1073. { from now on the result can be freed normally }
  1074. if inlined and ret_in_param(p^.resulttype) then
  1075. persistanttemptonormal(funcretref.offset);
  1076. { if return value is not used }
  1077. if (not p^.return_value_used) and (p^.resulttype<>pdef(voiddef)) then
  1078. begin
  1079. if p^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1080. { release unused temp }
  1081. ungetiftemp(p^.location.reference)
  1082. else if p^.location.loc=LOC_FPU then
  1083. { release FPU stack }
  1084. exprasmlist^.concat(new(pai386,op_reg(A_FSTP,S_NO,R_ST0)));
  1085. end;
  1086. end;
  1087. {*****************************************************************************
  1088. SecondProcInlineN
  1089. *****************************************************************************}
  1090. procedure secondprocinline(var p : ptree);
  1091. var st : psymtable;
  1092. oldprocsym : pprocsym;
  1093. para_size : longint;
  1094. oldprocinfo : tprocinfo;
  1095. { just dummies for genentrycode }
  1096. nostackframe,make_global : boolean;
  1097. proc_names : tstringcontainer;
  1098. inlineentrycode,inlineexitcode : paasmoutput;
  1099. oldexitlabel,oldexit2label,oldquickexitlabel:Plabel;
  1100. begin
  1101. oldexitlabel:=aktexitlabel;
  1102. oldexit2label:=aktexit2label;
  1103. oldquickexitlabel:=quickexitlabel;
  1104. getlabel(aktexitlabel);
  1105. getlabel(aktexit2label);
  1106. oldprocsym:=aktprocsym;
  1107. oldprocinfo:=procinfo;
  1108. { set the return value }
  1109. aktprocsym:=p^.inlineprocsym;
  1110. procinfo.retdef:=aktprocsym^.definition^.retdef;
  1111. procinfo.retoffset:=p^.retoffset;
  1112. { arg space has been filled by the parent secondcall }
  1113. st:=aktprocsym^.definition^.localst;
  1114. { set it to the same lexical level }
  1115. st^.symtablelevel:=oldprocsym^.definition^.localst^.symtablelevel;
  1116. if st^.datasize>0 then
  1117. begin
  1118. st^.address_fixup:=gettempofsizepersistant(st^.datasize);
  1119. {$ifdef extdebug}
  1120. Comment(V_debug,'local symtable is at offset '+tostr(st^.address_fixup));
  1121. exprasmlist^.concat(new(pai_asm_comment,init(strpnew(
  1122. 'local symtable is at offset '+tostr(st^.address_fixup)))));
  1123. {$endif extdebug}
  1124. end;
  1125. {$ifdef extdebug}
  1126. exprasmlist^.concat(new(pai_asm_comment,init('Start of inlined proc')));
  1127. {$endif extdebug}
  1128. { takes care of local data initialization }
  1129. inlineentrycode:=new(paasmoutput,init);
  1130. inlineexitcode:=new(paasmoutput,init);
  1131. proc_names.init;
  1132. para_size:=p^.para_size;
  1133. make_global:=false; { to avoid warning }
  1134. genentrycode(inlineentrycode,proc_names,make_global,0,para_size,nostackframe,true);
  1135. exprasmlist^.concatlist(inlineentrycode);
  1136. secondpass(p^.inlinetree);
  1137. genexitcode(inlineexitcode,0,false,true);
  1138. exprasmlist^.concatlist(inlineexitcode);
  1139. {$ifdef extdebug}
  1140. exprasmlist^.concat(new(pai_asm_comment,init('End of inlined proc')));
  1141. {$endif extdebug}
  1142. {we can free the local data now, reset also the fixup address }
  1143. if st^.datasize>0 then
  1144. begin
  1145. ungetpersistanttemp(st^.address_fixup,st^.datasize);
  1146. st^.address_fixup:=0;
  1147. end;
  1148. aktprocsym:=oldprocsym;
  1149. freelabel(aktexitlabel);
  1150. freelabel(aktexit2label);
  1151. aktexitlabel:=oldexitlabel;
  1152. aktexit2label:=oldexit2label;
  1153. quickexitlabel:=oldquickexitlabel;
  1154. procinfo:=oldprocinfo;
  1155. end;
  1156. end.
  1157. {
  1158. $Log$
  1159. Revision 1.78 1999-05-01 13:24:02 peter
  1160. * merged nasm compiler
  1161. * old asm moved to oldasm/
  1162. Revision 1.77 1999/04/29 22:12:21 pierre
  1163. * fix for ID 388 removing real from stack was wrong
  1164. Revision 1.76 1999/04/25 22:33:19 pierre
  1165. * fix for TESTOBJEXT code
  1166. Revision 1.75 1999/04/19 09:45:46 pierre
  1167. + cdecl or stdcall push all args with longint size
  1168. * tempansi stuff cleaned up
  1169. Revision 1.74 1999/04/16 13:42:23 jonas
  1170. * more regalloc fixes (still not complete)
  1171. Revision 1.73 1999/04/16 10:26:56 pierre
  1172. * no add $0,%esp for cdecl functions without parameters
  1173. Revision 1.72 1999/04/09 08:41:48 peter
  1174. * define to get ansistring returns in ref instead of reg
  1175. Revision 1.71 1999/03/31 13:55:04 peter
  1176. * assembler inlining working for ag386bin
  1177. Revision 1.70 1999/03/24 23:16:46 peter
  1178. * fixed bugs 212,222,225,227,229,231,233
  1179. Revision 1.69 1999/02/25 21:02:21 peter
  1180. * ag386bin updates
  1181. + coff writer
  1182. Revision 1.68 1999/02/22 02:15:04 peter
  1183. * updates for ag386bin
  1184. Revision 1.67 1999/02/11 09:46:21 pierre
  1185. * fix for normal method calls inside static methods :
  1186. WARNING there were both parser and codegen errors !!
  1187. added static_call boolean to calln tree
  1188. Revision 1.66 1999/02/09 15:45:46 florian
  1189. + complex results for assembler functions, fixes bug0155
  1190. Revision 1.65 1999/02/08 11:29:04 pierre
  1191. * fix for bug0214
  1192. several problems where combined
  1193. search_class_member did not set srsymtable
  1194. => in do_member_read the call node got a wrong symtable
  1195. in cg386cal the vmt was pushed twice without chacking if it exists
  1196. now %esi is set to zero and pushed if not vmt
  1197. (not very efficient but should work !)
  1198. Revision 1.64 1999/02/04 10:49:39 florian
  1199. + range checking for ansi- and widestrings
  1200. * made it compilable with TP
  1201. Revision 1.63 1999/02/03 10:18:14 pierre
  1202. * conditionnal code for extended check of virtual methods
  1203. Revision 1.62 1999/02/02 23:52:32 florian
  1204. * problem with calls to method pointers in methods fixed
  1205. - double ansistrings temp management removed
  1206. Revision 1.61 1999/02/02 11:04:36 florian
  1207. * class destructors fixed, class instances weren't disposed correctly
  1208. Revision 1.60 1999/01/28 23:56:44 florian
  1209. * the reference in the result location of a function call wasn't resetted =>
  1210. problem with unallowed far pointer, is solved now
  1211. Revision 1.59 1999/01/27 00:13:52 florian
  1212. * "procedure of object"-stuff fixed
  1213. Revision 1.58 1999/01/21 22:10:35 peter
  1214. * fixed array of const
  1215. * generic platform independent high() support
  1216. Revision 1.57 1999/01/21 16:40:51 pierre
  1217. * fix for constructor inside with statements
  1218. Revision 1.56 1998/12/30 13:41:05 peter
  1219. * released valuepara
  1220. Revision 1.55 1998/12/22 13:10:58 florian
  1221. * memory leaks for ansistring type casts fixed
  1222. Revision 1.54 1998/12/19 00:23:41 florian
  1223. * ansistring memory leaks fixed
  1224. Revision 1.53 1998/12/11 00:02:47 peter
  1225. + globtype,tokens,version unit splitted from globals
  1226. Revision 1.52 1998/12/10 14:39:29 florian
  1227. * bug with p(const a : ansistring) fixed
  1228. * duplicate constant ansistrings were handled wrong, fixed
  1229. Revision 1.51 1998/12/10 09:47:15 florian
  1230. + basic operations with int64/qord (compiler with -dint64)
  1231. + rtti of enumerations extended: names are now written
  1232. Revision 1.50 1998/12/06 13:12:44 florian
  1233. * better code generation for classes which are passed as parameters to
  1234. subroutines
  1235. Revision 1.49 1998/11/30 09:43:00 pierre
  1236. * some range check bugs fixed (still not working !)
  1237. + added DLL writing support for win32 (also accepts variables)
  1238. + TempAnsi for code that could be used for Temporary ansi strings
  1239. handling
  1240. Revision 1.48 1998/11/27 14:50:30 peter
  1241. + open strings, $P switch support
  1242. Revision 1.47 1998/11/26 21:30:03 peter
  1243. * fix for valuepara
  1244. Revision 1.46 1998/11/26 14:39:10 peter
  1245. * ansistring -> pchar fixed
  1246. * ansistring constants fixed
  1247. * ansistring constants are now written once
  1248. Revision 1.45 1998/11/18 15:44:07 peter
  1249. * VALUEPARA for tp7 compatible value parameters
  1250. Revision 1.44 1998/11/16 15:35:36 peter
  1251. * rename laod/copystring -> load/copyshortstring
  1252. * fixed int-bool cnv bug
  1253. + char-ansistring conversion
  1254. Revision 1.43 1998/11/15 16:32:33 florian
  1255. * some stuff of Pavel implement (win32 dll creation)
  1256. * bug with ansistring function results fixed
  1257. Revision 1.42 1998/11/13 15:40:13 pierre
  1258. + added -Se in Makefile cvstest target
  1259. + lexlevel cleanup
  1260. normal_function_level main_program_level and unit_init_level defined
  1261. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1262. (test added in code !)
  1263. * -Un option was wrong
  1264. * _FAIL and _SELF only keyword inside
  1265. constructors and methods respectively
  1266. Revision 1.41 1998/11/12 11:19:40 pierre
  1267. * fix for first line of function break
  1268. Revision 1.40 1998/11/10 10:09:08 peter
  1269. * va_list -> array of const
  1270. Revision 1.39 1998/11/09 11:44:33 peter
  1271. + va_list for printf support
  1272. Revision 1.38 1998/10/21 15:12:49 pierre
  1273. * bug fix for IOCHECK inside a procedure with iocheck modifier
  1274. * removed the GPF for unexistant overloading
  1275. (firstcall was called with procedinition=nil !)
  1276. * changed typen to what Florian proposed
  1277. gentypenode(p : pdef) sets the typenodetype field
  1278. and resulttype is only set if inside bt_type block !
  1279. Revision 1.37 1998/10/21 08:39:57 florian
  1280. + ansistring operator +
  1281. + $h and string[n] for n>255 added
  1282. * small problem with TP fixed
  1283. Revision 1.36 1998/10/20 08:06:39 pierre
  1284. * several memory corruptions due to double freemem solved
  1285. => never use p^.loc.location:=p^.left^.loc.location;
  1286. + finally I added now by default
  1287. that ra386dir translates global and unit symbols
  1288. + added a first field in tsymtable and
  1289. a nextsym field in tsym
  1290. (this allows to obtain ordered type info for
  1291. records and objects in gdb !)
  1292. Revision 1.35 1998/10/16 08:51:45 peter
  1293. + target_os.stackalignment
  1294. + stack can be aligned at 2 or 4 byte boundaries
  1295. Revision 1.34 1998/10/09 08:56:22 pierre
  1296. * several memory leaks fixed
  1297. Revision 1.33 1998/10/06 17:16:39 pierre
  1298. * some memory leaks fixed (thanks to Peter for heaptrc !)
  1299. Revision 1.32 1998/10/01 09:22:52 peter
  1300. * fixed value openarray
  1301. * ungettemp of arrayconstruct
  1302. Revision 1.31 1998/09/28 16:57:15 pierre
  1303. * changed all length(p^.value_str^) into str_length(p)
  1304. to get it work with and without ansistrings
  1305. * changed sourcefiles field of tmodule to a pointer
  1306. Revision 1.30 1998/09/26 15:03:02 florian
  1307. * small problems with DOM and excpetions fixed (code generation
  1308. of raise was wrong and self was sometimes destroyed :()
  1309. Revision 1.29 1998/09/25 00:04:00 florian
  1310. * problems when calling class methods fixed
  1311. Revision 1.28 1998/09/24 14:27:37 peter
  1312. * some better support for openarray
  1313. Revision 1.27 1998/09/24 09:02:13 peter
  1314. * rewritten isconvertable to use case
  1315. * array of .. and single variable are compatible
  1316. Revision 1.26 1998/09/21 08:45:06 pierre
  1317. + added vmt_offset in tobjectdef.write for fututre use
  1318. (first steps to have objects without vmt if no virtual !!)
  1319. + added fpu_used field for tabstractprocdef :
  1320. sets this level to 2 if the functions return with value in FPU
  1321. (is then set to correct value at parsing of implementation)
  1322. THIS MIGHT refuse some code with FPU expression too complex
  1323. that were accepted before and even in some cases
  1324. that don't overflow in fact
  1325. ( like if f : float; is a forward that finally in implementation
  1326. only uses one fpu register !!)
  1327. Nevertheless I think that it will improve security on
  1328. FPU operations !!
  1329. * most other changes only for UseBrowser code
  1330. (added symtable references for record and objects)
  1331. local switch for refs to args and local of each function
  1332. (static symtable still missing)
  1333. UseBrowser still not stable and probably broken by
  1334. the definition hash array !!
  1335. Revision 1.25 1998/09/20 12:26:35 peter
  1336. * merged fixes
  1337. Revision 1.24 1998/09/17 09:42:10 peter
  1338. + pass_2 for cg386
  1339. * Message() -> CGMessage() for pass_1/pass_2
  1340. Revision 1.23 1998/09/14 10:43:45 peter
  1341. * all internal RTL functions start with FPC_
  1342. Revision 1.22.2.1 1998/09/20 12:20:06 peter
  1343. * Fixed stack not on 4 byte boundary when doing a call
  1344. Revision 1.22 1998/09/04 08:41:37 peter
  1345. * updated some error CGMessages
  1346. Revision 1.21 1998/09/01 12:47:57 peter
  1347. * use pdef^.size instead of orddef^.typ
  1348. Revision 1.20 1998/08/31 12:22:15 peter
  1349. * secondinline moved to cg386inl
  1350. Revision 1.19 1998/08/31 08:52:03 peter
  1351. * fixed error 10 with succ() and pref()
  1352. Revision 1.18 1998/08/20 21:36:38 peter
  1353. * fixed 'with object do' bug
  1354. Revision 1.17 1998/08/19 16:07:36 jonas
  1355. * changed optimizer switches + cleanup of DestroyRefs in daopt386.pas
  1356. Revision 1.16 1998/08/18 09:24:36 pierre
  1357. * small warning position bug fixed
  1358. * support_mmx switches splitting was missing
  1359. * rhide error and warning output corrected
  1360. Revision 1.15 1998/08/13 11:00:09 peter
  1361. * fixed procedure<>procedure construct
  1362. Revision 1.14 1998/08/11 14:05:33 peter
  1363. * fixed sizeof(array of char)
  1364. Revision 1.13 1998/08/10 14:49:45 peter
  1365. + localswitches, moduleswitches, globalswitches splitting
  1366. Revision 1.12 1998/07/30 13:30:31 florian
  1367. * final implemenation of exception support, maybe it needs
  1368. some fixes :)
  1369. Revision 1.11 1998/07/24 22:16:52 florian
  1370. * internal error 10 together with array access fixed. I hope
  1371. that's the final fix.
  1372. Revision 1.10 1998/07/18 22:54:23 florian
  1373. * some ansi/wide/longstring support fixed:
  1374. o parameter passing
  1375. o returning as result from functions
  1376. Revision 1.9 1998/07/07 17:40:37 peter
  1377. * packrecords 4 works
  1378. * word aligning of parameters
  1379. Revision 1.8 1998/07/06 15:51:15 michael
  1380. Added length checking for string reading
  1381. Revision 1.7 1998/07/06 14:19:51 michael
  1382. + Added calls for reading/writing ansistrings
  1383. Revision 1.6 1998/07/01 15:28:48 peter
  1384. + better writeln/readln handling, now 100% like tp7
  1385. Revision 1.5 1998/06/25 14:04:17 peter
  1386. + internal inc/dec
  1387. Revision 1.4 1998/06/25 08:48:06 florian
  1388. * first version of rtti support
  1389. Revision 1.3 1998/06/09 16:01:33 pierre
  1390. + added procedure directive parsing for procvars
  1391. (accepted are popstack cdecl and pascal)
  1392. + added C vars with the following syntax
  1393. var C calias 'true_c_name';(can be followed by external)
  1394. reason is that you must add the Cprefix
  1395. which is target dependent
  1396. Revision 1.2 1998/06/08 13:13:29 pierre
  1397. + temporary variables now in temp_gen.pas unit
  1398. because it is processor independent
  1399. * mppc68k.bat modified to undefine i386 and support_mmx
  1400. (which are defaults for i386)
  1401. Revision 1.1 1998/06/05 17:44:10 peter
  1402. * splitted cgi386
  1403. }