cg386cal.pas 68 KB

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