nx64flw.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. {
  2. Copyright (c) 2011 by Free Pascal development team
  3. Generate Win64-specific exception handling code
  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 nx64flw;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nflw,ncgflw,psub;
  22. type
  23. tx64raisenode=class(tcgraisenode)
  24. function pass_1 : tnode;override;
  25. end;
  26. tx64onnode=class(tcgonnode)
  27. procedure pass_generate_code;override;
  28. end;
  29. tx64tryexceptnode=class(tcgtryexceptnode)
  30. procedure pass_generate_code;override;
  31. end;
  32. tx64tryfinallynode=class(tcgtryfinallynode)
  33. finalizepi: tcgprocinfo;
  34. constructor create(l,r:TNode);override;
  35. constructor create_implicit(l,r:TNode);override;
  36. function dogetcopy : tnode;override;
  37. function simplify(forinline: boolean): tnode;override;
  38. procedure pass_generate_code;override;
  39. end;
  40. implementation
  41. uses
  42. globtype,globals,verbose,systems,
  43. nbas,ncal,nutils,
  44. symconst,symsym,symdef,
  45. cgbase,cgobj,cgutils,tgobj,
  46. cpubase,htypechk,
  47. pass_1,pass_2,
  48. aasmbase,aasmtai,aasmdata,aasmcpu,
  49. procinfo,cpupi,procdefutil;
  50. var
  51. endexceptlabel: tasmlabel;
  52. { tx64raisenode }
  53. function tx64raisenode.pass_1 : tnode;
  54. var
  55. statements : tstatementnode;
  56. raisenode : tcallnode;
  57. begin
  58. { difference from generic code is that address stack is not popped on reraise }
  59. if (target_info.system<>system_x86_64_win64) or assigned(left) then
  60. result:=inherited pass_1
  61. else
  62. begin
  63. result:=internalstatements(statements);
  64. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  65. include(raisenode.callnodeflags,cnf_call_never_returns);
  66. addstatement(statements,raisenode);
  67. end;
  68. end;
  69. { tx64onnode }
  70. procedure tx64onnode.pass_generate_code;
  71. var
  72. exceptvarsym : tlocalvarsym;
  73. begin
  74. if (target_info.system<>system_x86_64_win64) then
  75. begin
  76. inherited pass_generate_code;
  77. exit;
  78. end;
  79. location_reset(location,LOC_VOID,OS_NO);
  80. { RTL will put exceptobject into RAX when jumping here }
  81. cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  82. { Retrieve exception variable }
  83. if assigned(excepTSymtable) then
  84. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  85. else
  86. exceptvarsym:=nil;
  87. if assigned(exceptvarsym) then
  88. begin
  89. exceptvarsym.localloc.loc:=LOC_REFERENCE;
  90. exceptvarsym.localloc.size:=OS_ADDR;
  91. tg.GetLocal(current_asmdata.CurrAsmList,sizeof(pint),voidpointertype,exceptvarsym.localloc.reference);
  92. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_FUNCTION_RESULT_REG,exceptvarsym.localloc.reference);
  93. end;
  94. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  95. if assigned(right) then
  96. secondpass(right);
  97. { deallocate exception symbol }
  98. if assigned(exceptvarsym) then
  99. begin
  100. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  101. exceptvarsym.localloc.loc:=LOC_INVALID;
  102. end;
  103. cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
  104. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  105. end;
  106. { tx64tryfinallynode }
  107. function reset_regvars(var n: tnode; arg: pointer): foreachnoderesult;
  108. begin
  109. case n.nodetype of
  110. temprefn:
  111. make_not_regable(n,[]);
  112. calln:
  113. include(tprocinfo(arg).flags,pi_do_call);
  114. end;
  115. result:=fen_true;
  116. end;
  117. function copy_parasize(var n: tnode; arg: pointer): foreachnoderesult;
  118. begin
  119. case n.nodetype of
  120. calln:
  121. tcgprocinfo(arg).allocate_push_parasize(tcallnode(n).pushed_parasize);
  122. end;
  123. result:=fen_true;
  124. end;
  125. constructor tx64tryfinallynode.create(l, r: TNode);
  126. begin
  127. inherited create(l,r);
  128. if (target_info.system=system_x86_64_win64) and
  129. { Don't create child procedures for generic methods, their nested-like
  130. behavior causes compilation errors because real nested procedures
  131. aren't allowed for generics. Not creating them doesn't harm because
  132. generic node tree is discarded without generating code. }
  133. not (df_generic in current_procinfo.procdef.defoptions) then
  134. begin
  135. finalizepi:=tcgprocinfo(current_procinfo.create_for_outlining('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype,r));
  136. { the init/final code is messing with asm nodes, so inform the compiler about this }
  137. include(finalizepi.flags,pi_has_assembler_block);
  138. { Regvar optimization for symbols is suppressed when using exceptions, but
  139. temps may be still placed into registers. This must be fixed. }
  140. foreachnodestatic(r,@reset_regvars,finalizepi);
  141. end;
  142. end;
  143. constructor tx64tryfinallynode.create_implicit(l, r: TNode);
  144. begin
  145. inherited create_implicit(l, r);
  146. if (target_info.system=system_x86_64_win64) then
  147. begin
  148. if df_generic in current_procinfo.procdef.defoptions then
  149. InternalError(2013012501);
  150. finalizepi:=tcgprocinfo(current_procinfo.create_for_outlining('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype,r));
  151. include(finalizepi.flags,pi_do_call);
  152. { the init/final code is messing with asm nodes, so inform the compiler about this }
  153. include(finalizepi.flags,pi_has_assembler_block);
  154. finalizepi.allocate_push_parasize(32);
  155. end;
  156. end;
  157. function tx64tryfinallynode.dogetcopy: tnode;
  158. var
  159. n: tx64tryfinallynode;
  160. begin
  161. n:=tx64tryfinallynode(inherited dogetcopy);
  162. if target_info.system=system_x86_64_win64 then
  163. begin
  164. n.finalizepi:=tcgprocinfo(cprocinfo.create(finalizepi.parent));
  165. n.finalizepi.force_nested;
  166. n.finalizepi.procdef:=create_outline_procdef('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype);
  167. n.finalizepi.entrypos:=finalizepi.entrypos;
  168. n.finalizepi.entryswitches:=finalizepi.entryswitches;
  169. n.finalizepi.exitpos:=finalizepi.exitpos;
  170. n.finalizepi.exitswitches:=finalizepi.exitswitches;
  171. n.finalizepi.flags:=finalizepi.flags;
  172. { node already transformed? }
  173. if assigned(finalizepi.code) then
  174. begin
  175. n.finalizepi.code:=finalizepi.code.getcopy;
  176. n.right:=ccallnode.create(nil,tprocsym(n.finalizepi.procdef.procsym),nil,nil,[],nil);
  177. end;
  178. end;
  179. result:=n;
  180. end;
  181. function tx64tryfinallynode.simplify(forinline: boolean): tnode;
  182. begin
  183. result:=inherited simplify(forinline);
  184. if (target_info.system<>system_x86_64_win64) then
  185. exit;
  186. if (result=nil) then
  187. begin
  188. { actually, this is not really the right place to do a node transformation like this }
  189. if not(assigned(finalizepi.code)) then
  190. begin
  191. finalizepi.code:=right;
  192. foreachnodestatic(right,@copy_parasize,finalizepi);
  193. right:=ccallnode.create(nil,tprocsym(finalizepi.procdef.procsym),nil,nil,[],nil);
  194. firstpass(right);
  195. { For implicit frames, no actual code is available at this time,
  196. it is added later in assembler form. So store the nested procinfo
  197. for later use. }
  198. if implicitframe then
  199. begin
  200. current_procinfo.finalize_procinfo:=finalizepi;
  201. end;
  202. { don't leave dangling pointer }
  203. tcgprocinfo(current_procinfo).final_asmnode:=nil;
  204. end;
  205. end;
  206. end;
  207. procedure emit_nop;
  208. var
  209. dummy: TAsmLabel;
  210. begin
  211. { To avoid optimizing away the whole thing, prepend a jumplabel with increased refcount }
  212. current_asmdata.getjumplabel(dummy);
  213. dummy.increfs;
  214. cg.a_label(current_asmdata.CurrAsmList,dummy);
  215. current_asmdata.CurrAsmList.concat(Taicpu.op_none(A_NOP,S_NO));
  216. end;
  217. procedure tx64tryfinallynode.pass_generate_code;
  218. var
  219. trylabel,
  220. endtrylabel,
  221. finallylabel,
  222. endfinallylabel,
  223. templabel,
  224. oldexitlabel: tasmlabel;
  225. oldflowcontrol: tflowcontrol;
  226. catch_frame: boolean;
  227. begin
  228. if (target_info.system<>system_x86_64_win64) then
  229. begin
  230. inherited pass_generate_code;
  231. exit;
  232. end;
  233. location_reset(location,LOC_VOID,OS_NO);
  234. { Do not generate a frame that catches exceptions if the only action
  235. would be reraising it. Doing so is extremely inefficient with SEH
  236. (in contrast with setjmp/longjmp exception handling) }
  237. catch_frame:=implicitframe and
  238. (current_procinfo.procdef.proccalloption=pocall_safecall);
  239. oldflowcontrol:=flowcontrol;
  240. flowcontrol:=[fc_inflowcontrol];
  241. templabel:=nil;
  242. current_asmdata.getjumplabel(trylabel);
  243. current_asmdata.getjumplabel(endtrylabel);
  244. current_asmdata.getjumplabel(finallylabel);
  245. current_asmdata.getjumplabel(endfinallylabel);
  246. oldexitlabel:=current_procinfo.CurrExitLabel;
  247. if implicitframe then
  248. current_procinfo.CurrExitLabel:=finallylabel;
  249. { Start of scope }
  250. { Padding with NOP is necessary here because exceptions in called
  251. procedures are seen at the next instruction, while CPU/OS exceptions
  252. like AV are seen at the current instruction.
  253. So in the following code
  254. raise_some_exception; //(a)
  255. try
  256. pchar(nil)^:='0'; //(b)
  257. ...
  258. without NOP, exceptions (a) and (b) will be seen at the same address
  259. and fall into the same scope. However they should be seen in different scopes.
  260. }
  261. emit_nop;
  262. cg.a_label(current_asmdata.CurrAsmList,trylabel);
  263. { try code }
  264. if assigned(left) then
  265. begin
  266. { fc_unwind_xx tells exit/continue/break statements to emit special
  267. unwind code instead of just JMP }
  268. if not implicitframe then
  269. flowcontrol:=flowcontrol+[fc_catching_exceptions,fc_unwind_exit,fc_unwind_loop];
  270. secondpass(left);
  271. flowcontrol:=flowcontrol-[fc_catching_exceptions,fc_unwind_exit,fc_unwind_loop];
  272. if codegenerror then
  273. exit;
  274. end;
  275. { finallylabel is only used in implicit frames as an exit point from nested try..finally
  276. statements, if any. To prevent finalizer from being executed twice, it must come before
  277. endtrylabel (bug #34772) }
  278. if catch_frame then
  279. begin
  280. current_asmdata.getjumplabel(templabel);
  281. cg.a_label(current_asmdata.CurrAsmList, finallylabel);
  282. { jump over exception handler }
  283. cg.a_jmp_always(current_asmdata.CurrAsmList,templabel);
  284. { Handle the except block first, so endtrylabel serves both
  285. as end of scope and as unwind target. This way it is possible to
  286. encode everything into a single scope record. }
  287. cg.a_label(current_asmdata.CurrAsmList,endtrylabel);
  288. if (current_procinfo.procdef.proccalloption=pocall_safecall) then
  289. begin
  290. handle_safecall_exception;
  291. cg.a_jmp_always(current_asmdata.CurrAsmList,endfinallylabel);
  292. end
  293. else
  294. InternalError(2014031601);
  295. cg.a_label(current_asmdata.CurrAsmList,templabel);
  296. end
  297. else
  298. begin
  299. { same as emit_nop but using finallylabel instead of dummy }
  300. cg.a_label(current_asmdata.CurrAsmList,finallylabel);
  301. finallylabel.increfs;
  302. current_asmdata.CurrAsmList.concat(Taicpu.op_none(A_NOP,S_NO));
  303. cg.a_label(current_asmdata.CurrAsmList,endtrylabel);
  304. end;
  305. { i32913 - if the try..finally block is also inside a try..finally or
  306. try..except block, make a note of any Exit calls so all necessary labels
  307. are generated. [Kit] }
  308. if ((flowcontrol*[fc_exit,fc_break,fc_continue])<>[]) and (fc_inflowcontrol in oldflowcontrol) then
  309. oldflowcontrol:=oldflowcontrol+(flowcontrol*[fc_exit,fc_break,fc_continue]);
  310. flowcontrol:=[fc_inflowcontrol];
  311. { generate finally code as a separate procedure }
  312. if not implicitframe then
  313. tcgprocinfo(current_procinfo).generate_exceptfilter(finalizepi);
  314. { right is a call to finalizer procedure }
  315. secondpass(right);
  316. if codegenerror then
  317. exit;
  318. { normal exit from safecall proc must zero the result register }
  319. if implicitframe and (current_procinfo.procdef.proccalloption=pocall_safecall) then
  320. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,NR_FUNCTION_RESULT_REG);
  321. cg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  322. { generate the scope record in .xdata }
  323. tcpuprocinfo(current_procinfo).add_finally_scope(trylabel,endtrylabel,
  324. current_asmdata.RefAsmSymbol(finalizepi.procdef.mangledname,AT_FUNCTION),catch_frame);
  325. if implicitframe then
  326. current_procinfo.CurrExitLabel:=oldexitlabel;
  327. flowcontrol:=oldflowcontrol;
  328. end;
  329. { tx64tryexceptnode }
  330. procedure tx64tryexceptnode.pass_generate_code;
  331. var
  332. trylabel,
  333. exceptlabel,oldendexceptlabel,
  334. lastonlabel,
  335. exitexceptlabel,
  336. continueexceptlabel,
  337. breakexceptlabel,
  338. oldCurrExitLabel,
  339. oldContinueLabel,
  340. oldBreakLabel : tasmlabel;
  341. onlabel,
  342. filterlabel: tasmlabel;
  343. oldflowcontrol,tryflowcontrol,
  344. exceptflowcontrol : tflowcontrol;
  345. hnode : tnode;
  346. hlist : tasmlist;
  347. onnodecount : tai_const;
  348. label
  349. errorexit;
  350. begin
  351. if (target_info.system<>system_x86_64_win64) then
  352. begin
  353. inherited pass_generate_code;
  354. exit;
  355. end;
  356. location_reset(location,LOC_VOID,OS_NO);
  357. oldflowcontrol:=flowcontrol;
  358. exceptflowcontrol:=[];
  359. continueexceptlabel:=nil;
  360. breakexceptlabel:=nil;
  361. include(flowcontrol,fc_inflowcontrol);
  362. { this can be called recursivly }
  363. oldBreakLabel:=nil;
  364. oldContinueLabel:=nil;
  365. oldendexceptlabel:=endexceptlabel;
  366. { save the old labels for control flow statements }
  367. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  368. current_asmdata.getjumplabel(exitexceptlabel);
  369. if assigned(current_procinfo.CurrBreakLabel) then
  370. begin
  371. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  372. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  373. current_asmdata.getjumplabel(breakexceptlabel);
  374. current_asmdata.getjumplabel(continueexceptlabel);
  375. end;
  376. current_asmdata.getjumplabel(exceptlabel);
  377. current_asmdata.getjumplabel(endexceptlabel);
  378. current_asmdata.getjumplabel(lastonlabel);
  379. filterlabel:=nil;
  380. { start of scope }
  381. current_asmdata.getjumplabel(trylabel);
  382. emit_nop;
  383. cg.a_label(current_asmdata.CurrAsmList,trylabel);
  384. { control flow in try block needs no special handling,
  385. just make sure that target labels are outside the scope }
  386. secondpass(left);
  387. tryflowcontrol:=flowcontrol;
  388. if codegenerror then
  389. goto errorexit;
  390. { jump over except handlers }
  391. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  392. { end of scope }
  393. cg.a_label(current_asmdata.CurrAsmList,exceptlabel);
  394. { set control flow labels for the except block }
  395. { and the on statements }
  396. current_procinfo.CurrExitLabel:=exitexceptlabel;
  397. if assigned(oldBreakLabel) then
  398. begin
  399. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  400. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  401. end;
  402. { i32913 - if the try..finally block is also inside a try..finally or
  403. try..except block, make a note of any Exit calls so all necessary labels
  404. are generated. [Kit] }
  405. if ((flowcontrol*[fc_exit,fc_break,fc_continue])<>[]) and (fc_inflowcontrol in oldflowcontrol) then
  406. oldflowcontrol:=oldflowcontrol+(flowcontrol*[fc_exit,fc_break,fc_continue]);
  407. flowcontrol:=[fc_inflowcontrol];
  408. { on statements }
  409. if assigned(right) then
  410. begin
  411. { emit filter table to a temporary asmlist }
  412. hlist:=TAsmList.Create;
  413. current_asmdata.getaddrlabel(filterlabel);
  414. new_section(hlist,sec_rodata_norel,filterlabel.name,4);
  415. cg.a_label(hlist,filterlabel);
  416. onnodecount:=tai_const.create_32bit(0);
  417. hlist.concat(onnodecount);
  418. hnode:=right;
  419. while assigned(hnode) do
  420. begin
  421. if hnode.nodetype<>onn then
  422. InternalError(2011103101);
  423. current_asmdata.getjumplabel(onlabel);
  424. hlist.concat(tai_const.create_rva_sym(current_asmdata.RefAsmSymbol(tonnode(hnode).excepttype.vmt_mangledname,AT_DATA)));
  425. hlist.concat(tai_const.create_rva_sym(onlabel));
  426. cg.a_label(current_asmdata.CurrAsmList,onlabel);
  427. secondpass(hnode);
  428. inc(onnodecount.value);
  429. hnode:=tonnode(hnode).left;
  430. end;
  431. { add 'else' node to the filter list, too }
  432. if assigned(t1) then
  433. begin
  434. hlist.concat(tai_const.create_32bit(-1));
  435. hlist.concat(tai_const.create_rva_sym(lastonlabel));
  436. inc(onnodecount.value);
  437. end;
  438. { now move filter table to permanent list all at once }
  439. current_procinfo.aktlocaldata.concatlist(hlist);
  440. hlist.free;
  441. end;
  442. cg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  443. if assigned(t1) then
  444. begin
  445. { here we don't have to reset flowcontrol }
  446. { the default and on flowcontrols are handled equal }
  447. secondpass(t1);
  448. cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
  449. if (flowcontrol*[fc_exit,fc_break,fc_continue]<>[]) then
  450. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  451. end;
  452. exceptflowcontrol:=flowcontrol;
  453. if fc_exit in exceptflowcontrol then
  454. begin
  455. { do some magic for exit in the try block }
  456. cg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
  457. cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
  458. if (fc_unwind_exit in oldflowcontrol) then
  459. cg.g_local_unwind(current_asmdata.CurrAsmList,oldCurrExitLabel)
  460. else
  461. cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  462. end;
  463. if fc_break in exceptflowcontrol then
  464. begin
  465. cg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
  466. cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
  467. if (fc_unwind_loop in oldflowcontrol) then
  468. cg.g_local_unwind(current_asmdata.CurrAsmList,oldBreakLabel)
  469. else
  470. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  471. end;
  472. if fc_continue in exceptflowcontrol then
  473. begin
  474. cg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
  475. cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
  476. if (fc_unwind_loop in oldflowcontrol) then
  477. cg.g_local_unwind(current_asmdata.CurrAsmList,oldContinueLabel)
  478. else
  479. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  480. end;
  481. emit_nop;
  482. cg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  483. tcpuprocinfo(current_procinfo).add_except_scope(trylabel,exceptlabel,endexceptlabel,filterlabel);
  484. errorexit:
  485. { restore all saved labels }
  486. endexceptlabel:=oldendexceptlabel;
  487. { i32913 - if the try..finally block is also inside a try..finally or
  488. try..except block, make a note of any Exit calls so all necessary labels
  489. are generated. [Kit] }
  490. if ((flowcontrol*[fc_exit,fc_break,fc_continue])<>[]) and (fc_inflowcontrol in oldflowcontrol) then
  491. oldflowcontrol:=oldflowcontrol+(flowcontrol*[fc_exit,fc_break,fc_continue]);
  492. { restore the control flow labels }
  493. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  494. if assigned(oldBreakLabel) then
  495. begin
  496. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  497. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  498. end;
  499. { return all used control flow statements }
  500. flowcontrol:=oldflowcontrol+(exceptflowcontrol +
  501. tryflowcontrol - [fc_inflowcontrol]);
  502. end;
  503. initialization
  504. craisenode:=tx64raisenode;
  505. connode:=tx64onnode;
  506. ctryexceptnode:=tx64tryexceptnode;
  507. ctryfinallynode:=tx64tryfinallynode;
  508. end.