cg386cal.pas 67 KB

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