diff options
author | John Högberg <john@erlang.org> | 2021-01-28 13:34:16 +0100 |
---|---|---|
committer | John Högberg <john@erlang.org> | 2021-01-28 13:38:57 +0100 |
commit | 424167b36657b0546074b3d88c8511b370fa84ea (patch) | |
tree | 0189455327dda6153f0e0531cb4b5a4f03b4252f /lib/compiler | |
parent | 7d5fa20a463395045fef400445514e59db0a71ae (diff) | |
parent | 1dcc1a3c571b6927ccbac17189b86f3b2b3bf018 (diff) | |
download | erlang-424167b36657b0546074b3d88c8511b370fa84ea.tar.gz |
Merge branch 'maint'
* maint:
beam_validator: Ignore 'fcheckerror' / 'fclearerror'
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 145 | ||||
-rw-r--r-- | lib/compiler/test/beam_validator_SUITE.erl | 26 | ||||
-rw-r--r-- | lib/compiler/test/beam_validator_SUITE_data/freg_state.S | 59 | ||||
-rw-r--r-- | lib/compiler/test/float_SUITE.erl | 22 |
4 files changed, 69 insertions, 183 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 2ab751f6e9..02eecea29c 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -193,8 +193,6 @@ validate_0([{function, Name, Arity, Entry, Code} | Fs], Module, Level, Ft) -> hl=0, %%Available heap size for floats. hf=0, - %% Floating point state. - fls=undefined, %% List of hot catch/try tags ct=[], %% Previous instruction was setelement/3. @@ -307,8 +305,9 @@ init_function_args(-1, Vst) -> init_function_args(X, Vst) -> init_function_args(X - 1, create_term(any, argument, [], {x,X}, Vst)). -kill_heap_allocation(St) -> - St#st{h=0,hl=0,hf=0}. +kill_heap_allocation(#vst{current=St0}=Vst) -> + St = St0#st{h=0,hl=0,hf=0}, + Vst#vst{current=St}. validate_branches(MFA, Vst) -> #vst{ branched=Targets0, labels=Labels0 } = Vst, @@ -397,7 +396,6 @@ vi({fmove,Src,{fr,_}=Dst}, Vst) -> set_freg(Dst, Vst); vi({fmove,{fr,_}=Src,Dst}, Vst0) -> assert_freg_set(Src, Vst0), - assert_fls(checked, Vst0), Vst = eat_heap_float(Vst0), create_term(#t_float{}, fmove, [], Dst, Vst); vi({kill,Reg}, Vst) -> @@ -704,9 +702,8 @@ vi({gc_bif,Op,{f,Fail},Live,Ss,Dst}, Vst0) -> %% Heap allocations and X registers are killed regardless of whether we %% fail or not, as we may fail after GC. - #vst{current=St0} = Vst0, - St = kill_heap_allocation(St0), - Vst = prune_x_regs(Live, Vst0#vst{current=St}), + Vst1 = kill_heap_allocation(Vst0), + Vst = prune_x_regs(Live, Vst1), validate_bif(gc_bif, Op, Fail, Ss, Dst, Vst0, Vst); @@ -762,13 +759,10 @@ vi({wait,{f,Lbl}}, Vst) -> vi({wait_timeout,{f,Lbl},Src}, Vst0) -> assert_no_exception(Lbl), - %% Note that the receive state is not cleared since we may re-enter the - %% loop while waiting. If we time out we'll be transferred to a timeout - %% instruction that clears the state. assert_term(Src, Vst0), verify_y_init(Vst0), - Vst = branch(Lbl, prune_x_regs(0, Vst0)), + Vst = branch(Lbl, schedule_out(0, Vst0)), branch(?EXCEPTION_LABEL, Vst); %% @@ -799,9 +793,11 @@ vi({try_end,Reg}, #vst{current=#st{ct=[Tag|_]}}=Vst) -> vi({try_case,Reg}, #vst{current=#st{ct=[Tag|_]}}=Vst0) -> case get_tag_type(Reg, Vst0) of {trytag,_Fail}=Tag -> - %% Kill the catch tag and all x registers. + %% Kill the catch tag and all other state (as if we've been + %% scheduled out with no live registers). Only previously allocated + %% Y registers are alive at this point. Vst1 = kill_catch_tag(Reg, Vst0), - Vst2 = prune_x_regs(0, Vst1), + Vst2 = schedule_out(0, Vst1), %% Class:Error:Stacktrace ClassType = #t_atom{elements=[error,exit,throw]}, @@ -812,7 +808,6 @@ vi({try_case,Reg}, #vst{current=#st{ct=[Tag|_]}}=Vst0) -> error({wrong_tag_type,Type}) end; vi(build_stacktrace, Vst0) -> - assert_float_checked(Vst0), verify_y_init(Vst0), verify_live(1, Vst0), @@ -971,26 +966,13 @@ vi({fconv,Src,{fr,_}=Dst}, Vst) -> assert_term(Src, Vst), branch(?EXCEPTION_LABEL, Vst, - fun(FailVst) -> - %% This is a hack to supress assert_float_checked/1 in - %% fork_state/2, since this instruction is legal even when - %% the state is unchecked. - set_fls(checked, FailVst) - end, fun(SuccVst0) -> SuccVst = update_type(fun meet/2, number, Src, SuccVst0), set_freg(Dst, SuccVst) end); vi(fclearerror, Vst) -> - case get_fls(Vst) of - undefined -> ok; - checked -> ok; - Fls -> error({bad_floating_point_state,Fls}) - end, - set_fls(cleared, Vst); -vi({fcheckerror,_}, Vst0) -> - assert_fls(cleared, Vst0), - Vst = set_fls(checked, Vst0), + Vst; +vi({fcheckerror, _}, Vst) -> branch(?EXCEPTION_LABEL, Vst); %% @@ -1162,8 +1144,6 @@ validate_var_info([], _Reg, Vst) -> %% The stackframe must have a known size and be initialized. %% Does not return to the instruction following the call. validate_tail_call(Deallocate, Func, Live, #vst{current=#st{numy=NumY}}=Vst0) -> - assert_float_checked(Vst0), - verify_y_init(Vst0), verify_live(Live, Vst0), verify_call_args(Func, Live, Vst0), @@ -1190,18 +1170,15 @@ validate_tail_call(Deallocate, Func, Live, #vst{current=#st{numy=NumY}}=Vst0) -> %% The instruction will return to the instruction following the call. validate_body_call(Func, Live, #vst{current=#st{numy=NumY}}=Vst) when is_integer(NumY)-> - assert_float_checked(Vst), - verify_y_init(Vst), verify_live(Live, Vst), verify_call_args(Func, Live, Vst), - SuccFun = fun(#vst{current=St0}=SuccVst0) -> + SuccFun = fun(SuccVst0) -> {RetType, _, _} = call_types(Func, Live, SuccVst0), true = RetType =/= none, %Assertion. - St = St0#st{f=init_fregs()}, - SuccVst = prune_x_regs(0, SuccVst0#vst{current=St}), + SuccVst = schedule_out(0, SuccVst0), create_term(RetType, call, [], {x,0}, SuccVst) end, @@ -1217,13 +1194,6 @@ validate_body_call(Func, Live, validate_body_call(_, _, #vst{current=#st{numy=NumY}}) -> error({allocated, NumY}). -assert_float_checked(Vst) -> - case get_fls(Vst) of - undefined -> ok; - checked -> ok; - Fls -> error({unsafe_instruction,{float_error_state,Fls}}) - end. - init_try_catch_branch(Kind, Dst, Fail, Vst0) -> assert_no_exception(Fail), @@ -1360,7 +1330,6 @@ verify_return(#vst{current=#st{recv_state=State}}) when State =/= none -> %% Returning in the middle of a receive loop will ruin the next receive. error({return_in_receive,State}); verify_return(Vst) -> - assert_float_checked(Vst), verify_no_ct(Vst), kill_state(Vst). @@ -1373,7 +1342,6 @@ verify_return(Vst) -> %% validate_bif(Kind, Op, Fail, Ss, Dst, OrigVst, Vst) -> - assert_float_checked(Vst), case will_bif_succeed(Op, Ss, Vst) of yes -> %% This BIF cannot fail (neither throw nor branch), make sure it's @@ -1761,25 +1729,31 @@ test_heap(Heap, Live, Vst0) -> heap_alloc(Heap, Vst). heap_alloc(Heap, #vst{current=St0}=Vst) -> - St1 = kill_heap_allocation(St0), - St = heap_alloc_1(Heap, St1), + {HeapWords, Floats, Funs} = heap_alloc_1(Heap), + + St = St0#st{h=HeapWords,hf=Floats,hl=Funs}, + Vst#vst{current=St}. -heap_alloc_1({alloc,Alloc}, St) -> - heap_alloc_2(Alloc, St); -heap_alloc_1(HeapWords, St) when is_integer(HeapWords) -> - St#st{h=HeapWords}. - -heap_alloc_2([{words,HeapWords}|T], St0) -> - St = St0#st{h=HeapWords}, - heap_alloc_2(T, St); -heap_alloc_2([{funs,Funs}|T], St0) -> - St = St0#st{hl=Funs}, - heap_alloc_2(T, St); -heap_alloc_2([{floats,Floats}|T], St0) -> - St = St0#st{hf=Floats}, - heap_alloc_2(T, St); -heap_alloc_2([], St) -> St. +heap_alloc_1({alloc, Alloc}) -> + heap_alloc_2(Alloc, 0, 0, 0); +heap_alloc_1(HeapWords) when is_integer(HeapWords) -> + {HeapWords, 0, 0}. + +heap_alloc_2([{words, HeapWords} | T], 0, Floats, Funs) -> + heap_alloc_2(T, HeapWords, Floats, Funs); +heap_alloc_2([{floats, Floats} | T], HeapWords, 0, Funs) -> + heap_alloc_2(T, HeapWords, Floats, Funs); +heap_alloc_2([{funs, Funs} | T], HeapWords, Floats, 0) -> + heap_alloc_2(T, HeapWords, Floats, Funs); +heap_alloc_2([], HeapWords, Floats, Funs) -> + {HeapWords, Floats, Funs}. + +schedule_out(Live, Vst0) when is_integer(Live) -> + Vst1 = prune_x_regs(Live, Vst0), + Vst2 = kill_heap_allocation(Vst1), + Vst = kill_fregs(Vst2), + update_receive_state(none, Vst). prune_x_regs(Live, #vst{current=St0}=Vst) when is_integer(Live) -> #st{fragile=Fragile0,xs=Xs0} = St0, @@ -1818,22 +1792,10 @@ assert_arities(_) -> error(bad_tuple_arity_list). %%% -%%% Floating point checking. -%%% -%%% Possible values for the fls field (=floating point error state). -%%% -%%% undefined - Undefined (initial state). No float operations allowed. -%%% -%%% cleared - fclearerror/0 has been executed. Float operations -%%% are allowed (such as fadd). +%%% Floating point helpers. %%% -%%% checked - fcheckerror/1 has been executed. It is allowed to -%%% move values out of floating point registers. -%%% -%%% The following instructions may be executed in any state: -%%% -%%% fconv Src {fr,_} -%%% fmove Src {fr,_} %% Move INTO floating point register. +%%% fconv Src {fr,_} +%%% fmove Src {fr,_} %% Move known float INTO floating point register. %%% is_float_arith_bif(fadd, [_, _]) -> true; @@ -1843,25 +1805,16 @@ is_float_arith_bif(fnegate, [_]) -> true; is_float_arith_bif(fsub, [_, _]) -> true; is_float_arith_bif(_, _) -> false. -validate_float_arith_bif(Ss, Dst, Vst0) -> - _ = [assert_freg_set(S, Vst0) || S <- Ss], - assert_fls(cleared, Vst0), - Vst = set_fls(cleared, Vst0), +validate_float_arith_bif(Ss, Dst, Vst) -> + _ = [assert_freg_set(S, Vst) || S <- Ss], set_freg(Dst, Vst). -assert_fls(Fls, Vst) -> - case get_fls(Vst) of - Fls -> ok; - OtherFls -> error({bad_floating_point_state,OtherFls}) - end. - -set_fls(Fls, #vst{current=#st{}=St}=Vst) when is_atom(Fls) -> - Vst#vst{current=St#st{fls=Fls}}. - -get_fls(#vst{current=#st{fls=Fls}}) when is_atom(Fls) -> Fls. - init_fregs() -> 0. +kill_fregs(#vst{current=St0}=Vst) -> + St = St0#st{f=init_fregs()}, + Vst#vst{current=St}. + set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst) -> check_limit(Freg), Bit = 1 bsl Fr, @@ -2306,7 +2259,7 @@ new_value(Type, Op, Ss, #vst{current=#st{vs=Vs0}=St,ref_ctr=Counter}=Vst) -> {Ref, Vst#vst{current=St#st{vs=Vs},ref_ctr=Counter+1}}. kill_catch_tag(Reg, #vst{current=#st{ct=[Tag|Tags]}=St}=Vst0) -> - Vst = Vst0#vst{current=St#st{ct=Tags,fls=undefined}}, + Vst = Vst0#vst{current=St#st{ct=Tags}}, Tag = get_tag_type(Reg, Vst), %Assertion. kill_tag(Reg, Vst). @@ -2568,10 +2521,6 @@ branch(Fail, Vst) -> fork_state(?EXCEPTION_LABEL, Vst0) -> #vst{current=#st{ct=CatchTags,numy=NumY}} = Vst0, - %% Floating-point exceptions must be checked before any other kind of - %% exception can be raised. - assert_float_checked(Vst0), - %% The stack will be scanned looking for a catch tag, so all Y registers %% must be initialized. verify_y_init(Vst0), diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index 0aa7b246fe..8295e09d36 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -28,7 +28,7 @@ dead_code/1, overwrite_catchtag/1,overwrite_trytag/1,accessing_tags/1,bad_catch_try/1, cons_guard/1, - freg_range/1,freg_uninit/1,freg_state/1, + freg_range/1,freg_uninit/1, bad_bin_match/1,bad_dsetel/1, state_after_fault_in_catch/1,no_exception_in_catch/1, undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1, @@ -63,7 +63,7 @@ groups() -> unsafe_catch,dead_code, overwrite_catchtag,overwrite_trytag,accessing_tags, bad_catch_try,cons_guard,freg_range,freg_uninit, - freg_state,bad_bin_match,bad_dsetel, + bad_bin_match,bad_dsetel, state_after_fault_in_catch,no_exception_in_catch, undef_label,illegal_instruction,failing_gc_guard_bif, map_field_lists,cover_bin_opt,val_dsetel, @@ -290,28 +290,6 @@ freg_uninit(Config) when is_list(Config) -> {uninitialized_reg,{fr,0}}}}] = Errors, ok. -freg_state(Config) when is_list(Config) -> - Errors = do_val(freg_state, Config), - [{{t,sum_1,2}, - {{bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}}, - 6, - {bad_floating_point_state,undefined}}}, - {{t,sum_2,2}, - {{fmove,{fr,0},{x,0}}, - 8, - {bad_floating_point_state,cleared}}}, - {{t,sum_3,2}, - {{bif,'-',{f,0},[{x,1},{x,0}],{x,1}}, - 8, - {unsafe_instruction,{float_error_state,cleared}}}}, - {{t,sum_4,2}, - {{fcheckerror,{f,0}}, - 4, - {bad_floating_point_state,undefined}}}, - {{t,sum_5,2}, - {fclearerror,5,{bad_floating_point_state,cleared}}}] = Errors, - ok. - bad_bin_match(Config) when is_list(Config) -> [{{t,t,1},{return,5,{match_context,{x,0}}}}] = do_val(bad_bin_match, Config), diff --git a/lib/compiler/test/beam_validator_SUITE_data/freg_state.S b/lib/compiler/test/beam_validator_SUITE_data/freg_state.S deleted file mode 100644 index 7466763482..0000000000 --- a/lib/compiler/test/beam_validator_SUITE_data/freg_state.S +++ /dev/null @@ -1,59 +0,0 @@ -{module, freg_state}. %% version = 0 - -{exports, [{sum_1,2},{sum_2,2},{sum_3,2},{sum_4,2},{sum_5,2}]}. - -{attributes, []}. - - -{function, sum_1, 2, 2}. - {label,1}. - {func_info,{atom,t},{atom,sum_1},2}. - {label,2}. - {fconv,{x,0},{fr,0}}. - {fconv,{x,1},{fr,1}}. - {bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}}. - {'%live',1}. - return. - -{function, sum_2, 2, 4}. - {label,3}. - {func_info,{atom,t},{atom,sum_2},2}. - {label,4}. - {fconv,{x,0},{fr,0}}. - {fconv,{x,1},{fr,1}}. - fclearerror. - {bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}}. - {fmove,{fr,0},{x,0}}. - {'%live',1}. - return. - -{function, sum_3, 2, 6}. - {label,5}. - {func_info,{atom,t},{atom,sum_3},2}. - {label,6}. - {fconv,{x,0},{fr,0}}. - {fconv,{x,1},{fr,1}}. - fclearerror. - {bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}}. - {bif,'-',{f,0},[{x,1},{x,0}],{x,1}}. - {fcheckerror,{f,0}}. - {fmove,{fr,0},{x,0}}. - {'%live',1}. - return. - -{function, sum_4, 2, 8}. - {label,6}. - {func_info,{atom,t},{atom,sum_4},2}. - {label,8}. - {fcheckerror,{f,0}}. - {fmove,{fr,0},{x,0}}. - {'%live',1}. - return. - -{function, sum_5, 2, 10}. - {label,9}. - {func_info,{atom,t},{atom,sum_5},2}. - {label,10}. - fclearerror. - fclearerror. - return. diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl index c9c0beb70f..44d54de84c 100644 --- a/lib/compiler/test/float_SUITE.erl +++ b/lib/compiler/test/float_SUITE.erl @@ -22,7 +22,7 @@ init_per_group/2,end_per_group/2, pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1, subtract_number_type/1,float_followed_by_guard/1, - fconv_line_numbers/1,float_zero/1]). + fconv_line_numbers/1,float_zero/1,exception_signals/1]). -include_lib("common_test/include/ct.hrl"). @@ -31,7 +31,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [pending, bif_calls, math_functions, float_zero, mixed_float_and_int, subtract_number_type, - float_followed_by_guard,fconv_line_numbers]. + float_followed_by_guard,fconv_line_numbers, + exception_signals]. groups() -> []. @@ -226,5 +227,22 @@ fconv_line_numbers_1(A) -> false end, Stacktrace). +%% ERL-1471: compiler generated invalid 'fclearerror' / 'fcheckerror' +%% sequences. +exception_signals(Config) when is_list(Config) -> + 2.0 = exception_signals_1(id(25), id(true), []), + 2.0 = exception_signals_1(id(25), id(false), []), + 2.0 = exception_signals_1(id(25.0), id(true), []), + 2.0 = exception_signals_1(id(25.0), id(false), []), + ok. + +exception_signals_1(Width, Value, _Opts) -> + Height = Width / 25.0, + _Middle = case Value of + true -> Width / 2.0; + false -> 0 + end, + _More = Height + 1. + id(I) -> I. |