nwasmflw.pas 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  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. function pass_1_native_exceptions : tnode;
  43. function pass_1_bf_exceptions : tnode;
  44. public
  45. function pass_1 : tnode;override;
  46. end;
  47. { twasmtryexceptnode }
  48. twasmtryexceptnode = class(tcgtryexceptnode)
  49. private
  50. procedure pass_generate_code_no_exceptions;
  51. procedure pass_generate_code_js_exceptions;
  52. procedure pass_generate_code_native_exceptions;
  53. procedure pass_generate_code_bf_exceptions;
  54. public
  55. procedure pass_generate_code;override;
  56. end;
  57. { twasmtryfinallynode }
  58. twasmtryfinallynode = class(tcgtryfinallynode)
  59. private
  60. procedure pass_generate_code_no_exceptions;
  61. procedure pass_generate_code_js_exceptions;
  62. procedure pass_generate_code_native_exceptions;
  63. procedure pass_generate_code_bf_exceptions;
  64. public
  65. procedure pass_generate_code;override;
  66. end;
  67. { twasmonnode }
  68. twasmonnode = class(tcgonnode)
  69. private
  70. procedure pass_generate_code_no_exceptions;
  71. procedure pass_generate_code_js_exceptions;
  72. procedure pass_generate_code_native_exceptions;
  73. procedure pass_generate_code_bf_exceptions;
  74. public
  75. procedure pass_generate_code;override;
  76. end;
  77. implementation
  78. uses
  79. verbose,globals,systems,globtype,constexp,
  80. symconst,symdef,symsym,symtype,aasmtai,aasmdata,aasmcpu,defutil,defcmp,
  81. procinfo,cgbase,cgexcept,pass_1,pass_2,parabase,compinnr,
  82. cpubase,cpuinfo,
  83. nbas,nld,ncon,ncnv,ncal,ninl,nmem,nadd,nutils,
  84. tgobj,paramgr,
  85. cgutils,hlcgobj,hlcgcpu;
  86. {*****************************************************************************
  87. twasmwhilerepeatnode
  88. *****************************************************************************}
  89. procedure twasmwhilerepeatnode.pass_generate_code_condition;
  90. begin
  91. secondpass(left);
  92. thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  93. // reversing the condition
  94. if not (lnf_checknegate in loopflags) then
  95. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i32_eqz));
  96. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,1) );
  97. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  98. end;
  99. procedure twasmwhilerepeatnode.pass_generate_code;
  100. var
  101. lcont,lbreak,lloop,
  102. oldclabel,oldblabel : tasmlabel;
  103. truelabel,falselabel : tasmlabel;
  104. oldflowcontrol : tflowcontrol;
  105. oldloopcontbroffset: Integer;
  106. oldloopbreakbroffset: Integer;
  107. begin
  108. location_reset(location,LOC_VOID,OS_NO);
  109. current_asmdata.getjumplabel(lloop);
  110. current_asmdata.getjumplabel(lcont);
  111. current_asmdata.getjumplabel(lbreak);
  112. oldflowcontrol:=flowcontrol;
  113. oldloopcontbroffset:=thlcgwasm(hlcg).loopContBr;
  114. oldloopbreakbroffset:=thlcgwasm(hlcg).loopBreakBr;
  115. oldclabel:=current_procinfo.CurrContinueLabel;
  116. oldblabel:=current_procinfo.CurrBreakLabel;
  117. include(flowcontrol,fc_inflowcontrol);
  118. exclude(flowcontrol,fc_unwind_loop);
  119. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  120. thlcgwasm(hlcg).incblock;
  121. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  122. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_loop));
  123. thlcgwasm(hlcg).incblock;
  124. if lnf_testatbegin in loopflags then
  125. begin
  126. pass_generate_code_condition;
  127. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  128. end else
  129. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks+1;
  130. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  131. thlcgwasm(hlcg).incblock;
  132. current_procinfo.CurrContinueLabel:=lcont;
  133. current_procinfo.CurrBreakLabel:=lbreak;
  134. secondpass(right);
  135. if (lnf_testatbegin in loopflags) then
  136. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1) ); // jump back to the external loop
  137. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  138. thlcgwasm(hlcg).decblock;
  139. if not (lnf_testatbegin in loopflags) then begin
  140. pass_generate_code_condition;
  141. end;
  142. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,0) ); // jump back to loop
  143. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_loop));
  144. thlcgwasm(hlcg).decblock;
  145. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  146. thlcgwasm(hlcg).decblock;
  147. current_procinfo.CurrContinueLabel:=oldclabel;
  148. current_procinfo.CurrBreakLabel:=oldblabel;
  149. thlcgwasm(hlcg).loopContBr:=oldloopcontbroffset;
  150. thlcgwasm(hlcg).loopBreakBr:=oldloopbreakbroffset;
  151. { a break/continue in a while/repeat block can't be seen outside }
  152. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  153. end;
  154. {*****************************************************************************
  155. twasmifnode
  156. *****************************************************************************}
  157. procedure twasmifnode.pass_generate_code;
  158. var
  159. oldflowcontrol: tflowcontrol;
  160. begin
  161. // left - condition
  162. // right - then
  163. // t1 - else (optional)
  164. location_reset(location,LOC_VOID,OS_NO);
  165. oldflowcontrol := flowcontrol;
  166. include(flowcontrol,fc_inflowcontrol);
  167. //todo: MOVE all current_asm_data actions to Wasm HL CodeGen
  168. secondpass(left); // condition exprssions
  169. thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  170. if is_64bit(left.resultdef) then
  171. begin
  172. thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,left.resultdef,0,R_INTREGISTER);
  173. current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_i64_ne));
  174. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  175. end;
  176. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  177. thlcgwasm(hlcg).incblock;
  178. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  179. if Assigned(right) then
  180. secondpass(right); // then branchs
  181. if Assigned(t1) then // else branch
  182. begin
  183. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_else));
  184. secondpass(t1);
  185. end;
  186. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  187. thlcgwasm(hlcg).decblock;
  188. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  189. end;
  190. {*****************************************************************************
  191. twasmraisenode
  192. *****************************************************************************}
  193. function twasmraisenode.pass_1_no_exceptions : tnode;
  194. var
  195. statements : tstatementnode;
  196. //current_addr : tlabelnode;
  197. raisenode : tcallnode;
  198. begin
  199. result:=internalstatements(statements);
  200. if assigned(left) then
  201. begin
  202. { first para must be a class }
  203. firstpass(left);
  204. { insert needed typeconvs for addr,frame }
  205. if assigned(right) then
  206. begin
  207. { addr }
  208. firstpass(right);
  209. { frame }
  210. if assigned(third) then
  211. firstpass(third)
  212. else
  213. third:=cpointerconstnode.Create(0,voidpointertype);
  214. end
  215. else
  216. begin
  217. third:=cinlinenode.create(in_get_frame,false,nil);
  218. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  219. //addstatement(statements,current_addr);
  220. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  221. right:=cnilnode.create;
  222. { raise address off by one so we are for sure inside the action area for the raise }
  223. if tf_use_psabieh in target_info.flags then
  224. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  225. end;
  226. raisenode:=ccallnode.createintern('fpc_raiseexception',
  227. ccallparanode.create(third,
  228. ccallparanode.create(right,
  229. ccallparanode.create(left,nil)))
  230. );
  231. include(raisenode.callnodeflags,cnf_call_never_returns);
  232. addstatement(statements,raisenode);
  233. end
  234. else
  235. begin
  236. addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  237. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  238. include(raisenode.callnodeflags,cnf_call_never_returns);
  239. addstatement(statements,raisenode);
  240. end;
  241. left:=nil;
  242. right:=nil;
  243. third:=nil;
  244. end;
  245. function twasmraisenode.pass_1_native_exceptions : tnode;
  246. var
  247. statements : tstatementnode;
  248. //current_addr : tlabelnode;
  249. raisenode : tcallnode;
  250. begin
  251. result:=internalstatements(statements);
  252. if assigned(left) then
  253. begin
  254. { first para must be a class }
  255. firstpass(left);
  256. { insert needed typeconvs for addr,frame }
  257. if assigned(right) then
  258. begin
  259. { addr }
  260. firstpass(right);
  261. { frame }
  262. if assigned(third) then
  263. firstpass(third)
  264. else
  265. third:=cpointerconstnode.Create(0,voidpointertype);
  266. end
  267. else
  268. begin
  269. third:=cinlinenode.create(in_get_frame,false,nil);
  270. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  271. //addstatement(statements,current_addr);
  272. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  273. right:=cnilnode.create;
  274. { raise address off by one so we are for sure inside the action area for the raise }
  275. if tf_use_psabieh in target_info.flags then
  276. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  277. end;
  278. raisenode:=ccallnode.createintern('fpc_raiseexception',
  279. ccallparanode.create(third,
  280. ccallparanode.create(right,
  281. ccallparanode.create(left,nil)))
  282. );
  283. include(raisenode.callnodeflags,cnf_call_never_returns);
  284. addstatement(statements,raisenode);
  285. end
  286. else
  287. begin
  288. //addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  289. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  290. include(raisenode.callnodeflags,cnf_call_never_returns);
  291. addstatement(statements,raisenode);
  292. end;
  293. left:=nil;
  294. right:=nil;
  295. third:=nil;
  296. end;
  297. function twasmraisenode.pass_1_bf_exceptions : tnode;
  298. var
  299. statements : tstatementnode;
  300. //current_addr : tlabelnode;
  301. raisenode : tcallnode;
  302. begin
  303. result:=internalstatements(statements);
  304. if assigned(left) then
  305. begin
  306. { first para must be a class }
  307. firstpass(left);
  308. { insert needed typeconvs for addr,frame }
  309. if assigned(right) then
  310. begin
  311. { addr }
  312. firstpass(right);
  313. { frame }
  314. if assigned(third) then
  315. firstpass(third)
  316. else
  317. third:=cpointerconstnode.Create(0,voidpointertype);
  318. end
  319. else
  320. begin
  321. third:=cinlinenode.create(in_get_frame,false,nil);
  322. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  323. //addstatement(statements,current_addr);
  324. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  325. right:=cnilnode.create;
  326. { raise address off by one so we are for sure inside the action area for the raise }
  327. if tf_use_psabieh in target_info.flags then
  328. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  329. end;
  330. raisenode:=ccallnode.createintern('fpc_raiseexception',
  331. ccallparanode.create(third,
  332. ccallparanode.create(right,
  333. ccallparanode.create(left,nil)))
  334. );
  335. include(raisenode.callnodeflags,cnf_call_never_returns);
  336. addstatement(statements,raisenode);
  337. end
  338. else
  339. begin
  340. //addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  341. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  342. include(raisenode.callnodeflags,cnf_call_never_returns);
  343. addstatement(statements,raisenode);
  344. end;
  345. left:=nil;
  346. right:=nil;
  347. third:=nil;
  348. end;
  349. function twasmraisenode.pass_1 : tnode;
  350. begin
  351. if ts_wasm_no_exceptions in current_settings.targetswitches then
  352. result:=pass_1_no_exceptions
  353. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  354. result:=pass_1_native_exceptions
  355. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  356. result:=pass_1_bf_exceptions
  357. else
  358. result:=inherited;
  359. end;
  360. {*****************************************************************************
  361. twasmtryexceptnode
  362. *****************************************************************************}
  363. procedure twasmtryexceptnode.pass_generate_code_no_exceptions;
  364. begin
  365. location_reset(location,LOC_VOID,OS_NO);
  366. secondpass(left);
  367. end;
  368. procedure twasmtryexceptnode.pass_generate_code_js_exceptions;
  369. begin
  370. internalerror(2021091706);
  371. end;
  372. procedure twasmtryexceptnode.pass_generate_code_native_exceptions;
  373. var
  374. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  375. destroytemps,
  376. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  377. afteronflowcontrol: tflowcontrol;
  378. label
  379. errorexit;
  380. begin
  381. location_reset(location,LOC_VOID,OS_NO);
  382. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  383. { Exception temps? We don't need no stinking exception temps! :) }
  384. fillchar(excepttemps,sizeof(excepttemps),0);
  385. reference_reset(excepttemps.envbuf,0,[]);
  386. reference_reset(excepttemps.jmpbuf,0,[]);
  387. reference_reset(excepttemps.reasonbuf,0,[]);
  388. //exceptstate.oldflowcontrol:=flowcontrol;
  389. //flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  390. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  391. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  392. thlcgwasm(hlcg).incblock;
  393. { try block }
  394. secondpass(left);
  395. if codegenerror then
  396. goto errorexit;
  397. //exceptionstate.newflowcontrol:=flowcontrol;
  398. //flowcontrol:=exceptionstate.oldflowcontrol;
  399. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,nil);
  400. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  401. flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
  402. { on statements }
  403. if assigned(right) then
  404. secondpass(right);
  405. afteronflowcontrol:=flowcontrol;
  406. { default handling except handling }
  407. if assigned(t1) then
  408. begin
  409. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  410. it doesn't change any state and its return value is ignored (Sergei)
  411. }
  412. { the destruction of the exception object must be also }
  413. { guarded by an exception frame, but it can be omitted }
  414. { if there's no user code in 'except' block }
  415. if not (has_no_code(t1)) then
  416. begin
  417. { if there is an outer frame that catches exceptions, remember this for the "except"
  418. part of this try/except }
  419. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  420. { Exception temps? We don't need no stinking exception temps! :) }
  421. fillchar(excepttemps,sizeof(destroytemps),0);
  422. reference_reset(destroytemps.envbuf,0,[]);
  423. reference_reset(destroytemps.jmpbuf,0,[]);
  424. reference_reset(destroytemps.reasonbuf,0,[]);
  425. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  426. { the flowcontrol from the default except-block must be merged
  427. with the flowcontrol flags potentially set by the
  428. on-statements handled above (secondpass(right)), as they are
  429. at the same program level }
  430. flowcontrol:=
  431. flowcontrol+
  432. afteronflowcontrol;
  433. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  434. thlcgwasm(hlcg).incblock;
  435. secondpass(t1);
  436. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  437. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  438. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  439. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  440. thlcgwasm(hlcg).decblock;
  441. end
  442. else
  443. begin
  444. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  445. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  446. end;
  447. end
  448. else
  449. begin
  450. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_rethrow,0));
  451. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  452. end;
  453. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  454. thlcgwasm(hlcg).decblock;
  455. errorexit:
  456. { return all used control flow statements }
  457. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  458. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  459. end;
  460. procedure twasmtryexceptnode.pass_generate_code_bf_exceptions;
  461. var
  462. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  463. destroytemps,
  464. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  465. afteronflowcontrol: tflowcontrol;
  466. label
  467. errorexit;
  468. begin
  469. location_reset(location,LOC_VOID,OS_NO);
  470. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  471. { Exception temps? We don't need no stinking exception temps! :) }
  472. fillchar(excepttemps,sizeof(excepttemps),0);
  473. reference_reset(excepttemps.envbuf,0,[]);
  474. reference_reset(excepttemps.jmpbuf,0,[]);
  475. reference_reset(excepttemps.reasonbuf,0,[]);
  476. //exceptstate.oldflowcontrol:=flowcontrol;
  477. //flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  478. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  479. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  480. //thlcgwasm(hlcg).incblock;
  481. { try block }
  482. secondpass(left);
  483. if codegenerror then
  484. goto errorexit;
  485. //exceptionstate.newflowcontrol:=flowcontrol;
  486. //flowcontrol:=exceptionstate.oldflowcontrol;
  487. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,nil);
  488. //current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  489. flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
  490. { on statements }
  491. if assigned(right) then
  492. secondpass(right);
  493. afteronflowcontrol:=flowcontrol;
  494. { default handling except handling }
  495. if assigned(t1) then
  496. begin
  497. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  498. it doesn't change any state and its return value is ignored (Sergei)
  499. }
  500. { the destruction of the exception object must be also }
  501. { guarded by an exception frame, but it can be omitted }
  502. { if there's no user code in 'except' block }
  503. if not (has_no_code(t1)) then
  504. begin
  505. { if there is an outer frame that catches exceptions, remember this for the "except"
  506. part of this try/except }
  507. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  508. { Exception temps? We don't need no stinking exception temps! :) }
  509. fillchar(excepttemps,sizeof(destroytemps),0);
  510. reference_reset(destroytemps.envbuf,0,[]);
  511. reference_reset(destroytemps.jmpbuf,0,[]);
  512. reference_reset(destroytemps.reasonbuf,0,[]);
  513. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  514. { the flowcontrol from the default except-block must be merged
  515. with the flowcontrol flags potentially set by the
  516. on-statements handled above (secondpass(right)), as they are
  517. at the same program level }
  518. flowcontrol:=
  519. flowcontrol+
  520. afteronflowcontrol;
  521. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  522. //thlcgwasm(hlcg).incblock;
  523. secondpass(t1);
  524. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  525. //current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  526. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  527. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  528. //thlcgwasm(hlcg).decblock;
  529. end
  530. else
  531. begin
  532. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  533. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  534. end;
  535. end
  536. else
  537. begin
  538. //current_asmdata.CurrAsmList.concat(taicpu.op_const(a_rethrow,0));
  539. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  540. end;
  541. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  542. //thlcgwasm(hlcg).decblock;
  543. errorexit:
  544. { return all used control flow statements }
  545. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  546. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  547. end;
  548. procedure twasmtryexceptnode.pass_generate_code;
  549. begin
  550. if ts_wasm_no_exceptions in current_settings.targetswitches then
  551. pass_generate_code_no_exceptions
  552. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  553. pass_generate_code_js_exceptions
  554. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  555. pass_generate_code_native_exceptions
  556. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  557. pass_generate_code_bf_exceptions
  558. else
  559. internalerror(2021091705);
  560. end;
  561. {*****************************************************************************
  562. twasmtryfinallynode
  563. *****************************************************************************}
  564. procedure twasmtryfinallynode.pass_generate_code_no_exceptions;
  565. var
  566. exitfinallylabel,
  567. continuefinallylabel,
  568. breakfinallylabel,
  569. oldCurrExitLabel,
  570. oldContinueLabel,
  571. oldBreakLabel: tasmlabel;
  572. oldLoopContBr: integer;
  573. oldLoopBreakBr: integer;
  574. oldExitBr: integer;
  575. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  576. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  577. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  578. in_loop: Boolean;
  579. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  580. var
  581. reasonreg : tregister;
  582. begin
  583. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  584. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  585. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  586. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  587. thlcgwasm(hlcg).incblock;
  588. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  589. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
  590. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  591. thlcgwasm(hlcg).decblock;
  592. end;
  593. begin
  594. location_reset(location,LOC_VOID,OS_NO);
  595. oldBreakLabel:=nil;
  596. oldContinueLabel:=nil;
  597. continuefinallylabel:=nil;
  598. breakfinallylabel:=nil;
  599. oldLoopBreakBr:=0;
  600. oldLoopContBr:=0;
  601. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  602. if not implicitframe then
  603. exceptframekind:=tek_normalfinally
  604. else
  605. exceptframekind:=tek_implicitfinally;
  606. { in 'no exceptions' mode, we still want to handle properly exit,
  607. continue and break (they still need to execute the 'finally'
  608. statements), so for this we need excepttemps.reasonbuf, and for this
  609. reason, we need to allocate excepttemps }
  610. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  611. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  612. { the finally block must catch break, continue and exit }
  613. { statements }
  614. { the outer 'try..finally' block }
  615. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  616. thlcgwasm(hlcg).incblock;
  617. { the 'exit' block }
  618. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  619. thlcgwasm(hlcg).incblock;
  620. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  621. oldExitBr:=thlcgwasm(hlcg).exitBr;
  622. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  623. current_procinfo.CurrExitLabel:=exitfinallylabel;
  624. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  625. { the 'break' block }
  626. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  627. thlcgwasm(hlcg).incblock;
  628. if in_loop then
  629. begin
  630. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  631. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  632. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  633. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  634. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  635. end;
  636. { the 'continue' block }
  637. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  638. thlcgwasm(hlcg).incblock;
  639. if in_loop then
  640. begin
  641. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  642. oldLoopContBr:=thlcgwasm(hlcg).loopContBr;
  643. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  644. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  645. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  646. end;
  647. { try code }
  648. if assigned(left) then
  649. begin
  650. secondpass(left);
  651. if codegenerror then
  652. exit;
  653. end;
  654. { don't generate line info for internal cleanup }
  655. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  656. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  657. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  658. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  659. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,3)); // jump to the 'finally' section
  660. { exit the 'continue' block }
  661. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  662. thlcgwasm(hlcg).decblock;
  663. { exceptionreason:=4 (continue) }
  664. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  665. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  666. { exit the 'break' block }
  667. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  668. thlcgwasm(hlcg).decblock;
  669. { exceptionreason:=3 (break) }
  670. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  671. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  672. { exit the 'exit' block }
  673. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  674. thlcgwasm(hlcg).decblock;
  675. { exceptionreason:=2 (exit) }
  676. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  677. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  678. { exit the outer 'try..finally' block }
  679. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  680. thlcgwasm(hlcg).decblock;
  681. { end cleanup }
  682. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  683. { finally code (don't unconditionally set fc_inflowcontrol, since the
  684. finally code is unconditionally executed; we do have to filter out
  685. flags regarding break/contrinue/etc. because we have to give an
  686. error in case one of those is used in the finally-code }
  687. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  688. secondpass(right);
  689. { goto is allowed if it stays inside the finally block,
  690. this is checked using the exception block number }
  691. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  692. CGMessage(cg_e_control_flow_outside_finally);
  693. if codegenerror then
  694. exit;
  695. { don't generate line info for internal cleanup }
  696. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  697. if fc_exit in finallyexceptionstate.newflowcontrol then
  698. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  699. if fc_break in finallyexceptionstate.newflowcontrol then
  700. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  701. if fc_continue in finallyexceptionstate.newflowcontrol then
  702. generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
  703. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  704. { end cleanup }
  705. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  706. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  707. thlcgwasm(hlcg).exitBr:=oldExitBr;
  708. if assigned(current_procinfo.CurrBreakLabel) then
  709. begin
  710. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  711. thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
  712. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  713. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  714. end;
  715. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  716. end;
  717. procedure twasmtryfinallynode.pass_generate_code_js_exceptions;
  718. begin
  719. internalerror(2021091702);
  720. end;
  721. procedure twasmtryfinallynode.pass_generate_code_native_exceptions;
  722. var
  723. exitfinallylabel,
  724. continuefinallylabel,
  725. breakfinallylabel,
  726. oldCurrExitLabel,
  727. oldContinueLabel,
  728. oldBreakLabel: tasmlabel;
  729. oldLoopContBr: integer;
  730. oldLoopBreakBr: integer;
  731. oldExitBr: integer;
  732. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  733. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  734. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  735. in_loop: Boolean;
  736. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  737. var
  738. reasonreg : tregister;
  739. begin
  740. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  741. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  742. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  743. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  744. thlcgwasm(hlcg).incblock;
  745. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  746. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
  747. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  748. thlcgwasm(hlcg).decblock;
  749. end;
  750. procedure generate_exceptreason_throw(reason: tcgint);
  751. var
  752. reasonreg : tregister;
  753. begin
  754. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  755. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  756. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  757. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  758. thlcgwasm(hlcg).incblock;
  759. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  760. current_asmdata.CurrAsmList.Concat(taicpu.op_sym(a_throw,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  761. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  762. thlcgwasm(hlcg).decblock;
  763. end;
  764. begin
  765. location_reset(location,LOC_VOID,OS_NO);
  766. oldBreakLabel:=nil;
  767. oldContinueLabel:=nil;
  768. continuefinallylabel:=nil;
  769. breakfinallylabel:=nil;
  770. oldLoopBreakBr:=0;
  771. oldLoopContBr:=0;
  772. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  773. if not implicitframe then
  774. exceptframekind:=tek_normalfinally
  775. else
  776. exceptframekind:=tek_implicitfinally;
  777. { in 'no exceptions' mode, we still want to handle properly exit,
  778. continue and break (they still need to execute the 'finally'
  779. statements), so for this we need excepttemps.reasonbuf, and for this
  780. reason, we need to allocate excepttemps }
  781. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  782. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  783. { the finally block must catch break, continue and exit }
  784. { statements }
  785. { the outer 'try..finally' block }
  786. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  787. thlcgwasm(hlcg).incblock;
  788. { the 'exit' block }
  789. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  790. thlcgwasm(hlcg).incblock;
  791. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  792. oldExitBr:=thlcgwasm(hlcg).exitBr;
  793. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  794. current_procinfo.CurrExitLabel:=exitfinallylabel;
  795. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  796. { the 'break' block }
  797. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  798. thlcgwasm(hlcg).incblock;
  799. if in_loop then
  800. begin
  801. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  802. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  803. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  804. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  805. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  806. end;
  807. { the 'continue' block }
  808. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  809. thlcgwasm(hlcg).incblock;
  810. if in_loop then
  811. begin
  812. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  813. oldLoopContBr:=thlcgwasm(hlcg).loopContBr;
  814. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  815. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  816. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  817. end;
  818. { the inner 'try..end_try' block }
  819. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  820. thlcgwasm(hlcg).incblock;
  821. { try code }
  822. if assigned(left) then
  823. begin
  824. secondpass(left);
  825. if codegenerror then
  826. exit;
  827. end;
  828. { don't generate line info for internal cleanup }
  829. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  830. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  831. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  832. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  833. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  834. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  835. { exceptionreason:=1 (exception) }
  836. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,1,excepttemps.reasonbuf);
  837. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  838. { exit the inner 'try..end_try' block }
  839. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  840. thlcgwasm(hlcg).decblock;
  841. { exit the 'continue' block }
  842. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  843. thlcgwasm(hlcg).decblock;
  844. { exceptionreason:=4 (continue) }
  845. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  846. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  847. { exit the 'break' block }
  848. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  849. thlcgwasm(hlcg).decblock;
  850. { exceptionreason:=3 (break) }
  851. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  852. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  853. { exit the 'exit' block }
  854. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  855. thlcgwasm(hlcg).decblock;
  856. { exceptionreason:=2 (exit) }
  857. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  858. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  859. { exit the outer 'try..finally' block }
  860. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  861. thlcgwasm(hlcg).decblock;
  862. { end cleanup }
  863. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  864. { finally code (don't unconditionally set fc_inflowcontrol, since the
  865. finally code is unconditionally executed; we do have to filter out
  866. flags regarding break/contrinue/etc. because we have to give an
  867. error in case one of those is used in the finally-code }
  868. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  869. secondpass(right);
  870. { goto is allowed if it stays inside the finally block,
  871. this is checked using the exception block number }
  872. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  873. CGMessage(cg_e_control_flow_outside_finally);
  874. if codegenerror then
  875. exit;
  876. { don't generate line info for internal cleanup }
  877. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  878. if fc_exit in finallyexceptionstate.newflowcontrol then
  879. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  880. if fc_break in finallyexceptionstate.newflowcontrol then
  881. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  882. if fc_continue in finallyexceptionstate.newflowcontrol then
  883. generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
  884. generate_exceptreason_throw(1);
  885. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  886. { end cleanup }
  887. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  888. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  889. thlcgwasm(hlcg).exitBr:=oldExitBr;
  890. if assigned(current_procinfo.CurrBreakLabel) then
  891. begin
  892. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  893. thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
  894. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  895. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  896. end;
  897. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  898. end;
  899. procedure twasmtryfinallynode.pass_generate_code_bf_exceptions;
  900. var
  901. exitfinallylabel,
  902. continuefinallylabel,
  903. breakfinallylabel,
  904. oldCurrExitLabel,
  905. oldContinueLabel,
  906. oldBreakLabel: tasmlabel;
  907. oldLoopContBr: integer;
  908. oldLoopBreakBr: integer;
  909. oldExitBr: integer;
  910. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  911. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  912. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  913. in_loop: Boolean;
  914. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  915. var
  916. reasonreg : tregister;
  917. begin
  918. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  919. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  920. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  921. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  922. thlcgwasm(hlcg).incblock;
  923. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  924. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
  925. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  926. thlcgwasm(hlcg).decblock;
  927. end;
  928. procedure generate_exceptreason_throw(reason: tcgint);
  929. var
  930. reasonreg : tregister;
  931. begin
  932. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  933. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  934. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  935. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  936. thlcgwasm(hlcg).incblock;
  937. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  938. //current_asmdata.CurrAsmList.Concat(taicpu.op_sym(a_throw,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  939. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  940. thlcgwasm(hlcg).decblock;
  941. end;
  942. begin
  943. location_reset(location,LOC_VOID,OS_NO);
  944. oldBreakLabel:=nil;
  945. oldContinueLabel:=nil;
  946. continuefinallylabel:=nil;
  947. breakfinallylabel:=nil;
  948. oldLoopBreakBr:=0;
  949. oldLoopContBr:=0;
  950. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  951. if not implicitframe then
  952. exceptframekind:=tek_normalfinally
  953. else
  954. exceptframekind:=tek_implicitfinally;
  955. { in 'no exceptions' mode, we still want to handle properly exit,
  956. continue and break (they still need to execute the 'finally'
  957. statements), so for this we need excepttemps.reasonbuf, and for this
  958. reason, we need to allocate excepttemps }
  959. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  960. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  961. { the finally block must catch break, continue and exit }
  962. { statements }
  963. { the outer 'try..finally' block }
  964. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  965. thlcgwasm(hlcg).incblock;
  966. { the 'exit' block }
  967. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  968. thlcgwasm(hlcg).incblock;
  969. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  970. oldExitBr:=thlcgwasm(hlcg).exitBr;
  971. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  972. current_procinfo.CurrExitLabel:=exitfinallylabel;
  973. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  974. { the 'break' block }
  975. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  976. thlcgwasm(hlcg).incblock;
  977. if in_loop then
  978. begin
  979. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  980. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  981. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  982. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  983. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  984. end;
  985. { the 'continue' block }
  986. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  987. thlcgwasm(hlcg).incblock;
  988. if in_loop then
  989. begin
  990. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  991. oldLoopContBr:=thlcgwasm(hlcg).loopContBr;
  992. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  993. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  994. thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
  995. end;
  996. { the inner 'try..end_try' block }
  997. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  998. //thlcgwasm(hlcg).incblock;
  999. { try code }
  1000. if assigned(left) then
  1001. begin
  1002. secondpass(left);
  1003. if codegenerror then
  1004. exit;
  1005. end;
  1006. { don't generate line info for internal cleanup }
  1007. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1008. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  1009. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  1010. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  1011. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  1012. //current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  1013. { exceptionreason:=1 (exception) }
  1014. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,1,excepttemps.reasonbuf);
  1015. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  1016. { exit the inner 'try..end_try' block }
  1017. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  1018. //thlcgwasm(hlcg).decblock;
  1019. { exit the 'continue' block }
  1020. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1021. thlcgwasm(hlcg).decblock;
  1022. { exceptionreason:=4 (continue) }
  1023. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  1024. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  1025. { exit the 'break' block }
  1026. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1027. thlcgwasm(hlcg).decblock;
  1028. { exceptionreason:=3 (break) }
  1029. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  1030. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  1031. { exit the 'exit' block }
  1032. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1033. thlcgwasm(hlcg).decblock;
  1034. { exceptionreason:=2 (exit) }
  1035. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  1036. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  1037. { exit the outer 'try..finally' block }
  1038. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1039. thlcgwasm(hlcg).decblock;
  1040. { end cleanup }
  1041. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1042. { finally code (don't unconditionally set fc_inflowcontrol, since the
  1043. finally code is unconditionally executed; we do have to filter out
  1044. flags regarding break/contrinue/etc. because we have to give an
  1045. error in case one of those is used in the finally-code }
  1046. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1047. secondpass(right);
  1048. { goto is allowed if it stays inside the finally block,
  1049. this is checked using the exception block number }
  1050. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  1051. CGMessage(cg_e_control_flow_outside_finally);
  1052. if codegenerror then
  1053. exit;
  1054. { don't generate line info for internal cleanup }
  1055. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1056. if fc_exit in finallyexceptionstate.newflowcontrol then
  1057. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  1058. if fc_break in finallyexceptionstate.newflowcontrol then
  1059. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  1060. if fc_continue in finallyexceptionstate.newflowcontrol then
  1061. generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
  1062. generate_exceptreason_throw(1);
  1063. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1064. { end cleanup }
  1065. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1066. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1067. thlcgwasm(hlcg).exitBr:=oldExitBr;
  1068. if assigned(current_procinfo.CurrBreakLabel) then
  1069. begin
  1070. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1071. thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
  1072. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1073. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  1074. end;
  1075. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1076. end;
  1077. procedure twasmtryfinallynode.pass_generate_code;
  1078. begin
  1079. if ts_wasm_no_exceptions in current_settings.targetswitches then
  1080. pass_generate_code_no_exceptions
  1081. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  1082. pass_generate_code_js_exceptions
  1083. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  1084. pass_generate_code_native_exceptions
  1085. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  1086. pass_generate_code_bf_exceptions
  1087. else
  1088. internalerror(2021091704);
  1089. end;
  1090. {*****************************************************************************
  1091. twasmonnode
  1092. *****************************************************************************}
  1093. procedure twasmonnode.pass_generate_code_no_exceptions;
  1094. begin
  1095. { should not be called }
  1096. internalerror(2021092803);
  1097. end;
  1098. procedure twasmonnode.pass_generate_code_js_exceptions;
  1099. begin
  1100. { not yet implemented }
  1101. internalerror(2021092804);
  1102. end;
  1103. procedure twasmonnode.pass_generate_code_native_exceptions;
  1104. var
  1105. exceptvarsym : tlocalvarsym;
  1106. exceptlocdef: tdef;
  1107. exceptlocreg: tregister;
  1108. begin
  1109. location_reset(location,LOC_VOID,OS_NO);
  1110. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nil,exceptlocdef,exceptlocreg);
  1111. { Retrieve exception variable }
  1112. if assigned(excepTSymtable) then
  1113. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1114. else
  1115. internalerror(2011020401);
  1116. if assigned(exceptvarsym) then
  1117. begin
  1118. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  1119. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  1120. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  1121. end;
  1122. { in the case that another exception is risen
  1123. we've to destroy the old one, so create a new
  1124. exception frame for the catch-handler }
  1125. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  1126. thlcgwasm(hlcg).incblock;
  1127. if assigned(right) then
  1128. secondpass(right);
  1129. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1130. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2));
  1131. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  1132. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  1133. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  1134. thlcgwasm(hlcg).decblock;
  1135. { clear some stuff }
  1136. if assigned(exceptvarsym) then
  1137. begin
  1138. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1139. exceptvarsym.localloc.loc:=LOC_INVALID;
  1140. end;
  1141. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  1142. { next on node }
  1143. if assigned(left) then
  1144. secondpass(left);
  1145. end;
  1146. procedure twasmonnode.pass_generate_code_bf_exceptions;
  1147. var
  1148. exceptvarsym : tlocalvarsym;
  1149. exceptlocdef: tdef;
  1150. exceptlocreg: tregister;
  1151. begin
  1152. location_reset(location,LOC_VOID,OS_NO);
  1153. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nil,exceptlocdef,exceptlocreg);
  1154. { Retrieve exception variable }
  1155. if assigned(excepTSymtable) then
  1156. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1157. else
  1158. internalerror(2011020401);
  1159. if assigned(exceptvarsym) then
  1160. begin
  1161. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  1162. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  1163. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  1164. end;
  1165. { in the case that another exception is risen
  1166. we've to destroy the old one, so create a new
  1167. exception frame for the catch-handler }
  1168. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  1169. //thlcgwasm(hlcg).incblock;
  1170. if assigned(right) then
  1171. secondpass(right);
  1172. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1173. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2));
  1174. //current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  1175. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  1176. //current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  1177. //thlcgwasm(hlcg).decblock;
  1178. { clear some stuff }
  1179. if assigned(exceptvarsym) then
  1180. begin
  1181. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1182. exceptvarsym.localloc.loc:=LOC_INVALID;
  1183. end;
  1184. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  1185. { next on node }
  1186. if assigned(left) then
  1187. secondpass(left);
  1188. end;
  1189. procedure twasmonnode.pass_generate_code;
  1190. begin
  1191. if ts_wasm_no_exceptions in current_settings.targetswitches then
  1192. pass_generate_code_no_exceptions
  1193. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  1194. pass_generate_code_js_exceptions
  1195. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  1196. pass_generate_code_native_exceptions
  1197. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  1198. pass_generate_code_bf_exceptions
  1199. else
  1200. internalerror(2021092802);
  1201. end;
  1202. initialization
  1203. cifnode:=twasmifnode;
  1204. cwhilerepeatnode:=twasmwhilerepeatnode;
  1205. craisenode:=twasmraisenode;
  1206. ctryexceptnode:=twasmtryexceptnode;
  1207. ctryfinallynode:=twasmtryfinallynode;
  1208. connode:=twasmonnode;
  1209. end.