cg386cal.pas 65 KB

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