cg386cal.pas 70 KB

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