nwasmflw.pas 75 KB

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