* cloned the WASM no exceptions mode code generation for try..finally blocks

for the native WASM exceptions mode. Eventually, it is going to be changed
  to support exceptions fully, and it's going to evolve separately, so this
  code is only used as a starting point
This commit is contained in:
Nikolay Nikolov 2021-09-17 21:01:00 +03:00
parent 65a5b299c6
commit 45e53ddc16
2 changed files with 197 additions and 3 deletions

View File

@ -99,19 +99,38 @@ implementation
type
twasmexceptionstatehandler_jsexceptions = class(tcgexceptionstatehandler)
class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
end;
class procedure twasmexceptionstatehandler_jsexceptions.get_exception_temps(list:TAsmList;var t:texceptiontemps);
begin
if not assigned(exceptionreasontype) then
exceptionreasontype:=search_system_proc('fpc_setjmp').returndef;
reference_reset(t.envbuf,0,[]);
reference_reset(t.jmpbuf,0,[]);
tg.gethltemp(list,exceptionreasontype,exceptionreasontype.size,tt_persistent,t.reasonbuf);
end;
class procedure twasmexceptionstatehandler_jsexceptions.unget_exception_temps(list:TAsmList;const t:texceptiontemps);
begin
tg.ungettemp(list,t.reasonbuf);
end;
class procedure twasmexceptionstatehandler_jsexceptions.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
begin
list.Concat(tai_comment.Create(strpnew('TODO: new_exception')));
exceptstate.exceptionlabel:=nil;
exceptstate.oldflowcontrol:=flowcontrol;
exceptstate.finallycodelabel:=nil;
flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
end;
class procedure twasmexceptionstatehandler_jsexceptions.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
begin
list.Concat(tai_comment.Create(strpnew('TODO: free_exception')));
end;
class procedure twasmexceptionstatehandler_jsexceptions.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);

View File

@ -511,8 +511,183 @@ implementation
end;
procedure twasmtryfinallynode.pass_generate_code_native_exceptions;
var
exitfinallylabel,
continuefinallylabel,
breakfinallylabel,
oldCurrExitLabel,
oldContinueLabel,
oldBreakLabel: tasmlabel;
oldLoopContBr: integer;
oldLoopBreakBr: integer;
oldExitBr: integer;
finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
excepttemps : tcgexceptionstatehandler.texceptiontemps;
exceptframekind: tcgexceptionstatehandler.texceptframekind;
in_loop: Boolean;
procedure generate_exceptreason_check_br(reason: tcgint; br: aint);
var
reasonreg : tregister;
begin
reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,exceptionreasontype);
hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,exceptionreasontype,exceptionreasontype,excepttemps.reasonbuf,reasonreg);
thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,exceptionreasontype,OC_EQ,reason,reasonreg);
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
thlcgwasm(hlcg).incblock;
thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,br+1));
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
thlcgwasm(hlcg).decblock;
end;
begin
internalerror(2021091703);
location_reset(location,LOC_VOID,OS_NO);
oldBreakLabel:=nil;
oldContinueLabel:=nil;
continuefinallylabel:=nil;
breakfinallylabel:=nil;
in_loop:=assigned(current_procinfo.CurrBreakLabel);
if not implicitframe then
exceptframekind:=tek_normalfinally
else
exceptframekind:=tek_implicitfinally;
{ in 'no exceptions' mode, we still want to handle properly exit,
continue and break (they still need to execute the 'finally'
statements), so for this we need excepttemps.reasonbuf, and for this
reason, we need to allocate excepttemps }
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
{ the finally block must catch break, continue and exit }
{ statements }
{ the outer 'try..finally' block }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
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;
exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
current_procinfo.CurrExitLabel:=exitfinallylabel;
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;
breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
current_procinfo.CurrBreakLabel:=breakfinallylabel;
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;
continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
current_procinfo.CurrContinueLabel:=continuefinallylabel;
thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
end;
{ try code }
if assigned(left) then
begin
secondpass(left);
if codegenerror then
exit;
end;
{ don't generate line info for internal cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,nil);
{ we've reached the end of the 'try' block, with no exceptions/exit/break/continue, so set exceptionreason:=0 }
hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,0,excepttemps.reasonbuf);
current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,3)); // jump to the 'finally' section
{ exit the 'continue' block }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
thlcgwasm(hlcg).decblock;
{ exceptionreason:=4 (continue) }
hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,4,excepttemps.reasonbuf);
current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,2)); // jump to the 'finally' section
{ exit the 'break' block }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
thlcgwasm(hlcg).decblock;
{ exceptionreason:=3 (break) }
hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,3,excepttemps.reasonbuf);
current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1)); // jump to the 'finally' section
{ exit the 'exit' block }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
thlcgwasm(hlcg).decblock;
{ exceptionreason:=2 (exit) }
hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,exceptionreasontype,2,excepttemps.reasonbuf);
{ proceed to the 'finally' section, which follow immediately, no need for jumps }
{ exit the outer 'try..finally' block }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
thlcgwasm(hlcg).decblock;
{ end cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
{ finally code (don't unconditionally set fc_inflowcontrol, since the
finally code is unconditionally executed; we do have to filter out
flags regarding break/contrinue/etc. because we have to give an
error in case one of those is used in the finally-code }
flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
secondpass(right);
{ goto is allowed if it stays inside the finally block,
this is checked using the exception block number }
if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
CGMessage(cg_e_control_flow_outside_finally);
if codegenerror then
exit;
{ don't generate line info for internal cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
if fc_exit in finallyexceptionstate.newflowcontrol then
generate_exceptreason_check_br(2,thlcgwasm(hlcg).br_blocks-oldExitBr);
if fc_break in finallyexceptionstate.newflowcontrol then
generate_exceptreason_check_br(3,thlcgwasm(hlcg).br_blocks-oldLoopBreakBr);
if fc_continue in finallyexceptionstate.newflowcontrol then
generate_exceptreason_check_br(4,thlcgwasm(hlcg).br_blocks-oldLoopContBr);
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
{ end cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
current_procinfo.CurrExitLabel:=oldCurrExitLabel;
thlcgwasm(hlcg).exitBr:=oldExitBr;
if assigned(current_procinfo.CurrBreakLabel) then
begin
current_procinfo.CurrContinueLabel:=oldContinueLabel;
thlcgwasm(hlcg).loopContBr:=oldLoopContBr;
current_procinfo.CurrBreakLabel:=oldBreakLabel;
thlcgwasm(hlcg).loopBreakBr:=oldLoopBreakBr;
end;
flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
end;
procedure twasmtryfinallynode.pass_generate_code;