cg386cal.pas 70 KB

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