nwasmflw.pas 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864
  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. oldloopbreakbroffset: Integer;
  106. begin
  107. location_reset(location,LOC_VOID,OS_NO);
  108. current_asmdata.getjumplabel(lloop);
  109. current_asmdata.getjumplabel(lcont);
  110. current_asmdata.getjumplabel(lbreak);
  111. oldflowcontrol:=flowcontrol;
  112. oldloopbreakbroffset:=thlcgwasm(hlcg).loopBreakBr;
  113. oldclabel:=current_procinfo.CurrContinueLabel;
  114. oldblabel:=current_procinfo.CurrBreakLabel;
  115. include(flowcontrol,fc_inflowcontrol);
  116. exclude(flowcontrol,fc_unwind_loop);
  117. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  118. thlcgwasm(hlcg).incblock;
  119. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  120. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_loop));
  121. thlcgwasm(hlcg).incblock;
  122. if lnf_testatbegin in loopflags then
  123. begin
  124. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  125. pass_generate_code_condition;
  126. end;
  127. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  128. thlcgwasm(hlcg).incblock;
  129. current_procinfo.CurrContinueLabel:=lcont;
  130. current_procinfo.CurrBreakLabel:=lbreak;
  131. secondpass(right);
  132. if (lnf_testatbegin in loopflags) then
  133. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1) ); // jump back to the external loop
  134. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  135. thlcgwasm(hlcg).decblock;
  136. if not (lnf_testatbegin in loopflags) then
  137. begin
  138. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  139. pass_generate_code_condition;
  140. end;
  141. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,0) ); // jump back to loop
  142. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_loop));
  143. thlcgwasm(hlcg).decblock;
  144. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  145. thlcgwasm(hlcg).decblock;
  146. current_procinfo.CurrContinueLabel:=oldclabel;
  147. current_procinfo.CurrBreakLabel:=oldblabel;
  148. thlcgwasm(hlcg).loopBreakBr:=oldloopbreakbroffset;
  149. { a break/continue in a while/repeat block can't be seen outside }
  150. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  151. end;
  152. {*****************************************************************************
  153. twasmifnode
  154. *****************************************************************************}
  155. procedure twasmifnode.pass_generate_code;
  156. var
  157. oldflowcontrol: tflowcontrol;
  158. begin
  159. // left - condition
  160. // right - then
  161. // t1 - else (optional)
  162. location_reset(location,LOC_VOID,OS_NO);
  163. oldflowcontrol := flowcontrol;
  164. include(flowcontrol,fc_inflowcontrol);
  165. //todo: MOVE all current_asm_data actions to Wasm HL CodeGen
  166. secondpass(left); // condition exprssions
  167. thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  168. if is_64bit(left.resultdef) then
  169. begin
  170. thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,left.resultdef,0,R_INTREGISTER);
  171. current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_i64_ne));
  172. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  173. end;
  174. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  175. thlcgwasm(hlcg).incblock;
  176. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  177. if Assigned(right) then
  178. secondpass(right); // then branchs
  179. if Assigned(t1) then // else branch
  180. begin
  181. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_else));
  182. secondpass(t1);
  183. end;
  184. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  185. thlcgwasm(hlcg).decblock;
  186. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  187. end;
  188. {*****************************************************************************
  189. twasmraisenode
  190. *****************************************************************************}
  191. function twasmraisenode.pass_1_no_exceptions : tnode;
  192. var
  193. statements : tstatementnode;
  194. //current_addr : tlabelnode;
  195. raisenode : tcallnode;
  196. begin
  197. result:=internalstatements(statements);
  198. if assigned(left) then
  199. begin
  200. { first para must be a class }
  201. firstpass(left);
  202. { insert needed typeconvs for addr,frame }
  203. if assigned(right) then
  204. begin
  205. { addr }
  206. firstpass(right);
  207. { frame }
  208. if assigned(third) then
  209. firstpass(third)
  210. else
  211. third:=cpointerconstnode.Create(0,voidpointertype);
  212. end
  213. else
  214. begin
  215. third:=cinlinenode.create(in_get_frame,false,nil);
  216. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  217. //addstatement(statements,current_addr);
  218. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  219. right:=cnilnode.create;
  220. { raise address off by one so we are for sure inside the action area for the raise }
  221. if tf_use_psabieh in target_info.flags then
  222. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  223. end;
  224. raisenode:=ccallnode.createintern('fpc_raiseexception',
  225. ccallparanode.create(third,
  226. ccallparanode.create(right,
  227. ccallparanode.create(left,nil)))
  228. );
  229. include(raisenode.callnodeflags,cnf_call_never_returns);
  230. addstatement(statements,raisenode);
  231. end
  232. else
  233. begin
  234. addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  235. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  236. include(raisenode.callnodeflags,cnf_call_never_returns);
  237. addstatement(statements,raisenode);
  238. end;
  239. left:=nil;
  240. right:=nil;
  241. third:=nil;
  242. end;
  243. function twasmraisenode.pass_1_native_exceptions : tnode;
  244. var
  245. statements : tstatementnode;
  246. //current_addr : tlabelnode;
  247. raisenode : tcallnode;
  248. begin
  249. result:=internalstatements(statements);
  250. if assigned(left) then
  251. begin
  252. { first para must be a class }
  253. firstpass(left);
  254. { insert needed typeconvs for addr,frame }
  255. if assigned(right) then
  256. begin
  257. { addr }
  258. firstpass(right);
  259. { frame }
  260. if assigned(third) then
  261. firstpass(third)
  262. else
  263. third:=cpointerconstnode.Create(0,voidpointertype);
  264. end
  265. else
  266. begin
  267. third:=cinlinenode.create(in_get_frame,false,nil);
  268. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  269. //addstatement(statements,current_addr);
  270. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  271. right:=cnilnode.create;
  272. { raise address off by one so we are for sure inside the action area for the raise }
  273. if tf_use_psabieh in target_info.flags then
  274. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  275. end;
  276. raisenode:=ccallnode.createintern('fpc_raiseexception',
  277. ccallparanode.create(third,
  278. ccallparanode.create(right,
  279. ccallparanode.create(left,nil)))
  280. );
  281. include(raisenode.callnodeflags,cnf_call_never_returns);
  282. addstatement(statements,raisenode);
  283. end
  284. else
  285. begin
  286. //addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  287. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  288. include(raisenode.callnodeflags,cnf_call_never_returns);
  289. addstatement(statements,raisenode);
  290. end;
  291. left:=nil;
  292. right:=nil;
  293. third:=nil;
  294. end;
  295. function twasmraisenode.pass_1_bf_exceptions : tnode;
  296. var
  297. statements : tstatementnode;
  298. //current_addr : tlabelnode;
  299. raisenode : tcallnode;
  300. begin
  301. result:=internalstatements(statements);
  302. if assigned(left) then
  303. begin
  304. { first para must be a class }
  305. firstpass(left);
  306. { insert needed typeconvs for addr,frame }
  307. if assigned(right) then
  308. begin
  309. { addr }
  310. firstpass(right);
  311. { frame }
  312. if assigned(third) then
  313. firstpass(third)
  314. else
  315. third:=cpointerconstnode.Create(0,voidpointertype);
  316. end
  317. else
  318. begin
  319. third:=cinlinenode.create(in_get_frame,false,nil);
  320. //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
  321. //addstatement(statements,current_addr);
  322. //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
  323. right:=cnilnode.create;
  324. { raise address off by one so we are for sure inside the action area for the raise }
  325. if tf_use_psabieh in target_info.flags then
  326. right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
  327. end;
  328. raisenode:=ccallnode.createintern('fpc_raiseexception',
  329. ccallparanode.create(third,
  330. ccallparanode.create(right,
  331. ccallparanode.create(left,nil)))
  332. );
  333. include(raisenode.callnodeflags,cnf_call_never_returns);
  334. addstatement(statements,raisenode);
  335. end
  336. else
  337. begin
  338. //addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
  339. raisenode:=ccallnode.createintern('fpc_reraise',nil);
  340. include(raisenode.callnodeflags,cnf_call_never_returns);
  341. addstatement(statements,raisenode);
  342. end;
  343. left:=nil;
  344. right:=nil;
  345. third:=nil;
  346. end;
  347. function twasmraisenode.pass_1 : tnode;
  348. begin
  349. if ts_wasm_no_exceptions in current_settings.targetswitches then
  350. result:=pass_1_no_exceptions
  351. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  352. result:=pass_1_native_exceptions
  353. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  354. result:=pass_1_bf_exceptions
  355. else
  356. result:=inherited;
  357. end;
  358. {*****************************************************************************
  359. twasmtryexceptnode
  360. *****************************************************************************}
  361. procedure twasmtryexceptnode.pass_generate_code_no_exceptions;
  362. begin
  363. location_reset(location,LOC_VOID,OS_NO);
  364. secondpass(left);
  365. end;
  366. procedure twasmtryexceptnode.pass_generate_code_js_exceptions;
  367. begin
  368. internalerror(2021091706);
  369. end;
  370. procedure twasmtryexceptnode.pass_generate_code_native_exceptions;
  371. var
  372. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  373. destroytemps,
  374. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  375. afteronflowcontrol: tflowcontrol;
  376. oldCurrExitLabel,
  377. oldContinueLabel,
  378. oldBreakLabel, NewContinueLabel: tasmlabel;
  379. oldLoopBreakBr: integer;
  380. oldExitBr: integer;
  381. in_loop: Boolean;
  382. label
  383. errorexit;
  384. begin
  385. oldCurrExitLabel:=nil;
  386. oldContinueLabel:=nil;
  387. oldBreakLabel:=nil;
  388. oldLoopBreakBr:=0;
  389. oldExitBr:=0;
  390. location_reset(location,LOC_VOID,OS_NO);
  391. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  392. { Exception temps? We don't need no stinking exception temps! :) }
  393. fillchar(excepttemps,sizeof(excepttemps),0);
  394. reference_reset(excepttemps.envbuf,0,[]);
  395. reference_reset(excepttemps.jmpbuf,0,[]);
  396. reference_reset(excepttemps.reasonbuf,0,[]);
  397. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  398. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  399. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  400. thlcgwasm(hlcg).incblock;
  401. { try block }
  402. secondpass(left);
  403. if codegenerror then
  404. goto errorexit;
  405. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,nil);
  406. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  407. flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
  408. { on statements }
  409. if assigned(right) then
  410. secondpass(right);
  411. afteronflowcontrol:=flowcontrol;
  412. { default handling except handling }
  413. if assigned(t1) then
  414. begin
  415. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  416. it doesn't change any state and its return value is ignored (Sergei)
  417. }
  418. { the destruction of the exception object must be also }
  419. { guarded by an exception frame, but it can be omitted }
  420. { if there's no user code in 'except' block }
  421. if not (has_no_code(t1)) then
  422. begin
  423. { if there is an outer frame that catches exceptions, remember this for the "except"
  424. part of this try/except }
  425. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  426. { Exception temps? We don't need no stinking exception temps! :) }
  427. fillchar(excepttemps,sizeof(destroytemps),0);
  428. reference_reset(destroytemps.envbuf,0,[]);
  429. reference_reset(destroytemps.jmpbuf,0,[]);
  430. reference_reset(destroytemps.reasonbuf,0,[]);
  431. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  432. { the flowcontrol from the default except-block must be merged
  433. with the flowcontrol flags potentially set by the
  434. on-statements handled above (secondpass(right)), as they are
  435. at the same program level }
  436. flowcontrol:=
  437. flowcontrol+
  438. afteronflowcontrol;
  439. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  440. thlcgwasm(hlcg).incblock;
  441. { the 'exit' block }
  442. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  443. thlcgwasm(hlcg).incblock;
  444. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  445. oldExitBr:=thlcgwasm(hlcg).exitBr;
  446. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  447. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  448. { the 'break' block }
  449. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  450. thlcgwasm(hlcg).incblock;
  451. if in_loop then
  452. begin
  453. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  454. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  455. current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
  456. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  457. end;
  458. { the 'continue' block }
  459. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  460. thlcgwasm(hlcg).incblock;
  461. if in_loop then
  462. begin
  463. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  464. current_asmdata.getjumplabel(NewContinueLabel);
  465. current_procinfo.CurrContinueLabel:=NewContinueLabel;
  466. end;
  467. secondpass(t1);
  468. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,destroytemps,doobjectdestroyandreraisestate,nil);
  469. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  470. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4));
  471. { exit the 'continue' block }
  472. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  473. thlcgwasm(hlcg).decblock;
  474. if in_loop then
  475. hlcg.a_label(current_asmdata.CurrAsmList,NewContinueLabel);
  476. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  477. begin
  478. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  479. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br,oldContinueLabel));
  480. end;
  481. { exit the 'break' block }
  482. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // break
  483. thlcgwasm(hlcg).decblock;
  484. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  485. begin
  486. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  487. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr));
  488. end;
  489. { exit the 'exit' block }
  490. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // exit
  491. thlcgwasm(hlcg).decblock;
  492. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  493. begin
  494. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  495. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldExitBr));
  496. end;
  497. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  498. thlcgwasm(hlcg).exitBr:=oldExitBr;
  499. if in_loop then
  500. begin
  501. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  502. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  503. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  504. end;
  505. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  506. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  507. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  508. thlcgwasm(hlcg).decblock;
  509. end
  510. else
  511. begin
  512. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  513. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  514. end;
  515. end
  516. else
  517. begin
  518. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_rethrow,0));
  519. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  520. end;
  521. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  522. thlcgwasm(hlcg).decblock;
  523. errorexit:
  524. { return all used control flow statements }
  525. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  526. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  527. end;
  528. procedure twasmtryexceptnode.pass_generate_code_bf_exceptions;
  529. var
  530. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  531. destroytemps,
  532. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  533. afteronflowcontrol: tflowcontrol;
  534. oldCurrExitLabel,
  535. oldContinueLabel,
  536. oldBreakLabel, NewContinueLabel: tasmlabel;
  537. oldLoopBreakBr: integer;
  538. oldExitBr: integer;
  539. oldRaiseBr: Integer;
  540. in_loop: Boolean;
  541. label
  542. errorexit;
  543. begin
  544. oldCurrExitLabel:=nil;
  545. oldContinueLabel:=nil;
  546. oldBreakLabel:=nil;
  547. oldLoopBreakBr:=0;
  548. oldExitBr:=0;
  549. oldRaiseBr:=0;
  550. location_reset(location,LOC_VOID,OS_NO);
  551. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  552. { Exception temps? We don't need no stinking exception temps! :) }
  553. fillchar(excepttemps,sizeof(excepttemps),0);
  554. reference_reset(excepttemps.envbuf,0,[]);
  555. reference_reset(excepttemps.jmpbuf,0,[]);
  556. reference_reset(excepttemps.reasonbuf,0,[]);
  557. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  558. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  559. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  560. thlcgwasm(hlcg).incblock;
  561. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  562. thlcgwasm(hlcg).incblock;
  563. oldRaiseBr:=thlcgwasm(hlcg).raiseBr;
  564. thlcgwasm(hlcg).raiseBr:=thlcgwasm(hlcg).br_blocks;
  565. { try block }
  566. secondpass(left);
  567. if codegenerror then
  568. goto errorexit;
  569. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,nil);
  570. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1));
  571. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  572. thlcgwasm(hlcg).decblock;
  573. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_clear_exception_flag',[],nil).resetiftemp;
  574. thlcgwasm(hlcg).raiseBr:=oldRaiseBr;
  575. flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
  576. { on statements }
  577. if assigned(right) then
  578. secondpass(right);
  579. afteronflowcontrol:=flowcontrol;
  580. { default handling except handling }
  581. if assigned(t1) then
  582. begin
  583. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  584. it doesn't change any state and its return value is ignored (Sergei)
  585. }
  586. { the destruction of the exception object must be also }
  587. { guarded by an exception frame, but it can be omitted }
  588. { if there's no user code in 'except' block }
  589. if not (has_no_code(t1)) then
  590. begin
  591. { if there is an outer frame that catches exceptions, remember this for the "except"
  592. part of this try/except }
  593. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  594. { Exception temps? We don't need no stinking exception temps! :) }
  595. fillchar(excepttemps,sizeof(destroytemps),0);
  596. reference_reset(destroytemps.envbuf,0,[]);
  597. reference_reset(destroytemps.jmpbuf,0,[]);
  598. reference_reset(destroytemps.reasonbuf,0,[]);
  599. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  600. { the flowcontrol from the default except-block must be merged
  601. with the flowcontrol flags potentially set by the
  602. on-statements handled above (secondpass(right)), as they are
  603. at the same program level }
  604. flowcontrol:=
  605. flowcontrol+
  606. afteronflowcontrol;
  607. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  608. thlcgwasm(hlcg).incblock;
  609. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  610. thlcgwasm(hlcg).incblock;
  611. oldRaiseBr:=thlcgwasm(hlcg).raiseBr;
  612. thlcgwasm(hlcg).raiseBr:=thlcgwasm(hlcg).br_blocks;
  613. { the 'exit' block }
  614. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  615. thlcgwasm(hlcg).incblock;
  616. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  617. oldExitBr:=thlcgwasm(hlcg).exitBr;
  618. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  619. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  620. { the 'break' block }
  621. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  622. thlcgwasm(hlcg).incblock;
  623. if in_loop then
  624. begin
  625. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  626. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  627. current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
  628. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  629. end;
  630. { the 'continue' block }
  631. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  632. thlcgwasm(hlcg).incblock;
  633. if in_loop then
  634. begin
  635. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  636. current_asmdata.getjumplabel(NewContinueLabel);
  637. current_procinfo.CurrContinueLabel:=NewContinueLabel;
  638. end;
  639. secondpass(t1);
  640. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,destroytemps,doobjectdestroyandreraisestate,nil);
  641. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  642. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4));
  643. { exit the 'continue' block }
  644. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  645. thlcgwasm(hlcg).decblock;
  646. if in_loop then
  647. hlcg.a_label(current_asmdata.CurrAsmList,NewContinueLabel);
  648. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  649. begin
  650. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  651. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br,OldContinueLabel));
  652. end;
  653. { exit the 'break' block }
  654. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // break
  655. thlcgwasm(hlcg).decblock;
  656. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  657. begin
  658. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  659. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr));
  660. end;
  661. { exit the 'exit' block }
  662. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // exit
  663. thlcgwasm(hlcg).decblock;
  664. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  665. begin
  666. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  667. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldExitBr));
  668. end;
  669. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  670. thlcgwasm(hlcg).decblock;
  671. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  672. thlcgwasm(hlcg).exitBr:=oldExitBr;
  673. if in_loop then
  674. begin
  675. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  676. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  677. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  678. end;
  679. thlcgwasm(hlcg).raiseBr:=oldRaiseBr;
  680. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_clear_exception_flag',[],nil).resetiftemp;
  681. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  682. hlcg.g_maybe_checkforexceptions(current_asmdata.CurrAsmList);
  683. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  684. thlcgwasm(hlcg).decblock;
  685. end
  686. else
  687. begin
  688. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  689. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  690. end;
  691. end
  692. else
  693. begin
  694. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  695. hlcg.g_maybe_checkforexceptions(current_asmdata.CurrAsmList);
  696. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  697. end;
  698. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  699. thlcgwasm(hlcg).decblock;
  700. errorexit:
  701. { return all used control flow statements }
  702. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  703. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  704. thlcgwasm(hlcg).raiseBr:=oldRaiseBr;
  705. end;
  706. procedure twasmtryexceptnode.pass_generate_code;
  707. begin
  708. if ts_wasm_no_exceptions in current_settings.targetswitches then
  709. pass_generate_code_no_exceptions
  710. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  711. pass_generate_code_js_exceptions
  712. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  713. pass_generate_code_native_exceptions
  714. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  715. pass_generate_code_bf_exceptions
  716. else
  717. internalerror(2021091705);
  718. end;
  719. {*****************************************************************************
  720. twasmtryfinallynode
  721. *****************************************************************************}
  722. procedure twasmtryfinallynode.pass_generate_code_no_exceptions;
  723. var
  724. exitfinallylabel,
  725. continuefinallylabel,
  726. breakfinallylabel,
  727. oldCurrExitLabel,
  728. oldContinueLabel,
  729. oldBreakLabel: tasmlabel;
  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_const(a_br_if,br));
  744. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  745. end;
  746. procedure generate_exceptreason_check_br(reason: tcgint; l: TAsmLabel);
  747. var
  748. reasonreg : tregister;
  749. begin
  750. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  751. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  752. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  753. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br_if,l));
  754. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  755. end;
  756. begin
  757. location_reset(location,LOC_VOID,OS_NO);
  758. oldBreakLabel:=nil;
  759. oldContinueLabel:=nil;
  760. continuefinallylabel:=nil;
  761. breakfinallylabel:=nil;
  762. oldLoopBreakBr:=0;
  763. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  764. if not implicitframe then
  765. exceptframekind:=tek_normalfinally
  766. else
  767. exceptframekind:=tek_implicitfinally;
  768. { in 'no exceptions' mode, we still want to handle properly exit,
  769. continue and break (they still need to execute the 'finally'
  770. statements), so for this we need excepttemps.reasonbuf, and for this
  771. reason, we need to allocate excepttemps }
  772. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  773. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  774. { the finally block must catch break, continue and exit }
  775. { statements }
  776. { the outer 'try..finally' block }
  777. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  778. thlcgwasm(hlcg).incblock;
  779. { the 'exit' block }
  780. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  781. thlcgwasm(hlcg).incblock;
  782. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  783. oldExitBr:=thlcgwasm(hlcg).exitBr;
  784. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  785. current_procinfo.CurrExitLabel:=exitfinallylabel;
  786. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  787. { the 'break' block }
  788. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  789. thlcgwasm(hlcg).incblock;
  790. if in_loop then
  791. begin
  792. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  793. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  794. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  795. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  796. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  797. end;
  798. { the 'continue' block }
  799. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  800. thlcgwasm(hlcg).incblock;
  801. if in_loop then
  802. begin
  803. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  804. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  805. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  806. end;
  807. { try code }
  808. if assigned(left) then
  809. begin
  810. secondpass(left);
  811. if codegenerror then
  812. exit;
  813. end;
  814. { don't generate line info for internal cleanup }
  815. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  816. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  817. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  818. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  819. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,3)); // jump to the 'finally' section
  820. { exit the 'continue' block }
  821. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  822. thlcgwasm(hlcg).decblock;
  823. if in_loop then
  824. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  825. { exceptionreason:=4 (continue) }
  826. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  827. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  828. { exit the 'break' block }
  829. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  830. thlcgwasm(hlcg).decblock;
  831. { exceptionreason:=3 (break) }
  832. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  833. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  834. { exit the 'exit' block }
  835. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  836. thlcgwasm(hlcg).decblock;
  837. { exceptionreason:=2 (exit) }
  838. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  839. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  840. { exit the outer 'try..finally' block }
  841. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  842. thlcgwasm(hlcg).decblock;
  843. { end cleanup }
  844. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  845. { finally code (don't unconditionally set fc_inflowcontrol, since the
  846. finally code is unconditionally executed; we do have to filter out
  847. flags regarding break/contrinue/etc. because we have to give an
  848. error in case one of those is used in the finally-code }
  849. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  850. secondpass(right);
  851. { goto is allowed if it stays inside the finally block,
  852. this is checked using the exception block number }
  853. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  854. CGMessage(cg_e_control_flow_outside_finally);
  855. if codegenerror then
  856. exit;
  857. { don't generate line info for internal cleanup }
  858. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  859. if fc_exit in finallyexceptionstate.newflowcontrol then
  860. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  861. if fc_break in finallyexceptionstate.newflowcontrol then
  862. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  863. if fc_continue in finallyexceptionstate.newflowcontrol then
  864. generate_exceptreason_check_br(4,oldContinueLabel);
  865. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  866. { end cleanup }
  867. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  868. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  869. thlcgwasm(hlcg).exitBr:=oldExitBr;
  870. if assigned(current_procinfo.CurrBreakLabel) then
  871. begin
  872. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  873. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  874. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  875. end;
  876. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  877. end;
  878. procedure twasmtryfinallynode.pass_generate_code_js_exceptions;
  879. begin
  880. internalerror(2021091702);
  881. end;
  882. procedure twasmtryfinallynode.pass_generate_code_native_exceptions;
  883. var
  884. exitfinallylabel,
  885. continuefinallylabel,
  886. breakfinallylabel,
  887. oldCurrExitLabel,
  888. oldContinueLabel,
  889. oldBreakLabel: tasmlabel;
  890. oldLoopBreakBr: integer;
  891. oldExitBr: integer;
  892. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  893. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  894. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  895. in_loop: Boolean;
  896. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  897. var
  898. reasonreg : tregister;
  899. begin
  900. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  901. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  902. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  903. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
  904. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  905. end;
  906. procedure generate_exceptreason_check_br(reason: tcgint; l: tasmlabel);
  907. var
  908. reasonreg : tregister;
  909. begin
  910. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  911. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  912. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  913. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br_if,l));
  914. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  915. end;
  916. procedure generate_exceptreason_throw(reason: tcgint);
  917. var
  918. reasonreg : tregister;
  919. begin
  920. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  921. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  922. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  923. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  924. thlcgwasm(hlcg).incblock;
  925. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  926. current_asmdata.CurrAsmList.Concat(taicpu.op_sym(a_throw,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  927. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  928. thlcgwasm(hlcg).decblock;
  929. end;
  930. begin
  931. location_reset(location,LOC_VOID,OS_NO);
  932. oldBreakLabel:=nil;
  933. oldContinueLabel:=nil;
  934. continuefinallylabel:=nil;
  935. breakfinallylabel:=nil;
  936. oldLoopBreakBr:=0;
  937. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  938. if not implicitframe then
  939. exceptframekind:=tek_normalfinally
  940. else
  941. exceptframekind:=tek_implicitfinally;
  942. { in 'no exceptions' mode, we still want to handle properly exit,
  943. continue and break (they still need to execute the 'finally'
  944. statements), so for this we need excepttemps.reasonbuf, and for this
  945. reason, we need to allocate excepttemps }
  946. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  947. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  948. { the finally block must catch break, continue and exit }
  949. { statements }
  950. { the outer 'try..finally' block }
  951. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  952. thlcgwasm(hlcg).incblock;
  953. { the 'exit' block }
  954. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  955. thlcgwasm(hlcg).incblock;
  956. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  957. oldExitBr:=thlcgwasm(hlcg).exitBr;
  958. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  959. current_procinfo.CurrExitLabel:=exitfinallylabel;
  960. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  961. { the 'break' block }
  962. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  963. thlcgwasm(hlcg).incblock;
  964. if in_loop then
  965. begin
  966. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  967. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  968. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  969. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  970. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  971. end;
  972. { the 'continue' block }
  973. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  974. thlcgwasm(hlcg).incblock;
  975. if in_loop then
  976. begin
  977. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  978. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  979. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  980. end;
  981. { the inner 'try..end_try' block }
  982. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  983. thlcgwasm(hlcg).incblock;
  984. { try code }
  985. if assigned(left) then
  986. begin
  987. secondpass(left);
  988. if codegenerror then
  989. exit;
  990. end;
  991. { don't generate line info for internal cleanup }
  992. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  993. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  994. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  995. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  996. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  997. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  998. { exceptionreason:=1 (exception) }
  999. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,1,excepttemps.reasonbuf);
  1000. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  1001. { exit the inner 'try..end_try' block }
  1002. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  1003. thlcgwasm(hlcg).decblock;
  1004. { exit the 'continue' block }
  1005. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1006. thlcgwasm(hlcg).decblock;
  1007. if in_loop then
  1008. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  1009. { exceptionreason:=4 (continue) }
  1010. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  1011. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  1012. { exit the 'break' block }
  1013. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1014. thlcgwasm(hlcg).decblock;
  1015. { exceptionreason:=3 (break) }
  1016. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  1017. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  1018. { exit the 'exit' block }
  1019. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1020. thlcgwasm(hlcg).decblock;
  1021. { exceptionreason:=2 (exit) }
  1022. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  1023. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  1024. { exit the outer 'try..finally' block }
  1025. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1026. thlcgwasm(hlcg).decblock;
  1027. { end cleanup }
  1028. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1029. { finally code (don't unconditionally set fc_inflowcontrol, since the
  1030. finally code is unconditionally executed; we do have to filter out
  1031. flags regarding break/contrinue/etc. because we have to give an
  1032. error in case one of those is used in the finally-code }
  1033. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1034. secondpass(right);
  1035. { goto is allowed if it stays inside the finally block,
  1036. this is checked using the exception block number }
  1037. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  1038. CGMessage(cg_e_control_flow_outside_finally);
  1039. if codegenerror then
  1040. exit;
  1041. { don't generate line info for internal cleanup }
  1042. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1043. if fc_exit in finallyexceptionstate.newflowcontrol then
  1044. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  1045. if fc_break in finallyexceptionstate.newflowcontrol then
  1046. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  1047. if fc_continue in finallyexceptionstate.newflowcontrol then
  1048. generate_exceptreason_check_br(4,oldContinueLabel);
  1049. generate_exceptreason_throw(1);
  1050. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1051. { end cleanup }
  1052. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1053. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1054. thlcgwasm(hlcg).exitBr:=oldExitBr;
  1055. if assigned(current_procinfo.CurrBreakLabel) then
  1056. begin
  1057. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1058. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1059. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  1060. end;
  1061. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1062. end;
  1063. procedure twasmtryfinallynode.pass_generate_code_bf_exceptions;
  1064. var
  1065. exitfinallylabel,
  1066. continuefinallylabel,
  1067. breakfinallylabel,
  1068. oldCurrExitLabel,
  1069. oldContinueLabel,
  1070. oldBreakLabel: tasmlabel;
  1071. oldLoopBreakBr: integer;
  1072. oldExitBr: integer;
  1073. oldRaiseBr: integer;
  1074. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  1075. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  1076. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  1077. in_loop: Boolean;
  1078. procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
  1079. var
  1080. reasonreg : tregister;
  1081. begin
  1082. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  1083. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  1084. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  1085. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
  1086. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  1087. end;
  1088. procedure generate_exceptreason_check_br(reason: tcgint; l: tasmsymbol);
  1089. var
  1090. reasonreg : tregister;
  1091. begin
  1092. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  1093. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  1094. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  1095. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br_if,l));
  1096. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  1097. end;
  1098. procedure generate_exceptreason_reraise(reason: tcgint);
  1099. var
  1100. reasonreg : tregister;
  1101. begin
  1102. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
  1103. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
  1104. thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
  1105. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  1106. thlcgwasm(hlcg).incblock;
  1107. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  1108. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  1109. hlcg.g_maybe_checkforexceptions(current_asmdata.CurrAsmList);
  1110. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  1111. thlcgwasm(hlcg).decblock;
  1112. end;
  1113. begin
  1114. location_reset(location,LOC_VOID,OS_NO);
  1115. oldBreakLabel:=nil;
  1116. oldContinueLabel:=nil;
  1117. continuefinallylabel:=nil;
  1118. breakfinallylabel:=nil;
  1119. oldLoopBreakBr:=0;
  1120. oldRaiseBr:=0;
  1121. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  1122. if not implicitframe then
  1123. exceptframekind:=tek_normalfinally
  1124. else
  1125. exceptframekind:=tek_implicitfinally;
  1126. { in 'no exceptions' mode, we still want to handle properly exit,
  1127. continue and break (they still need to execute the 'finally'
  1128. statements), so for this we need excepttemps.reasonbuf, and for this
  1129. reason, we need to allocate excepttemps }
  1130. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1131. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  1132. { the finally block must catch break, continue and exit }
  1133. { statements }
  1134. { the outer 'try..finally' block }
  1135. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1136. thlcgwasm(hlcg).incblock;
  1137. { the 'exit' block }
  1138. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1139. thlcgwasm(hlcg).incblock;
  1140. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1141. oldExitBr:=thlcgwasm(hlcg).exitBr;
  1142. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1143. current_procinfo.CurrExitLabel:=exitfinallylabel;
  1144. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  1145. { the 'break' block }
  1146. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1147. thlcgwasm(hlcg).incblock;
  1148. if in_loop then
  1149. begin
  1150. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1151. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  1152. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1153. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  1154. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  1155. end;
  1156. { the 'continue' block }
  1157. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1158. thlcgwasm(hlcg).incblock;
  1159. if in_loop then
  1160. begin
  1161. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1162. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1163. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  1164. end;
  1165. { the inner 'try..end_try' block }
  1166. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1167. thlcgwasm(hlcg).incblock;
  1168. oldRaiseBr:=thlcgwasm(hlcg).raiseBr;
  1169. thlcgwasm(hlcg).raiseBr:=thlcgwasm(hlcg).br_blocks;
  1170. { try code }
  1171. if assigned(left) then
  1172. begin
  1173. secondpass(left);
  1174. if codegenerror then
  1175. exit;
  1176. end;
  1177. { don't generate line info for internal cleanup }
  1178. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1179. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
  1180. { we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
  1181. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
  1182. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); // jump to the 'finally' section
  1183. { exit the inner 'try..end_try' block }
  1184. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1185. thlcgwasm(hlcg).decblock;
  1186. { exceptionreason:=1 (exception) }
  1187. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_clear_exception_flag',[],nil).resetiftemp;
  1188. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,1,excepttemps.reasonbuf);
  1189. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,3)); // jump to the 'finally' section
  1190. { exit the 'continue' block }
  1191. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1192. thlcgwasm(hlcg).decblock;
  1193. if in_loop then
  1194. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  1195. { exceptionreason:=4 (continue) }
  1196. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
  1197. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
  1198. { exit the 'break' block }
  1199. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1200. thlcgwasm(hlcg).decblock;
  1201. { exceptionreason:=3 (break) }
  1202. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
  1203. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
  1204. { exit the 'exit' block }
  1205. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1206. thlcgwasm(hlcg).decblock;
  1207. { exceptionreason:=2 (exit) }
  1208. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
  1209. { proceed to the 'finally' section, which follow immediately, no need for jumps }
  1210. { exit the outer 'try..finally' block }
  1211. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1212. thlcgwasm(hlcg).decblock;
  1213. { end cleanup }
  1214. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1215. { restore previous raiseBr }
  1216. thlcgwasm(hlcg).raiseBr:=oldRaiseBr;
  1217. { finally code (don't unconditionally set fc_inflowcontrol, since the
  1218. finally code is unconditionally executed; we do have to filter out
  1219. flags regarding break/contrinue/etc. because we have to give an
  1220. error in case one of those is used in the finally-code }
  1221. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1222. secondpass(right);
  1223. { goto is allowed if it stays inside the finally block,
  1224. this is checked using the exception block number }
  1225. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  1226. CGMessage(cg_e_control_flow_outside_finally);
  1227. if codegenerror then
  1228. exit;
  1229. { don't generate line info for internal cleanup }
  1230. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1231. if fc_exit in finallyexceptionstate.newflowcontrol then
  1232. generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
  1233. if fc_break in finallyexceptionstate.newflowcontrol then
  1234. generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
  1235. if fc_continue in finallyexceptionstate.newflowcontrol then
  1236. generate_exceptreason_check_br(4,oldContinueLabel);
  1237. generate_exceptreason_reraise(1);
  1238. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1239. { end cleanup }
  1240. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1241. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1242. thlcgwasm(hlcg).exitBr:=oldExitBr;
  1243. if assigned(current_procinfo.CurrBreakLabel) then
  1244. begin
  1245. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1246. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1247. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  1248. end;
  1249. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1250. end;
  1251. procedure twasmtryfinallynode.pass_generate_code;
  1252. begin
  1253. if ts_wasm_no_exceptions in current_settings.targetswitches then
  1254. pass_generate_code_no_exceptions
  1255. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  1256. pass_generate_code_js_exceptions
  1257. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  1258. pass_generate_code_native_exceptions
  1259. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  1260. pass_generate_code_bf_exceptions
  1261. else
  1262. internalerror(2021091704);
  1263. end;
  1264. {*****************************************************************************
  1265. twasmonnode
  1266. *****************************************************************************}
  1267. procedure twasmonnode.pass_generate_code_no_exceptions;
  1268. begin
  1269. { should not be called }
  1270. internalerror(2021092803);
  1271. end;
  1272. procedure twasmonnode.pass_generate_code_js_exceptions;
  1273. begin
  1274. { not yet implemented }
  1275. internalerror(2021092804);
  1276. end;
  1277. procedure twasmonnode.pass_generate_code_native_exceptions;
  1278. var
  1279. exceptvarsym : tlocalvarsym;
  1280. exceptlocdef: tdef;
  1281. exceptlocreg: tregister;
  1282. oldCurrExitLabel,
  1283. oldContinueLabel,
  1284. oldBreakLabel, NewContinueLabel: tasmlabel;
  1285. oldLoopBreakBr: integer;
  1286. oldExitBr: integer;
  1287. in_loop: Boolean;
  1288. doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  1289. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  1290. begin
  1291. oldCurrExitLabel:=nil;
  1292. oldContinueLabel:=nil;
  1293. oldBreakLabel:=nil;
  1294. oldLoopBreakBr:=0;
  1295. oldExitBr:=0;
  1296. location_reset(location,LOC_VOID,OS_NO);
  1297. { Exception temps? We don't need no stinking exception temps! :) }
  1298. fillchar(excepttemps,sizeof(excepttemps),0);
  1299. reference_reset(excepttemps.envbuf,0,[]);
  1300. reference_reset(excepttemps.jmpbuf,0,[]);
  1301. reference_reset(excepttemps.reasonbuf,0,[]);
  1302. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  1303. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nil,exceptlocdef,exceptlocreg);
  1304. { Retrieve exception variable }
  1305. if assigned(excepTSymtable) then
  1306. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1307. else
  1308. internalerror(2011020401);
  1309. if assigned(exceptvarsym) then
  1310. begin
  1311. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  1312. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  1313. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  1314. end;
  1315. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,doobjectdestroyandreraisestate);
  1316. { in the case that another exception is risen
  1317. we've to destroy the old one, so create a new
  1318. exception frame for the catch-handler }
  1319. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try));
  1320. thlcgwasm(hlcg).incblock;
  1321. { the 'exit' block }
  1322. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1323. thlcgwasm(hlcg).incblock;
  1324. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1325. oldExitBr:=thlcgwasm(hlcg).exitBr;
  1326. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  1327. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  1328. { the 'break' block }
  1329. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1330. thlcgwasm(hlcg).incblock;
  1331. if in_loop then
  1332. begin
  1333. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1334. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  1335. current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
  1336. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  1337. end;
  1338. { the 'continue' block }
  1339. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1340. thlcgwasm(hlcg).incblock;
  1341. if in_loop then
  1342. begin
  1343. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1344. current_asmdata.getjumplabel(NewContinueLabel);
  1345. current_procinfo.CurrContinueLabel:=NewContinueLabel;
  1346. end;
  1347. if assigned(right) then
  1348. secondpass(right);
  1349. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,doobjectdestroyandreraisestate,nil);
  1350. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1351. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,5));
  1352. { exit the 'continue' block }
  1353. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1354. thlcgwasm(hlcg).decblock;
  1355. if in_loop then
  1356. hlcg.a_label(current_asmdata.CurrAsmList,NewContinueLabel);
  1357. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  1358. begin
  1359. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1360. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br,oldContinueLabel));
  1361. end;
  1362. { exit the 'break' block }
  1363. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // break
  1364. thlcgwasm(hlcg).decblock;
  1365. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  1366. begin
  1367. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1368. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr));
  1369. end;
  1370. { exit the 'exit' block }
  1371. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // exit
  1372. thlcgwasm(hlcg).decblock;
  1373. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  1374. begin
  1375. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1376. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldExitBr));
  1377. end;
  1378. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1379. thlcgwasm(hlcg).exitBr:=oldExitBr;
  1380. if in_loop then
  1381. begin
  1382. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1383. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1384. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  1385. end;
  1386. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));
  1387. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  1388. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_try));
  1389. thlcgwasm(hlcg).decblock;
  1390. { clear some stuff }
  1391. if assigned(exceptvarsym) then
  1392. begin
  1393. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1394. exceptvarsym.localloc.loc:=LOC_INVALID;
  1395. end;
  1396. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  1397. { propagate exit/break/continue }
  1398. flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1399. { next on node }
  1400. if assigned(left) then
  1401. secondpass(left);
  1402. end;
  1403. procedure twasmonnode.pass_generate_code_bf_exceptions;
  1404. var
  1405. exceptvarsym : tlocalvarsym;
  1406. exceptlocdef: tdef;
  1407. exceptlocreg: tregister;
  1408. oldCurrExitLabel,
  1409. oldContinueLabel,
  1410. oldBreakLabel, NewContinueLabel: tasmlabel;
  1411. oldLoopBreakBr: integer;
  1412. oldExitBr: integer;
  1413. oldRaiseBr: Integer;
  1414. in_loop: Boolean;
  1415. doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  1416. excepttemps: tcgexceptionstatehandler.texceptiontemps;
  1417. begin
  1418. oldCurrExitLabel:=nil;
  1419. oldContinueLabel:=nil;
  1420. oldBreakLabel:=nil;
  1421. oldLoopBreakBr:=0;
  1422. oldExitBr:=0;
  1423. oldRaiseBr:=0;
  1424. location_reset(location,LOC_VOID,OS_NO);
  1425. { Exception temps? We don't need no stinking exception temps! :) }
  1426. fillchar(excepttemps,sizeof(excepttemps),0);
  1427. reference_reset(excepttemps.envbuf,0,[]);
  1428. reference_reset(excepttemps.jmpbuf,0,[]);
  1429. reference_reset(excepttemps.reasonbuf,0,[]);
  1430. in_loop:=assigned(current_procinfo.CurrBreakLabel);
  1431. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nil,exceptlocdef,exceptlocreg);
  1432. { Retrieve exception variable }
  1433. if assigned(excepTSymtable) then
  1434. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1435. else
  1436. internalerror(2011020401);
  1437. if assigned(exceptvarsym) then
  1438. begin
  1439. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  1440. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  1441. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  1442. end;
  1443. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,doobjectdestroyandreraisestate);
  1444. { in the case that another exception is risen
  1445. we've to destroy the old one, so create a new
  1446. exception frame for the catch-handler }
  1447. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1448. thlcgwasm(hlcg).incblock;
  1449. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1450. thlcgwasm(hlcg).incblock;
  1451. oldRaiseBr:=thlcgwasm(hlcg).raiseBr;
  1452. thlcgwasm(hlcg).raiseBr:=thlcgwasm(hlcg).br_blocks;
  1453. { the 'exit' block }
  1454. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1455. thlcgwasm(hlcg).incblock;
  1456. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1457. oldExitBr:=thlcgwasm(hlcg).exitBr;
  1458. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  1459. thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks;
  1460. { the 'break' block }
  1461. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1462. thlcgwasm(hlcg).incblock;
  1463. if in_loop then
  1464. begin
  1465. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1466. oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr;
  1467. current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
  1468. thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
  1469. end;
  1470. { the 'continue' block }
  1471. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
  1472. thlcgwasm(hlcg).incblock;
  1473. if in_loop then
  1474. begin
  1475. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1476. current_asmdata.getjumplabel(NewContinueLabel);
  1477. current_procinfo.CurrContinueLabel:=NewContinueLabel;
  1478. end;
  1479. if assigned(right) then
  1480. secondpass(right);
  1481. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,doobjectdestroyandreraisestate,nil);
  1482. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1483. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,6));
  1484. { exit the 'continue' block }
  1485. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1486. thlcgwasm(hlcg).decblock;
  1487. if in_loop then
  1488. hlcg.a_label(current_asmdata.CurrAsmList,NewContinueLabel);
  1489. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  1490. begin
  1491. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1492. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_br,oldContinueLabel));
  1493. end;
  1494. { exit the 'break' block }
  1495. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // break
  1496. thlcgwasm(hlcg).decblock;
  1497. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  1498. begin
  1499. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1500. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr));
  1501. end;
  1502. { exit the 'exit' block }
  1503. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // exit
  1504. thlcgwasm(hlcg).decblock;
  1505. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  1506. begin
  1507. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp;
  1508. current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldExitBr));
  1509. end;
  1510. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1511. thlcgwasm(hlcg).decblock;
  1512. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1513. thlcgwasm(hlcg).exitBr:=oldExitBr;
  1514. if in_loop then
  1515. begin
  1516. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1517. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1518. thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
  1519. end;
  1520. thlcgwasm(hlcg).raiseBr:=oldRaiseBr;
  1521. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_clear_exception_flag',[],nil).resetiftemp;
  1522. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_raise_nested',[],nil).resetiftemp;
  1523. hlcg.g_maybe_checkforexceptions(current_asmdata.CurrAsmList);
  1524. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
  1525. thlcgwasm(hlcg).decblock;
  1526. { clear some stuff }
  1527. if assigned(exceptvarsym) then
  1528. begin
  1529. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1530. exceptvarsym.localloc.loc:=LOC_INVALID;
  1531. end;
  1532. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  1533. { propagate exit/break/continue }
  1534. flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1535. { next on node }
  1536. if assigned(left) then
  1537. secondpass(left);
  1538. end;
  1539. procedure twasmonnode.pass_generate_code;
  1540. begin
  1541. if ts_wasm_no_exceptions in current_settings.targetswitches then
  1542. pass_generate_code_no_exceptions
  1543. else if ts_wasm_js_exceptions in current_settings.targetswitches then
  1544. pass_generate_code_js_exceptions
  1545. else if ts_wasm_native_exceptions in current_settings.targetswitches then
  1546. pass_generate_code_native_exceptions
  1547. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  1548. pass_generate_code_bf_exceptions
  1549. else
  1550. internalerror(2021092802);
  1551. end;
  1552. initialization
  1553. cifnode:=twasmifnode;
  1554. cwhilerepeatnode:=twasmwhilerepeatnode;
  1555. craisenode:=twasmraisenode;
  1556. ctryexceptnode:=twasmtryexceptnode;
  1557. ctryfinallynode:=twasmtryfinallynode;
  1558. connode:=twasmonnode;
  1559. end.