2
0

nwasmflw.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. {
  2. Copyright (c) 2019 by Dmitry Boyarintsev
  3. Generate assembler for nodes that influence the flow for the JVM
  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 nwasmflw;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. aasmbase,node,nflw,ncgflw, cutils;
  22. type
  23. { twasmifnode }
  24. { Wasm doesn't have any jump(+offset) operations
  25. It only provide structured blockes to handle jumps
  26. (It's possible to jump-out-of-block at any time)
  27. "If" is also implemented as a block, identical to high-level language. }
  28. twasmifnode = class(tcgifnode)
  29. public
  30. procedure pass_generate_code;override;
  31. end;
  32. { twasmwhilerepeatnode }
  33. twasmwhilerepeatnode = class(tcgwhilerepeatnode)
  34. public
  35. procedure pass_generate_code_condition;
  36. procedure pass_generate_code;override;
  37. end;
  38. { twasmraisenode }
  39. twasmraisenode = class(tcgraisenode)
  40. private
  41. function pass_1_no_exceptions : tnode;
  42. public
  43. function pass_1 : tnode;override;
  44. end;
  45. { twasmtryexceptnode }
  46. twasmtryexceptnode = class(tcgtryexceptnode)
  47. private
  48. procedure pass_generate_code_no_exceptions;
  49. procedure pass_generate_code_js_exceptions;
  50. procedure pass_generate_code_native_exceptions;
  51. public
  52. procedure pass_generate_code;override;
  53. end;
  54. { twasmtryfinallynode }
  55. twasmtryfinallynode = class(tcgtryfinallynode)
  56. private
  57. procedure pass_generate_code_no_exceptions;
  58. procedure pass_generate_code_js_exceptions;
  59. procedure pass_generate_code_native_exceptions;
  60. public
  61. procedure pass_generate_code;override;
  62. end;
  63. implementation
  64. uses
  65. verbose,globals,systems,globtype,constexp,
  66. symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,defcmp,
  67. procinfo,cgbase,cgexcept,pass_1,pass_2,parabase,compinnr,
  68. cpubase,cpuinfo,
  69. nbas,nld,ncon,ncnv,ncal,ninl,nmem,nadd,
  70. tgobj,paramgr,
  71. cgutils,hlcgobj,hlcgcpu;
  72. {*****************************************************************************
  73. twasmwhilerepeatnode
  74. *****************************************************************************}
  75. procedure twasmwhilerepeatnode.pass_generate_code_condition;
  76. begin
  77. secondpass(left);
  78. thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  79. // reversing the condition
  80. if not (lnf_checknegate in loopflags) then
  81. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i32_eqz));
  82. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,1) );
  83. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  84. end;
  85. procedure twasmwhilerepeatnode.pass_generate_code;
  86. var
  87. lcont,lbreak,lloop,
  88. oldclabel,oldblabel : tasmlabel;
  89. truelabel,falselabel : tasmlabel;
  90. oldflowcontrol : tflowcontrol;
  91. oldloopcontbroffset: Integer;
  92. oldloopbreakbroffset: Integer;
  93. begin
  94. location_reset(location,LOC_VOID,OS_NO);
  95. current_asmdata.getjumplabel(lloop);
  96. current_asmdata.getjumplabel(lcont);
  97. current_asmdata.getjumplabel(lbreak);
  98. oldflowcontrol:=flowcontrol;
  99. oldloopcontbroffset:=thlcgwasm(hlcg).loopContBr;
  100. oldloopbreakbroffset:=thlcgwasm(hlcg).loopBreakBr;
  101. oldclabel:=current_procinfo.CurrContinueLabel;
  102. oldblabel:=current_procinfo.CurrBreakLabel;
  103. include(flowcontrol,fc_inflowcontrol);
  104. exclude(flowcontrol,fc_unwind_loop);
  105. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  106. thlcgwasm(hlcg).incblock;
  107. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  108. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_loop));
  109. thlcgwasm(hlcg).incblock;
  110. if lnf_testatbegin in loopflags then
  111. begin
  112. pass_generate_code_condition;
  113. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  114. end else
  115. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks+1;
  116. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  117. thlcgwasm(hlcg).incblock;
  118. current_procinfo.CurrContinueLabel:=lcont;
  119. current_procinfo.CurrBreakLabel:=lbreak;
  120. secondpass(right);
  121. if (lnf_testatbegin in loopflags) then
  122. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1) ); // jump back to the external loop
  123. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  124. thlcgwasm(hlcg).decblock;
  125. if not (lnf_testatbegin in loopflags) then begin
  126. pass_generate_code_condition;
  127. end;
  128. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,0) ); // jump back to loop
  129. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_loop));
  130. thlcgwasm(hlcg).decblock;
  131. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  132. thlcgwasm(hlcg).decblock;
  133. current_procinfo.CurrContinueLabel:=oldclabel;
  134. current_procinfo.CurrBreakLabel:=oldblabel;
  135. thlcgwasm(hlcg).loopContBr:=oldloopcontbroffset;
  136. thlcgwasm(hlcg).loopBreakBr:=oldloopbreakbroffset;
  137. { a break/continue in a while/repeat block can't be seen outside }
  138. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  139. end;
  140. {*****************************************************************************
  141. twasmifnode
  142. *****************************************************************************}
  143. procedure twasmifnode.pass_generate_code;
  144. var
  145. oldflowcontrol: tflowcontrol;
  146. begin
  147. // left - condition
  148. // right - then
  149. // t1 - else (optional)
  150. location_reset(location,LOC_VOID,OS_NO);
  151. oldflowcontrol := flowcontrol;
  152. include(flowcontrol,fc_inflowcontrol);
  153. //todo: MOVE all current_asm_data actions to Wasm HL CodeGen
  154. secondpass(left); // condition exprssions
  155. thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  156. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  157. thlcgwasm(hlcg).incblock;
  158. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  159. if Assigned(right) then
  160. secondpass(right); // then branchs
  161. if Assigned(t1) then // else branch
  162. begin
  163. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_else));
  164. secondpass(t1);
  165. end;
  166. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  167. thlcgwasm(hlcg).decblock;
  168. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  169. end;
  170. {*****************************************************************************
  171. twasmraisenode
  172. *****************************************************************************}
  173. function twasmraisenode.pass_1_no_exceptions : tnode;
  174. var
  175. statements : tstatementnode;
  176. //current_addr : tlabelnode;
  177. raisenode : tcallnode;
  178. begin
  179. result:=internalstatements(statements);
  180. if assigned(left) then
  181. begin
  182. { first para must be a class }
  183. firstpass(left);
  184. { insert needed typeconvs for addr,frame }
  185. if assigned(right) then
  186. begin
  187. { addr }
  188. firstpass(right);
  189. { frame }
  190. if assigned(third) then
  191. firstpass(third)
  192. else
  193. third:=cpointerconstnode.Create(0,voidpointertype);
  194. end
  195. else
  196. begin
  197. third:=cinlinenode.create(in_get_frame,false,nil);
  198. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  199. //addstatement(statements,current_addr);
  200. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  201. right:=cnilnode.create;
  202. { raise address off by one so we are for sure inside the action area for the raise }
  203. if tf_use_psabieh in target_info.flags then
  204. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  205. end;
  206. raisenode:=ccallnode.createintern('fpc_raiseexception',
  207. ccallparanode.create(third,
  208. ccallparanode.create(right,
  209. ccallparanode.create(left,nil)))
  210. );
  211. include(raisenode.callnodeflags,cnf_call_never_returns);
  212. addstatement(statements,raisenode);
  213. end
  214. else
  215. begin
  216. addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  217. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  218. include(raisenode.callnodeflags,cnf_call_never_returns);
  219. addstatement(statements,raisenode);
  220. end;
  221. left:=nil;
  222. right:=nil;
  223. third:=nil;
  224. end;
  225. function twasmraisenode.pass_1 : tnode;
  226. begin
  227. if ts_wasm_no_exceptions in current_settings.targetswitches then
  228. result:=pass_1_no_exceptions
  229. else
  230. result:=inherited;
  231. end;
  232. {*****************************************************************************
  233. twasmtryexceptnode
  234. *****************************************************************************}
  235. procedure twasmtryexceptnode.pass_generate_code_no_exceptions;
  236. begin
  237. location_reset(location,LOC_VOID,OS_NO);
  238. secondpass(left);
  239. end;
  240. procedure twasmtryexceptnode.pass_generate_code_js_exceptions;
  241. begin
  242. internalerror(2021091706);
  243. end;
  244. procedure twasmtryexceptnode.pass_generate_code_native_exceptions;
  245. begin
  246. internalerror(2021091707);
  247. end;
  248. procedure twasmtryexceptnode.pass_generate_code;
  249. begin
  250. if ts_wasm_no_exceptions in current_settings.targetswitches then
  251. pass_generate_code_no_exceptions
  252. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  253. pass_generate_code_js_exceptions
  254. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  255. pass_generate_code_native_exceptions
  256. else
  257. internalerror(2021091705);
  258. end;
  259. {*****************************************************************************
  260. twasmtryfinallynode
  261. *****************************************************************************}
  262. procedure twasmtryfinallynode.pass_generate_code_no_exceptions;
  263. var
  264. exitfinallylabel,
  265. continuefinallylabel,
  266. breakfinallylabel,
  267. oldCurrExitLabel,
  268. oldContinueLabel,
  269. oldBreakLabel: tasmlabel;
  270. oldLoopContBr: integer;
  271. oldLoopBreakBr: integer;
  272. oldExitBr: integer;
  273. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  274. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  275. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  276. in_loop: Boolean;
  277. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  278. var
  279. reasonreg : tregister;
  280. begin
  281. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  282. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  283. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  284. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  285. thlcgwasm(hlcg).incblock;
  286. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  287. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
  288. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  289. thlcgwasm(hlcg).decblock;
  290. end;
  291. begin
  292. location_reset(location,LOC_VOID,OS_NO);
  293. oldBreakLabel:=nil;
  294. oldContinueLabel:=nil;
  295. continuefinallylabel:=nil;
  296. breakfinallylabel:=nil;
  297. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  298. if not implicitframe then
  299. exceptframekind:=tek_normalfinally
  300. else
  301. exceptframekind:=tek_implicitfinally;
  302. { in 'no exceptions' mode, we still want to handle properly exit,
  303. continue and break (they still need to execute the 'finally'
  304. statements), so for this we need excepttemps.reasonbuf, and for this
  305. reason, we need to allocate excepttemps }
  306. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  307. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  308. { the finally block must catch break, continue and exit }
  309. { statements }
  310. { the outer 'try..finally' block }
  311. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  312. thlcgwasm(hlcg).incblock;
  313. { the 'exit' block }
  314. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  315. thlcgwasm(hlcg).incblock;
  316. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  317. oldExitBr:=thlcgwasm(hlcg).exitBr;
  318. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  319. current_procinfo.CurrExitLabel:=exitfinallylabel;
  320. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  321. { the 'break' block }
  322. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  323. thlcgwasm(hlcg).incblock;
  324. if in_loop then
  325. begin
  326. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  327. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  328. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  329. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  330. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  331. end;
  332. { the 'continue' block }
  333. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  334. thlcgwasm(hlcg).incblock;
  335. if in_loop then
  336. begin
  337. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  338. oldLoopContBr:=thlcgwasm(hlcg).loopContBr;
  339. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  340. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  341. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  342. end;
  343. { try code }
  344. if assigned(left) then
  345. begin
  346. secondpass(left);
  347. if codegenerror then
  348. exit;
  349. end;
  350. { don't generate line info for internal cleanup }
  351. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  352. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  353. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  354. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  355. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,3)); // jump to the 'finally' section
  356. { exit the 'continue' block }
  357. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  358. thlcgwasm(hlcg).decblock;
  359. { exceptionreason:=4 (continue) }
  360. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  361. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  362. { exit the 'break' block }
  363. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  364. thlcgwasm(hlcg).decblock;
  365. { exceptionreason:=3 (break) }
  366. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  367. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  368. { exit the 'exit' block }
  369. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  370. thlcgwasm(hlcg).decblock;
  371. { exceptionreason:=2 (exit) }
  372. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  373. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  374. { exit the outer 'try..finally' block }
  375. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  376. thlcgwasm(hlcg).decblock;
  377. { end cleanup }
  378. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  379. { finally code (don't unconditionally set fc_inflowcontrol, since the
  380. finally code is unconditionally executed; we do have to filter out
  381. flags regarding break/contrinue/etc. because we have to give an
  382. error in case one of those is used in the finally-code }
  383. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  384. secondpass(right);
  385. { goto is allowed if it stays inside the finally block,
  386. this is checked using the exception block number }
  387. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  388. CGMessage(cg_e_control_flow_outside_finally);
  389. if codegenerror then
  390. exit;
  391. { don't generate line info for internal cleanup }
  392. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  393. if fc_exit in finallyexceptionstate.newflowcontrol then
  394. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  395. if fc_break in finallyexceptionstate.newflowcontrol then
  396. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  397. if fc_continue in finallyexceptionstate.newflowcontrol then
  398. generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
  399. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  400. { end cleanup }
  401. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  402. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  403. thlcgwasm(hlcg).exitBr:=oldExitBr;
  404. if assigned(current_procinfo.CurrBreakLabel) then
  405. begin
  406. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  407. thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
  408. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  409. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  410. end;
  411. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  412. end;
  413. procedure twasmtryfinallynode.pass_generate_code_js_exceptions;
  414. begin
  415. internalerror(2021091702);
  416. end;
  417. procedure twasmtryfinallynode.pass_generate_code_native_exceptions;
  418. var
  419. exitfinallylabel,
  420. continuefinallylabel,
  421. breakfinallylabel,
  422. oldCurrExitLabel,
  423. oldContinueLabel,
  424. oldBreakLabel: tasmlabel;
  425. oldLoopContBr: integer;
  426. oldLoopBreakBr: integer;
  427. oldExitBr: integer;
  428. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  429. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  430. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  431. in_loop: Boolean;
  432. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  433. var
  434. reasonreg : tregister;
  435. begin
  436. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  437. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  438. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  439. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  440. thlcgwasm(hlcg).incblock;
  441. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  442. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
  443. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  444. thlcgwasm(hlcg).decblock;
  445. end;
  446. begin
  447. location_reset(location,LOC_VOID,OS_NO);
  448. oldBreakLabel:=nil;
  449. oldContinueLabel:=nil;
  450. continuefinallylabel:=nil;
  451. breakfinallylabel:=nil;
  452. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  453. if not implicitframe then
  454. exceptframekind:=tek_normalfinally
  455. else
  456. exceptframekind:=tek_implicitfinally;
  457. { in 'no exceptions' mode, we still want to handle properly exit,
  458. continue and break (they still need to execute the 'finally'
  459. statements), so for this we need excepttemps.reasonbuf, and for this
  460. reason, we need to allocate excepttemps }
  461. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  462. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  463. { the finally block must catch break, continue and exit }
  464. { statements }
  465. { the outer 'try..finally' block }
  466. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  467. thlcgwasm(hlcg).incblock;
  468. { the 'exit' block }
  469. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  470. thlcgwasm(hlcg).incblock;
  471. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  472. oldExitBr:=thlcgwasm(hlcg).exitBr;
  473. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  474. current_procinfo.CurrExitLabel:=exitfinallylabel;
  475. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  476. { the 'break' block }
  477. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  478. thlcgwasm(hlcg).incblock;
  479. if in_loop then
  480. begin
  481. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  482. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  483. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  484. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  485. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  486. end;
  487. { the 'continue' block }
  488. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  489. thlcgwasm(hlcg).incblock;
  490. if in_loop then
  491. begin
  492. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  493. oldLoopContBr:=thlcgwasm(hlcg).loopContBr;
  494. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  495. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  496. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  497. end;
  498. { the inner 'try..end_try' block }
  499. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  500. thlcgwasm(hlcg).incblock;
  501. { try code }
  502. if assigned(left) then
  503. begin
  504. secondpass(left);
  505. if codegenerror then
  506. exit;
  507. end;
  508. { don't generate line info for internal cleanup }
  509. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  510. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  511. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  512. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  513. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  514. { exit the inner 'try..end_try' block }
  515. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  516. thlcgwasm(hlcg).decblock;
  517. { exit the 'continue' block }
  518. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  519. thlcgwasm(hlcg).decblock;
  520. { exceptionreason:=4 (continue) }
  521. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  522. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  523. { exit the 'break' block }
  524. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  525. thlcgwasm(hlcg).decblock;
  526. { exceptionreason:=3 (break) }
  527. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  528. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  529. { exit the 'exit' block }
  530. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  531. thlcgwasm(hlcg).decblock;
  532. { exceptionreason:=2 (exit) }
  533. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  534. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  535. { exit the outer 'try..finally' block }
  536. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  537. thlcgwasm(hlcg).decblock;
  538. { end cleanup }
  539. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  540. { finally code (don't unconditionally set fc_inflowcontrol, since the
  541. finally code is unconditionally executed; we do have to filter out
  542. flags regarding break/contrinue/etc. because we have to give an
  543. error in case one of those is used in the finally-code }
  544. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  545. secondpass(right);
  546. { goto is allowed if it stays inside the finally block,
  547. this is checked using the exception block number }
  548. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  549. CGMessage(cg_e_control_flow_outside_finally);
  550. if codegenerror then
  551. exit;
  552. { don't generate line info for internal cleanup }
  553. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  554. if fc_exit in finallyexceptionstate.newflowcontrol then
  555. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  556. if fc_break in finallyexceptionstate.newflowcontrol then
  557. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  558. if fc_continue in finallyexceptionstate.newflowcontrol then
  559. generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
  560. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  561. { end cleanup }
  562. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  563. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  564. thlcgwasm(hlcg).exitBr:=oldExitBr;
  565. if assigned(current_procinfo.CurrBreakLabel) then
  566. begin
  567. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  568. thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
  569. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  570. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  571. end;
  572. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  573. end;
  574. procedure twasmtryfinallynode.pass_generate_code;
  575. begin
  576. if ts_wasm_no_exceptions in current_settings.targetswitches then
  577. pass_generate_code_no_exceptions
  578. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  579. pass_generate_code_js_exceptions
  580. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  581. pass_generate_code_native_exceptions
  582. else
  583. internalerror(2021091704);
  584. end;
  585. initialization
  586. cifnode:=twasmifnode;
  587. cwhilerepeatnode:=twasmwhilerepeatnode;
  588. craisenode:=twasmraisenode;
  589. ctryexceptnode:=twasmtryexceptnode;
  590. ctryfinallynode:=twasmtryfinallynode;
  591. end.