From 99ab6bd56d4d60aa3cf5ec2680514a143da4dd1b Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Tue, 5 Oct 2021 07:41:42 +0300 Subject: [PATCH] + proper exception object cleanup when using break, continue or exit in try except blocks in WebAssembly native exceptions mode --- compiler/wasm32/nwasmflw.pas | 92 ++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/compiler/wasm32/nwasmflw.pas b/compiler/wasm32/nwasmflw.pas index 9838768d4e..ff7ca542f9 100644 --- a/compiler/wasm32/nwasmflw.pas +++ b/compiler/wasm32/nwasmflw.pas @@ -451,9 +451,22 @@ implementation destroytemps, excepttemps: tcgexceptionstatehandler.texceptiontemps; afteronflowcontrol: tflowcontrol; + oldCurrExitLabel, + oldContinueLabel, + oldBreakLabel: tasmlabel; + oldLoopContBr: integer; + oldLoopBreakBr: integer; + oldExitBr: integer; + in_loop: Boolean; label errorexit; begin + oldCurrExitLabel:=nil; + oldContinueLabel:=nil; + oldBreakLabel:=nil; + oldLoopContBr:=0; + oldLoopBreakBr:=0; + oldExitBr:=0; location_reset(location,LOC_VOID,OS_NO); doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate); @@ -463,8 +476,8 @@ implementation reference_reset(excepttemps.jmpbuf,0,[]); reference_reset(excepttemps.reasonbuf,0,[]); - //exceptstate.oldflowcontrol:=flowcontrol; - //flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions]; + in_loop:=assigned(current_procinfo.CurrBreakLabel); + cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate); current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try)); @@ -475,8 +488,6 @@ implementation if codegenerror then goto errorexit; - //exceptionstate.newflowcontrol:=flowcontrol; - //flowcontrol:=exceptionstate.oldflowcontrol; cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,nil); current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG))); @@ -521,9 +532,82 @@ implementation current_asmdata.CurrAsmList.concat(taicpu.op_none(a_try)); thlcgwasm(hlcg).incblock; + { the 'exit' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block)); + thlcgwasm(hlcg).incblock; + + oldCurrExitLabel:=current_procinfo.CurrExitLabel; + oldExitBr:=thlcgwasm(hlcg).exitBr; + current_asmdata.getjumplabel(current_procinfo.CurrExitLabel); + thlcgwasm(hlcg).exitBr:=thlcgwasm(hlcg).br_blocks; + + { the 'break' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block)); + thlcgwasm(hlcg).incblock; + + if in_loop then + begin + oldBreakLabel:=current_procinfo.CurrBreakLabel; + oldLoopBreakBr:=thlcgwasm(hlcg).loopBreakBr; + current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel); + thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks; + end; + + { the 'continue' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block)); + thlcgwasm(hlcg).incblock; + + if in_loop then + begin + oldContinueLabel:=current_procinfo.CurrContinueLabel; + oldLoopContBr:=thlcgwasm(hlcg).loopContBr; + current_asmdata.getjumplabel(current_procinfo.CurrContinueLabel); + thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks; + end; + secondpass(t1); + cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,destroytemps,doobjectdestroyandreraisestate,nil); + hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp; + current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,4)); + + { exit the 'continue' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); + thlcgwasm(hlcg).decblock; + if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then + begin + hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp; + current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopContBr)); + end; + + { exit the 'break' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // break + thlcgwasm(hlcg).decblock; + if fc_break in doobjectdestroyandreraisestate.newflowcontrol then + begin + hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp; + current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr)); + end; + + { exit the 'exit' block } + current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block)); // exit + thlcgwasm(hlcg).decblock; + if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then + begin + hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil).resetiftemp; + current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-oldExitBr)); + end; + + current_procinfo.CurrExitLabel:=oldCurrExitLabel; + thlcgwasm(hlcg).exitBr:=oldExitBr; + if in_loop then + begin + current_procinfo.CurrContinueLabel:=oldContinueLabel; + thlcgwasm(hlcg).loopContBr:=oldLoopContBr; + current_procinfo.CurrBreakLabel:=oldBreakLabel; + thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr; + end; current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_catch,current_asmdata.WeakRefAsmSymbol(FPC_EXCEPTION_TAG_SYM,AT_WASM_EXCEPTION_TAG)));