1 { 2 Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione 3 4 Does the parsing and codegeneration at subroutine level 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 **************************************************************************** 21 } 22 unit psub; 23 24 {$i fpcdefs.inc} 25 26 interface 27 28 uses 29 globals, 30 node,nbas, 31 symdef,procinfo,optdfa; 32 33 type 34 tcgprocinfo = class(tprocinfo) 35 private 36 procedure CreateInlineInfo; 37 { returns the node which is the start of the user code, this is needed by the dfa } GetUserCodenull38 function GetUserCode: tnode; 39 procedure maybe_add_constructor_wrapper(var tocode: tnode; withexceptblock: boolean); 40 procedure add_entry_exit_code; 41 procedure setup_tempgen; 42 public 43 { code for the subroutine as tree } 44 code : tnode; 45 { positions in the tree for init/final } 46 entry_asmnode, 47 loadpara_asmnode, 48 exitlabel_asmnode, 49 stackcheck_asmnode, 50 init_asmnode, 51 final_asmnode : tasmnode; 52 final_used : boolean; 53 dfabuilder : TDFABuilder; 54 55 destructor destroy;override; 56 calc_stackframe_sizenull57 function calc_stackframe_size : longint;override; 58 59 procedure printproc(pass:string); 60 procedure generate_code; 61 procedure generate_code_tree; 62 procedure generate_exceptfilter(nestedpi: tcgprocinfo); 63 procedure resetprocdef; 64 procedure add_to_symtablestack; 65 procedure remove_from_symtablestack; 66 procedure parse_body; 67 has_assembler_childnull68 function has_assembler_child : boolean; 69 end; 70 71 72 procedure printnode_reset; 73 74 { reads the declaration blocks } 75 procedure read_declarations(islibrary : boolean); 76 77 { reads declarations in the interface part of a unit } 78 procedure read_interface_declarations; 79 80 { reads any routine in the implementation, or a non-method routine 81 declaration in the interface (depending on whether or not parse_only is 82 true) } 83 procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean); 84 85 { parses only the body of a non nested routine; needs a correctly setup pd } 86 procedure read_proc_body(pd:tprocdef); 87 88 procedure import_external_proc(pd:tprocdef); 89 90 91 implementation 92 93 uses 94 sysutils, 95 { common } 96 cutils, 97 { global } 98 globtype,tokens,verbose,comphook,constexp, 99 systems,cpubase,aasmbase,aasmtai,aasmdata, 100 { symtable } 101 symconst,symbase,symsym,symtype,symtable,defutil,defcmp,symcreat, 102 paramgr, 103 fmodule, 104 { pass 1 } 105 nutils,ngenutil,nld,ncal,ncon,nflw,nadd,ncnv,nmem, 106 pass_1, 107 {$ifdef state_tracking} 108 nstate, 109 {$endif state_tracking} 110 { pass 2 } 111 {$ifndef NOPASS2} 112 pass_2, 113 {$endif} 114 { parser } 115 scanner,gendef, 116 pbase,pstatmnt,pdecl,pdecsub,pexports,pgenutil,pparautl, 117 { codegen } 118 tgobj,cgbase,cgobj,hlcgobj,hlcgcpu,dbgbase, 119 {$ifdef llvm} 120 { override create_hlcodegen from hlcgcpu } 121 hlcgllvm, 122 {$endif} 123 ncgutil, 124 optbase, 125 opttail, 126 optcse, 127 optloop, 128 optconstprop, 129 optdeadstore, 130 optloadmodifystore, 131 optutils 132 {$if defined(arm)} 133 ,cpuinfo 134 {$endif arm} 135 {$ifndef NOOPT} 136 ,aopt 137 {$endif} 138 ; 139 checknodeinliningnull140 function checknodeinlining(procdef: tprocdef): boolean; 141 var 142 i : integer; 143 currpara : tparavarsym; 144 begin 145 result := false; 146 { this code will never be used (only specialisations can be inlined), 147 and moreover contains references to defs that are not stored in the 148 ppu file } 149 if df_generic in current_procinfo.procdef.defoptions then 150 exit; 151 if pi_has_assembler_block in current_procinfo.flags then 152 begin 153 Message1(parser_h_not_supported_for_inline,'assembler'); 154 Message(parser_h_inlining_disabled); 155 exit; 156 end; 157 if pi_has_global_goto in current_procinfo.flags then 158 begin 159 Message1(parser_h_not_supported_for_inline,'global goto'); 160 Message(parser_h_inlining_disabled); 161 exit; 162 end; 163 if pi_has_nested_exit in current_procinfo.flags then 164 begin 165 Message1(parser_h_not_supported_for_inline,'nested exit'); 166 Message(parser_h_inlining_disabled); 167 exit; 168 end; 169 if pi_calls_c_varargs in current_procinfo.flags then 170 begin 171 Message1(parser_h_not_supported_for_inline,'called C-style varargs functions'); 172 Message(parser_h_inlining_disabled); 173 exit; 174 end; 175 { the compiler cannot handle inherited in inlined subroutines because 176 it tries to search for self in the symtable, however, the symtable 177 is not available } 178 if pi_has_inherited in current_procinfo.flags then 179 begin 180 Message1(parser_h_not_supported_for_inline,'inherited'); 181 Message(parser_h_inlining_disabled); 182 exit; 183 end; 184 for i:=0 to procdef.paras.count-1 do 185 begin 186 currpara:=tparavarsym(procdef.paras[i]); 187 case currpara.vardef.typ of 188 formaldef : 189 begin 190 if (currpara.varspez in [vs_out,vs_var,vs_const,vs_constref]) then 191 begin 192 Message1(parser_h_not_supported_for_inline,'formal parameter'); 193 Message(parser_h_inlining_disabled); 194 exit; 195 end; 196 end; 197 arraydef : 198 begin 199 if is_array_of_const(currpara.vardef) or 200 is_variant_array(currpara.vardef) then 201 begin 202 Message1(parser_h_not_supported_for_inline,'array of const'); 203 Message(parser_h_inlining_disabled); 204 exit; 205 end; 206 { open arrays might need re-basing of the index, i.e. if you pass 207 an array[1..10] as open array, you have to add 1 to all index operations 208 if you directly inline it } 209 if is_open_array(currpara.vardef) then 210 begin 211 Message1(parser_h_not_supported_for_inline,'open array'); 212 Message(parser_h_inlining_disabled); 213 exit; 214 end; 215 end; 216 end; 217 end; 218 result:=true; 219 end; 220 221 222 {**************************************************************************** 223 PROCEDURE/FUNCTION BODY PARSING 224 ****************************************************************************} 225 226 procedure initializedefaultvars(p:TObject;arg:pointer); 227 var 228 b : tblocknode; 229 begin 230 if tsym(p).typ<>localvarsym then 231 exit; 232 with tabstractnormalvarsym(p) do 233 begin 234 if (vo_is_default_var in varoptions) and (vardef.size>0) then 235 begin 236 b:=tblocknode(arg); 237 b.left:=cstatementnode.create( 238 ccallnode.createintern('fpc_zeromem', 239 ccallparanode.create( 240 cordconstnode.create(vardef.size,sizeuinttype,false), 241 ccallparanode.create( 242 caddrnode.create_internal( 243 cloadnode.create(tsym(p),tsym(p).owner)), 244 nil 245 ) 246 ) 247 ), 248 b.left); 249 end; 250 end; 251 end; 252 253 254 procedure initializevars(p:TObject;arg:pointer); 255 var 256 b : tblocknode; 257 begin 258 if not (tsym(p).typ in [localvarsym,staticvarsym]) then 259 exit; 260 with tabstractnormalvarsym(p) do 261 begin 262 if assigned(defaultconstsym) then 263 begin 264 b:=tblocknode(arg); 265 b.left:=cstatementnode.create( 266 cassignmentnode.create( 267 cloadnode.create(tsym(p),tsym(p).owner), 268 cloadnode.create(defaultconstsym,defaultconstsym.owner)), 269 b.left); 270 end 271 else 272 initializedefaultvars(p,arg); 273 end; 274 end; 275 276 277 procedure check_finalize_paras(p:TObject;arg:pointer); 278 begin 279 if (tsym(p).typ=paravarsym) then 280 begin 281 if tparavarsym(p).needs_finalization then 282 begin 283 include(current_procinfo.flags,pi_needs_implicit_finally); 284 include(current_procinfo.flags,pi_do_call); 285 end; 286 if (tparavarsym(p).varspez in [vs_value,vs_out]) and 287 (cs_create_pic in current_settings.moduleswitches) and 288 (tf_pic_uses_got in target_info.flags) and 289 is_rtti_managed_type(tparavarsym(p).vardef) then 290 include(current_procinfo.flags,pi_needs_got); 291 end; 292 end; 293 294 295 procedure check_finalize_locals(p:TObject;arg:pointer); 296 begin 297 { include the result: it needs to be finalized in case an exception } 298 { occurs } 299 if (tsym(p).typ=localvarsym) and 300 (tlocalvarsym(p).refs>0) and 301 is_managed_type(tlocalvarsym(p).vardef) then 302 begin 303 include(current_procinfo.flags,pi_needs_implicit_finally); 304 include(current_procinfo.flags,pi_do_call); 305 if is_rtti_managed_type(tlocalvarsym(p).vardef) and 306 (cs_create_pic in current_settings.moduleswitches) and 307 (tf_pic_uses_got in target_info.flags) then 308 include(current_procinfo.flags,pi_needs_got); 309 end; 310 end; 311 312 blocknull313 function block(islibrary : boolean) : tnode; 314 var 315 oldfilepos: tfileposinfo; 316 begin 317 { parse const,types and vars } 318 read_declarations(islibrary); 319 320 { do we have an assembler block without the po_assembler? 321 we should allow this for Delphi compatibility (PFV) } 322 if (token=_ASM) and (m_delphi in current_settings.modeswitches) then 323 include(current_procinfo.procdef.procoptions,po_assembler); 324 325 { Handle assembler block different } 326 if (po_assembler in current_procinfo.procdef.procoptions) then 327 begin 328 block:=assembler_block; 329 exit; 330 end; 331 332 {Unit initialization?.} 333 if ( 334 assigned(current_procinfo.procdef.localst) and 335 (current_procinfo.procdef.localst.symtablelevel=main_program_level) and 336 (current_module.is_unit or islibrary) 337 ) then 338 begin 339 if (token=_END) then 340 begin 341 consume(_END); 342 { We need at least a node, else the entry/exit code is not 343 generated and thus no PASCALMAIN symbol which we need (PFV) } 344 if islibrary then 345 block:=cnothingnode.create 346 else 347 block:=nil; 348 end 349 else 350 begin 351 if token=_INITIALIZATION then 352 begin 353 { The library init code is already called and does not 354 need to be in the initfinal table (PFV) } 355 block:=statement_block(_INITIALIZATION); 356 end 357 else if token=_FINALIZATION then 358 begin 359 { when a unit has only a finalization section, we can come to this 360 point when we try to read the nonh existing initalization section 361 so we've to check if we are really try to parse the finalization } 362 if current_procinfo.procdef.proctypeoption=potype_unitfinalize then 363 block:=statement_block(_FINALIZATION) 364 else 365 block:=nil; 366 end 367 else 368 block:=statement_block(_BEGIN); 369 end; 370 end 371 else 372 begin 373 { parse routine body } 374 block:=statement_block(_BEGIN); 375 { initialized variables } 376 if current_procinfo.procdef.localst.symtabletype=localsymtable then 377 begin 378 { initialization of local variables with their initial 379 values: part of function entry } 380 oldfilepos:=current_filepos; 381 current_filepos:=current_procinfo.entrypos; 382 current_procinfo.procdef.localst.SymList.ForEachCall(@initializevars,block); 383 current_filepos:=oldfilepos; 384 end 385 else if current_procinfo.procdef.localst.symtabletype=staticsymtable then 386 begin 387 { for program and unit initialization code we also need to 388 initialize the local variables used of Default() } 389 oldfilepos:=current_filepos; 390 current_filepos:=current_procinfo.entrypos; 391 current_procinfo.procdef.localst.SymList.ForEachCall(@initializedefaultvars,block); 392 current_filepos:=oldfilepos; 393 end; 394 395 if assigned(current_procinfo.procdef.parentfpstruct) then 396 begin 397 { we only do this after the code has been parsed because 398 otherwise for-loop counters moved to the struct cause 399 errors; we still do it nevertheless to prevent false 400 "unused" symbols warnings and to assist debug info 401 generation } 402 redirect_parentfpstruct_local_syms(current_procinfo.procdef); 403 { finish the parentfpstruct (add padding, ...) } 404 finish_parentfpstruct(current_procinfo.procdef); 405 end; 406 end; 407 end; 408 409 410 {**************************************************************************** 411 PROCEDURE/FUNCTION COMPILING 412 ****************************************************************************} 413 414 procedure printnode_reset; 415 begin 416 assign(printnodefile,treelogfilename); 417 {$push}{$I-} 418 rewrite(printnodefile); 419 {$pop} 420 if ioresult<>0 then 421 begin 422 Comment(V_Error,'Error creating '+treelogfilename); 423 exit; 424 end; 425 close(printnodefile); 426 end; 427 428 429 procedure add_label_init(p:TObject;arg:pointer); 430 begin 431 if tstoredsym(p).typ=labelsym then 432 begin 433 addstatement(tstatementnode(arg^), 434 cifnode.create(caddnode.create(equaln, 435 ccallnode.createintern('fpc_setjmp', 436 ccallparanode.create(cloadnode.create(tlabelsym(p).jumpbuf,tlabelsym(p).jumpbuf.owner),nil)), 437 cordconstnode.create(1,sinttype,true)) 438 ,cgotonode.create(tlabelsym(p)),nil) 439 ); 440 end; 441 end; 442 443 generate_bodyentry_blocknull444 function generate_bodyentry_block:tnode; 445 var 446 srsym : tsym; 447 para : tcallparanode; 448 call : tcallnode; 449 newstatement : tstatementnode; 450 def : tabstractrecorddef; 451 begin 452 result:=internalstatements(newstatement); 453 454 if assigned(current_structdef) then 455 begin 456 { a constructor needs a help procedure } 457 if (current_procinfo.procdef.proctypeoption=potype_constructor) then 458 begin 459 if is_class(current_structdef) or 460 ( 461 is_objectpascal_helper(current_structdef) and 462 is_class(tobjectdef(current_structdef).extendeddef) 463 ) then 464 begin 465 if is_objectpascal_helper(current_structdef) then 466 def:=tabstractrecorddef(tobjectdef(current_structdef).extendeddef) 467 else 468 def:=current_structdef; 469 srsym:=search_struct_member(def,'NEWINSTANCE'); 470 if assigned(srsym) and 471 (srsym.typ=procsym) then 472 begin 473 { if vmt=1 then newinstance } 474 addstatement(newstatement,cifnode.create( 475 caddnode.create_internal(equaln, 476 ctypeconvnode.create_internal( 477 load_vmt_pointer_node, 478 voidpointertype), 479 cpointerconstnode.create(1,voidpointertype)), 480 cassignmentnode.create( 481 ctypeconvnode.create_internal( 482 load_self_pointer_node, 483 voidpointertype), 484 ccallnode.create(nil,tprocsym(srsym),srsym.owner, 485 ctypeconvnode.create_internal(load_self_pointer_node,cclassrefdef.create(current_structdef)), 486 [],nil)), 487 nil)); 488 end 489 else 490 internalerror(200305108); 491 end 492 else 493 if is_object(current_structdef) then 494 begin 495 { parameter 3 : vmt_offset } 496 { parameter 2 : address of pointer to vmt, 497 this is required to allow setting the vmt to -1 to indicate 498 that memory was allocated } 499 { parameter 1 : self pointer } 500 para:=ccallparanode.create( 501 cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false), 502 ccallparanode.create( 503 ctypeconvnode.create_internal( 504 load_vmt_pointer_node, 505 voidpointertype), 506 ccallparanode.create( 507 ctypeconvnode.create_internal( 508 load_self_pointer_node, 509 voidpointertype), 510 nil))); 511 addstatement(newstatement,cassignmentnode.create( 512 ctypeconvnode.create_internal( 513 load_self_pointer_node, 514 voidpointertype), 515 ccallnode.createintern('fpc_help_constructor',para))); 516 end 517 else 518 if is_javaclass(current_structdef) or 519 ((target_info.system in systems_jvm) and 520 is_record(current_structdef)) then 521 begin 522 if (current_procinfo.procdef.proctypeoption=potype_constructor) and 523 not current_procinfo.ConstructorCallingConstructor then 524 begin 525 { call inherited constructor } 526 if is_javaclass(current_structdef) then 527 srsym:=search_struct_member_no_helper(tobjectdef(current_structdef).childof,'CREATE') 528 else 529 srsym:=search_struct_member_no_helper(java_fpcbaserecordtype,'CREATE'); 530 if assigned(srsym) and 531 (srsym.typ=procsym) then 532 begin 533 call:=ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[cnf_inherited],nil); 534 exclude(tcallnode(call).callnodeflags,cnf_return_value_used); 535 addstatement(newstatement,call); 536 end 537 else 538 internalerror(2011010312); 539 end; 540 end 541 else 542 if not is_record(current_structdef) and 543 not ( 544 is_objectpascal_helper(current_structdef) and 545 (tobjectdef(current_structdef).extendeddef.typ<>objectdef) 546 ) then 547 internalerror(200305103); 548 { if self=nil then exit 549 calling fail instead of exit is useless because 550 there is nothing to dispose (PFV) } 551 if is_class_or_object(current_structdef) then 552 addstatement(newstatement,cifnode.create( 553 caddnode.create(equaln, 554 load_self_pointer_node, 555 cnilnode.create), 556 cexitnode.create(nil), 557 nil)); 558 end; 559 560 { maybe call BeforeDestruction for classes } 561 if (current_procinfo.procdef.proctypeoption=potype_destructor) and 562 is_class(current_structdef) then 563 begin 564 srsym:=search_struct_member(current_structdef,'BEFOREDESTRUCTION'); 565 if assigned(srsym) and 566 (srsym.typ=procsym) then 567 begin 568 { if vmt>0 then beforedestruction } 569 addstatement(newstatement,cifnode.create( 570 caddnode.create(gtn, 571 ctypeconvnode.create_internal( 572 load_vmt_pointer_node,ptrsinttype), 573 ctypeconvnode.create_internal( 574 cnilnode.create,ptrsinttype)), 575 ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil), 576 nil)); 577 end 578 else 579 internalerror(200305104); 580 end; 581 end; 582 if m_non_local_goto in current_settings.modeswitches then 583 tsymtable(current_procinfo.procdef.localst).SymList.ForEachCall(@add_label_init,@newstatement); 584 end; 585 586 generate_bodyexit_blocknull587 function generate_bodyexit_block:tnode; 588 var 589 srsym : tsym; 590 para : tcallparanode; 591 newstatement : tstatementnode; 592 oldlocalswitches: tlocalswitches; 593 begin 594 result:=internalstatements(newstatement); 595 596 if assigned(current_structdef) then 597 begin 598 { Don't test self and the vmt here. The reason is that } 599 { a constructor already checks whether these are valid } 600 { before. Further, in case of TThread the thread may } 601 { free the class instance right after AfterConstruction } 602 { has been called, so it may no longer be valid (JM) } 603 oldlocalswitches:=current_settings.localswitches; 604 current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range]; 605 606 { a destructor needs a help procedure } 607 if (current_procinfo.procdef.proctypeoption=potype_destructor) then 608 begin 609 if is_class(current_structdef) then 610 begin 611 srsym:=search_struct_member(current_structdef,'FREEINSTANCE'); 612 if assigned(srsym) and 613 (srsym.typ=procsym) then 614 begin 615 { if self<>0 and vmt<>0 then freeinstance } 616 addstatement(newstatement,cifnode.create( 617 caddnode.create(andn, 618 caddnode.create(unequaln, 619 load_self_pointer_node, 620 cnilnode.create), 621 caddnode.create(unequaln, 622 ctypeconvnode.create( 623 load_vmt_pointer_node, 624 voidpointertype), 625 cpointerconstnode.create(0,voidpointertype))), 626 ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil), 627 nil)); 628 end 629 else 630 internalerror(200305108); 631 end 632 else 633 if is_object(current_structdef) then 634 begin 635 { finalize object data, but only if not in inherited call } 636 if is_managed_type(current_structdef) then 637 begin 638 addstatement(newstatement,cifnode.create( 639 caddnode.create(unequaln, 640 ctypeconvnode.create_internal(load_vmt_pointer_node,voidpointertype), 641 cnilnode.create), 642 cnodeutils.finalize_data_node(load_self_node), 643 nil)); 644 end; 645 { parameter 3 : vmt_offset } 646 { parameter 2 : pointer to vmt } 647 { parameter 1 : self pointer } 648 para:=ccallparanode.create( 649 cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false), 650 ccallparanode.create( 651 ctypeconvnode.create_internal( 652 load_vmt_pointer_node, 653 voidpointertype), 654 ccallparanode.create( 655 ctypeconvnode.create_internal( 656 load_self_pointer_node, 657 voidpointertype), 658 nil))); 659 addstatement(newstatement, 660 ccallnode.createintern('fpc_help_destructor',para)); 661 end 662 else if is_javaclass(current_structdef) then 663 begin 664 { nothing to do } 665 end 666 else 667 internalerror(200305105); 668 end; 669 current_settings.localswitches:=oldlocalswitches; 670 end; 671 end; 672 673 674 {**************************************************************************** 675 TCGProcInfo 676 ****************************************************************************} 677 678 destructor tcgprocinfo.destroy; 679 begin 680 code.free; 681 if not final_used then 682 final_asmnode.free; 683 inherited destroy; 684 end; 685 686 tcgprocinfo.calc_stackframe_sizenull687 function tcgprocinfo.calc_stackframe_size:longint; 688 begin 689 result:=Align(tg.direction*tg.lasttemp,current_settings.alignment.localalignmin); 690 end; 691 692 693 procedure tcgprocinfo.printproc(pass:string); 694 begin 695 assign(printnodefile,treelogfilename); 696 {$push}{$I-} 697 append(printnodefile); 698 if ioresult<>0 then 699 rewrite(printnodefile); 700 {$pop} 701 if ioresult<>0 then 702 begin 703 Comment(V_Error,'Error creating '+treelogfilename); 704 exit; 705 end; 706 writeln(printnodefile); 707 writeln(printnodefile,'*******************************************************************************'); 708 writeln(printnodefile, pass); 709 writeln(printnodefile,procdef.fullprocname(false)); 710 writeln(printnodefile,'*******************************************************************************'); 711 printnode(printnodefile,code); 712 close(printnodefile); 713 end; 714 715 716 procedure tcgprocinfo.maybe_add_constructor_wrapper(var tocode: tnode; withexceptblock: boolean); 717 var 718 oldlocalswitches: tlocalswitches; 719 srsym: tsym; 720 constructionblock, 721 exceptblock, 722 newblock: tblocknode; 723 newstatement: tstatementnode; 724 pd: tprocdef; 725 constructionsuccessful: tlocalvarsym; 726 begin 727 if assigned(procdef.struct) and 728 (procdef.proctypeoption=potype_constructor) then 729 begin 730 withexceptblock:= 731 withexceptblock and 732 not(target_info.system in systems_garbage_collected_managed_types); 733 { Don't test self and the vmt here. See generate_bodyexit_block } 734 { why (JM) } 735 oldlocalswitches:=current_settings.localswitches; 736 current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range]; 737 738 { call AfterConstruction for classes } 739 constructionsuccessful:=nil; 740 if is_class(procdef.struct) then 741 begin 742 constructionsuccessful:=clocalvarsym.create(internaltypeprefixName[itp_vmt_afterconstruction_local],vs_value,ptrsinttype,[]); 743 procdef.localst.insert(constructionsuccessful,false); 744 srsym:=search_struct_member(procdef.struct,'AFTERCONSTRUCTION'); 745 if not assigned(srsym) or 746 (srsym.typ<>procsym) then 747 internalerror(200305106); 748 749 current_filepos:=entrypos; 750 constructionblock:=internalstatements(newstatement); 751 { initialise constructionsuccessful with -1, indicating that 752 the construction was not successful and hence 753 beforedestruction should not be called if a destructor is 754 called from the constructor } 755 addstatement(newstatement,cassignmentnode.create( 756 cloadnode.create(constructionsuccessful,procdef.localst), 757 genintconstnode(-1)) 758 ); 759 { first execute all constructor code. If no exception 760 occurred then we will execute afterconstruction, 761 otherwise we won't (the exception will jump over us) } 762 addstatement(newstatement,tocode); 763 current_filepos:=exitpos; 764 { if implicit finally node wasn't created, then exit label and 765 finalization code must be handled here and placed before 766 afterconstruction } 767 if not ((pi_needs_implicit_finally in flags) and 768 (cs_implicit_exceptions in current_settings.moduleswitches)) then 769 begin 770 include(tocode.flags,nf_block_with_exit); 771 addstatement(newstatement,final_asmnode); 772 cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement); 773 final_used:=true; 774 end; 775 776 { construction successful -> beforedestruction should be called 777 if an exception happens now } 778 addstatement(newstatement,cassignmentnode.create( 779 cloadnode.create(constructionsuccessful,procdef.localst), 780 genintconstnode(1)) 781 ); 782 { Self can be nil when fail is called } 783 { if self<>nil and vmt<>nil then afterconstruction } 784 addstatement(newstatement,cifnode.create( 785 caddnode.create(andn, 786 caddnode.create(unequaln, 787 load_self_node, 788 cnilnode.create), 789 caddnode.create(unequaln, 790 load_vmt_pointer_node, 791 cnilnode.create)), 792 ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil), 793 nil)); 794 tocode:=constructionblock; 795 end; 796 797 if withexceptblock and (procdef.struct.typ=objectdef) then 798 begin 799 { Generate the implicit "fail" code for a constructor (destroy 800 in case an exception happened) } 801 pd:=tobjectdef(procdef.struct).find_destructor; 802 { this will always be the case for classes, since tobject has 803 a destructor } 804 if assigned(pd) or is_object(procdef.struct) then 805 begin 806 current_filepos:=exitpos; 807 exceptblock:=internalstatements(newstatement); 808 { first free the instance if non-nil } 809 if assigned(pd) then 810 { if vmt<>0 then call destructor } 811 addstatement(newstatement, 812 cifnode.create( 813 caddnode.create(unequaln, 814 load_vmt_pointer_node, 815 cnilnode.create), 816 { cnf_create_failed -> don't call BeforeDestruction } 817 ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[cnf_create_failed],nil), 818 nil)) 819 else 820 { object without destructor, call 'fail' helper } 821 addstatement(newstatement, 822 ccallnode.createintern('fpc_help_fail', 823 ccallparanode.create( 824 cordconstnode.create(tobjectdef(procdef.struct).vmt_offset,s32inttype,false), 825 ccallparanode.create( 826 ctypeconvnode.create_internal( 827 load_vmt_pointer_node, 828 voidpointertype), 829 ccallparanode.create( 830 ctypeconvnode.create_internal( 831 load_self_pointer_node, 832 voidpointertype), 833 nil)))) 834 ); 835 { then re-raise the exception } 836 addstatement(newstatement,craisenode.create(nil,nil,nil)); 837 current_filepos:=entrypos; 838 newblock:=internalstatements(newstatement); 839 { try 840 tocode 841 except 842 exceptblock 843 end 844 } 845 addstatement(newstatement,ctryexceptnode.create( 846 tocode, 847 nil, 848 exceptblock)); 849 tocode:=newblock; 850 end; 851 end; 852 current_settings.localswitches:=oldlocalswitches; 853 end; 854 end; 855 856 857 procedure tcgprocinfo.add_entry_exit_code; 858 var 859 finalcode, 860 bodyentrycode, 861 bodyexitcode, 862 wrappedbody, 863 newblock : tnode; 864 codestatement, 865 newstatement : tstatementnode; 866 oldfilepos : tfileposinfo; 867 is_constructor: boolean; 868 begin 869 is_constructor:=assigned(procdef.struct) and 870 (procdef.proctypeoption=potype_constructor); 871 872 oldfilepos:=current_filepos; 873 { Generate code/locations used at start of proc } 874 current_filepos:=entrypos; 875 entry_asmnode:=casmnode.create_get_position; 876 loadpara_asmnode:=casmnode.create_get_position; 877 stackcheck_asmnode:=casmnode.create_get_position; 878 init_asmnode:=casmnode.create_get_position; 879 bodyentrycode:=generate_bodyentry_block; 880 { Generate code/locations used at end of proc } 881 current_filepos:=exitpos; 882 exitlabel_asmnode:=casmnode.create_get_position; 883 final_asmnode:=casmnode.create_get_position; 884 final_used:=false; 885 bodyexitcode:=generate_bodyexit_block; 886 { Check if bodyexitcode is not empty } 887 with tstatementnode(tblocknode(bodyexitcode).statements) do 888 if (statement.nodetype<>nothingn) or assigned(next) then 889 { Indicate that the extra code is executed after the exit statement } 890 include(flowcontrol,fc_no_direct_exit); 891 892 { Generate procedure by combining init+body+final, 893 depending on the implicit finally we need to add 894 an try...finally...end wrapper } 895 current_filepos:=entrypos; 896 newblock:=internalstatements(newstatement); 897 { initialization is common for all cases } 898 addstatement(newstatement,loadpara_asmnode); 899 addstatement(newstatement,stackcheck_asmnode); 900 addstatement(newstatement,entry_asmnode); 901 cnodeutils.procdef_block_add_implicit_initialize_nodes(procdef,newstatement); 902 addstatement(newstatement,init_asmnode); 903 if assigned(procdef.parentfpinitblock) then 904 begin 905 if assigned(tblocknode(procdef.parentfpinitblock).left) then 906 begin 907 { could be an asmn in case of a pure assembler procedure, 908 but those shouldn't access nested variables } 909 addstatement(newstatement,procdef.parentfpinitblock); 910 end 911 else 912 procdef.parentfpinitblock.free; 913 procdef.parentfpinitblock:=nil; 914 end; 915 addstatement(newstatement,bodyentrycode); 916 917 if (cs_implicit_exceptions in current_settings.moduleswitches) and 918 (pi_needs_implicit_finally in flags) and 919 { but it's useless in init/final code of units } 920 not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and 921 not(target_info.system in systems_garbage_collected_managed_types) then 922 begin 923 { Any result of managed type must be returned in parameter } 924 if is_managed_type(procdef.returndef) and 925 (not paramanager.ret_in_param(procdef.returndef,procdef)) and 926 (not is_class(procdef.returndef)) then 927 InternalError(2013121301); 928 929 { Generate special exception block only needed when 930 implicit finaly is used } 931 current_filepos:=exitpos; 932 { Generate code that will be in the try...finally } 933 finalcode:=internalstatements(codestatement); 934 addstatement(codestatement,final_asmnode); 935 cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,codestatement); 936 final_used:=true; 937 938 current_filepos:=entrypos; 939 wrappedbody:=ctryfinallynode.create_implicit(code,finalcode); 940 { afterconstruction must be called after final_asmnode, because it 941 has to execute after the temps have been finalised in case of a 942 refcounted class (afterconstruction decreases the refcount 943 without freeing the instance if the count becomes nil, while 944 the finalising of the temps can free the instance) } 945 maybe_add_constructor_wrapper(wrappedbody,true); 946 addstatement(newstatement,wrappedbody); 947 addstatement(newstatement,exitlabel_asmnode); 948 addstatement(newstatement,bodyexitcode); 949 { set flag the implicit finally has been generated } 950 include(flags,pi_has_implicit_finally); 951 end 952 else 953 begin 954 { constructors need destroy-on-exception code even if they don't 955 have managed variables/temps } 956 maybe_add_constructor_wrapper(code, 957 cs_implicit_exceptions in current_settings.moduleswitches); 958 current_filepos:=entrypos; 959 addstatement(newstatement,code); 960 current_filepos:=exitpos; 961 if assigned(nestedexitlabel) then 962 addstatement(newstatement,clabelnode.create(cnothingnode.create,nestedexitlabel)); 963 addstatement(newstatement,exitlabel_asmnode); 964 addstatement(newstatement,bodyexitcode); 965 if not is_constructor then 966 begin 967 addstatement(newstatement,final_asmnode); 968 cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement); 969 final_used:=true; 970 end; 971 end; 972 if not final_used then 973 begin 974 current_filepos:=exitpos; 975 cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement); 976 end; 977 do_firstpass(newblock); 978 code:=newblock; 979 current_filepos:=oldfilepos; 980 end; 981 982 983 procedure clearrefs(p:TObject;arg:pointer); 984 begin 985 if (tsym(p).typ in [localvarsym,paravarsym,staticvarsym]) then 986 if tabstractvarsym(p).refs>1 then 987 tabstractvarsym(p).refs:=1; 988 end; 989 990 991 procedure translate_registers(p:TObject;list:pointer); 992 begin 993 if (tsym(p).typ in [localvarsym,paravarsym,staticvarsym]) and 994 (tabstractnormalvarsym(p).localloc.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_MMREGISTER, 995 LOC_CMMREGISTER,LOC_FPUREGISTER,LOC_CFPUREGISTER]) then 996 begin 997 if not(cs_no_regalloc in current_settings.globalswitches) then 998 begin 999 cg.translate_register(tabstractnormalvarsym(p).localloc.register); 1000 if (tabstractnormalvarsym(p).localloc.registerhi<>NR_NO) then 1001 cg.translate_register(tabstractnormalvarsym(p).localloc.registerhi); 1002 end; 1003 end; 1004 end; 1005 1006 1007 {$if defined(i386) or defined(x86_64) or defined(arm)} 1008 const 1009 exception_flags: array[boolean] of tprocinfoflags = ( 1010 [], 1011 [pi_uses_exceptions,pi_needs_implicit_finally,pi_has_implicit_finally] 1012 ); 1013 {$endif} 1014 1015 procedure tcgprocinfo.setup_tempgen; 1016 begin 1017 tg:=tgobjclass.create; 1018 1019 {$if defined(i386) or defined(x86_64) or defined(arm)} 1020 {$if defined(arm)} 1021 { frame and stack pointer must be always the same on arm thumb so it makes no 1022 sense to fiddle with a frame pointer } 1023 if GenerateThumbCode then 1024 begin 1025 framepointer:=NR_STACK_POINTER_REG; 1026 tg.direction:=1; 1027 end 1028 else 1029 {$endif defined(arm)} 1030 begin 1031 { try to strip the stack frame } 1032 { set the framepointer to esp if: 1033 - no assembler directive, those are handled in assembler_block 1034 in pstatment.pas (for cases not caught by the Delphi 1035 exception below) 1036 - no exceptions are used 1037 - no pushes are used/esp modifications, could be: 1038 * outgoing parameters on the stack on non-fixed stack target 1039 * incoming parameters on the stack 1040 * open arrays 1041 - no inline assembler 1042 or 1043 - Delphi mode 1044 - assembler directive 1045 - no pushes are used/esp modifications, could be: 1046 * outgoing parameters on the stack 1047 * incoming parameters on the stack 1048 * open arrays 1049 - no local variables 1050 1051 - stack frame cannot be optimized if using Win64 SEH 1052 (at least with the current state of our codegenerator). 1053 } 1054 if ((po_assembler in procdef.procoptions) and 1055 (m_delphi in current_settings.modeswitches) and 1056 { localst at main_program_level is a staticsymtable } 1057 (procdef.localst.symtablelevel<>main_program_level) and 1058 (tabstractlocalsymtable(procdef.localst).count_locals = 0)) or 1059 ((cs_opt_stackframe in current_settings.optimizerswitches) and 1060 not(cs_generate_stackframes in current_settings.localswitches) and 1061 not(cs_profile in current_settings.moduleswitches) and 1062 not(po_assembler in procdef.procoptions) and 1063 not ((pi_has_stackparameter in flags) 1064 {$ifndef arm} { Outgoing parameter(s) on stack do not need stackframe on x86 targets 1065 with fixed stack. On ARM it fails, see bug #25050 } 1066 and (not paramanager.use_fixed_stack) 1067 {$endif arm} 1068 ) and 1069 ((flags*([pi_has_assembler_block,pi_is_assembler, 1070 pi_needs_stackframe]+ 1071 exception_flags[(target_info.cpu=cpu_i386) 1072 {$ifndef DISABLE_WIN64_SEH} 1073 or (target_info.system=system_x86_64_win64) 1074 {$endif DISABLE_WIN64_SEH} 1075 ]))=[]) 1076 ) 1077 then 1078 begin 1079 { we need the parameter info here to determine if the procedure gets 1080 parameters on the stack 1081 1082 calling generate_parameter_info doesn't hurt but it costs time 1083 (necessary to init para_stack_size) 1084 } 1085 generate_parameter_info; 1086 1087 if not(procdef.stack_tainting_parameter(calleeside)) and 1088 not(has_assembler_child) and (para_stack_size=0) then 1089 begin 1090 { Only need to set the framepointer } 1091 framepointer:=NR_STACK_POINTER_REG; 1092 tg.direction:=1; 1093 end 1094 {$if defined(arm)} 1095 { On arm, the stack frame size can be estimated to avoid using an extra frame pointer, 1096 in case parameters are passed on the stack. 1097 1098 However, the draw back is, if the estimation fails, compilation will break later on 1099 with an internal error, so this switch is not enabled by default yet. To overcome this, 1100 multipass compilation of subroutines must be supported 1101 } 1102 else if (cs_opt_forcenostackframe in current_settings.optimizerswitches) and 1103 not(has_assembler_child) then 1104 begin 1105 { Only need to set the framepointer } 1106 framepointer:=NR_STACK_POINTER_REG; 1107 tg.direction:=1; 1108 include(flags,pi_estimatestacksize); 1109 set_first_temp_offset; 1110 procdef.has_paraloc_info:=callnoside; 1111 generate_parameter_info; 1112 exit; 1113 end; 1114 {$endif defined(arm)} 1115 end; 1116 end; 1117 {$endif defined(x86) or defined(arm)} 1118 { set the start offset to the start of the temp area in the stack } 1119 set_first_temp_offset; 1120 end; 1121 tcgprocinfo.has_assembler_childnull1122 function tcgprocinfo.has_assembler_child : boolean; 1123 var 1124 hp : tprocinfo; 1125 begin 1126 result:=false; 1127 hp:=get_first_nestedproc; 1128 while assigned(hp) do 1129 begin 1130 if (hp.flags*[pi_has_assembler_block,pi_is_assembler])<>[] then 1131 begin 1132 result:=true; 1133 exit; 1134 end; 1135 hp:=tprocinfo(hp.next); 1136 end; 1137 end; 1138 1139 procedure tcgprocinfo.generate_code_tree; 1140 var 1141 hpi : tcgprocinfo; 1142 begin 1143 { generate code for this procedure } 1144 generate_code; 1145 { process nested procedures } 1146 hpi:=tcgprocinfo(get_first_nestedproc); 1147 while assigned(hpi) do 1148 begin 1149 hpi.generate_code_tree; 1150 hpi:=tcgprocinfo(hpi.next); 1151 end; 1152 resetprocdef; 1153 end; 1154 1155 { For SEH, the code from 'finally' blocks must be put into a separate procedures, 1156 which can be called by OS during stack unwind. This resembles nested procedures, 1157 but finalizer procedures do not have their own local variables and work directly 1158 with the stack frame of parent. In particular, the tempgen must be shared, so 1159 1) finalizer procedure is able to finalize temps of the parent, 1160 2) if the finalizer procedure is complex enough to need its own temps, they are 1161 allocated in stack frame of parent, so second-level finalizer procedures are 1162 not needed. 1163 1164 Due to requirement of shared tempgen we cannot process finalizer as a regular nested 1165 procedure (after the parent) and have to do it inline. 1166 This is called by platform-specific tryfinallynodes during pass2. 1167 Here we put away the codegen (which carries the register allocator state), process 1168 the 'nested' procedure, then restore previous cg and continue processing the parent 1169 procedure. generate_code() will create another cg, but not another tempgen because 1170 setup_tempgen() is not called for potype_exceptfilter procedures. } 1171 1172 procedure tcgprocinfo.generate_exceptfilter(nestedpi: tcgprocinfo); 1173 var 1174 saved_cg: tcg; 1175 saved_hlcg: thlcgobj; 1176 {$ifdef cpu64bitalu} 1177 saved_cg128 : tcg128; 1178 {$else cpu64bitalu} 1179 saved_cg64 : tcg64; 1180 {$endif cpu64bitalu} 1181 begin 1182 if nestedpi.procdef.proctypeoption<>potype_exceptfilter then 1183 InternalError(201201141); 1184 { flush code generated this far } 1185 aktproccode.concatlist(current_asmdata.CurrAsmList); 1186 { save the codegen } 1187 saved_cg:=cg; 1188 saved_hlcg:=hlcg; 1189 cg:=nil; 1190 hlcg:=nil; 1191 {$ifdef cpu64bitalu} 1192 saved_cg128:=cg128; 1193 cg128:=nil; 1194 {$else cpu64bitalu} 1195 saved_cg64:=cg64; 1196 cg64:=nil; 1197 {$endif cpu64bitalu} 1198 nestedpi.generate_code; 1199 { prevents generating code the second time when processing nested procedures } 1200 nestedpi.resetprocdef; 1201 cg:=saved_cg; 1202 hlcg:=saved_hlcg; 1203 {$ifdef cpu64bitalu} 1204 cg128:=saved_cg128; 1205 {$else cpu64bitalu} 1206 cg64:=saved_cg64; 1207 {$endif cpu64bitalu} 1208 add_reg_instruction_hook:=@cg.add_reg_instruction; 1209 end; 1210 1211 1212 procedure TCGProcinfo.CreateInlineInfo; 1213 begin 1214 new(procdef.inlininginfo); 1215 procdef.inlininginfo^.code:=code.getcopy; 1216 procdef.inlininginfo^.flags:=flags; 1217 { The blocknode needs to set an exit label } 1218 if procdef.inlininginfo^.code.nodetype=blockn then 1219 include(procdef.inlininginfo^.code.flags,nf_block_with_exit); 1220 procdef.has_inlininginfo:=true; 1221 end; 1222 1223 searchusercodenull1224 function searchusercode(var n: tnode; arg: pointer): foreachnoderesult; 1225 begin 1226 if nf_usercode_entry in n.flags then 1227 begin 1228 pnode(arg)^:=n; 1229 result:=fen_norecurse_true 1230 end 1231 else 1232 result:=fen_false; 1233 end; 1234 1235 TCGProcinfo.GetUserCodenull1236 function TCGProcinfo.GetUserCode : tnode; 1237 var 1238 n : tnode; 1239 begin 1240 n:=nil; 1241 foreachnodestatic(code,@searchusercode,@n); 1242 if not(assigned(n)) then 1243 internalerror(2013111004); 1244 result:=n; 1245 end; 1246 1247 1248 procedure tcgprocinfo.generate_code; 1249 var 1250 old_current_procinfo : tprocinfo; 1251 oldmaxfpuregisters : longint; 1252 oldfilepos : tfileposinfo; 1253 old_current_structdef : tabstractrecorddef; 1254 templist : TAsmList; 1255 headertai : tai; 1256 i : integer; 1257 {RedoDFA : boolean;} 1258 1259 procedure delete_marker(anode: tasmnode); 1260 var 1261 ai: tai; 1262 begin 1263 if assigned(anode) then 1264 begin 1265 ai:=anode.currenttai; 1266 if assigned(ai) then 1267 begin 1268 aktproccode.remove(ai); 1269 ai.free; 1270 anode.currenttai:=nil; 1271 end; 1272 end; 1273 end; 1274 1275 begin 1276 { the initialization procedure can be empty, then we 1277 don't need to generate anything. When it was an empty 1278 procedure there would be at least a blocknode } 1279 if not assigned(code) then 1280 exit; 1281 1282 { We need valid code } 1283 if Errorcount<>0 then 1284 exit; 1285 1286 { No code can be generated for generic template } 1287 if (df_generic in procdef.defoptions) then 1288 internalerror(200511152); 1289 1290 { For regular procedures the RA and Tempgen shall not be available yet, 1291 but exception filters reuse Tempgen of parent } 1292 if assigned(tg)<>(procdef.proctypeoption=potype_exceptfilter) then 1293 internalerror(200309201); 1294 1295 old_current_procinfo:=current_procinfo; 1296 oldfilepos:=current_filepos; 1297 old_current_structdef:=current_structdef; 1298 oldmaxfpuregisters:=current_settings.maxfpuregisters; 1299 1300 current_procinfo:=self; 1301 current_filepos:=entrypos; 1302 current_structdef:=procdef.struct; 1303 1304 { store start of user code, it must be a block node, it will be used later one to 1305 check variable lifeness } 1306 include(code.flags,nf_usercode_entry); 1307 1308 { add wrapping code if necessary (initialization of typed constants on 1309 some platforms, initing of local variables and out parameters with 1310 trashing values, ...) } 1311 { init/final code must be wrapped later (after code for main proc body 1312 has been generated) } 1313 if not(current_procinfo.procdef.proctypeoption in [potype_unitinit,potype_unitfinalize]) then 1314 code:=cnodeutils.wrap_proc_body(procdef,code); 1315 1316 { automatic inlining? } 1317 if (cs_opt_autoinline in current_settings.optimizerswitches) and 1318 { inlining not turned off? } 1319 (cs_do_inline in current_settings.localswitches) and 1320 { no inlining yet? } 1321 not(procdef.has_inlininginfo) and not(has_nestedprocs) and 1322 not(procdef.proctypeoption in [potype_proginit,potype_unitinit,potype_unitfinalize,potype_constructor, 1323 potype_destructor,potype_class_constructor,potype_class_destructor]) and 1324 ((procdef.procoptions*[po_exports,po_external,po_interrupt,po_virtualmethod,po_iocheck])=[]) and 1325 (not(procdef.proccalloption in [pocall_safecall])) and 1326 { rough approximation if we should auto inline } 1327 (node_count(code)<=10) then 1328 begin 1329 { Can we inline this procedure? } 1330 if checknodeinlining(procdef) then 1331 begin 1332 Message1(cg_d_autoinlining,procdef.GetTypeName); 1333 include(procdef.procoptions,po_inline); 1334 CreateInlineInfo; 1335 end; 1336 end; 1337 1338 templist:=TAsmList.create; 1339 1340 { add parast/localst to symtablestack } 1341 add_to_symtablestack; 1342 1343 { clear register count } 1344 procdef.localst.SymList.ForEachCall(@clearrefs,nil); 1345 procdef.parast.SymList.ForEachCall(@clearrefs,nil); 1346 1347 { there's always a call to FPC_INITIALIZEUNITS/FPC_DO_EXIT in the main program } 1348 if (procdef.localst.symtablelevel=main_program_level) and 1349 (not current_module.is_unit) then 1350 begin 1351 include(flags,pi_do_call); 1352 { the main program never returns due to the do_exit call } 1353 if not(current_module.islibrary) and (procdef.proctypeoption=potype_proginit) then 1354 include(procdef.procoptions,po_noreturn); 1355 end; 1356 1357 { set implicit_finally flag when there are locals/paras to be finalized } 1358 if not(po_assembler in current_procinfo.procdef.procoptions) then 1359 begin 1360 procdef.parast.SymList.ForEachCall(@check_finalize_paras,nil); 1361 procdef.localst.SymList.ForEachCall(@check_finalize_locals,nil); 1362 end; 1363 1364 {$ifdef SUPPORT_SAFECALL} 1365 { set implicit_finally flag for if procedure is safecall } 1366 if (tf_safecall_exceptions in target_info.flags) and 1367 (procdef.proccalloption=pocall_safecall) then 1368 include(flags, pi_needs_implicit_finally); 1369 {$endif} 1370 { firstpass everything } 1371 flowcontrol:=[]; 1372 do_firstpass(code); 1373 1374 {$if defined(i386) or defined(i8086)} 1375 if node_resources_fpu(code)>0 then 1376 include(flags,pi_uses_fpu); 1377 {$endif i386 or i8086} 1378 1379 { Print the node to tree.log } 1380 if paraprintnodetree=1 then 1381 printproc( 'after the firstpass'); 1382 1383 { do this before adding the entry code else the tail recursion recognition won't work, 1384 if this causes troubles, it must be if'ed 1385 } 1386 if (cs_opt_tailrecursion in current_settings.optimizerswitches) and 1387 (pi_is_recursive in flags) then 1388 do_opttail(code,procdef); 1389 1390 if cs_opt_constant_propagate in current_settings.optimizerswitches then 1391 do_optconstpropagate(code); 1392 1393 if (cs_opt_nodedfa in current_settings.optimizerswitches) and 1394 { creating dfa is not always possible } 1395 ((flags*[pi_has_assembler_block,pi_uses_exceptions,pi_is_assembler])=[]) then 1396 begin 1397 dfabuilder:=TDFABuilder.Create; 1398 dfabuilder.createdfainfo(code); 1399 include(flags,pi_dfaavailable); 1400 1401 { when life info is available, we can give more sophisticated warning about uninitialized 1402 variables ... 1403 ... but not for the finalization section of a unit, we would need global dfa to handle 1404 it properly } 1405 if potype_unitfinalize<>procdef.proctypeoption then 1406 { iterate through life info of the first node } 1407 for i:=0 to dfabuilder.nodemap.count-1 do 1408 begin 1409 if DFASetIn(GetUserCode.optinfo^.life,i) then 1410 begin 1411 { do not warn for certain parameters: } 1412 if not((tnode(dfabuilder.nodemap[i]).nodetype=loadn) and (tloadnode(dfabuilder.nodemap[i]).symtableentry.typ=paravarsym) and 1413 { do not warn about parameters passed by var } 1414 (((tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varspez=vs_var) and 1415 { function result is passed by var but it must be initialized } 1416 not(vo_is_funcret in tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varoptions)) or 1417 { do not warn about initialized hidden parameters } 1418 ((tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varoptions*[vo_is_high_para,vo_is_parentfp,vo_is_result,vo_is_self])<>[]))) then 1419 CheckAndWarn(GetUserCode,tnode(dfabuilder.nodemap[i])); 1420 end 1421 else 1422 begin 1423 if (tnode(dfabuilder.nodemap[i]).nodetype=loadn) and 1424 (tloadnode(dfabuilder.nodemap[i]).symtableentry.typ in [staticvarsym,localvarsym]) then 1425 tabstractnormalvarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).noregvarinitneeded:=true 1426 end; 1427 end; 1428 end; 1429 1430 if (pi_dfaavailable in flags) and (cs_opt_dead_store_eliminate in current_settings.optimizerswitches) then 1431 do_optdeadstoreelim(code); 1432 1433 if (cs_opt_loopstrength in current_settings.optimizerswitches) 1434 { our induction variable strength reduction doesn't like 1435 for loops with more than one entry } 1436 and not(pi_has_label in flags) then 1437 begin 1438 {RedoDFA:=}OptimizeInductionVariables(code); 1439 end; 1440 1441 if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and 1442 (procdef.proctypeoption in [potype_operator,potype_procedure,potype_function]) and 1443 (code.nodetype=blockn) and (tblocknode(code).statements=nil) then 1444 procdef.isempty:=true; 1445 1446 { add implicit entry and exit code } 1447 add_entry_exit_code; 1448 1449 if cs_opt_nodecse in current_settings.optimizerswitches then 1450 do_optcse(code); 1451 1452 if cs_opt_use_load_modify_store in current_settings.optimizerswitches then 1453 do_optloadmodifystore(code); 1454 1455 { only do secondpass if there are no errors } 1456 if (ErrorCount=0) then 1457 begin 1458 create_hlcodegen; 1459 1460 if (procdef.proctypeoption<>potype_exceptfilter) then 1461 setup_tempgen; 1462 1463 { Create register allocator, must come after framepointer is known } 1464 hlcg.init_register_allocators; 1465 1466 generate_parameter_info; 1467 1468 { allocate got register if needed } 1469 allocate_got_register(aktproccode); 1470 1471 { Allocate space in temp/registers for parast and localst } 1472 current_filepos:=entrypos; 1473 gen_alloc_symtable(aktproccode,procdef,procdef.parast); 1474 gen_alloc_symtable(aktproccode,procdef,procdef.localst); 1475 1476 { Store temp offset for information about 'real' temps } 1477 tempstart:=tg.lasttemp; 1478 1479 { Generate code to load register parameters in temps and insert local 1480 copies for values parameters. This must be done before the code for the 1481 body is generated because the localloc is updated. 1482 Note: The generated code will be inserted after the code generation of 1483 the body is finished, because only then the position is known } 1484 {$ifdef oldregvars} 1485 assign_regvars(code); 1486 {$endif oldreg} 1487 current_filepos:=entrypos; 1488 1489 hlcg.gen_load_para_value(templist); 1490 1491 { caller paraloc info is also necessary in the stackframe_entry 1492 code of the ppc (and possibly other processors) } 1493 procdef.init_paraloc_info(callerside); 1494 1495 CalcExecutionWeights(code); 1496 1497 { Print the node to tree.log } 1498 if paraprintnodetree=1 then 1499 printproc( 'right before code generation'); 1500 1501 { generate code for the node tree } 1502 do_secondpass(code); 1503 aktproccode.concatlist(current_asmdata.CurrAsmList); 1504 1505 { The position of the loadpara_asmnode is now known } 1506 aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist); 1507 1508 { first generate entry and initialize code with the correct 1509 position and switches } 1510 current_filepos:=entrypos; 1511 current_settings.localswitches:=entryswitches; 1512 1513 cg.set_regalloc_live_range_direction(rad_backwards); 1514 1515 hlcg.gen_entry_code(templist); 1516 aktproccode.insertlistafter(entry_asmnode.currenttai,templist); 1517 hlcg.gen_initialize_code(templist); 1518 aktproccode.insertlistafter(init_asmnode.currenttai,templist); 1519 1520 { now generate finalize and exit code with the correct position 1521 and switches } 1522 current_filepos:=exitpos; 1523 current_settings.localswitches:=exitswitches; 1524 1525 cg.set_regalloc_live_range_direction(rad_forward); 1526 1527 if assigned(finalize_procinfo) then 1528 generate_exceptfilter(tcgprocinfo(finalize_procinfo)) 1529 else 1530 begin 1531 hlcg.gen_finalize_code(templist); 1532 { the finalcode must be concated if there was no position available, 1533 using insertlistafter will result in an insert at the start 1534 when currentai=nil } 1535 if assigned(final_asmnode) and assigned(final_asmnode.currenttai) then 1536 aktproccode.insertlistafter(final_asmnode.currenttai,templist) 1537 else 1538 aktproccode.concatlist(templist); 1539 end; 1540 { insert exit label at the correct position } 1541 hlcg.a_label(templist,CurrExitLabel); 1542 if assigned(exitlabel_asmnode.currenttai) then 1543 aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist) 1544 else 1545 aktproccode.concatlist(templist); 1546 { exit code } 1547 hlcg.gen_exit_code(templist); 1548 aktproccode.concatlist(templist); 1549 1550 {$ifdef OLDREGVARS} 1551 { note: this must be done only after as much code as possible has } 1552 { been generated. The result is that when you ungetregister() a } 1553 { regvar, it will actually free the regvar (and alse free the } 1554 { the regvars at the same time). Doing this too early will } 1555 { confuse the register allocator, as the regvars will still be } 1556 { used. It should be done before loading the result regs (so } 1557 { they don't conflict with the regvars) and before } 1558 { gen_entry_code (that one has to be able to allocate the } 1559 { regvars again) (JM) } 1560 free_regvars(aktproccode); 1561 {$endif OLDREGVARS} 1562 1563 { generate symbol and save end of header position } 1564 current_filepos:=entrypos; 1565 hlcg.gen_proc_symbol(templist); 1566 headertai:=tai(templist.last); 1567 { insert symbol } 1568 aktproccode.insertlist(templist); 1569 1570 { Free space in temp/registers for parast and localst, must be 1571 done after gen_entry_code } 1572 current_filepos:=exitpos; 1573 1574 { make sure the got/pic register doesn't get freed in the } 1575 { middle of a loop } 1576 if (cs_create_pic in current_settings.moduleswitches) and 1577 (pi_needs_got in flags) and 1578 (got<>NR_NO) then 1579 cg.a_reg_sync(aktproccode,got); 1580 1581 gen_free_symtable(aktproccode,procdef.localst); 1582 gen_free_symtable(aktproccode,procdef.parast); 1583 1584 { add code that will load the return value, this is not done 1585 for assembler routines when they didn't reference the result 1586 variable } 1587 hlcg.gen_load_return_value(templist); 1588 aktproccode.concatlist(templist); 1589 1590 { Already reserve all registers for stack checking code and 1591 generate the call to the helper function } 1592 if not(tf_no_generic_stackcheck in target_info.flags) and 1593 (cs_check_stack in entryswitches) and 1594 not(po_assembler in procdef.procoptions) and 1595 (procdef.proctypeoption<>potype_proginit) then 1596 begin 1597 current_filepos:=entrypos; 1598 hlcg.gen_stack_check_call(templist); 1599 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist) 1600 end; 1601 1602 { this code (got loading) comes before everything which has } 1603 { already been generated, so reset the info about already } 1604 { backwards extended registers (so their live range can be } 1605 { extended backwards even further if needed) } 1606 { This code must be } 1607 { a) generated after do_secondpass has been called } 1608 { (because pi_needs_got may be set there) } 1609 { b) generated before register allocation, because the } 1610 { got/pic register can be a virtual one } 1611 { c) inserted before the entry code, because the entry } 1612 { code may need global symbols such as init rtti } 1613 { d) inserted after the stackframe allocation, because } 1614 { this register may have to be spilled } 1615 cg.set_regalloc_live_range_direction(rad_backwards_reinit); 1616 current_filepos:=entrypos; 1617 { load got if necessary } 1618 cg.g_maybe_got_init(templist); 1619 1620 aktproccode.insertlistafter(headertai,templist); 1621 1622 { re-enable if more code at the end is ever generated here 1623 cg.set_regalloc_live_range_direction(rad_forward); 1624 } 1625 1626 1627 {$ifndef NoOpt} 1628 {$ifndef i386} 1629 if (cs_opt_scheduler in current_settings.optimizerswitches) and 1630 { do not optimize pure assembler procedures } 1631 not(pi_is_assembler in flags) then 1632 preregallocschedule(aktproccode); 1633 {$endif i386} 1634 {$endif NoOpt} 1635 1636 { The procedure body is finished, we can now 1637 allocate the registers } 1638 cg.do_register_allocation(aktproccode,headertai); 1639 1640 { translate imag. register to their real counter parts 1641 this is necessary for debuginfo and verbose assembler output 1642 when SSA will be implented, this will be more complicated because we've to 1643 maintain location lists } 1644 procdef.parast.SymList.ForEachCall(@translate_registers,templist); 1645 procdef.localst.SymList.ForEachCall(@translate_registers,templist); 1646 if (cs_create_pic in current_settings.moduleswitches) and 1647 (pi_needs_got in flags) and 1648 not(cs_no_regalloc in current_settings.globalswitches) and 1649 (got<>NR_NO) then 1650 cg.translate_register(got); 1651 1652 { Add save and restore of used registers } 1653 current_filepos:=entrypos; 1654 gen_save_used_regs(templist); 1655 { Remember the last instruction of register saving block 1656 (may be =nil for e.g. assembler procedures) } 1657 endprologue_ai:=templist.last; 1658 aktproccode.insertlistafter(headertai,templist); 1659 current_filepos:=exitpos; 1660 gen_restore_used_regs(aktproccode); 1661 { We know the size of the stack, now we can generate the 1662 parameter that is passed to the stack checking code } 1663 if not(tf_no_generic_stackcheck in target_info.flags) and 1664 (cs_check_stack in entryswitches) and 1665 not(po_assembler in procdef.procoptions) and 1666 (procdef.proctypeoption<>potype_proginit) then 1667 begin 1668 current_filepos:=entrypos; 1669 hlcg.gen_stack_check_size_para(templist); 1670 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist) 1671 end; 1672 { Add entry code (stack allocation) after header } 1673 current_filepos:=entrypos; 1674 gen_proc_entry_code(templist); 1675 aktproccode.insertlistafter(headertai,templist); 1676 {$ifdef SUPPORT_SAFECALL} 1677 { Set return value of safecall procedure if implicit try/finally blocks are disabled } 1678 if not (cs_implicit_exceptions in current_settings.moduleswitches) and 1679 (tf_safecall_exceptions in target_info.flags) and 1680 (procdef.proccalloption=pocall_safecall) then 1681 cg.a_load_const_reg(aktproccode,OS_ADDR,0,NR_FUNCTION_RETURN_REG); 1682 {$endif} 1683 { Add exit code at the end } 1684 current_filepos:=exitpos; 1685 gen_proc_exit_code(templist); 1686 aktproccode.concatlist(templist); 1687 1688 { check if the implicit finally has been generated. The flag 1689 should already be set in pass1 } 1690 if (cs_implicit_exceptions in current_settings.moduleswitches) and 1691 not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and 1692 (pi_needs_implicit_finally in flags) and 1693 not(pi_has_implicit_finally in flags) and 1694 not(target_info.system in systems_garbage_collected_managed_types) then 1695 internalerror(200405231); 1696 1697 { Position markers are only used to insert additional code after the secondpass 1698 and before this point. They are of no use in optimizer. Instead of checking and 1699 ignoring all over the optimizer, just remove them here. } 1700 delete_marker(entry_asmnode); 1701 delete_marker(loadpara_asmnode); 1702 delete_marker(exitlabel_asmnode); 1703 delete_marker(stackcheck_asmnode); 1704 delete_marker(init_asmnode); 1705 delete_marker(final_asmnode); 1706 1707 {$ifndef NoOpt} 1708 if not(cs_no_regalloc in current_settings.globalswitches) then 1709 begin 1710 if (cs_opt_level1 in current_settings.optimizerswitches) and 1711 { do not optimize pure assembler procedures } 1712 not(pi_is_assembler in flags) then 1713 optimize(aktproccode); 1714 {$ifndef i386} 1715 { schedule after assembler optimization, it could have brought up 1716 new schedule possibilities } 1717 if (cs_opt_scheduler in current_settings.optimizerswitches) and 1718 { do not optimize pure assembler procedures } 1719 not(pi_is_assembler in flags) then 1720 preregallocschedule(aktproccode); 1721 {$endif i386} 1722 end; 1723 {$endif NoOpt} 1724 1725 { Perform target-specific processing if necessary } 1726 postprocess_code; 1727 1728 { Add end symbol and debug info } 1729 { this must be done after the pcrelativedata is appended else the distance calculation of 1730 insertpcrelativedata will be wrong, further the pc indirect data is part of the procedure 1731 so it should be inserted before the end symbol (FK) 1732 } 1733 current_filepos:=exitpos; 1734 hlcg.gen_proc_symbol_end(templist); 1735 aktproccode.concatlist(templist); 1736 1737 { insert line debuginfo } 1738 if (cs_debuginfo in current_settings.moduleswitches) or 1739 (cs_use_lineinfo in current_settings.globalswitches) then 1740 current_debuginfo.insertlineinfo(aktproccode); 1741 1742 hlcg.record_generated_code_for_procdef(current_procinfo.procdef,aktproccode,aktlocaldata); 1743 1744 { only now we can remove the temps } 1745 if (procdef.proctypeoption<>potype_exceptfilter) then 1746 begin 1747 tg.resettempgen; 1748 tg.free; 1749 tg:=nil; 1750 end; 1751 { stop tempgen and ra } 1752 hlcg.done_register_allocators; 1753 destroy_hlcodegen; 1754 end; 1755 1756 dfabuilder.free; 1757 1758 { restore symtablestack } 1759 remove_from_symtablestack; 1760 1761 { restore } 1762 templist.free; 1763 current_settings.maxfpuregisters:=oldmaxfpuregisters; 1764 current_filepos:=oldfilepos; 1765 current_structdef:=old_current_structdef; 1766 current_procinfo:=old_current_procinfo; 1767 end; 1768 1769 1770 procedure tcgprocinfo.add_to_symtablestack; 1771 begin 1772 { insert symtables for the class, but only if it is no nested function } 1773 if assigned(procdef.struct) and 1774 not(assigned(parent) and 1775 assigned(parent.procdef) and 1776 assigned(parent.procdef.struct)) then 1777 push_nested_hierarchy(procdef.struct); 1778 1779 { insert parasymtable in symtablestack when parsing 1780 a function } 1781 if procdef.parast.symtablelevel>=normal_function_level then 1782 symtablestack.push(procdef.parast); 1783 1784 { insert localsymtable, except for the main procedure 1785 (in that case the localst is the unit's static symtable, 1786 which is already on the stack) } 1787 if procdef.localst.symtablelevel>=normal_function_level then 1788 symtablestack.push(procdef.localst); 1789 end; 1790 1791 1792 procedure tcgprocinfo.remove_from_symtablestack; 1793 begin 1794 { remove localsymtable } 1795 if procdef.localst.symtablelevel>=normal_function_level then 1796 symtablestack.pop(procdef.localst); 1797 1798 { remove parasymtable } 1799 if procdef.parast.symtablelevel>=normal_function_level then 1800 symtablestack.pop(procdef.parast); 1801 1802 { remove symtables for the class, but only if it is no nested function } 1803 if assigned(procdef.struct) and 1804 not(assigned(parent) and 1805 assigned(parent.procdef) and 1806 assigned(parent.procdef.struct)) then 1807 pop_nested_hierarchy(procdef.struct); 1808 end; 1809 1810 1811 procedure tcgprocinfo.resetprocdef; 1812 begin 1813 { remove code tree, if not inline procedure } 1814 if assigned(code) then 1815 begin 1816 { the inline procedure has already got a copy of the tree 1817 stored in procdef.inlininginfo } 1818 code.free; 1819 code:=nil; 1820 end; 1821 end; 1822 1823 1824 procedure tcgprocinfo.parse_body; 1825 var 1826 old_current_procinfo : tprocinfo; 1827 old_block_type : tblock_type; 1828 st : TSymtable; 1829 old_current_structdef: tabstractrecorddef; 1830 old_current_genericdef, 1831 old_current_specializedef: tstoreddef; 1832 parentfpinitblock: tnode; 1833 old_parse_generic: boolean; 1834 recordtokens : boolean; 1835 1836 begin 1837 old_current_procinfo:=current_procinfo; 1838 old_block_type:=block_type; 1839 old_current_structdef:=current_structdef; 1840 old_current_genericdef:=current_genericdef; 1841 old_current_specializedef:=current_specializedef; 1842 old_parse_generic:=parse_generic; 1843 1844 current_procinfo:=self; 1845 current_structdef:=procdef.struct; 1846 1847 1848 { check if the definitions of certain types are available which might not be available in older rtls and 1849 which are assigned "on the fly" in types_dec } 1850 {$ifndef jvm} 1851 if not assigned(rec_exceptaddr) then 1852 Message1(cg_f_internal_type_not_found,'TEXCEPTADDR'); 1853 if not assigned(rec_tguid) then 1854 Message1(cg_f_internal_type_not_found,'TGUID'); 1855 if not assigned(rec_jmp_buf) then 1856 Message1(cg_f_internal_type_not_found,'TJMPBUF'); 1857 {$endif} 1858 1859 { if the procdef is truly a generic (thus takes parameters itself) then 1860 /that/ is our genericdef, not the - potentially - generic struct } 1861 if procdef.is_generic then 1862 begin 1863 current_genericdef:=procdef; 1864 parse_generic:=true; 1865 end 1866 else if assigned(current_structdef) and (df_generic in current_structdef.defoptions) then 1867 begin 1868 current_genericdef:=current_structdef; 1869 parse_generic:=true; 1870 end; 1871 if assigned(current_structdef) and (df_specialization in current_structdef.defoptions) then 1872 current_specializedef:=current_structdef; 1873 1874 { calculate the lexical level } 1875 if procdef.parast.symtablelevel>maxnesting then 1876 Message(parser_e_too_much_lexlevel); 1877 block_type:=bt_body; 1878 1879 {$ifdef state_tracking} 1880 { aktstate:=Tstate_storage.create;} 1881 {$endif state_tracking} 1882 1883 { allocate the symbol for this procedure } 1884 alloc_proc_symbol(procdef); 1885 1886 { add parast/localst to symtablestack } 1887 add_to_symtablestack; 1888 1889 { save entry info } 1890 entrypos:=current_filepos; 1891 entryswitches:=current_settings.localswitches; 1892 1893 recordtokens:=procdef.is_generic or 1894 ( 1895 assigned(procdef.struct) and 1896 (df_generic in procdef.struct.defoptions) and 1897 assigned(procdef.owner) and 1898 (procdef.owner.defowner=procdef.struct) 1899 ); 1900 1901 if recordtokens then 1902 begin 1903 { start token recorder for generic template } 1904 procdef.initgeneric; 1905 current_scanner.startrecordtokens(procdef.generictokenbuf); 1906 end; 1907 1908 { parse the code ... } 1909 code:=block(current_module.islibrary); 1910 1911 if recordtokens then 1912 begin 1913 { stop token recorder for generic template } 1914 current_scanner.stoprecordtokens; 1915 1916 { Give an error for accesses in the static symtable that aren't visible 1917 outside the current unit } 1918 st:=procdef.owner; 1919 while (st.symtabletype in [ObjectSymtable,recordsymtable]) do 1920 st:=st.defowner.owner; 1921 if (pi_uses_static_symtable in flags) and 1922 (st.symtabletype<>staticsymtable) then 1923 Message(parser_e_global_generic_references_static); 1924 end; 1925 1926 { save exit info } 1927 exitswitches:=current_settings.localswitches; 1928 exitpos:=last_endtoken_filepos; 1929 1930 { the procedure is now defined } 1931 procdef.forwarddef:=false; 1932 1933 if assigned(code) then 1934 begin 1935 { get a better entry point } 1936 entrypos:=code.fileinfo; 1937 1938 { Finish type checking pass } 1939 do_typecheckpass(code); 1940 1941 if assigned(procdef.parentfpinitblock) then 1942 begin 1943 if assigned(tblocknode(procdef.parentfpinitblock).left) then 1944 begin 1945 parentfpinitblock:=procdef.parentfpinitblock; 1946 do_typecheckpass(parentfpinitblock); 1947 procdef.parentfpinitblock:=parentfpinitblock; 1948 end 1949 end; 1950 1951 end; 1952 1953 { Check for unused labels, forwards, symbols for procedures. Static 1954 symtable is checked in pmodules. 1955 The check must be done after the typecheckpass } 1956 if (Errorcount=0) and 1957 (tstoredsymtable(procdef.localst).symtabletype<>staticsymtable) then 1958 begin 1959 { check if forwards are resolved } 1960 tstoredsymtable(procdef.localst).check_forwards; 1961 { check if all labels are used } 1962 tstoredsymtable(procdef.localst).checklabels; 1963 { check for unused symbols, but only if there is no asm block } 1964 if not(pi_has_assembler_block in flags) then 1965 begin 1966 tstoredsymtable(procdef.localst).allsymbolsused; 1967 tstoredsymtable(procdef.parast).allsymbolsused; 1968 end; 1969 end; 1970 1971 if (po_inline in procdef.procoptions) and 1972 { Can we inline this procedure? } 1973 checknodeinlining(procdef) then 1974 CreateInlineInfo; 1975 1976 { Print the node to tree.log } 1977 if paraprintnodetree=1 then 1978 printproc( 'after parsing'); 1979 1980 { ... remove symbol tables } 1981 remove_from_symtablestack; 1982 1983 {$ifdef state_tracking} 1984 { aktstate.destroy;} 1985 {$endif state_tracking} 1986 1987 current_structdef:=old_current_structdef; 1988 current_genericdef:=old_current_genericdef; 1989 current_specializedef:=old_current_specializedef; 1990 current_procinfo:=old_current_procinfo; 1991 parse_generic:=old_parse_generic; 1992 1993 { Restore old state } 1994 block_type:=old_block_type; 1995 end; 1996 1997 1998 {**************************************************************************** 1999 PROCEDURE/FUNCTION PARSING 2000 ****************************************************************************} 2001 2002 2003 procedure check_init_paras(p:TObject;arg:pointer); 2004 begin 2005 if tsym(p).typ<>paravarsym then 2006 exit; 2007 with tparavarsym(p) do 2008 if (is_managed_type(vardef) and 2009 (varspez in [vs_value,vs_out])) or 2010 (is_shortstring(vardef) and 2011 (varspez=vs_value)) then 2012 include(current_procinfo.flags,pi_do_call); 2013 end; 2014 2015 2016 procedure read_proc_body(old_current_procinfo:tprocinfo;pd:tprocdef); 2017 { 2018 Parses the procedure directives, then parses the procedure body, then 2019 generates the code for it 2020 } 2021 2022 var 2023 oldfailtokenmode : tmodeswitches; 2024 isnestedproc : boolean; 2025 begin 2026 Message1(parser_d_procedure_start,pd.fullprocname(false)); 2027 oldfailtokenmode:=[]; 2028 2029 { create a new procedure } 2030 current_procinfo:=cprocinfo.create(old_current_procinfo); 2031 current_module.procinfo:=current_procinfo; 2032 current_procinfo.procdef:=pd; 2033 isnestedproc:=(current_procinfo.procdef.parast.symtablelevel>normal_function_level); 2034 2035 { Insert mangledname } 2036 pd.aliasnames.insert(pd.mangledname); 2037 2038 { Handle Export of this procedure } 2039 if (po_exports in pd.procoptions) and 2040 (target_info.system in [system_i386_os2,system_i386_emx]) then 2041 begin 2042 pd.aliasnames.insert(pd.procsym.realname); 2043 if cs_link_deffile in current_settings.globalswitches then 2044 deffile.AddExport(pd.mangledname); 2045 end; 2046 2047 { Insert result variables in the localst } 2048 insert_funcret_local(pd); 2049 2050 { check if there are para's which require initing -> set } 2051 { pi_do_call (if not yet set) } 2052 if not(pi_do_call in current_procinfo.flags) then 2053 pd.parast.SymList.ForEachCall(@check_init_paras,nil); 2054 2055 { set _FAIL as keyword if constructor } 2056 if (pd.proctypeoption=potype_constructor) then 2057 begin 2058 oldfailtokenmode:=tokeninfo^[_FAIL].keyword; 2059 tokeninfo^[_FAIL].keyword:=alllanguagemodes; 2060 end; 2061 2062 tcgprocinfo(current_procinfo).parse_body; 2063 2064 { reset _FAIL as _SELF normal } 2065 if (pd.proctypeoption=potype_constructor) then 2066 tokeninfo^[_FAIL].keyword:=oldfailtokenmode; 2067 2068 { We can't support inlining for procedures that have nested 2069 procedures because the nested procedures use a fixed offset 2070 for accessing locals in the parent procedure (PFV) } 2071 if current_procinfo.has_nestedprocs then 2072 begin 2073 if (po_inline in current_procinfo.procdef.procoptions) then 2074 begin 2075 Message1(parser_h_not_supported_for_inline,'nested procedures'); 2076 Message(parser_h_inlining_disabled); 2077 exclude(current_procinfo.procdef.procoptions,po_inline); 2078 end; 2079 end; 2080 2081 { When it's a nested procedure then defer the code generation, 2082 when back at normal function level then generate the code 2083 for all defered nested procedures and the current procedure } 2084 if not isnestedproc then 2085 begin 2086 if not(df_generic in current_procinfo.procdef.defoptions) then 2087 begin 2088 { also generate the bodies for all previously done 2089 specializations so that we might inline them } 2090 generate_specialization_procs; 2091 tcgprocinfo(current_procinfo).generate_code_tree; 2092 end; 2093 end; 2094 2095 { release procinfo } 2096 if tprocinfo(current_module.procinfo)<>current_procinfo then 2097 internalerror(200304274); 2098 current_module.procinfo:=current_procinfo.parent; 2099 2100 { For specialization we didn't record the last semicolon. Moving this parsing 2101 into the parse_body routine is not done because of having better file position 2102 information available } 2103 if not current_procinfo.procdef.is_specialization and 2104 ( 2105 not assigned(current_procinfo.procdef.struct) or 2106 not (df_specialization in current_procinfo.procdef.struct.defoptions) 2107 or not ( 2108 assigned(current_procinfo.procdef.owner) and 2109 (current_procinfo.procdef.owner.defowner=current_procinfo.procdef.struct) 2110 ) 2111 ) then 2112 consume(_SEMICOLON); 2113 2114 if not isnestedproc then 2115 { current_procinfo is checked for nil later on } 2116 freeandnil(current_procinfo); 2117 end; 2118 2119 2120 procedure read_proc_body(pd:tprocdef); 2121 var 2122 old_module_procinfo : tobject; 2123 old_current_procinfo : tprocinfo; 2124 begin 2125 old_current_procinfo:=current_procinfo; 2126 old_module_procinfo:=current_module.procinfo; 2127 current_procinfo:=nil; 2128 current_module.procinfo:=nil; 2129 read_proc_body(nil,pd); 2130 current_procinfo:=old_current_procinfo; 2131 current_module.procinfo:=old_module_procinfo; 2132 end; 2133 2134 2135 procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean); 2136 { 2137 Parses the procedure directives, then parses the procedure body, then 2138 generates the code for it 2139 } 2140 2141 var 2142 old_current_procinfo : tprocinfo; 2143 old_current_structdef: tabstractrecorddef; 2144 old_current_genericdef, 2145 old_current_specializedef: tstoreddef; 2146 pdflags : tpdflags; 2147 def,pd,firstpd : tprocdef; 2148 srsym : tsym; 2149 i : longint; 2150 begin 2151 { save old state } 2152 old_current_procinfo:=current_procinfo; 2153 old_current_structdef:=current_structdef; 2154 old_current_genericdef:=current_genericdef; 2155 old_current_specializedef:=current_specializedef; 2156 2157 { reset current_procinfo.procdef to nil to be sure that nothing is writing 2158 to another procdef } 2159 current_procinfo:=nil; 2160 current_structdef:=nil; 2161 current_genericdef:=nil; 2162 current_specializedef:=nil; 2163 2164 if not assigned(usefwpd) then 2165 { parse procedure declaration } 2166 pd:=parse_proc_dec(isclassmethod,old_current_structdef,isgeneric) 2167 else 2168 pd:=usefwpd; 2169 2170 { set the default function options } 2171 if parse_only then 2172 begin 2173 pd.forwarddef:=true; 2174 { set also the interface flag, for better error message when the 2175 implementation doesn't match this header } 2176 pd.interfacedef:=true; 2177 include(pd.procoptions,po_global); 2178 pdflags:=[pd_interface]; 2179 end 2180 else 2181 begin 2182 pdflags:=[pd_body]; 2183 if (not current_module.in_interface) then 2184 include(pdflags,pd_implemen); 2185 if (not current_module.is_unit) or 2186 create_smartlink_library then 2187 include(pd.procoptions,po_global); 2188 pd.forwarddef:=false; 2189 end; 2190 2191 if not assigned(usefwpd) then 2192 begin 2193 { parse the directives that may follow } 2194 parse_proc_directives(pd,pdflags); 2195 2196 { hint directives, these can be separated by semicolons here, 2197 that needs to be handled here with a loop (PFV) } 2198 while try_consume_hintdirective(pd.symoptions,pd.deprecatedmsg) do 2199 Consume(_SEMICOLON); 2200 2201 { Set calling convention } 2202 if parse_only then 2203 handle_calling_convention(pd,hcc_default_actions_intf) 2204 else 2205 handle_calling_convention(pd,hcc_default_actions_impl) 2206 end; 2207 2208 { search for forward declarations } 2209 if not proc_add_definition(pd) then 2210 begin 2211 { A method must be forward defined (in the object declaration) } 2212 if assigned(pd.struct) and 2213 (not assigned(old_current_structdef)) then 2214 begin 2215 MessagePos1(pd.fileinfo,parser_e_header_dont_match_any_member,pd.fullprocname(false)); 2216 tprocsym(pd.procsym).write_parameter_lists(pd); 2217 end 2218 else 2219 begin 2220 { Give a better error if there is a forward def in the interface and only 2221 a single implementation } 2222 firstpd:=tprocdef(tprocsym(pd.procsym).ProcdefList[0]); 2223 if (not pd.forwarddef) and 2224 (not pd.interfacedef) and 2225 (tprocsym(pd.procsym).ProcdefList.Count>1) and 2226 firstpd.forwarddef and 2227 firstpd.interfacedef and 2228 not(tprocsym(pd.procsym).ProcdefList.Count>2) and 2229 { don't give an error if it may be an overload } 2230 not(m_fpc in current_settings.modeswitches) and 2231 (not(po_overload in pd.procoptions) or 2232 not(po_overload in firstpd.procoptions)) then 2233 begin 2234 MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false)); 2235 tprocsym(pd.procsym).write_parameter_lists(pd); 2236 end 2237 else 2238 begin 2239 if pd.is_generic and not assigned(pd.struct) then 2240 tprocsym(pd.procsym).owner.includeoption(sto_has_generic); 2241 end; 2242 end; 2243 end; 2244 2245 { Set mangled name } 2246 proc_set_mangledname(pd); 2247 2248 { inherit generic flags from parent routine } 2249 if assigned(old_current_procinfo) and 2250 (old_current_procinfo.procdef.defoptions*[df_specialization,df_generic]<>[]) then 2251 begin 2252 if df_generic in old_current_procinfo.procdef.defoptions then 2253 include(pd.defoptions,df_generic); 2254 if df_specialization in old_current_procinfo.procdef.defoptions then 2255 begin 2256 include(pd.defoptions,df_specialization); 2257 { the procdefs encountered here are nested procdefs of which 2258 their complete definition also resides inside the current token 2259 stream, thus access to their genericdef is not required } 2260 {$ifdef genericdef_for_nested} 2261 { find the corresponding routine in the generic routine } 2262 if not assigned(old_current_procinfo.procdef.genericdef) then 2263 internalerror(2016121701); 2264 srsym:=tsym(tprocdef(old_current_procinfo.procdef.genericdef).getsymtable(gs_local).find(pd.procsym.name)); 2265 if not assigned(srsym) or (srsym.typ<>procsym) then 2266 internalerror(2016121702); 2267 { in practice the generic procdef should be at the same index 2268 as the index of the current procdef, but as there *might* be 2269 differences between the amount of defs generated for the 2270 specialization and the generic search for the def using 2271 parameter comparison } 2272 for i:=0 to tprocsym(srsym).procdeflist.count-1 do 2273 begin 2274 def:=tprocdef(tprocsym(srsym).procdeflist[i]); 2275 if (compare_paras(def.paras,pd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv])=te_exact) and 2276 (compare_defs(def.returndef,pd.returndef,nothingn)=te_exact) then 2277 begin 2278 pd.genericdef:=def; 2279 break; 2280 end; 2281 end; 2282 if not assigned(pd.genericdef) then 2283 internalerror(2016121703); 2284 {$endif} 2285 end; 2286 end; 2287 2288 { compile procedure when a body is needed } 2289 if (pd_body in pdflags) then 2290 begin 2291 read_proc_body(old_current_procinfo,pd); 2292 end 2293 else 2294 begin 2295 { Handle imports } 2296 if (po_external in pd.procoptions) then 2297 begin 2298 import_external_proc(pd); 2299 {$ifdef cpuhighleveltarget} 2300 { it's hard to factor this out in a virtual method, because the 2301 generic version (the one inside this ifdef) doesn't fit in 2302 hlcgobj but in symcreat or here, while the other version 2303 doesn't fit in symcreat (since it uses the code generator). 2304 Maybe we need another class for this kind of code that could 2305 either be symcreat- or hlcgobj-based 2306 } 2307 if (not pd.forwarddef) and 2308 (pd.hasforward) and 2309 (proc_get_importname(pd)<>'') then 2310 call_through_new_name(pd,proc_get_importname(pd)) 2311 else 2312 {$endif cpuhighleveltarget} 2313 begin 2314 create_hlcodegen; 2315 hlcg.handle_external_proc( 2316 current_asmdata.asmlists[al_procedures], 2317 pd, 2318 proc_get_importname(pd)); 2319 destroy_hlcodegen; 2320 end 2321 end; 2322 end; 2323 2324 { always register public functions that are only declared in the 2325 implementation section as they might be called using an external 2326 declaration from another unit } 2327 if (po_global in pd.procoptions) and 2328 not pd.interfacedef and 2329 ([df_generic,df_specialization]*pd.defoptions=[]) then 2330 begin 2331 pd.register_def; 2332 pd.procsym.register_sym; 2333 end; 2334 2335 { make sure that references to forward-declared functions are not } 2336 { treated as references to external symbols, needed for darwin. } 2337 2338 { make sure we don't change the binding of real external symbols } 2339 if (([po_external,po_weakexternal]*pd.procoptions)=[]) and (pocall_internproc<>pd.proccalloption) then 2340 begin 2341 if (po_global in pd.procoptions) or 2342 (cs_profile in current_settings.moduleswitches) then pdnull2343 current_asmdata.DefineAsmSymbol(pd.mangledname,AB_GLOBAL,AT_FUNCTION,pd) 2344 else 2345 current_asmdata.DefineAsmSymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION,pd); 2346 end; 2347 2348 current_structdef:=old_current_structdef; 2349 current_genericdef:=old_current_genericdef; 2350 current_specializedef:=old_current_specializedef; 2351 current_procinfo:=old_current_procinfo; 2352 end; 2353 2354 2355 procedure import_external_proc(pd:tprocdef); 2356 var 2357 name : string; 2358 begin 2359 if not (po_external in pd.procoptions) then 2360 internalerror(2015121101); 2361 2362 { Import DLL specified? } 2363 if assigned(pd.import_dll) then 2364 begin 2365 if assigned (pd.import_name) then 2366 current_module.AddExternalImport(pd.import_dll^, 2367 pd.import_name^,proc_get_importname(pd), 2368 pd.import_nr,false,false) 2369 else 2370 current_module.AddExternalImport(pd.import_dll^, 2371 proc_get_importname(pd),proc_get_importname(pd), 2372 pd.import_nr,false,true); 2373 end 2374 else 2375 begin 2376 name:=proc_get_importname(pd); 2377 { add import name to external list for DLL scanning } 2378 if tf_has_dllscanner in target_info.flags then 2379 current_module.dllscannerinputlist.Add(name,pd); 2380 { needed for units that use functions in packages this way } 2381 current_module.add_extern_asmsym(name,AB_EXTERNAL,AT_FUNCTION); endnull2382 end; 2383 end; 2384 2385 {**************************************************************************** 2386 DECLARATION PARSING 2387 ****************************************************************************} 2388 2389 { search in symtablestack for not complete classes } 2390 procedure check_forward_class(p:TObject;arg:pointer); 2391 begin 2392 if (tsym(p).typ=typesym) and 2393 (ttypesym(p).typedef.typ=objectdef) and 2394 (oo_is_forward in tobjectdef(ttypesym(p).typedef).objectoptions) then 2395 MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname); 2396 end; 2397 2398 2399 procedure read_declarations(islibrary : boolean); 2400 var 2401 hadgeneric : boolean; 2402 2403 procedure handle_unexpected_had_generic; 2404 begin 2405 if hadgeneric then 2406 begin 2407 Message(parser_e_procedure_or_function_expected); 2408 hadgeneric:=false; 2409 end; 2410 end; 2411 2412 var 2413 is_classdef:boolean; 2414 begin 2415 is_classdef:=false; 2416 hadgeneric:=false; 2417 repeat 2418 if not assigned(current_procinfo) then 2419 internalerror(200304251); 2420 case token of 2421 _LABEL: 2422 begin 2423 handle_unexpected_had_generic; 2424 label_dec; 2425 end; 2426 _CONST: 2427 begin 2428 handle_unexpected_had_generic; 2429 const_dec(hadgeneric); 2430 end; 2431 _TYPE: 2432 begin 2433 handle_unexpected_had_generic; 2434 type_dec(hadgeneric); 2435 end; 2436 _VAR: 2437 begin 2438 handle_unexpected_had_generic; 2439 var_dec(hadgeneric); 2440 end; 2441 _THREADVAR: 2442 begin 2443 handle_unexpected_had_generic; 2444 threadvar_dec(hadgeneric); 2445 end; 2446 _CLASS: 2447 begin 2448 is_classdef:=false; 2449 if try_to_consume(_CLASS) then 2450 begin 2451 { class modifier is only allowed for procedures, functions, } 2452 { constructors, destructors } _PROCEDUREnull2453 if not((token in [_FUNCTION,_PROCEDURE,_DESTRUCTOR,_OPERATOR]) or (token=_CONSTRUCTOR)) and 2454 not((token=_ID) and (idtoken=_OPERATOR)) then 2455 Message(parser_e_procedure_or_function_expected); 2456 2457 if is_interface(current_structdef) then 2458 Message(parser_e_no_static_method_in_interfaces) 2459 else 2460 { class methods are also allowed for Objective-C protocols } 2461 is_classdef:=true; 2462 end; 2463 end; 2464 _CONSTRUCTOR, 2465 _DESTRUCTOR, 2466 _FUNCTION, 2467 _PROCEDURE, 2468 _OPERATOR: 2469 begin 2470 if hadgeneric and not (token in [_PROCEDURE,_FUNCTION]) then 2471 begin 2472 Message(parser_e_procedure_or_function_expected); 2473 hadgeneric:=false; 2474 end; 2475 read_proc(is_classdef,nil,hadgeneric); 2476 is_classdef:=false; 2477 hadgeneric:=false; 2478 end; 2479 _EXPORTS: 2480 begin 2481 handle_unexpected_had_generic; 2482 if (current_procinfo.procdef.localst.symtablelevel>main_program_level) then 2483 begin 2484 Message(parser_e_syntax_error); 2485 consume_all_until(_SEMICOLON); 2486 end 2487 else if islibrary or 2488 (target_info.system in systems_unit_program_exports) then 2489 read_exports 2490 else 2491 begin 2492 Message(parser_w_unsupported_feature); 2493 consume(_BEGIN); 2494 end; 2495 end; 2496 _PROPERTY: 2497 begin 2498 handle_unexpected_had_generic; 2499 if (m_fpc in current_settings.modeswitches) then 2500 property_dec 2501 else 2502 break; 2503 end; 2504 else 2505 begin 2506 case idtoken of 2507 _RESOURCESTRING: 2508 begin 2509 handle_unexpected_had_generic; 2510 { m_class is needed, because the resourcestring 2511 loading is in the ObjPas unit } 2512 { if (m_class in current_settings.modeswitches) then} 2513 resourcestring_dec(hadgeneric) 2514 { else 2515 break;} 2516 end; 2517 _OPERATOR: 2518 begin 2519 handle_unexpected_had_generic; 2520 if is_classdef then 2521 begin 2522 read_proc(is_classdef,nil,false); 2523 is_classdef:=false; 2524 end 2525 else 2526 break; 2527 end; 2528 _GENERIC: 2529 begin 2530 handle_unexpected_had_generic; 2531 if not (m_delphi in current_settings.modeswitches) then 2532 begin 2533 consume(_ID); 2534 hadgeneric:=true; 2535 end 2536 else 2537 break; 2538 end 2539 else 2540 break; 2541 end; 2542 end; 2543 end; 2544 until false; 2545 2546 { add implementations for synthetic method declarations added by 2547 the compiler (not for unit/program init functions, their localst 2548 is the staticst -> would duplicate the work done in pmodules) } 2549 if current_procinfo.procdef.localst.symtabletype=localsymtable then 2550 add_synthetic_method_implementations(current_procinfo.procdef.localst); 2551 2552 { check for incomplete class definitions, this is only required 2553 for fpc modes } 2554 if (m_fpc in current_settings.modeswitches) then 2555 current_procinfo.procdef.localst.SymList.ForEachCall(@check_forward_class,nil); 2556 end; 2557 2558 2559 procedure read_interface_declarations; 2560 var 2561 hadgeneric : boolean; 2562 2563 procedure handle_unexpected_had_generic; 2564 begin 2565 if hadgeneric then 2566 begin 2567 Message(parser_e_procedure_or_function_expected); 2568 hadgeneric:=false; 2569 end; 2570 end; 2571 2572 begin 2573 hadgeneric:=false; 2574 repeat 2575 case token of 2576 _CONST : 2577 begin 2578 handle_unexpected_had_generic; 2579 const_dec(hadgeneric); 2580 end; 2581 _TYPE : 2582 begin 2583 handle_unexpected_had_generic; 2584 type_dec(hadgeneric); 2585 end; 2586 _VAR : 2587 begin 2588 handle_unexpected_had_generic; 2589 var_dec(hadgeneric); 2590 end; 2591 _THREADVAR : 2592 begin 2593 handle_unexpected_had_generic; 2594 threadvar_dec(hadgeneric); 2595 end; 2596 _FUNCTION, _PROCEDUREnull2597 _PROCEDURE, 2598 _OPERATOR : 2599 begin 2600 if hadgeneric and not (token in [_FUNCTION, _PROCEDURE]) then 2601 begin 2602 message(parser_e_procedure_or_function_expected); 2603 hadgeneric:=false; 2604 end; 2605 read_proc(false,nil,hadgeneric); 2606 hadgeneric:=false; 2607 end; 2608 else 2609 begin 2610 case idtoken of 2611 _RESOURCESTRING : 2612 begin 2613 handle_unexpected_had_generic; 2614 resourcestring_dec(hadgeneric); 2615 end; 2616 _PROPERTY: 2617 begin 2618 handle_unexpected_had_generic; 2619 if (m_fpc in current_settings.modeswitches) then 2620 property_dec 2621 else 2622 break; 2623 end; 2624 _GENERIC: 2625 begin 2626 handle_unexpected_had_generic; 2627 if not (m_delphi in current_settings.modeswitches) then 2628 begin 2629 hadgeneric:=true; 2630 consume(_ID); 2631 end 2632 else 2633 break; 2634 end 2635 else 2636 break; 2637 end; 2638 end; 2639 end; 2640 until false; 2641 { check for incomplete class definitions, this is only required 2642 for fpc modes } 2643 if (m_fpc in current_settings.modeswitches) then 2644 symtablestack.top.SymList.ForEachCall(@check_forward_class,nil); 2645 end; 2646 2647 2648 end. 2649