psub.pas 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
  3. Does the parsing and codegeneration at subroutine level
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit psub;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,globals,
  22. node,nbas,
  23. symdef,procinfo;
  24. type
  25. tcgprocinfo = class(tprocinfo)
  26. private
  27. procedure add_entry_exit_code;
  28. public
  29. { code for the subroutine as tree }
  30. code : tnode;
  31. { positions in the tree for init/final }
  32. entry_asmnode,
  33. loadpara_asmnode,
  34. exitlabel_asmnode,
  35. stackcheck_asmnode,
  36. init_asmnode,
  37. final_asmnode : tasmnode;
  38. { list to store the procinfo's of the nested procedures }
  39. nestedprocs : tlinkedlist;
  40. constructor create(aparent:tprocinfo);override;
  41. destructor destroy;override;
  42. procedure printproc;
  43. procedure generate_code;
  44. procedure resetprocdef;
  45. procedure add_to_symtablestack;
  46. procedure remove_from_symtablestack;
  47. procedure parse_body;
  48. function stack_tainting_parameter : boolean;
  49. end;
  50. procedure printnode_reset;
  51. { reads the declaration blocks }
  52. procedure read_declarations(islibrary : boolean);
  53. { reads declarations in the interface part of a unit }
  54. procedure read_interface_declarations;
  55. procedure generate_specialization_procs;
  56. implementation
  57. uses
  58. { common }
  59. cutils,
  60. { global }
  61. globtype,tokens,verbose,comphook,
  62. systems,
  63. { aasm }
  64. cpubase,aasmbase,aasmtai,
  65. { symtable }
  66. symconst,symbase,symsym,symtype,symtable,defutil,
  67. paramgr,
  68. ppu,fmodule,
  69. { pass 1 }
  70. nutils,nld,ncal,ncon,nflw,nadd,ncnv,nmem,
  71. pass_1,
  72. {$ifdef state_tracking}
  73. nstate,
  74. {$endif state_tracking}
  75. { pass 2 }
  76. {$ifndef NOPASS2}
  77. pass_2,
  78. {$endif}
  79. { parser }
  80. scanner,import,gendef,
  81. pbase,pstatmnt,pdecl,pdecsub,pexports,
  82. { codegen }
  83. tgobj,cgbase,cgobj,dbgbase,
  84. ncgutil,regvars
  85. {$if defined(arm) or defined(powerpc) or defined(powerpc64)}
  86. ,aasmcpu
  87. {$endif arm}
  88. {$ifndef NOOPT}
  89. {$ifdef i386}
  90. ,aopt386
  91. {$else i386}
  92. ,aopt
  93. {$endif i386}
  94. {$endif}
  95. ;
  96. {****************************************************************************
  97. PROCEDURE/FUNCTION BODY PARSING
  98. ****************************************************************************}
  99. procedure initializevars(p:tnamedindexitem;arg:pointer);
  100. var
  101. b : tblocknode;
  102. begin
  103. if not (tsym(p).typ in [localvarsym,globalvarsym]) then
  104. exit;
  105. with tabstractnormalvarsym(p) do
  106. begin
  107. if assigned(defaultconstsym) then
  108. begin
  109. b:=tblocknode(arg);
  110. b.left:=cstatementnode.create(
  111. cassignmentnode.create(
  112. cloadnode.create(tsym(p),tsym(p).owner),
  113. cloadnode.create(defaultconstsym,defaultconstsym.owner)),
  114. b.left);
  115. end;
  116. end;
  117. end;
  118. procedure check_finalize_paras(p : tnamedindexitem;arg:pointer);
  119. begin
  120. if (tsym(p).typ=paravarsym) and
  121. (tparavarsym(p).varspez=vs_value) and
  122. not is_class(tparavarsym(p).vartype.def) and
  123. tparavarsym(p).vartype.def.needs_inittable then
  124. include(current_procinfo.flags,pi_needs_implicit_finally);
  125. end;
  126. procedure check_finalize_locals(p : tnamedindexitem;arg:pointer);
  127. begin
  128. if (tsym(p).typ=localvarsym) and
  129. (tlocalvarsym(p).refs>0) and
  130. not(vo_is_funcret in tlocalvarsym(p).varoptions) and
  131. not(is_class(tlocalvarsym(p).vartype.def)) and
  132. tlocalvarsym(p).vartype.def.needs_inittable then
  133. include(current_procinfo.flags,pi_needs_implicit_finally);
  134. end;
  135. function block(islibrary : boolean) : tnode;
  136. begin
  137. { parse const,types and vars }
  138. read_declarations(islibrary);
  139. { do we have an assembler block without the po_assembler?
  140. we should allow this for Delphi compatibility (PFV) }
  141. if (token=_ASM) and (m_delphi in aktmodeswitches) then
  142. include(current_procinfo.procdef.procoptions,po_assembler);
  143. { Handle assembler block different }
  144. if (po_assembler in current_procinfo.procdef.procoptions) then
  145. begin
  146. block:=assembler_block;
  147. exit;
  148. end;
  149. {Unit initialization?.}
  150. if (
  151. assigned(current_procinfo.procdef.localst) and
  152. (current_procinfo.procdef.localst.symtablelevel=main_program_level) and
  153. (current_module.is_unit)
  154. ) or
  155. islibrary then
  156. begin
  157. if (token=_END) then
  158. begin
  159. consume(_END);
  160. { We need at least a node, else the entry/exit code is not
  161. generated and thus no PASCALMAIN symbol which we need (PFV) }
  162. if islibrary then
  163. block:=cnothingnode.create
  164. else
  165. block:=nil;
  166. end
  167. else
  168. begin
  169. if token=_INITIALIZATION then
  170. begin
  171. { The library init code is already called and does not
  172. need to be in the initfinal table (PFV) }
  173. if not islibrary then
  174. current_module.flags:=current_module.flags or uf_init;
  175. block:=statement_block(_INITIALIZATION);
  176. end
  177. else if (token=_FINALIZATION) then
  178. begin
  179. if (current_module.flags and uf_finalize)<>0 then
  180. block:=statement_block(_FINALIZATION)
  181. else
  182. begin
  183. { can we allow no INITIALIZATION for DLL ??
  184. I think it should work PM }
  185. block:=nil;
  186. exit;
  187. end;
  188. end
  189. else
  190. begin
  191. { The library init code is already called and does not
  192. need to be in the initfinal table (PFV) }
  193. if not islibrary then
  194. current_module.flags:=current_module.flags or uf_init;
  195. block:=statement_block(_BEGIN);
  196. end;
  197. end;
  198. end
  199. else
  200. begin
  201. block:=statement_block(_BEGIN);
  202. if symtablestack.symtabletype=localsymtable then
  203. symtablestack.foreach_static(@initializevars,block);
  204. end;
  205. end;
  206. {****************************************************************************
  207. PROCEDURE/FUNCTION COMPILING
  208. ****************************************************************************}
  209. procedure printnode_reset;
  210. begin
  211. assign(printnodefile,treelogfilename);
  212. {$I-}
  213. rewrite(printnodefile);
  214. {$I+}
  215. if ioresult<>0 then
  216. begin
  217. Comment(V_Error,'Error creating '+treelogfilename);
  218. exit;
  219. end;
  220. close(printnodefile);
  221. end;
  222. function generate_bodyentry_block:tnode;
  223. var
  224. srsym : tsym;
  225. para : tcallparanode;
  226. newstatement : tstatementnode;
  227. htype : ttype;
  228. begin
  229. result:=internalstatements(newstatement);
  230. if assigned(current_procinfo.procdef._class) then
  231. begin
  232. { a constructor needs a help procedure }
  233. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  234. begin
  235. if is_class(current_procinfo.procdef._class) then
  236. begin
  237. include(current_procinfo.flags,pi_needs_implicit_finally);
  238. srsym:=search_class_member(current_procinfo.procdef._class,'NEWINSTANCE');
  239. if assigned(srsym) and
  240. (srsym.typ=procsym) then
  241. begin
  242. { if vmt>1 then newinstance }
  243. addstatement(newstatement,cifnode.create(
  244. caddnode.create(gtn,
  245. ctypeconvnode.create_internal(
  246. load_vmt_pointer_node,
  247. voidpointertype),
  248. cpointerconstnode.create(1,voidpointertype)),
  249. cassignmentnode.create(
  250. ctypeconvnode.create_internal(
  251. load_self_pointer_node,
  252. voidpointertype),
  253. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_vmt_pointer_node,[])),
  254. nil));
  255. end
  256. else
  257. internalerror(200305108);
  258. end
  259. else
  260. if is_object(current_procinfo.procdef._class) then
  261. begin
  262. htype.setdef(current_procinfo.procdef._class);
  263. htype.setdef(tpointerdef.create(htype));
  264. { parameter 3 : vmt_offset }
  265. { parameter 2 : address of pointer to vmt,
  266. this is required to allow setting the vmt to -1 to indicate
  267. that memory was allocated }
  268. { parameter 1 : self pointer }
  269. para:=ccallparanode.create(
  270. cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
  271. ccallparanode.create(
  272. ctypeconvnode.create_internal(
  273. load_vmt_pointer_node,
  274. voidpointertype),
  275. ccallparanode.create(
  276. ctypeconvnode.create_internal(
  277. load_self_pointer_node,
  278. voidpointertype),
  279. nil)));
  280. addstatement(newstatement,cassignmentnode.create(
  281. ctypeconvnode.create_internal(
  282. load_self_pointer_node,
  283. voidpointertype),
  284. ccallnode.createintern('fpc_help_constructor',para)));
  285. end
  286. else
  287. internalerror(200305103);
  288. { if self=nil then exit
  289. calling fail instead of exit is useless because
  290. there is nothing to dispose (PFV) }
  291. addstatement(newstatement,cifnode.create(
  292. caddnode.create(equaln,
  293. load_self_pointer_node,
  294. cnilnode.create),
  295. cexitnode.create(nil),
  296. nil));
  297. end;
  298. { maybe call BeforeDestruction for classes }
  299. if (current_procinfo.procdef.proctypeoption=potype_destructor) and
  300. is_class(current_procinfo.procdef._class) then
  301. begin
  302. srsym:=search_class_member(current_procinfo.procdef._class,'BEFOREDESTRUCTION');
  303. if assigned(srsym) and
  304. (srsym.typ=procsym) then
  305. begin
  306. { if vmt<>0 then beforedestruction }
  307. addstatement(newstatement,cifnode.create(
  308. caddnode.create(unequaln,
  309. load_vmt_pointer_node,
  310. cnilnode.create),
  311. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  312. nil));
  313. end
  314. else
  315. internalerror(200305104);
  316. end;
  317. end;
  318. end;
  319. function generate_bodyexit_block:tnode;
  320. var
  321. srsym : tsym;
  322. para : tcallparanode;
  323. newstatement : tstatementnode;
  324. begin
  325. result:=internalstatements(newstatement);
  326. if assigned(current_procinfo.procdef._class) then
  327. begin
  328. { maybe call AfterConstruction for classes }
  329. if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  330. is_class(current_procinfo.procdef._class) then
  331. begin
  332. srsym:=search_class_member(current_procinfo.procdef._class,'AFTERCONSTRUCTION');
  333. if assigned(srsym) and
  334. (srsym.typ=procsym) then
  335. begin
  336. { Self can be nil when fail is called }
  337. { if self<>nil and vmt<>nil then afterconstruction }
  338. addstatement(newstatement,cifnode.create(
  339. caddnode.create(andn,
  340. caddnode.create(unequaln,
  341. load_self_pointer_node,
  342. cnilnode.create),
  343. caddnode.create(unequaln,
  344. load_vmt_pointer_node,
  345. cnilnode.create)),
  346. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  347. nil));
  348. end
  349. else
  350. internalerror(200305106);
  351. end;
  352. { a destructor needs a help procedure }
  353. if (current_procinfo.procdef.proctypeoption=potype_destructor) then
  354. begin
  355. if is_class(current_procinfo.procdef._class) then
  356. begin
  357. srsym:=search_class_member(current_procinfo.procdef._class,'FREEINSTANCE');
  358. if assigned(srsym) and
  359. (srsym.typ=procsym) then
  360. begin
  361. { if self<>0 and vmt=1 then freeinstance }
  362. addstatement(newstatement,cifnode.create(
  363. caddnode.create(andn,
  364. caddnode.create(unequaln,
  365. load_self_pointer_node,
  366. cnilnode.create),
  367. caddnode.create(equaln,
  368. ctypeconvnode.create(
  369. load_vmt_pointer_node,
  370. voidpointertype),
  371. cpointerconstnode.create(1,voidpointertype))),
  372. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  373. nil));
  374. end
  375. else
  376. internalerror(200305108);
  377. end
  378. else
  379. if is_object(current_procinfo.procdef._class) then
  380. begin
  381. { finalize object data }
  382. if current_procinfo.procdef._class.needs_inittable then
  383. addstatement(newstatement,finalize_data_node(load_self_node));
  384. { parameter 3 : vmt_offset }
  385. { parameter 2 : pointer to vmt }
  386. { parameter 1 : self pointer }
  387. para:=ccallparanode.create(
  388. cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
  389. ccallparanode.create(
  390. ctypeconvnode.create_internal(
  391. load_vmt_pointer_node,
  392. voidpointertype),
  393. ccallparanode.create(
  394. ctypeconvnode.create_internal(
  395. load_self_pointer_node,
  396. voidpointertype),
  397. nil)));
  398. addstatement(newstatement,
  399. ccallnode.createintern('fpc_help_destructor',para));
  400. end
  401. else
  402. internalerror(200305105);
  403. end;
  404. end;
  405. end;
  406. function generate_except_block:tnode;
  407. var
  408. pd : tprocdef;
  409. newstatement : tstatementnode;
  410. begin
  411. generate_except_block:=internalstatements(newstatement);
  412. { a constructor needs call destructor (if available) when it
  413. is not inherited }
  414. if assigned(current_procinfo.procdef._class) and
  415. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  416. begin
  417. pd:=current_procinfo.procdef._class.searchdestructor;
  418. if assigned(pd) then
  419. begin
  420. { if vmt<>0 then call destructor }
  421. addstatement(newstatement,cifnode.create(
  422. caddnode.create(unequaln,
  423. load_vmt_pointer_node,
  424. cnilnode.create),
  425. ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[]),
  426. nil));
  427. end;
  428. end
  429. else
  430. begin
  431. { no constructor }
  432. { must be the return value finalized before reraising the exception? }
  433. if (not is_void(current_procinfo.procdef.rettype.def)) and
  434. (current_procinfo.procdef.rettype.def.needs_inittable) and
  435. (not is_class(current_procinfo.procdef.rettype.def)) then
  436. addstatement(newstatement,finalize_data_node(load_result_node));
  437. end;
  438. end;
  439. {****************************************************************************
  440. TCGProcInfo
  441. ****************************************************************************}
  442. constructor tcgprocinfo.create(aparent:tprocinfo);
  443. begin
  444. inherited Create(aparent);
  445. nestedprocs:=tlinkedlist.create;
  446. end;
  447. destructor tcgprocinfo.destroy;
  448. begin
  449. nestedprocs.free;
  450. if assigned(code) then
  451. code.free;
  452. inherited destroy;
  453. end;
  454. procedure tcgprocinfo.printproc;
  455. begin
  456. assign(printnodefile,treelogfilename);
  457. {$I-}
  458. append(printnodefile);
  459. if ioresult<>0 then
  460. rewrite(printnodefile);
  461. {$I+}
  462. if ioresult<>0 then
  463. begin
  464. Comment(V_Error,'Error creating '+treelogfilename);
  465. exit;
  466. end;
  467. writeln(printnodefile);
  468. writeln(printnodefile,'*******************************************************************************');
  469. writeln(printnodefile,procdef.fullprocname(false));
  470. writeln(printnodefile,'*******************************************************************************');
  471. printnode(printnodefile,code);
  472. close(printnodefile);
  473. end;
  474. procedure tcgprocinfo.add_entry_exit_code;
  475. var
  476. finalcode,
  477. bodyentrycode,
  478. bodyexitcode,
  479. exceptcode : tnode;
  480. newblock : tblocknode;
  481. codestatement,
  482. newstatement : tstatementnode;
  483. oldfilepos : tfileposinfo;
  484. begin
  485. oldfilepos:=aktfilepos;
  486. { Generate code/locations used at start of proc }
  487. aktfilepos:=entrypos;
  488. entry_asmnode:=casmnode.create_get_position;
  489. loadpara_asmnode:=casmnode.create_get_position;
  490. stackcheck_asmnode:=casmnode.create_get_position;
  491. init_asmnode:=casmnode.create_get_position;
  492. bodyentrycode:=generate_bodyentry_block;
  493. { Generate code/locations used at end of proc }
  494. aktfilepos:=exitpos;
  495. exitlabel_asmnode:=casmnode.create_get_position;
  496. final_asmnode:=casmnode.create_get_position;
  497. bodyexitcode:=generate_bodyexit_block;
  498. { Generate procedure by combining init+body+final,
  499. depending on the implicit finally we need to add
  500. an try...finally...end wrapper }
  501. newblock:=internalstatements(newstatement);
  502. if (cs_implicit_exceptions in aktmoduleswitches) and
  503. (pi_needs_implicit_finally in flags) and
  504. { but it's useless in init/final code of units }
  505. not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  506. begin
  507. { Generate special exception block only needed when
  508. implicit finaly is used }
  509. aktfilepos:=exitpos;
  510. exceptcode:=generate_except_block;
  511. { Generate code that will be in the try...finally }
  512. finalcode:=internalstatements(codestatement);
  513. addstatement(codestatement,bodyexitcode);
  514. addstatement(codestatement,final_asmnode);
  515. { Initialize before try...finally...end frame }
  516. addstatement(newstatement,loadpara_asmnode);
  517. addstatement(newstatement,stackcheck_asmnode);
  518. addstatement(newstatement,entry_asmnode);
  519. addstatement(newstatement,init_asmnode);
  520. addstatement(newstatement,bodyentrycode);
  521. aktfilepos:=entrypos;
  522. addstatement(newstatement,ctryfinallynode.create_implicit(
  523. code,
  524. finalcode,
  525. exceptcode));
  526. addstatement(newstatement,exitlabel_asmnode);
  527. { set flag the implicit finally has been generated }
  528. include(flags,pi_has_implicit_finally);
  529. end
  530. else
  531. begin
  532. addstatement(newstatement,loadpara_asmnode);
  533. addstatement(newstatement,stackcheck_asmnode);
  534. addstatement(newstatement,entry_asmnode);
  535. addstatement(newstatement,init_asmnode);
  536. addstatement(newstatement,bodyentrycode);
  537. addstatement(newstatement,code);
  538. addstatement(newstatement,exitlabel_asmnode);
  539. addstatement(newstatement,bodyexitcode);
  540. addstatement(newstatement,final_asmnode);
  541. end;
  542. do_firstpass(newblock);
  543. code:=newblock;
  544. aktfilepos:=oldfilepos;
  545. end;
  546. procedure clearrefs(p : tnamedindexitem;arg:pointer);
  547. begin
  548. if (tsym(p).typ in [localvarsym,paravarsym,globalvarsym]) then
  549. if tabstractvarsym(p).refs>1 then
  550. tabstractvarsym(p).refs:=1;
  551. end;
  552. procedure check_for_stack(p : tnamedindexitem;arg:pointer);
  553. begin
  554. if tsym(p).typ=paravarsym then
  555. begin
  556. { check if there no parameter of the current procedure is stack dependend }
  557. if is_open_array(tparavarsym(p).vartype.def) or
  558. is_array_of_const(tparavarsym(p).vartype.def) then
  559. pboolean(arg)^:=true;
  560. if assigned(p) and
  561. assigned(tparavarsym(p).paraloc[calleeside].location) and
  562. (tparavarsym(p).paraloc[calleeside].location^.loc=LOC_REFERENCE) then
  563. pboolean(arg)^:=true;
  564. end;
  565. end;
  566. function tcgprocinfo.stack_tainting_parameter : boolean;
  567. begin
  568. result:=false;
  569. procdef.parast.foreach_static(@check_for_stack,@result);
  570. end;
  571. procedure tcgprocinfo.generate_code;
  572. var
  573. oldprocinfo : tprocinfo;
  574. oldaktmaxfpuregisters : longint;
  575. oldfilepos : tfileposinfo;
  576. templist : Taasmoutput;
  577. headertai : tai;
  578. begin
  579. { the initialization procedure can be empty, then we
  580. don't need to generate anything. When it was an empty
  581. procedure there would be at least a blocknode }
  582. if not assigned(code) then
  583. exit;
  584. { We need valid code }
  585. if Errorcount<>0 then
  586. exit;
  587. { No code can be generated for generic template }
  588. if (df_generic in procdef.defoptions) then
  589. internalerror(200511152);
  590. { The RA and Tempgen shall not be available yet }
  591. if assigned(tg) then
  592. internalerror(200309201);
  593. oldprocinfo:=current_procinfo;
  594. oldfilepos:=aktfilepos;
  595. oldaktmaxfpuregisters:=aktmaxfpuregisters;
  596. current_procinfo:=self;
  597. aktfilepos:=entrypos;
  598. { get new labels }
  599. aktbreaklabel:=nil;
  600. aktcontinuelabel:=nil;
  601. templist:=Taasmoutput.create;
  602. { add parast/localst to symtablestack }
  603. add_to_symtablestack;
  604. { when size optimization only count occurrence }
  605. if cs_littlesize in aktglobalswitches then
  606. cg.t_times:=1
  607. else
  608. { reference for repetition is 100 }
  609. cg.t_times:=100;
  610. { clear register count }
  611. symtablestack.foreach_static(@clearrefs,nil);
  612. symtablestack.next.foreach_static(@clearrefs,nil);
  613. { there's always a call to FPC_INITIALIZEUNITS/FPC_DO_EXIT in the main program }
  614. if (procdef.localst.symtablelevel=main_program_level) and
  615. (not current_module.is_unit) then
  616. include(flags,pi_do_call);
  617. { set implicit_finally flag when there are locals/paras to be finalized }
  618. current_procinfo.procdef.parast.foreach_static(@check_finalize_paras,nil);
  619. current_procinfo.procdef.localst.foreach_static(@check_finalize_locals,nil);
  620. { firstpass everything }
  621. flowcontrol:=[];
  622. do_firstpass(code);
  623. if code.registersfpu>0 then
  624. include(current_procinfo.flags,pi_uses_fpu);
  625. { add implicit entry and exit code }
  626. add_entry_exit_code;
  627. { only do secondpass if there are no errors }
  628. if (ErrorCount=0) then
  629. begin
  630. { set the start offset to the start of the temp area in the stack }
  631. tg:=ttgobj.create;
  632. {$ifdef i386}
  633. { try to strip the stack frame }
  634. { set the framepointer to esp if:
  635. - no assembler directive, those are handled elsewhere
  636. - no exceptions are used
  637. - no debug info
  638. - no pushes are used/esp modifications, could be:
  639. * outgoing parameters on the stack
  640. * incoming parameters on the stack
  641. * open arrays
  642. - no inline assembler
  643. }
  644. if (cs_optimize in aktglobalswitches) and
  645. not(po_assembler in procdef.procoptions) and
  646. ((flags*[pi_has_assembler_block,pi_uses_exceptions,pi_is_assembler,
  647. pi_needs_implicit_finally,pi_has_implicit_finally,pi_has_stackparameter])=[]) then
  648. begin
  649. { we need the parameter info here to determine if the procedure gets
  650. parameters on the stack
  651. calling generate_parameter_info doesn't hurt but it costs time
  652. }
  653. generate_parameter_info;
  654. if not(stack_tainting_parameter) then
  655. begin
  656. { Only need to set the framepointer }
  657. framepointer:=NR_STACK_POINTER_REG;
  658. tg.direction:=1;
  659. end;
  660. end;
  661. {$endif i386}
  662. { Create register allocator }
  663. cg.init_register_allocators;
  664. set_first_temp_offset;
  665. generate_parameter_info;
  666. { Allocate space in temp/registers for parast and localst }
  667. aktfilepos:=entrypos;
  668. gen_alloc_symtable(aktproccode,procdef.parast);
  669. gen_alloc_symtable(aktproccode,procdef.localst);
  670. { Store temp offset for information about 'real' temps }
  671. tempstart:=tg.lasttemp;
  672. { Generate code to load register parameters in temps and insert local
  673. copies for values parameters. This must be done before the code for the
  674. body is generated because the localloc is updated.
  675. Note: The generated code will be inserted after the code generation of
  676. the body is finished, because only then the position is known }
  677. {$ifdef oldregvars}
  678. assign_regvars(code);
  679. {$endif oldreg}
  680. aktfilepos:=entrypos;
  681. gen_load_para_value(templist);
  682. { caller paraloc info is also necessary in the stackframe_entry
  683. code of the ppc (and possibly other processors) }
  684. if not procdef.has_paraloc_info then
  685. begin
  686. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  687. procdef.has_paraloc_info:=true;
  688. end;
  689. { generate code for the node tree }
  690. do_secondpass(code);
  691. aktproccode.concatlist(exprasmlist);
  692. {$ifdef i386}
  693. procdef.fpu_used:=code.registersfpu;
  694. {$endif i386}
  695. { The position of the loadpara_asmnode is now known }
  696. aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist);
  697. { first generate entry and initialize code with the correct
  698. position and switches }
  699. aktfilepos:=entrypos;
  700. aktlocalswitches:=entryswitches;
  701. gen_entry_code(templist);
  702. aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
  703. gen_initialize_code(templist);
  704. aktproccode.insertlistafter(init_asmnode.currenttai,templist);
  705. { now generate finalize and exit code with the correct position
  706. and switches }
  707. aktfilepos:=exitpos;
  708. aktlocalswitches:=exitswitches;
  709. gen_finalize_code(templist);
  710. { the finalcode must be concated if there was no position available,
  711. using insertlistafter will result in an insert at the start
  712. when currentai=nil }
  713. if assigned(final_asmnode.currenttai) then
  714. aktproccode.insertlistafter(final_asmnode.currenttai,templist)
  715. else
  716. aktproccode.concatlist(templist);
  717. { insert exit label at the correct position }
  718. cg.a_label(templist,aktexitlabel);
  719. if assigned(exitlabel_asmnode.currenttai) then
  720. aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist)
  721. else
  722. aktproccode.concatlist(templist);
  723. { exit code }
  724. gen_exit_code(templist);
  725. aktproccode.concatlist(templist);
  726. {$ifdef OLDREGVARS}
  727. { note: this must be done only after as much code as possible has }
  728. { been generated. The result is that when you ungetregister() a }
  729. { regvar, it will actually free the regvar (and alse free the }
  730. { the regvars at the same time). Doing this too early will }
  731. { confuse the register allocator, as the regvars will still be }
  732. { used. It should be done before loading the result regs (so }
  733. { they don't conflict with the regvars) and before }
  734. { gen_entry_code (that one has to be able to allocate the }
  735. { regvars again) (JM) }
  736. free_regvars(aktproccode);
  737. {$endif OLDREGVARS}
  738. { generate symbol and save end of header position }
  739. aktfilepos:=entrypos;
  740. gen_proc_symbol(templist);
  741. headertai:=tai(templist.last);
  742. { insert symbol }
  743. aktproccode.insertlist(templist);
  744. { Free space in temp/registers for parast and localst, must be
  745. done after gen_entry_code }
  746. aktfilepos:=exitpos;
  747. gen_free_symtable(aktproccode,procdef.localst);
  748. gen_free_symtable(aktproccode,procdef.parast);
  749. { add code that will load the return value, this is not done
  750. for assembler routines when they didn't reference the result
  751. variable }
  752. gen_load_return_value(templist);
  753. aktproccode.concatlist(templist);
  754. { Already reserve all registers for stack checking code and
  755. generate the call to the helper function }
  756. if (cs_check_stack in entryswitches) and
  757. not(po_assembler in procdef.procoptions) and
  758. (current_procinfo.procdef.proctypeoption<>potype_proginit) then
  759. begin
  760. aktfilepos:=entrypos;
  761. gen_stack_check_call(templist);
  762. aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
  763. end;
  764. { load got if necessary }
  765. aktfilepos:=entrypos;
  766. gen_got_load(templist);
  767. aktproccode.insertlistafter(headertai,templist);
  768. { The procedure body is finished, we can now
  769. allocate the registers }
  770. cg.do_register_allocation(aktproccode,headertai);
  771. { Add save and restore of used registers }
  772. aktfilepos:=entrypos;
  773. gen_save_used_regs(templist);
  774. aktproccode.insertlistafter(headertai,templist);
  775. aktfilepos:=exitpos;
  776. gen_restore_used_regs(aktproccode);
  777. { We know the size of the stack, now we can generate the
  778. parameter that is passed to the stack checking code }
  779. if (cs_check_stack in entryswitches) and
  780. not(po_assembler in procdef.procoptions) and
  781. (current_procinfo.procdef.proctypeoption<>potype_proginit) then
  782. begin
  783. aktfilepos:=entrypos;
  784. gen_stack_check_size_para(templist);
  785. aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
  786. end;
  787. { Add entry code (stack allocation) after header }
  788. aktfilepos:=entrypos;
  789. gen_proc_entry_code(templist);
  790. aktproccode.insertlistafter(headertai,templist);
  791. { Add exit code at the end }
  792. aktfilepos:=exitpos;
  793. gen_proc_exit_code(templist);
  794. aktproccode.concatlist(templist);
  795. { check if the implicit finally has been generated. The flag
  796. should already be set in pass1 }
  797. if (cs_implicit_exceptions in aktmoduleswitches) and
  798. not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and
  799. (pi_needs_implicit_finally in flags) and
  800. not(pi_has_implicit_finally in flags) then
  801. internalerror(200405231);
  802. {$ifndef NoOpt}
  803. if not(cs_no_regalloc in aktglobalswitches) then
  804. begin
  805. if (cs_optimize in aktglobalswitches) and
  806. { do not optimize pure assembler procedures }
  807. not(pi_is_assembler in flags) then
  808. optimize(aktproccode);
  809. end;
  810. {$endif NoOpt}
  811. { Add end symbol and debug info }
  812. aktfilepos:=exitpos;
  813. gen_proc_symbol_end(templist);
  814. aktproccode.concatlist(templist);
  815. {$ifdef ARM}
  816. { because of the limited constant size of the arm, all data access is done pc relative }
  817. insertpcrelativedata(aktproccode,aktlocaldata);
  818. {$endif ARM}
  819. {$ifdef POWERPC}
  820. fixup_jmps(aktproccode);
  821. {$endif POWERPC}
  822. {$ifdef POWERPC64}
  823. fixup_jmps(aktproccode);
  824. {$endif POWERPC64}
  825. { insert line debuginfo }
  826. if (cs_debuginfo in aktmoduleswitches) or
  827. (cs_use_lineinfo in aktglobalswitches) then
  828. debuginfo.insertlineinfo(aktproccode);
  829. { add the procedure to the al_procedures }
  830. maybe_new_object_file(asmlist[al_procedures]);
  831. new_section(asmlist[al_procedures],sec_code,lower(procdef.mangledname),getprocalign);
  832. asmlist[al_procedures].concatlist(aktproccode);
  833. { save local data (casetable) also in the same file }
  834. if assigned(aktlocaldata) and
  835. (not aktlocaldata.empty) then
  836. asmlist[al_procedures].concatlist(aktlocaldata);
  837. { only now we can remove the temps }
  838. tg.resettempgen;
  839. { stop tempgen and ra }
  840. tg.free;
  841. cg.done_register_allocators;
  842. tg:=nil;
  843. end;
  844. { restore symtablestack }
  845. remove_from_symtablestack;
  846. { restore }
  847. templist.free;
  848. aktmaxfpuregisters:=oldaktmaxfpuregisters;
  849. aktfilepos:=oldfilepos;
  850. current_procinfo:=oldprocinfo;
  851. end;
  852. procedure tcgprocinfo.add_to_symtablestack;
  853. var
  854. _class,hp : tobjectdef;
  855. begin
  856. { allocate the symbol for this procedure }
  857. alloc_proc_symbol(procdef);
  858. { insert symtables for the class, but only if it is no nested function }
  859. if assigned(procdef._class) and
  860. not(assigned(parent) and
  861. assigned(parent.procdef) and
  862. assigned(parent.procdef._class)) then
  863. begin
  864. { insert them in the reverse order }
  865. hp:=nil;
  866. repeat
  867. _class:=procdef._class;
  868. while _class.childof<>hp do
  869. _class:=_class.childof;
  870. hp:=_class;
  871. _class.symtable.next:=symtablestack;
  872. symtablestack:=_class.symtable;
  873. until hp=procdef._class;
  874. end;
  875. { insert parasymtable in symtablestack when parsing
  876. a function }
  877. if procdef.parast.symtablelevel>=normal_function_level then
  878. begin
  879. procdef.parast.next:=symtablestack;
  880. symtablestack:=procdef.parast;
  881. end;
  882. procdef.localst.next:=symtablestack;
  883. symtablestack:=procdef.localst;
  884. end;
  885. procedure tcgprocinfo.remove_from_symtablestack;
  886. begin
  887. { remove localst/parast }
  888. if procdef.parast.symtablelevel>=normal_function_level then
  889. symtablestack:=symtablestack.next.next
  890. else
  891. symtablestack:=symtablestack.next;
  892. { remove class member symbol tables }
  893. while symtablestack.symtabletype=objectsymtable do
  894. symtablestack:=symtablestack.next;
  895. end;
  896. procedure tcgprocinfo.resetprocdef;
  897. begin
  898. { remove code tree, if not inline procedure }
  899. if assigned(code) then
  900. begin
  901. { the inline procedure has already got a copy of the tree
  902. stored in procdef.inlininginfo }
  903. code.free;
  904. code:=nil;
  905. end;
  906. end;
  907. function checknodeinlining(procdef: tprocdef): boolean;
  908. var
  909. i : integer;
  910. currpara : tparavarsym;
  911. begin
  912. result := false;
  913. if (pi_has_assembler_block in current_procinfo.flags) then
  914. exit;
  915. for i:=0 to procdef.paras.count-1 do
  916. begin
  917. currpara:=tparavarsym(procdef.paras[i]);
  918. { we can't handle formaldefs and special arrays (the latter may need a }
  919. { re-basing of the index, i.e. if you pass an array[1..10] as open array, }
  920. { you have to add 1 to all index operations if you directly inline it }
  921. if ((currpara.varspez in [vs_out,vs_var,vs_const]) and
  922. (currpara.vartype.def.deftype=formaldef)) or
  923. is_special_array(currpara.vartype.def) then
  924. exit;
  925. end;
  926. result:=true;
  927. end;
  928. procedure tcgprocinfo.parse_body;
  929. var
  930. oldprocinfo : tprocinfo;
  931. oldblock_type : tblock_type;
  932. oldconstsymtable : tsymtable;
  933. st : tsymtable;
  934. begin
  935. oldprocinfo:=current_procinfo;
  936. oldblock_type:=block_type;
  937. oldconstsymtable:=constsymtable;
  938. { reset break and continue labels }
  939. block_type:=bt_body;
  940. current_procinfo:=self;
  941. { calculate the lexical level }
  942. if procdef.parast.symtablelevel>maxnesting then
  943. Message(parser_e_too_much_lexlevel);
  944. { static is also important for local procedures !! }
  945. if (po_staticmethod in procdef.procoptions) then
  946. allow_only_static:=true
  947. else if (procdef.parast.symtablelevel=normal_function_level) then
  948. allow_only_static:=false;
  949. {$ifdef state_tracking}
  950. { aktstate:=Tstate_storage.create;}
  951. {$endif state_tracking}
  952. { create a local symbol table for this routine }
  953. if not assigned(procdef.localst) then
  954. procdef.insert_localst;
  955. { add parast/localst to symtablestack }
  956. add_to_symtablestack;
  957. { constant symbols are inserted in this symboltable }
  958. constsymtable:=symtablestack;
  959. { save entry info }
  960. entrypos:=aktfilepos;
  961. entryswitches:=aktlocalswitches;
  962. if (df_generic in procdef.defoptions) then
  963. begin
  964. { start token recorder for generic template }
  965. procdef.initgeneric;
  966. current_scanner.startrecordtokens(procdef.generictokenbuf);
  967. end;
  968. { parse the code ... }
  969. code:=block(current_module.islibrary);
  970. if (df_generic in procdef.defoptions) then
  971. begin
  972. { stop token recorder for generic template }
  973. current_scanner.stoprecordtokens;
  974. { Give a warning for accesses in the static symtable that aren't visible
  975. outside the current unit }
  976. st:=procdef.owner;
  977. while (st.symtabletype=objectsymtable) do
  978. st:=st.defowner.owner;
  979. if (pi_uses_static_symtable in flags) and
  980. (st.symtabletype<>staticsymtable) then
  981. Comment(V_Warning,'Global Generic template references static symtable');
  982. end;
  983. { save exit info }
  984. exitswitches:=aktlocalswitches;
  985. exitpos:=last_endtoken_filepos;
  986. { the procedure is now defined }
  987. procdef.forwarddef:=false;
  988. if assigned(code) then
  989. begin
  990. { get a better entry point }
  991. entrypos:=code.fileinfo;
  992. { Finish type checking pass }
  993. do_resulttypepass(code);
  994. end;
  995. { Check for unused labels, forwards, symbols for procedures. Static
  996. symtable is checked in pmodules.
  997. The check must be done after the resulttypepass }
  998. if (Errorcount=0) and
  999. (tstoredsymtable(procdef.localst).symtabletype<>staticsymtable) then
  1000. begin
  1001. { check if forwards are resolved }
  1002. tstoredsymtable(procdef.localst).check_forwards;
  1003. { check if all labels are used }
  1004. tstoredsymtable(procdef.localst).checklabels;
  1005. { remove cross unit overloads }
  1006. tstoredsymtable(procdef.localst).unchain_overloaded;
  1007. { check for unused symbols, but only if there is no asm block }
  1008. if not(pi_has_assembler_block in flags) then
  1009. begin
  1010. tstoredsymtable(procdef.localst).allsymbolsused;
  1011. tstoredsymtable(procdef.parast).allsymbolsused;
  1012. end;
  1013. end;
  1014. if (po_inline in procdef.procoptions) then
  1015. begin
  1016. { Can we inline this procedure? }
  1017. if checknodeinlining(procdef) then
  1018. begin
  1019. new(procdef.inlininginfo);
  1020. include(procdef.procoptions,po_has_inlininginfo);
  1021. procdef.inlininginfo^.code:=code.getcopy;
  1022. procdef.inlininginfo^.flags:=current_procinfo.flags;
  1023. { The blocknode needs to set an exit label }
  1024. if procdef.inlininginfo^.code.nodetype=blockn then
  1025. include(procdef.inlininginfo^.code.flags,nf_block_with_exit);
  1026. end;
  1027. end;
  1028. { Print the node to tree.log }
  1029. if paraprintnodetree=1 then
  1030. printproc;
  1031. { ... remove symbol tables }
  1032. remove_from_symtablestack;
  1033. {$ifdef state_tracking}
  1034. { aktstate.destroy;}
  1035. {$endif state_tracking}
  1036. { reset to normal non static function }
  1037. if (procdef.parast.symtablelevel=normal_function_level) then
  1038. allow_only_static:=false;
  1039. current_procinfo:=oldprocinfo;
  1040. { Restore old state }
  1041. constsymtable:=oldconstsymtable;
  1042. block_type:=oldblock_type;
  1043. end;
  1044. {****************************************************************************
  1045. PROCEDURE/FUNCTION PARSING
  1046. ****************************************************************************}
  1047. procedure check_init_paras(p:tnamedindexitem;arg:pointer);
  1048. begin
  1049. if tsym(p).typ<>paravarsym then
  1050. exit;
  1051. with tparavarsym(p) do
  1052. if (not is_class(vartype.def) and
  1053. vartype.def.needs_inittable and
  1054. (varspez in [vs_value,vs_out])) then
  1055. include(current_procinfo.flags,pi_do_call);
  1056. end;
  1057. procedure read_proc_body(old_current_procinfo:tprocinfo;pd:tprocdef);
  1058. {
  1059. Parses the procedure directives, then parses the procedure body, then
  1060. generates the code for it
  1061. }
  1062. procedure do_generate_code(pi:tcgprocinfo);
  1063. var
  1064. hpi : tcgprocinfo;
  1065. begin
  1066. { generate code for this procedure }
  1067. pi.generate_code;
  1068. { process nested procs }
  1069. hpi:=tcgprocinfo(pi.nestedprocs.first);
  1070. while assigned(hpi) do
  1071. begin
  1072. do_generate_code(hpi);
  1073. hpi:=tcgprocinfo(hpi.next);
  1074. end;
  1075. pi.resetprocdef;
  1076. end;
  1077. var
  1078. oldfailtokenmode : tmodeswitch;
  1079. isnestedproc : boolean;
  1080. begin
  1081. Message1(parser_d_procedure_start,pd.fullprocname(false));
  1082. { create a new procedure }
  1083. current_procinfo:=cprocinfo.create(old_current_procinfo);
  1084. current_module.procinfo:=current_procinfo;
  1085. current_procinfo.procdef:=pd;
  1086. isnestedproc:=(current_procinfo.procdef.parast.symtablelevel>normal_function_level);
  1087. { Insert mangledname }
  1088. pd.aliasnames.insert(pd.mangledname);
  1089. { Handle Export of this procedure }
  1090. if (po_exports in pd.procoptions) and
  1091. (target_info.system in [system_i386_os2,system_i386_emx]) then
  1092. begin
  1093. pd.aliasnames.insert(pd.procsym.realname);
  1094. if cs_link_deffile in aktglobalswitches then
  1095. deffile.AddExport(pd.mangledname);
  1096. end;
  1097. { Insert result variables in the localst }
  1098. insert_funcret_local(pd);
  1099. { check if there are para's which require initing -> set }
  1100. { pi_do_call (if not yet set) }
  1101. if not(pi_do_call in current_procinfo.flags) then
  1102. pd.parast.foreach_static(@check_init_paras,nil);
  1103. { set _FAIL as keyword if constructor }
  1104. if (pd.proctypeoption=potype_constructor) then
  1105. begin
  1106. oldfailtokenmode:=tokeninfo^[_FAIL].keyword;
  1107. tokeninfo^[_FAIL].keyword:=m_all;
  1108. end;
  1109. tcgprocinfo(current_procinfo).parse_body;
  1110. { When it's a nested procedure then defer the code generation,
  1111. when back at normal function level then generate the code
  1112. for all defered nested procedures and the current procedure }
  1113. if isnestedproc then
  1114. tcgprocinfo(current_procinfo.parent).nestedprocs.insert(current_procinfo)
  1115. else
  1116. begin
  1117. { We can't support inlining for procedures that have nested
  1118. procedures because the nested procedures use a fixed offset
  1119. for accessing locals in the parent procedure (PFV) }
  1120. if (tcgprocinfo(current_procinfo).nestedprocs.count>0) then
  1121. begin
  1122. if (df_generic in current_procinfo.procdef.defoptions) then
  1123. {$warning TODO Add error message for nested procs in generics}
  1124. internalerror(200511151)
  1125. else if (po_inline in current_procinfo.procdef.procoptions) then
  1126. begin
  1127. Message1(parser_w_not_supported_for_inline,'nested procedures');
  1128. Message(parser_w_inlining_disabled);
  1129. current_procinfo.procdef.proccalloption:=pocall_default;
  1130. end;
  1131. end;
  1132. if not(df_generic in current_procinfo.procdef.defoptions) then
  1133. do_generate_code(tcgprocinfo(current_procinfo));
  1134. end;
  1135. { reset _FAIL as _SELF normal }
  1136. if (pd.proctypeoption=potype_constructor) then
  1137. tokeninfo^[_FAIL].keyword:=oldfailtokenmode;
  1138. { release procinfo }
  1139. if tprocinfo(current_module.procinfo)<>current_procinfo then
  1140. internalerror(200304274);
  1141. current_module.procinfo:=current_procinfo.parent;
  1142. { For specialization we didn't record the last semicolon. Moving this parsing
  1143. into the parse_body routine is not done because of having better file position
  1144. information available }
  1145. if not(df_specialization in current_procinfo.procdef.defoptions) then
  1146. consume(_SEMICOLON);
  1147. if not isnestedproc then
  1148. current_procinfo.free;
  1149. end;
  1150. procedure read_proc;
  1151. {
  1152. Parses the procedure directives, then parses the procedure body, then
  1153. generates the code for it
  1154. }
  1155. procedure do_generate_code(pi:tcgprocinfo);
  1156. var
  1157. hpi : tcgprocinfo;
  1158. begin
  1159. { generate code for this procedure }
  1160. pi.generate_code;
  1161. { process nested procs }
  1162. hpi:=tcgprocinfo(pi.nestedprocs.first);
  1163. while assigned(hpi) do
  1164. begin
  1165. do_generate_code(hpi);
  1166. hpi:=tcgprocinfo(hpi.next);
  1167. end;
  1168. pi.resetprocdef;
  1169. end;
  1170. var
  1171. old_current_procinfo : tprocinfo;
  1172. pdflags : tpdflags;
  1173. pd : tprocdef;
  1174. s : string;
  1175. begin
  1176. { save old state }
  1177. old_current_procinfo:=current_procinfo;
  1178. { reset current_procinfo.procdef to nil to be sure that nothing is writing
  1179. to an other procdef }
  1180. current_procinfo:=nil;
  1181. { parse procedure declaration }
  1182. if assigned(old_current_procinfo) and
  1183. assigned(old_current_procinfo.procdef) then
  1184. pd:=parse_proc_dec(old_current_procinfo.procdef._class)
  1185. else
  1186. pd:=parse_proc_dec(nil);
  1187. { set the default function options }
  1188. if parse_only then
  1189. begin
  1190. pd.forwarddef:=true;
  1191. { set also the interface flag, for better error message when the
  1192. implementation doesn't much this header }
  1193. pd.interfacedef:=true;
  1194. include(pd.procoptions,po_global);
  1195. pdflags:=[pd_interface];
  1196. end
  1197. else
  1198. begin
  1199. pdflags:=[pd_body];
  1200. if (not current_module.in_interface) then
  1201. include(pdflags,pd_implemen);
  1202. if (not current_module.is_unit) or
  1203. maybe_smartlink_symbol or
  1204. {
  1205. taking addresses of static procedures goes wrong
  1206. if they aren't global when pic is used (FK)
  1207. }
  1208. (cs_create_pic in aktmoduleswitches) then
  1209. include(pd.procoptions,po_global);
  1210. pd.forwarddef:=false;
  1211. end;
  1212. { parse the directives that may follow }
  1213. parse_proc_directives(pd,pdflags);
  1214. { hint directives, these can be separated by semicolons here,
  1215. that needs to be handled here with a loop (PFV) }
  1216. while try_consume_hintdirective(pd.symoptions) do
  1217. Consume(_SEMICOLON);
  1218. { Set calling convention }
  1219. handle_calling_convention(pd);
  1220. { search for forward declarations }
  1221. if not proc_add_definition(pd) then
  1222. begin
  1223. { A method must be forward defined (in the object declaration) }
  1224. if assigned(pd._class) and
  1225. (not assigned(old_current_procinfo.procdef._class)) then
  1226. begin
  1227. MessagePos1(pd.fileinfo,parser_e_header_dont_match_any_member,pd.fullprocname(false));
  1228. tprocsym(pd.procsym).write_parameter_lists(pd);
  1229. end
  1230. else
  1231. begin
  1232. { Give a better error if there is a forward def in the interface and only
  1233. a single implementation }
  1234. if (not pd.forwarddef) and
  1235. (not pd.interfacedef) and
  1236. (tprocsym(pd.procsym).procdef_count>1) and
  1237. tprocsym(pd.procsym).first_procdef.forwarddef and
  1238. tprocsym(pd.procsym).first_procdef.interfacedef and
  1239. not(tprocsym(pd.procsym).procdef_count>2) then
  1240. begin
  1241. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  1242. tprocsym(pd.procsym).write_parameter_lists(pd);
  1243. end;
  1244. end;
  1245. end;
  1246. { Set mangled name }
  1247. proc_set_mangledname(pd);
  1248. { compile procedure when a body is needed }
  1249. if (pd_body in pdflags) then
  1250. begin
  1251. read_proc_body(old_current_procinfo,pd);
  1252. end
  1253. else
  1254. begin
  1255. { Handle imports }
  1256. if (po_external in pd.procoptions) then
  1257. begin
  1258. { External declared in implementation, and there was already a
  1259. forward (or interface) declaration then we need to generate
  1260. a stub that calls the external routine }
  1261. if (not pd.forwarddef) and
  1262. (pd.hasforward) and
  1263. not(
  1264. assigned(pd.import_dll) and
  1265. (target_info.system in [system_i386_win32,system_i386_wdosx,
  1266. system_i386_emx,system_i386_os2,system_arm_wince,system_i386_wince])
  1267. ) then
  1268. begin
  1269. s:=proc_get_importname(pd);
  1270. if s<>'' then
  1271. gen_external_stub(asmlist[al_procedures],pd,{$IFDEF POWERPC64}'.'+{$ENDIF}s);
  1272. end;
  1273. { Import DLL specified? }
  1274. if assigned(pd.import_dll) then
  1275. begin
  1276. { create importlib if not already done }
  1277. if not(current_module.uses_imports) then
  1278. begin
  1279. current_module.uses_imports:=true;
  1280. importlib.preparelib(current_module.realmodulename^);
  1281. end;
  1282. if assigned(pd.import_name) then
  1283. importlib.importprocedure(pd,pd.import_dll^,pd.import_nr,pd.import_name^)
  1284. else
  1285. importlib.importprocedure(pd,pd.import_dll^,pd.import_nr,'');
  1286. end
  1287. else
  1288. begin
  1289. { add import name to external list for DLL scanning }
  1290. if target_info.DllScanSupported then
  1291. current_module.externals.insert(tExternalsItem.create(proc_get_importname(pd)));
  1292. end;
  1293. end;
  1294. end;
  1295. { make sure that references to forward-declared functions are not }
  1296. { treated as references to external symbols, needed for darwin. }
  1297. { make sure we don't change the binding of real external symbols }
  1298. if not(po_external in pd.procoptions) then
  1299. begin
  1300. if (po_global in pd.procoptions) or
  1301. (cs_profile in aktmoduleswitches) then
  1302. objectlibrary.newasmsymbol(pd.mangledname,AB_GLOBAL,AT_FUNCTION)
  1303. else
  1304. objectlibrary.newasmsymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION);
  1305. end;
  1306. current_procinfo:=old_current_procinfo;
  1307. end;
  1308. {****************************************************************************
  1309. DECLARATION PARSING
  1310. ****************************************************************************}
  1311. { search in symtablestack for not complete classes }
  1312. procedure check_forward_class(p : tnamedindexitem;arg:pointer);
  1313. begin
  1314. if (tsym(p).typ=typesym) and
  1315. (ttypesym(p).restype.def.deftype=objectdef) and
  1316. (oo_is_forward in tobjectdef(ttypesym(p).restype.def).objectoptions) then
  1317. MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
  1318. end;
  1319. procedure read_declarations(islibrary : boolean);
  1320. begin
  1321. repeat
  1322. if not assigned(current_procinfo) then
  1323. internalerror(200304251);
  1324. case token of
  1325. _LABEL:
  1326. label_dec;
  1327. _CONST:
  1328. const_dec;
  1329. _TYPE:
  1330. type_dec;
  1331. _VAR:
  1332. var_dec;
  1333. _THREADVAR:
  1334. threadvar_dec;
  1335. _CONSTRUCTOR,
  1336. _DESTRUCTOR,
  1337. _FUNCTION,
  1338. _PROCEDURE,
  1339. _OPERATOR,
  1340. _CLASS:
  1341. read_proc;
  1342. _EXPORTS:
  1343. begin
  1344. if not(assigned(current_procinfo.procdef.localst)) or
  1345. (current_procinfo.procdef.localst.symtablelevel>main_program_level) then
  1346. begin
  1347. Message(parser_e_syntax_error);
  1348. consume_all_until(_SEMICOLON);
  1349. end
  1350. else if islibrary or
  1351. (target_info.system in system_unit_program_exports) then
  1352. read_exports
  1353. else
  1354. begin
  1355. Message(parser_w_unsupported_feature);
  1356. consume(_BEGIN);
  1357. end;
  1358. end
  1359. else
  1360. begin
  1361. case idtoken of
  1362. _RESOURCESTRING :
  1363. begin
  1364. { m_class is needed, because the resourcestring
  1365. loading is in the ObjPas unit }
  1366. if (m_class in aktmodeswitches) then
  1367. resourcestring_dec
  1368. else
  1369. break;
  1370. end;
  1371. _PROPERTY:
  1372. begin
  1373. if (m_fpc in aktmodeswitches) then
  1374. property_dec
  1375. else
  1376. break;
  1377. end;
  1378. else
  1379. break;
  1380. end;
  1381. end;
  1382. end;
  1383. until false;
  1384. { check for incomplete class definitions, this is only required
  1385. for fpc modes }
  1386. if (m_fpc in aktmodeswitches) then
  1387. symtablestack.foreach_static(@check_forward_class,nil);
  1388. end;
  1389. procedure read_interface_declarations;
  1390. begin
  1391. repeat
  1392. case token of
  1393. _CONST :
  1394. const_dec;
  1395. _TYPE :
  1396. type_dec;
  1397. _VAR :
  1398. var_dec;
  1399. _THREADVAR :
  1400. threadvar_dec;
  1401. _FUNCTION,
  1402. _PROCEDURE,
  1403. _OPERATOR :
  1404. read_proc;
  1405. else
  1406. begin
  1407. case idtoken of
  1408. _RESOURCESTRING :
  1409. resourcestring_dec;
  1410. _PROPERTY:
  1411. begin
  1412. if (m_fpc in aktmodeswitches) then
  1413. property_dec
  1414. else
  1415. break;
  1416. end;
  1417. else
  1418. break;
  1419. end;
  1420. end;
  1421. end;
  1422. until false;
  1423. { check for incomplete class definitions, this is only required
  1424. for fpc modes }
  1425. if (m_fpc in aktmodeswitches) then
  1426. symtablestack.foreach_static(@check_forward_class,nil);
  1427. end;
  1428. {****************************************************************************
  1429. SPECIALIZATION BODY GENERATION
  1430. ****************************************************************************}
  1431. procedure specialize_objectdefs(p:tnamedindexitem;arg:pointer);
  1432. var
  1433. hp : tdef;
  1434. oldaktfilepos : tfileposinfo;
  1435. begin
  1436. if not((tsym(p).typ=typesym) and
  1437. (ttypesym(p).restype.def.deftype=objectdef) and
  1438. (df_specialization in ttypesym(p).restype.def.defoptions)
  1439. ) then
  1440. exit;
  1441. { definitions }
  1442. hp:=tdef(tobjectdef(ttypesym(p).restype.def).symtable.defindex.first);
  1443. while assigned(hp) do
  1444. begin
  1445. if hp.deftype=procdef then
  1446. begin
  1447. if not(
  1448. assigned(tprocdef(hp).genericdef) and
  1449. (tprocdef(hp).genericdef.deftype=procdef) and
  1450. assigned(tprocdef(tprocdef(hp).genericdef).generictokenbuf)
  1451. ) then
  1452. internalerror(200512111);
  1453. oldaktfilepos:=aktfilepos;
  1454. aktfilepos:=tprocdef(tprocdef(hp).genericdef).fileinfo;
  1455. akttokenpos:=aktfilepos;
  1456. current_scanner.startreplaytokens(tprocdef(tprocdef(hp).genericdef).generictokenbuf);
  1457. read_proc_body(nil,tprocdef(hp));
  1458. aktfilepos:=oldaktfilepos;
  1459. end;
  1460. hp:=tdef(hp.indexnext);
  1461. end;
  1462. end;
  1463. procedure generate_specialization_procs;
  1464. var
  1465. oldsymtablestack : tsymtable;
  1466. begin
  1467. if assigned(current_module.globalsymtable) then
  1468. current_module.globalsymtable.foreach_static(@specialize_objectdefs,nil);
  1469. if assigned(current_module.localsymtable) then
  1470. begin
  1471. oldsymtablestack:=symtablestack;
  1472. current_module.localsymtable.next:=symtablestack;
  1473. symtablestack:=current_module.localsymtable;
  1474. current_module.localsymtable.foreach_static(@specialize_objectdefs,nil);
  1475. symtablestack:=oldsymtablestack;
  1476. end;
  1477. end;
  1478. end.