2
0

nwasmflw.pas 76 KB

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