cg386cal.pas 69 KB

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