aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/arm/hipe_arm_assemble.erl2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl51
-rw-r--r--lib/hipe/cerl/erl_types.erl582
-rw-r--r--lib/hipe/doc/src/hipe_app.xml17
-rw-r--r--lib/hipe/doc/src/notes.xml121
-rw-r--r--lib/hipe/llvm/hipe_llvm_merge.erl2
-rw-r--r--lib/hipe/main/hipe.app.src2
-rw-r--r--lib/hipe/main/hipe.erl12
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl2
-rw-r--r--lib/hipe/rtl/Makefile2
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl9
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl104
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl30
-rw-r--r--lib/hipe/sparc/hipe_sparc_assemble.erl2
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_construct.erl16
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_match.erl108
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl2
18 files changed, 759 insertions, 307 deletions
diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl
index 7859e2d4a8..5f98c6593e 100644
--- a/lib/hipe/arm/hipe_arm_assemble.erl
+++ b/lib/hipe/arm/hipe_arm_assemble.erl
@@ -48,7 +48,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 41a6c731c9..c2fb79c089 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2015. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -93,7 +93,7 @@
t_list/0,
t_list/1,
t_list_elements/2,
- t_list_termination/1,
+ t_list_termination/2,
t_mfa/0,
t_module/0,
t_nil/0,
@@ -514,14 +514,15 @@ type(erlang, 'bsl', 2, Xs, Opaques) ->
type(erlang, 'bnot', 1, Xs, Opaques) ->
strict(erlang, 'bnot', 1, Xs,
fun ([X1]) ->
- case arith('bnot', X1, Opaques) of
+ case arith_bnot(X1, Opaques) of
error -> t_integer();
{ok, T} -> T
end
end, Opaques);
%% Guard bif, needs to be here.
type(erlang, abs, 1, Xs, Opaques) ->
- strict(erlang, abs, 1, Xs, fun ([X]) -> X end, Opaques);
+ strict(erlang, abs, 1, Xs,
+ fun ([X1]) -> arith_abs(X1, Opaques) end, Opaques);
%% This returns (-X)-1, so it often gives a negative result.
%% strict(erlang, 'bnot', 1, Xs, fun (_) -> t_integer() end, Opaques);
type(erlang, append, 2, Xs, _Opaques) -> type(erlang, '++', 2, Xs); % alias
@@ -767,6 +768,18 @@ type(erlang, length, 1, Xs, Opaques) ->
%% Guard bif, needs to be here.
type(erlang, map_size, 1, Xs, Opaques) ->
strict(erlang, map_size, 1, Xs, fun (_) -> t_non_neg_integer() end, Opaques);
+type(erlang, make_fun, 3, Xs, Opaques) ->
+ strict(erlang, make_fun, 3, Xs,
+ fun ([_, _, Arity]) ->
+ case t_number_vals(Arity, Opaques) of
+ [N] ->
+ case is_integer(N) andalso 0 =< N andalso N =< 255 of
+ true -> t_fun(N, t_any());
+ false -> t_none()
+ end;
+ _Other -> t_fun()
+ end
+ end, Opaques);
type(erlang, make_tuple, 2, Xs, Opaques) ->
strict(erlang, make_tuple, 2, Xs,
fun ([Int, _]) ->
@@ -1336,8 +1349,8 @@ type(lists, foldr, 3, Xs, _Opaques) -> type(lists, foldl, 3, Xs); % same
type(lists, keydelete, 3, Xs, Opaques) ->
strict(lists, keydelete, 3, Xs,
fun ([_, _, L]) ->
- Term = t_list_termination(L),
- t_sup(Term, erl_types:lift_list_to_pos_empty(L))
+ Term = t_list_termination(L, Opaques),
+ t_sup(Term, erl_types:lift_list_to_pos_empty(L, Opaques))
end, Opaques);
type(lists, keyfind, 3, Xs, Opaques) ->
strict(lists, keyfind, 3, Xs,
@@ -1927,7 +1940,7 @@ negwidth(X, N) ->
false -> negwidth(X, N+1)
end.
-arith('bnot', X1, Opaques) ->
+arith_bnot(X1, Opaques) ->
case t_is_integer(X1, Opaques) of
false -> error;
true ->
@@ -1937,6 +1950,28 @@ arith('bnot', X1, Opaques) ->
infinity_add(infinity_inv(Min1), -1))}
end.
+arith_abs(X1, Opaques) ->
+ case t_is_integer(X1, Opaques) of
+ false ->
+ case t_is_float(X1, Opaques) of
+ true -> t_float();
+ false -> t_number()
+ end;
+ true ->
+ Min1 = number_min(X1, Opaques),
+ Max1 = number_max(X1, Opaques),
+ {NewMin, NewMax} =
+ case infinity_geq(Min1, 0) of
+ true -> {Min1, Max1};
+ false ->
+ case infinity_geq(Max1, 0) of
+ true -> {0, infinity_inv(Min1)};
+ false -> {infinity_inv(Max1), infinity_inv(Min1)}
+ end
+ end,
+ t_from_range(NewMin, NewMax)
+ end.
+
arith_mult(Min1, Max1, Min2, Max2) ->
Tmp_list = [infinity_mult(Min1, Min2), infinity_mult(Min1, Max2),
infinity_mult(Max1, Min2), infinity_mult(Max1, Max2)],
@@ -2338,6 +2373,8 @@ arg_types(erlang, length, 1) ->
%% Guard bif, needs to be here.
arg_types(erlang, map_size, 1) ->
[t_map()];
+arg_types(erlang, make_fun, 3) ->
+ [t_atom(), t_atom(), t_arity()];
arg_types(erlang, make_tuple, 2) ->
[t_non_neg_fixnum(), t_any()]; % the value 0 is OK as first argument
arg_types(erlang, make_tuple, 3) ->
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 25cf1a7ae1..cd2d2fe207 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -82,7 +82,7 @@
t_form_to_string/1,
t_from_form/4,
t_from_form/5,
- t_from_form_without_remote/2,
+ t_from_form_without_remote/3,
t_check_record_fields/4,
t_check_record_fields/5,
t_from_range/2,
@@ -150,7 +150,7 @@
t_list/0,
t_list/1,
t_list_elements/1, t_list_elements/2,
- t_list_termination/1,
+ t_list_termination/1, t_list_termination/2,
t_map/0,
t_map/1,
t_matchstate/0,
@@ -209,7 +209,7 @@
record_field_diffs_to_string/2,
subst_all_vars_to_any/1,
subst_all_remote/2,
- lift_list_to_pos_empty/1,
+ lift_list_to_pos_empty/1, lift_list_to_pos_empty/2,
is_opaque_type/2,
is_erl_type/1,
atom_to_string/1
@@ -1510,6 +1510,11 @@ t_list_elements(Type, Opaques) ->
list_elements(?list(Contents, _, _)) -> Contents;
list_elements(?nil) -> ?none.
+-spec t_list_termination(erl_type(), opaques()) -> erl_type().
+
+t_list_termination(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun t_list_termination/1).
+
-spec t_list_termination(erl_type()) -> erl_type().
t_list_termination(?nil) -> ?nil;
@@ -1585,6 +1590,11 @@ is_maybe_improper_list(_) -> false.
%% %% false = t_is_subtype(t_nil(), Termination),
%% ?list(Content, Termination, ?any).
+-spec lift_list_to_pos_empty(erl_type(), opaques()) -> erl_type().
+
+lift_list_to_pos_empty(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun lift_list_to_pos_empty/1).
+
-spec lift_list_to_pos_empty(erl_type()) -> erl_type().
lift_list_to_pos_empty(?nil) -> ?nil;
@@ -2702,7 +2712,87 @@ is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
is_compat_arg(A, A) -> true;
-is_compat_arg(A1, A2) -> t_is_any(A1) orelse t_is_any(A2).
+is_compat_arg(A1, A2) ->
+ is_specialization(A1, A2) orelse is_specialization(A2, A1).
+
+-spec is_specialization(erl_type(), erl_type()) -> boolean().
+
+%% Returns true if the first argument is a specialization of the
+%% second argument in the sense that every type is a specialization of
+%% any(). For example, {_,_} is a specialization of any(), but not of
+%% tuple(). Does not handle variables, but any() and unions (sort of).
+
+is_specialization(_, ?any) -> true;
+is_specialization(?any, _) -> false;
+is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_specialization(Domain1, Domain2) andalso
+ is_specialization(Range1, Range2));
+is_specialization(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
+ (Size1 =:= Size2 andalso
+ is_specialization(Contents1, Contents2) andalso
+ is_specialization(Termination1, Termination2));
+is_specialization(?product(Types1), ?product(Types2)) ->
+ specialization_list(Types1, Types2);
+is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(Elements1, Elements2);
+is_specialization(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(sup_tuple_elements(List), Elements2);
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ specialization_list(Elements1, sup_tuple_elements(List));
+is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ try
+ specialization_list(lists:append([T || {_Arity, T} <- List1]),
+ lists:append([T || {_Arity, T} <- List2]))
+ catch _:_ -> false
+ end;
+is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
+ case specialization_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_specialization(Type1, Type2);
+ no -> specialization_list(List1, List2)
+ end;
+is_specialization(?union(List), T2) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(Type, T2);
+ no -> false
+ end;
+is_specialization(T1, ?union(List)) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(T1, Type);
+ no -> false
+ end;
+is_specialization(?opaque(_) = T1, T2) ->
+ is_specialization(t_opaque_structure(T1), T2);
+is_specialization(T1, ?opaque(_) = T2) ->
+ is_specialization(T1, t_opaque_structure(T2));
+is_specialization(?var(_), _) -> exit(error);
+is_specialization(_, ?var(_)) -> exit(error);
+is_specialization(T, T) -> true;
+is_specialization(?none, _) -> false;
+is_specialization(_, ?none) -> false;
+is_specialization(?unit, _) -> false;
+is_specialization(_, ?unit) -> false;
+is_specialization(#c{}, #c{}) -> false.
+
+specialization_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
+
+specialization_list1([], []) -> true;
+specialization_list1([T1|L1], [T2|L2]) ->
+ is_specialization(T1, T2) andalso specialization_list1(L1, L2).
+
+specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+ case {unify_union(List1), unify_union(List2)} of
+ {{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
+ {{yes, Type1}, no} -> {yes, Type1, T2};
+ {no, {yes, Type2}} -> {yes, T1, Type2};
+ {no, no} -> no
+ end.
-spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()].
@@ -3961,27 +4051,32 @@ mod_name(Mod, Name) ->
-type type_names() :: [type_key() | record_key()].
+-type mta() :: {module(), atom(), arity()}.
+-type mra() :: {module(), atom(), arity()}.
+-type site() :: {'type', mta()} | {'spec', mfa()} | {'record', mra()}.
+
-spec t_from_form(parse_form(), sets:set(mfa()),
- module(), mod_records()) -> erl_type().
+ site(), mod_records()) -> erl_type().
-t_from_form(Form, ExpTypes, Module, RecDict) ->
- t_from_form(Form, ExpTypes, Module, RecDict, dict:new()).
+t_from_form(Form, ExpTypes, Site, RecDict) ->
+ t_from_form(Form, ExpTypes, Site, RecDict, dict:new()).
-spec t_from_form(parse_form(), sets:set(mfa()),
- module(), mod_records(), var_table()) -> erl_type().
+ site(), mod_records(), var_table()) -> erl_type().
-t_from_form(Form, ExpTypes, Module, RecDict, VarDict) ->
- {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, VarDict),
+t_from_form(Form, ExpTypes, Site, RecDict, VarDict) ->
+ {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, VarDict),
T.
%% Replace external types with with none().
--spec t_from_form_without_remote(parse_form(), type_table()) -> erl_type().
+-spec t_from_form_without_remote(parse_form(), site(), type_table()) ->
+ erl_type().
-t_from_form_without_remote(Form, TypeTable) ->
- Module = mod,
+t_from_form_without_remote(Form, Site, TypeTable) ->
+ Module = site_module(Site),
RecDict = dict:from_list([{Module, TypeTable}]),
ExpTypes = replace_by_none,
- {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, dict:new()),
+ {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, dict:new()),
T.
%% REC_TYPE_LIMIT is used for limiting the depth of recursive types.
@@ -3995,23 +4090,32 @@ t_from_form_without_remote(Form, TypeTable) ->
-type expand_depth() :: integer().
-t_from_form1(Form, TypeNames, ET, M, MR, V) ->
- t_from_form1(Form, TypeNames, ET, M, MR, V, ?EXPAND_DEPTH).
+-spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none',
+ site(), mod_records(), var_table()) ->
+ {erl_type(), expand_limit()}.
+
+t_from_form1(Form, ET, Site, MR, V) ->
+ TypeNames = initial_typenames(Site),
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, ?EXPAND_DEPTH).
-t_from_form1(Form, TypeNames, ET, M, MR, V, D) ->
+initial_typenames({type, _MTA}=Site) -> [Site];
+initial_typenames({spec, _MFA}) -> [];
+initial_typenames({record, _MRA}) -> [].
+
+t_from_form1(Form, TypeNames, ET, Site, MR, V, D) ->
L = ?EXPAND_LIMIT,
- {T, L1} = t_from_form(Form, TypeNames, ET, M, MR, V, D, L),
+ {T, L1} = t_from_form(Form, TypeNames, ET, Site, MR, V, D, L),
if
L1 =< 0, D > 1 ->
D1 = D div 2,
- t_from_form1(Form, TypeNames, ET, M, MR, V, D1);
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, D1);
true ->
{T, L1}
end.
-spec t_from_form(parse_form(), type_names(),
sets:set(mfa()) | 'replace_by_none',
- module(), mod_records(), var_table(),
+ site(), mod_records(), var_table(),
expand_depth(), expand_limit())
-> {erl_type(), expand_limit()}.
@@ -4021,193 +4125,194 @@ t_from_form1(Form, TypeNames, ET, M, MR, V, D) ->
%% self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}
%% is called, unless 'replace_by_none' is given.
%%
-%% It is assumed that M can be found in MR.
+%% It is assumed that site_module(S) can be found in MR.
-t_from_form(_, _TypeNames, _ET, _M, _MR, _V, D, L) when D =< 0 ; L =< 0 ->
+t_from_form(_, _TypeNames, _ET, _S, _MR, _V, D, L) when D =< 0 ; L =< 0 ->
{t_any(), L};
-t_from_form({var, _L, '_'}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({var, _L, '_'}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({var, _L, Name}, _TypeNames, _ET, _M, _MR, V, _D, L) ->
+t_from_form({var, _L, Name}, _TypeNames, _ET, _S, _MR, V, _D, L) ->
case dict:find(Name, V) of
error -> {t_var(Name), L};
{ok, Val} -> {Val, L}
end;
-t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, M, MR, V, D, L) ->
- t_from_form(Type, TypeNames, ET, M, MR, V, D, L);
-t_from_form({paren_type, _L, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- t_from_form(Type, TypeNames, ET, M, MR, V, D, L);
+t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ t_from_form(Type, TypeNames, ET, S, MR, V, D, L);
+t_from_form({paren_type, _L, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ t_from_form(Type, TypeNames, ET, S, MR, V, D, L);
t_from_form({remote_type, _L, [{atom, _, Module}, {atom, _, Type}, Args]},
- TypeNames, ET, M, MR, V, D, L) ->
- remote_from_form(Module, Type, Args, TypeNames, ET, M, MR, V, D, L);
-t_from_form({atom, _L, Atom}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ TypeNames, ET, S, MR, V, D, L) ->
+ remote_from_form(Module, Type, Args, TypeNames, ET, S, MR, V, D, L);
+t_from_form({atom, _L, Atom}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_atom(Atom), L};
-t_from_form({integer, _L, Int}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({integer, _L, Int}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_integer(Int), L};
-t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
{t_integer(Val), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
end;
t_from_form({op, _L, _Op, _Arg1, _Arg2} = Op, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
{t_integer(Val), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
end;
-t_from_form({type, _L, any, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, any, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({type, _L, arity, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, arity, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_arity(), L};
-t_from_form({type, _L, atom, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, atom, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_atom(), L};
-t_from_form({type, _L, binary, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, binary, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_binary(), L};
t_from_form({type, _L, binary, [Base, Unit]} = Type,
- _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of
{{integer, _, B}, {integer, _, U}} when B >= 0, U >= 0 ->
{t_bitstr(U, B), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
end;
-t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_bitstr(), L};
-t_from_form({type, _L, bool, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, bool, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_boolean(), L}; % XXX: Temporarily
-t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_boolean(), L};
-t_from_form({type, _L, byte, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, byte, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_byte(), L};
-t_from_form({type, _L, char, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, char, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_char(), L};
-t_from_form({type, _L, float, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, float, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_float(), L};
-t_from_form({type, _L, function, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, function, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_fun(), L};
-t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_fun(), L};
t_from_form({type, _L, 'fun', [{type, _, any}, Range]}, TypeNames,
- ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L - 1),
+ ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L - 1),
{t_fun(T), L1};
t_from_form({type, _L, 'fun', [{type, _, product, Domain}, Range]},
- TypeNames, ET, M, MR, V, D, L) ->
- {Dom1, L1} = list_from_form(Domain, TypeNames, ET, M, MR, V, D, L),
- {Ran1, L2} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {Dom1, L1} = list_from_form(Domain, TypeNames, ET, S, MR, V, D, L),
+ {Ran1, L2} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L1),
{t_fun(Dom1, Ran1), L2};
-t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_identifier(), L};
-t_from_form({type, _L, integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_integer(), L};
-t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_iodata(), L};
-t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_iolist(), L};
-t_from_form({type, _L, list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_list(), L};
-t_from_form({type, _L, list, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D - 1, L - 1),
+t_from_form({type, _L, list, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D - 1, L - 1),
{t_list(T), L1};
-t_from_form({type, _L, map, _}, TypeNames, ET, M, MR, V, D, L) ->
- builtin_type(map, t_map([]), TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, map, _}, TypeNames, ET, S, MR, V, D, L) ->
+ builtin_type(map, t_map([]), TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_mfa(), L};
-t_from_form({type, _L, module, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, module, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_module(), L};
-t_from_form({type, _L, nil, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nil, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nil(), L};
-t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_neg_integer(), L};
-t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _M, _MR,
+t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _S, _MR,
_V, _D, L) ->
{t_non_neg_integer(), L};
-t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_unit(), L};
-t_from_form({type, _L, node, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, node, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_node(), L};
-t_from_form({type, _L, none, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, none, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_none(), L};
-t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nonempty_list(), L};
-t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1),
+t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1),
{t_nonempty_list(T), L1};
t_from_form({type, _L, nonempty_improper_list, [Cont, Term]}, TypeNames,
- ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1),
+ ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1),
{t_cons(T1, T2), L2};
t_from_form({type, _L, nonempty_maybe_improper_list, []}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
{t_cons(?any, ?any), L};
t_from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]},
- TypeNames, ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1),
{t_cons(T1, T2), L2};
-t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nonempty_string(), L};
-t_from_form({type, _L, number, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, number, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_number(), L};
-t_from_form({type, _L, pid, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, pid, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_pid(), L};
-t_from_form({type, _L, port, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, port, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_port(), L};
-t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_pos_integer(), L};
t_from_form({type, _L, maybe_improper_list, []}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
{t_maybe_improper_list(), L};
t_from_form({type, _L, maybe_improper_list, [Content, Termination]},
- TypeNames, ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Content, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Termination, TypeNames, ET, M, MR, V, D, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Content, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Termination, TypeNames, ET, S, MR, V, D, L1),
{t_maybe_improper_list(T1, T2), L2};
-t_from_form({type, _L, product, Elements}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Elements, TypeNames, ET, M, MR, V, D - 1, L),
+t_from_form({type, _L, product, Elements}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Elements, TypeNames, ET, S, MR, V, D - 1, L),
{t_product(Lst), L1};
t_from_form({type, _L, range, [From, To]} = Type,
- _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
{{integer, _, FromVal}, {integer, _, ToVal}} ->
{t_from_range(FromVal, ToVal), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
end;
-t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, M, MR, V, D, L) ->
- record_from_form(Name, Fields, TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, reference, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, S, MR, V, D, L) ->
+ record_from_form(Name, Fields, TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, reference, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_reference(), L};
-t_from_form({type, _L, string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_string(), L};
-t_from_form({type, _L, term, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, term, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_timeout(), L};
-t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_tuple(), L};
-t_from_form({type, _L, tuple, Args}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D - 1, L),
+t_from_form({type, _L, tuple, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D - 1, L),
{t_tuple(Lst), L1};
-t_from_form({type, _L, union, Args}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
+t_from_form({type, _L, union, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D, L),
{t_sup(Lst), L1};
-t_from_form({user_type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) ->
- type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) ->
+t_from_form({user_type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) ->
%% Compatibility: modules compiled before Erlang/OTP 18.0.
- type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L);
+ type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L);
t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
%% XXX. To be removed.
{t_opaque(Mod, Name, Args, Rep), L}.
-builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) ->
+builtin_type(Name, Type, TypeNames, ET, Site, MR, V, D, L) ->
+ M = site_module(Site),
case dict:find(M, MR) of
{ok, R} ->
case lookup_type(Name, 0, R) of
{_, {{_M, _FL, _F, _A}, _T}} ->
- type_from_form(Name, [], TypeNames, ET, M, MR, V, D, L);
+ type_from_form(Name, [], TypeNames, ET, Site, MR, V, D, L);
error ->
{Type, L}
end;
@@ -4215,92 +4320,107 @@ builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) ->
{Type, L}
end.
-type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L) ->
+type_from_form(Name, Args, TypeNames, ET, Site0, MR, V, D, L) ->
ArgsLen = length(Args),
- {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
- {ok, R} = dict:find(M, MR),
+ Module = site_module(Site0),
+ {ok, R} = dict:find(Module, MR),
+ TypeName = {type, {Module, Name, ArgsLen}},
case lookup_type(Name, ArgsLen, R) of
{type, {{Module, _FileName, Form, ArgNames}, _Type}} ->
- TypeName = {type, Module, Name, ArgsLen},
case can_unfold_more(TypeName, TypeNames) of
true ->
+ NewTypeNames = [TypeName|TypeNames],
+ {ArgTypes, L1} =
+ list_from_form(Args, TypeNames, ET, Site0, MR, V, D, L),
List = lists:zip(ArgNames, ArgTypes),
TmpV = dict:from_list(List),
- t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1);
+ Site = TypeName,
+ t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1);
false ->
- {t_any(), L1}
+ {t_any(), L}
end;
{opaque, {{Module, _FileName, Form, ArgNames}, Type}} ->
- TypeName = {opaque, Module, Name, ArgsLen},
- {Rep, L2} =
- case can_unfold_more(TypeName, TypeNames) of
- true ->
- List = lists:zip(ArgNames, ArgTypes),
- TmpV = dict:from_list(List),
- t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1);
- false -> {t_any(), L1}
- end,
- Rep1 = choose_opaque_type(Rep, Type),
- Rep2 = case t_is_none(Rep1) of
- true -> Rep1;
- false ->
- Args2 = [subst_all_vars_to_any(ArgType) ||
- ArgType <- ArgTypes],
- t_opaque(Module, Name, Args2, Rep1)
- end,
- {Rep2, L2};
+ case can_unfold_more(TypeName, TypeNames) of
+ true ->
+ NewTypeNames = [TypeName|TypeNames],
+ {ArgTypes, L1} =
+ list_from_form(Args, NewTypeNames, ET, Site0, MR, V, D, L),
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpV = dict:from_list(List),
+ Site = TypeName,
+ {Rep, L2} =
+ t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1),
+ Rep1 = choose_opaque_type(Rep, Type),
+ Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
+ true -> Rep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Module, Name, ArgTypes2, Rep1)
+ end,
+ {Rep2, L2};
+ false -> {t_any(), L}
+ end;
error ->
Msg = io_lib:format("Unable to find type ~w/~w\n", [Name, ArgsLen]),
throw({error, Msg})
end.
-remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) ->
- {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
+remote_from_form(RemMod, Name, Args, TypeNames, ET, S, MR, V, D, L) ->
if
ET =:= replace_by_none ->
- {t_none(), L1};
+ {t_none(), L};
true ->
ArgsLen = length(Args),
+ MFA = {RemMod, Name, ArgsLen},
case dict:find(RemMod, MR) of
error ->
- self() ! {self(), ext_types, {RemMod, Name, ArgsLen}},
- {t_any(), L1};
+ self() ! {self(), ext_types, MFA},
+ {t_any(), L};
{ok, RemDict} ->
- MFA = {RemMod, Name, ArgsLen},
+ RemType = {type, MFA},
case sets:is_element(MFA, ET) of
true ->
case lookup_type(Name, ArgsLen, RemDict) of
{type, {{_Mod, _FileLine, Form, ArgNames}, _Type}} ->
- RemType = {type, RemMod, Name, ArgsLen},
case can_unfold_more(RemType, TypeNames) of
true ->
+ NewTypeNames = [RemType|TypeNames],
+ {ArgTypes, L1} = list_from_form(Args, TypeNames,
+ ET, S, MR, V, D, L),
List = lists:zip(ArgNames, ArgTypes),
TmpVarDict = dict:from_list(List),
- NewTypeNames = [RemType|TypeNames],
+ Site = RemType,
t_from_form(Form, NewTypeNames, ET,
- RemMod, MR, TmpVarDict, D, L1);
+ Site, MR, TmpVarDict, D, L1);
false ->
- {t_any(), L1}
+ {t_any(), L}
end;
{opaque, {{Mod, _FileLine, Form, ArgNames}, Type}} ->
- RemType = {opaque, RemMod, Name, ArgsLen},
- List = lists:zip(ArgNames, ArgTypes),
- TmpVarDict = dict:from_list(List),
- {NewRep, L2} =
- case can_unfold_more(RemType, TypeNames) of
- true ->
- NewTypeNames = [RemType|TypeNames],
- t_from_form(Form, NewTypeNames, ET, RemMod, MR,
- TmpVarDict, D, L1);
- false ->
- {t_any(), L1}
- end,
- NewRep1 = choose_opaque_type(NewRep, Type),
- NewRep2 = case t_is_none(NewRep1) of
- true -> NewRep1;
- false -> t_opaque(Mod, Name, ArgTypes, NewRep1)
- end,
- {NewRep2, L2};
+ case can_unfold_more(RemType, TypeNames) of
+ true ->
+ NewTypeNames = [RemType|TypeNames],
+ {ArgTypes, L1} = list_from_form(Args, NewTypeNames,
+ ET, S, MR, V, D, L),
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpVarDict = dict:from_list(List),
+ Site = RemType,
+ {NewRep, L2} =
+ t_from_form(Form, NewTypeNames, ET, Site, MR,
+ TmpVarDict, D, L1),
+ NewRep1 = choose_opaque_type(NewRep, Type),
+ NewRep2 =
+ case
+ cannot_have_opaque(NewRep1, RemType, TypeNames)
+ of
+ true -> NewRep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Mod, Name, ArgTypes2, NewRep1)
+ end,
+ {NewRep2, L2};
+ false ->
+ {t_any(), L}
+ end;
error ->
Msg = io_lib:format("Unable to find remote type ~w:~w()\n",
[RemMod, Name]),
@@ -4308,11 +4428,14 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) ->
end;
false ->
self() ! {self(), ext_types, {RemMod, Name, ArgsLen}},
- {t_any(), L1}
+ {t_any(), L}
end
end
end.
+subst_all_vars_to_any_list(Types) ->
+ [subst_all_vars_to_any(Type) || Type <- Types].
+
%% Opaque types (both local and remote) are problematic when it comes
%% to the limits (TypeNames, D, and L). The reason is that if any() is
%% substituted for a more specialized subtype of an opaque type, the
@@ -4332,22 +4455,24 @@ choose_opaque_type(Type, DeclType) ->
false -> DeclType
end.
-record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) ->
+record_from_form({atom, _, Name}, ModFields, TypeNames, ET, S, MR, V, D, L) ->
case can_unfold_more({record, Name}, TypeNames) of
true ->
+ M = site_module(S),
{ok, R} = dict:find(M, MR),
case lookup_record(Name, R) of
{ok, DeclFields} ->
NewTypeNames = [{record, Name}|TypeNames],
+ S1 = {record, {M, Name, length(DeclFields)}},
{GetModRec, L1} = get_mod_record(ModFields, DeclFields,
- NewTypeNames, ET, M, MR, V, D, L),
+ NewTypeNames, ET, S1, MR, V, D, L),
case GetModRec of
{error, FieldName} ->
throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
[Name, FieldName])});
{ok, NewFields} ->
{NewFields1, L2} =
- fields_from_form(NewFields, NewTypeNames, ET, M, MR,
+ fields_from_form(NewFields, NewTypeNames, ET, S1, MR,
dict:new(), D, L1),
Rec = t_tuple(
[t_atom(Name)|[Type
@@ -4361,12 +4486,12 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) ->
{t_any(), L}
end.
-get_mod_record([], DeclFields, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+get_mod_record([], DeclFields, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{{ok, DeclFields}, L};
-get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) ->
+get_mod_record(ModFields, DeclFields, TypeNames, ET, S, MR, V, D, L) ->
DeclFieldsDict = lists:keysort(1, DeclFields),
{ModFieldsDict, L1} =
- build_field_dict(ModFields, TypeNames, ET, M, MR, V, D, L),
+ build_field_dict(ModFields, TypeNames, ET, S, MR, V, D, L),
case get_mod_record_types(DeclFieldsDict, ModFieldsDict, []) of
{error, _FieldName} = Error -> {Error, L1};
{ok, FinalKeyDict} ->
@@ -4375,17 +4500,17 @@ get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) ->
{{ok, Fields}, L1}
end.
-build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L) ->
- build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L, []).
+build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L) ->
+ build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L, []).
build_field_dict([{type, _, field_type, [{atom, _, Name}, Type]}|Left],
- TypeNames, ET, M, MR, V, D, L, Acc) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1),
+ TypeNames, ET, S, MR, V, D, L, Acc) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1),
NewAcc = [{Name, Type, T}|Acc],
{Dict, L2} =
- build_field_dict(Left, TypeNames, ET, M, MR, V, D, L1, NewAcc),
+ build_field_dict(Left, TypeNames, ET, S, MR, V, D, L1, NewAcc),
{Dict, L2};
-build_field_dict([], _TypeNames, _ET, _M, _MR, _V, _D, L, Acc) ->
+build_field_dict([], _TypeNames, _ET, _S, _MR, _V, _D, L, Acc) ->
{lists:keysort(1, Acc), L}.
get_mod_record_types([{FieldName, _Abstr, _DeclType}|Left1],
@@ -4404,88 +4529,94 @@ get_mod_record_types(_, [{FieldName2, _FormType, _ModType}|_], _Acc) ->
%% It is important to create a limited version of the record type
%% since nested record types can otherwise easily result in huge
%% terms.
-fields_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+fields_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{[], L};
-fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, M, MR,
+fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, S, MR,
V, D, L) ->
- {T, L1} = t_from_form(Abstr, TypeNames, ET, M, MR, V, D, L),
- {F, L2} = fields_from_form(Tail, TypeNames, ET, M, MR, V, D, L1),
+ {T, L1} = t_from_form(Abstr, TypeNames, ET, S, MR, V, D, L),
+ {F, L2} = fields_from_form(Tail, TypeNames, ET, S, MR, V, D, L1),
{[{Name, T}|F], L2}.
-list_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+list_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{[], L};
-list_from_form([H|Tail], TypeNames, ET, M, MR, V, D, L) ->
- {H1, L1} = t_from_form(H, TypeNames, ET, M, MR, V, D, L - 1),
- {T1, L2} = list_from_form(Tail, TypeNames, ET, M, MR, V, D, L1),
+list_from_form([H|Tail], TypeNames, ET, S, MR, V, D, L) ->
+ {H1, L1} = t_from_form(H, TypeNames, ET, S, MR, V, D, L - 1),
+ {T1, L2} = list_from_form(Tail, TypeNames, ET, S, MR, V, D, L1),
{[H1|T1], L2}.
--spec t_check_record_fields(parse_form(), sets:set(mfa()), module(),
+-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(),
mod_records()) -> ok.
-t_check_record_fields(Form, ExpTypes, Module, RecDict) ->
- t_check_record_fields(Form, ExpTypes, Module, RecDict, dict:new()).
+t_check_record_fields(Form, ExpTypes, Site, RecDict) ->
+ t_check_record_fields(Form, ExpTypes, Site, RecDict, dict:new()).
--spec t_check_record_fields(parse_form(), sets:set(mfa()), module(),
+-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(),
mod_records(), var_table()) -> ok.
%% If there is something wrong with parse_form()
%% throw({error, io_lib:chars()} is called.
-t_check_record_fields({var, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, M, MR, V) ->
- t_check_record_fields(Type, ET, M, MR, V);
-t_check_record_fields({paren_type, _L, [Type]}, ET, M, MR, V) ->
- t_check_record_fields(Type, ET, M, MR, V);
+t_check_record_fields({var, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, S, MR, V) ->
+ t_check_record_fields(Type, ET, S, MR, V);
+t_check_record_fields({paren_type, _L, [Type]}, ET, S, MR, V) ->
+ t_check_record_fields(Type, ET, S, MR, V);
t_check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
- ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V);
-t_check_record_fields({atom, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({integer, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({op, _L, _Op, _Arg}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, tuple, any}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, map, any}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _M, _MR, _V) ->
+ ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V);
+t_check_record_fields({atom, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({integer, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({op, _L, _Op, _Arg}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, tuple, any}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, map, any}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _S, _MR, _V) ->
ok;
t_check_record_fields({type, _L, 'fun', [{type, _, any}, Range]},
- ET, M, MR, V) ->
- t_check_record_fields(Range, ET, M, MR, V);
-t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _M, _MR, _V) ->
+ ET, S, MR, V) ->
+ t_check_record_fields(Range, ET, S, MR, V);
+t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _S, _MR, _V) ->
ok;
-t_check_record_fields({type, _L, record, [Name|Fields]}, ET, M, MR, V) ->
- check_record(Name, Fields, ET, M, MR, V);
-t_check_record_fields({type, _L, _, Args}, ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V);
-t_check_record_fields({user_type, _L, _Name, Args}, ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V).
-
-check_record({atom, _, Name}, ModFields, ET, M, MR, V) ->
+t_check_record_fields({type, _L, record, [Name|Fields]}, ET, S, MR, V) ->
+ check_record(Name, Fields, ET, S, MR, V);
+t_check_record_fields({type, _L, _, Args}, ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V);
+t_check_record_fields({user_type, _L, _Name, Args}, ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V).
+
+check_record({atom, _, Name}, ModFields, ET, Site, MR, V) ->
+ M = site_module(Site),
{ok, R} = dict:find(M, MR),
{ok, DeclFields} = lookup_record(Name, R),
- case check_fields(ModFields, DeclFields, ET, M, MR, V) of
+ case check_fields(Name, ModFields, DeclFields, ET, Site, MR, V) of
{error, FieldName} ->
throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
[Name, FieldName])});
ok -> ok
end.
-check_fields([{type, _, field_type, [{atom, _, Name}, Abstr]}|Left],
- DeclFields, ET, M, MR, V) ->
- Type = t_from_form(Abstr, ET, M, MR, V),
+check_fields(RecName, [{type, _, field_type, [{atom, _, Name}, Abstr]}|Left],
+ DeclFields, ET, Site0, MR, V) ->
+ M = site_module(Site0),
+ Site = {record, {M, RecName, length(DeclFields)}},
+ Type = t_from_form(Abstr, ET, Site, MR, V),
{Name, _, DeclType} = lists:keyfind(Name, 1, DeclFields),
TypeNoVars = subst_all_vars_to_any(Type),
case t_is_subtype(TypeNoVars, DeclType) of
false -> {error, Name};
- true -> check_fields(Left, DeclFields, ET, M, MR, V)
+ true -> check_fields(RecName, Left, DeclFields, ET, Site0, MR, V)
end;
-check_fields([], _Decl, _ET, _M, _MR, _V) ->
+check_fields(_RecName, [], _Decl, _ET, _Site, _MR, _V) ->
ok.
-list_check_record_fields([], _ET, _M, _MR, _V) ->
+list_check_record_fields([], _ET, _S, _MR, _V) ->
ok;
-list_check_record_fields([H|Tail], ET, M, MR, V) ->
- ok = t_check_record_fields(H, ET, M, MR, V),
- list_check_record_fields(Tail, ET, M, MR, V).
+list_check_record_fields([H|Tail], ET, S, MR, V) ->
+ ok = t_check_record_fields(H, ET, S, MR, V),
+ list_check_record_fields(Tail, ET, S, MR, V).
+
+site_module({_, {Module, _, _}}) ->
+ Module.
-spec t_var_names([erl_type()]) -> [atom()].
@@ -4580,8 +4711,9 @@ t_form_to_string({type, _L, Name, []} = T) ->
M = mod,
D0 = dict:new(),
MR = dict:from_list([{M, D0}]),
+ S = {type, {M,Name,0}},
{T1, _} =
- t_from_form(T, [], sets:new(), M, MR, D0, _Deep=1000, _ALot=100000),
+ t_from_form(T, [], sets:new(), S, MR, D0, _Deep=1000, _ALot=100000),
t_to_string(T1)
catch throw:{error, _} -> atom_to_string(Name) ++ "()"
end;
@@ -4673,6 +4805,12 @@ lookup_type(Name, Arity, RecDict) ->
type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+cannot_have_opaque(Type, TypeName, TypeNames) ->
+ t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
+
+is_recursive(TypeName, TypeNames) ->
+ lists:member(TypeName, TypeNames).
+
can_unfold_more(TypeName, TypeNames) ->
Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end,
lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT.
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
index 98fec900af..bf4bdbb3b3 100644
--- a/lib/hipe/doc/src/hipe_app.xml
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -37,15 +37,14 @@
<description>
<p>
The normal way to native-compile an Erlang module using HiPE is to include the atom native
- in the Erlang compiler options, as in:
- <code>
- 1> <input>c(my_module, [native]).</input></code>
- Options to the HiPE compiler are then passed as follows:
- <code>
- 1> <input>c(my_module, [native,{hipe,Options}]).</input></code>
- For on-line help in the Erlang shell, call <c>hipe:help()</c>.
- Details on HiPE compiler options are given by <c>hipe:help_options()</c>.
- </p>
+ in the Erlang compiler options, as in:</p>
+ <pre>
+ 1> <input>c(my_module, [native]).</input></pre>
+ <p>Options to the HiPE compiler are then passed as follows:</p>
+ <pre>
+ 1> <input>c(my_module, [native,{hipe,Options}]).</input></pre>
+ <p>For on-line help in the Erlang shell, call <c>hipe:help()</c>.
+ Details on HiPE compiler options are given by <c>hipe:help_options()</c>.</p>
</description>
<section>
<title>SEE ALSO</title>
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 33a18ff7ef..b5b13948e9 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,95 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix hipe bug causing segfaults when native code
+ constructs binaries starting with a zero-length integer
+ field.</p>
+ <p>
+ Own Id: OTP-13048</p>
+ </item>
+ <item>
+ <p>
+ Reintroduce the <c>erlang:make_fun/3</c> BIF in
+ erl_bif_types.</p>
+ <p>
+ Own Id: OTP-13068</p>
+ </item>
+ <item>
+ <p>
+ In certain cases of matching with very big binaries, the
+ HiPE compiler generated code that would fail the match,
+ even in cases that the matching was successful. The
+ problem was more quite noticeable on 32-bit platforms.</p>
+ <p>
+ Own Id: OTP-13092</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ mikpe/hipe_x86_signal-musl-support</p>
+ <p>
+ Own Id: OTP-13159</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix bugs concerning <c>erlang:abs/1</c>. </p>
+ <p>
+ Own Id: OTP-12948</p>
+ </item>
+ <item>
+ <p> Fix a bug concerning <c>lists:keydelete/3</c> with
+ union and opaque types. </p>
+ <p>
+ Own Id: OTP-12949</p>
+ </item>
+ <item>
+ <p>
+ A beam file compiled by hipe for an incompatible runtime
+ system was sometimes not rejected by the loader, which
+ could lead to vm crash. This fix will also allow the same
+ hipe compiler to be used by both normal and debug-built
+ vm.</p>
+ <p>
+ Own Id: OTP-12962</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function <c>hipe:erts_checksum/0</c> which returns a
+ value identifying the target runtime system for the
+ compiler. Used by dialyzer for its beam cache directory.</p>
+ <p>
+ Own Id: OTP-12963 Aux Id: OTP-12962, OTP-12964 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -275,22 +364,28 @@
<p>
EEP43: New data type - Maps</p>
<p>
- With Maps you may for instance: <taglist> <item><c>M0 =
- #{ a =&gt; 1, b =&gt; 2}, % create
- associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
- update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
- "hello"}, % add new associations</c></item> <item><c>#{
- "hi" := V1, a := V2, b := V3} = M2. % match keys with
- values</c></item> </taglist></p>
+ With Maps you may for instance:</p>
+ <taglist>
+ <tag/> <item><c>M0 = #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item>
+ <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item>
+ <tag/><item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item>
+ <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2.
+ % match keys with values</c></item>
+ </taglist>
<p>
For information on how to use Maps please see Map Expressions in the
<seealso marker="doc/reference_manual:expressions#map_expressions">
Reference Manual</seealso>.</p>
<p>
The current implementation is without the following
- features: <taglist> <item>No variable keys</item>
- <item>No single value access</item> <item>No map
- comprehensions</item> </taglist></p>
+ features:</p>
+ <taglist>
+ <tag/><item>No variable keys</item>
+ <tag/><item>No single value access</item>
+ <tag/><item>No map comprehensions</item>
+ </taglist>
<p>
Note that Maps is <em>experimental</em> during OTP 17.0.</p>
<p>
@@ -558,19 +653,17 @@
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
- <p>
<list> <item><p>No warnings for underspecs with remote
types</p></item> <item><p> Fix crash in Typer</p></item>
<item><p>Fix Dialyzer's warning for its own
code</p></item> <item><p>Fix Dialyzer's warnings in
HiPE</p></item> <item><p>Add file/line info in a
particular Dialyzer crash</p></item> <item><p>Update
- inets test results</p></item> </list></p>
+ inets test results</p></item> </list>
<p>
Own Id: OTP-9758</p>
</item>
<item>
- <p>
<list> <item><p>Correct callback spec in application
module</p></item> <item><p>Refine warning about callback
specs with extra ranges</p></item> <item><p>Cleanup
@@ -581,7 +674,7 @@
analysis</p></item> <item><p>Fix crash in
Dialyzer</p></item> <item><p>Variable substitution was
not generalizing any unknown variables.</p></item>
- </list></p>
+ </list>
<p>
Own Id: OTP-9776</p>
</item>
diff --git a/lib/hipe/llvm/hipe_llvm_merge.erl b/lib/hipe/llvm/hipe_llvm_merge.erl
index 3ababfc21a..6e891ac3b0 100644
--- a/lib/hipe/llvm/hipe_llvm_merge.erl
+++ b/lib/hipe/llvm/hipe_llvm_merge.erl
@@ -27,7 +27,7 @@ finalize(CompiledCode, Closures, Exports) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC, % ConstMap
DataRelocs, % LabelMap
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index 008393e63c..aa86b6dc5b 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -225,4 +225,4 @@
{applications, [kernel,stdlib]},
{env, []},
{runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.5","kernel-3.0",
- "erts-7.0","compiler-5.0"]}]}.
+ "erts-7.1","compiler-5.0"]}]}.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index ce4f49ffa7..1a4bbf179f 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -208,7 +208,8 @@
help_options/0,
help_option/1,
help_debug_options/0,
- version/0]).
+ version/0,
+ erts_checksum/0]).
-ifndef(DEBUG).
-define(DEBUG,true).
@@ -216,6 +217,7 @@
-include("hipe.hrl").
-include("../../compiler/src/beam_disasm.hrl").
+-include("../rtl/hipe_literals.hrl").
%%-------------------------------------------------------------------
%% Basic type declaration for exported functions of the 'hipe' module
@@ -1032,6 +1034,12 @@ post(Res, Icode, Options) ->
version() ->
?VERSION_STRING().
+%% @doc Returns checksum identifying the target runtime system.
+-spec erts_checksum() -> integer().
+
+erts_checksum() ->
+ ?HIPE_ERTS_CHECKSUM.
+
%% --------------------------------------------------------------------
%% D O C U M E N T A T I O N - H E L P
%% --------------------------------------------------------------------
@@ -1062,6 +1070,8 @@ help() ->
" Prints a description of debug options.\n" ++
" version() ->\n" ++
" Returns the HiPE version as a string'.\n" ++
+ " erts_checksum() ->\n" ++
+ " Returns a checksum identifying the target runtime system.\n" ++
"\n" ++
" For HiPE developers only:\n" ++
" Use `help_hiper()' for information about HiPE's low-level interface\n",
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index 4d419978ef..00f28d60e4 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -50,7 +50,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index d2517b13fc..1bf52fe312 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -75,7 +75,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_exported_vars
+ERL_COMPILE_FLAGS += -Werror +inline +warn_unused_import +warn_exported_vars
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index 40bd22aa8e..692bad7d96 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1192,7 +1192,10 @@ copy_little_word(Base, Offset, NewOffset, Word) ->
hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
-copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
+copy_offset_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
+ [hipe_rtl:mk_move(NewOffset, Offset)];
+copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1)
+ when is_integer(Size), Size > 0 ->
Tmp2 = hipe_rtl:mk_new_reg(),
Tmp3 = hipe_rtl:mk_new_reg(),
Tmp4 = hipe_rtl:mk_new_reg(),
@@ -1203,7 +1206,7 @@ copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) -
Tmp9 = hipe_rtl:mk_new_reg(),
OldByte = hipe_rtl:mk_new_reg(),
TmpOffset = hipe_rtl:mk_new_reg(),
- BranchLbl = hipe_rtl:mk_new_label(),
+ BranchLbl = hipe_rtl:mk_new_label(),
BodyLbl = hipe_rtl:mk_new_label(),
EndLbl = hipe_rtl:mk_new_label(),
NextLbl = hipe_rtl:mk_new_label(),
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 364aab1b6f..51213b71d1 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
@@ -181,17 +181,20 @@ gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
[hipe_rtl:mk_goto(FalseLblName)];
false ->
Unsafe = unsafe(Flags),
- case Args of
- [Ms] ->
- SizeReg = hipe_rtl:mk_new_reg(),
- SizeCode = [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))];
- [Ms, BitsVar] ->
- {SizeCode, SizeReg} = make_size(Size, BitsVar, FalseLblName)
- end,
- InCode = get_binary(Dst, Ms, SizeReg, Unsafe,
+ {OldMs, SizeReg, SizeCode} =
+ case Args of
+ [Ms] ->
+ SzReg = hipe_rtl:mk_new_reg(),
+ SzCode = [hipe_rtl:mk_move(SzReg, hipe_rtl:mk_imm(Size))],
+ {Ms, SzReg, SzCode};
+ [Ms, BitsVar] ->
+ {SzCode, SzReg} = make_size(Size, BitsVar, FalseLblName),
+ {Ms, SzReg, SzCode}
+ end,
+ InCode = get_binary(Dst, OldMs, SizeReg, Unsafe,
TrueLblName, FalseLblName),
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
- update_ms(NewMs, Ms) ++ SizeCode ++ InCode
+ update_ms(NewMs, OldMs) ++ SizeCode ++ InCode
end;
%% ----- bs_get_utf8 -----
gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
@@ -230,14 +233,26 @@ gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
%% ----- bs_skip_bits -----
gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
+ MaxValue = (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)),
opt_update_ms(Dst, Ms) ++
- case Args of
- [] ->
- skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
- [Arg] ->
- {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
- InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
- SizeCode ++ InCode
+ case Bits < MaxValue of
+ true ->
+ case Args of
+ [] ->
+ skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
+ [Arg] ->
+ {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
+ InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end;
+ false -> % handle overflow case
+ case Args of
+ [] ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ [Arg] ->
+ [hipe_rtl:mk_branch(Arg, 'eq', hipe_tagscheme:mk_fixnum(0),
+ TrueLblName, FalseLblName, 0.5)]
+ end
end;
%% ----- bs_restore -----
gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
@@ -1086,23 +1101,47 @@ create_gcsafe_regs(0) ->
[].
first_part(Var, Register, FalseLblName) ->
- [SuccessLbl1, SuccessLbl2] = create_lbls(2),
- [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1),
- FalseLblName, 0.99),
- SuccessLbl1,
- hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99),
- SuccessLbl2,
- hipe_tagscheme:untag_fixnum(Register, Var)].
+ [EndLbl] = create_lbls(1),
+ EndName = hipe_rtl:label_name(EndLbl),
+ first_part(Var, Register, FalseLblName, EndName, EndName, [EndLbl]).
+
+first_part(Var, Register, FalseLblName, TrueLblName, BigLblName, Tail) ->
+ [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4),
+ [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl),
+ hipe_rtl:label_name(NotFixnumLbl), 0.99),
+ FixnumLbl,
+ hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
+ hipe_rtl:label_name(SuccessLbl), FalseLblName,
+ 0.99),
+ SuccessLbl,
+ hipe_tagscheme:untag_fixnum(Register, Var),
+ hipe_rtl:mk_goto(TrueLblName),
+ NotFixnumLbl,
+ %% Since binaries are not allowed to be larger than 2^wordsize bits
+ %% and since bignum digits are words, we know that a bignum with an
+ %% arity larger than one can't match.
+ hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl),
+ FalseLblName, 0.99),
+ BignumLbl,
+ hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var),
+ hipe_rtl:mk_goto(BigLblName) | Tail].
make_size(1, BitsVar, FalseLblName) ->
[DstReg] = create_regs(1),
{first_part(BitsVar, DstReg, FalseLblName), DstReg};
make_size(?BYTE_SIZE, BitsVar, FalseLblName) ->
[DstReg] = create_regs(1),
- Code =
- first_part(BitsVar, DstReg, FalseLblName) ++
- [hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
+ [FixnumLbl, BignumLbl] = create_lbls(2),
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ FixnumLblName = hipe_rtl:label_name(FixnumLbl),
+ Tail = [BignumLbl,
+ hipe_rtl:mk_branch(DstReg, 'ltu',
+ hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)),
+ FixnumLblName, FalseLblName, 0.99),
+ FixnumLbl,
+ hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
+ Code = first_part(BitsVar, DstReg, FalseLblName, FixnumLblName,
+ hipe_rtl:label_name(BignumLbl), Tail),
{Code, DstReg};
make_size(UnitImm, BitsVar, FalseLblName) ->
[DstReg] = create_regs(1),
@@ -1151,12 +1190,13 @@ floorlog2(X) ->
round(math:log(X)/math:log(2)-0.5).
set_high(X) ->
- set_high(X, 0).
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ set_high(min(X, WordBits), WordBits, 0).
-set_high(0, Y) ->
+set_high(0, _, Y) ->
Y;
-set_high(X, Y) ->
- set_high(X-1, Y+(1 bsl (27-X))).
+set_high(X, WordBits, Y) ->
+ set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))).
is_illegal_const(Const) ->
Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 1bb4c3cc5f..d77078acb6 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,8 @@
test_any_pid/4, test_any_port/4,
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
test_binary/4, test_bitstr/4, test_list/4, test_map/4,
- test_integer/4, test_number/4, test_tuple_N/5]).
+ test_integer/4, test_number/4, test_tuple_N/5,
+ test_pos_bignum_arity/5]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
unsafe_fixnum_sub/3,
@@ -53,9 +54,10 @@
-export([unsafe_closure_element/3]).
-export([mk_fun_header/0, tag_fun/2]).
-export([unsafe_untag_float/2, unsafe_tag_float/2]).
--export([mk_sub_binary/6,mk_sub_binary/7]).
+-export([mk_sub_binary/6, mk_sub_binary/7]).
-export([unsafe_mk_big/3, unsafe_load_float/3]).
--export([bignum_sizeneed/1,bignum_sizeneed_code/2, get_one_word_pos_bignum/3]).
+-export([bignum_sizeneed/1, bignum_sizeneed_code/2, get_one_word_pos_bignum/3,
+ unsafe_get_one_word_pos_bignum/2]).
-export([test_subbinary/3, test_heap_binary/3]).
-export([create_heap_binary/3, create_refc_binary/3, create_refc_binary/4]).
-export([create_matchstate/6, convert_matchstate/1, compare_matchstate/4]).
@@ -349,6 +351,15 @@ test_pos_bignum(X, TrueLab, FalseLab, Pred) ->
mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
TrueLab, FalseLab, Pred)].
+test_pos_bignum_arity(X, Arity, TrueLab, FalseLab, Pred) ->
+ Tmp = hipe_rtl:mk_new_reg_gcsafe(),
+ HalfTrueLab = hipe_rtl:mk_new_label(),
+ HeaderImm = hipe_rtl:mk_imm(mk_header(Arity, ?TAG_HEADER_POS_BIG)),
+ [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
+ HalfTrueLab,
+ get_header(Tmp, X),
+ hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)].
+
test_matchstate(X, TrueLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
HalfTrueLab = hipe_rtl:mk_new_label(),
@@ -963,13 +974,16 @@ get_one_word_pos_bignum(USize, Size, Fail) ->
Header = hipe_rtl:mk_new_reg(),
HalfLbl = hipe_rtl:mk_new_label(),
HalfLblName = hipe_rtl:label_name(HalfLbl),
- WordSize = hipe_rtl_arch:word_size(),
PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)),
[get_header(Header, Size),
hipe_rtl:mk_branch(Header, eq, PosHead, HalfLblName, Fail),
- HalfLbl,
- hipe_rtl:mk_load(USize, Size, hipe_rtl:mk_imm(1*WordSize
- -?TAG_PRIMARY_BOXED))].
+ HalfLbl |
+ unsafe_get_one_word_pos_bignum(USize, Size)].
+
+unsafe_get_one_word_pos_bignum(USize, Size) ->
+ WordSize = hipe_rtl_arch:word_size(),
+ Imm = hipe_rtl:mk_imm(1*WordSize-?TAG_PRIMARY_BOXED),
+ [hipe_rtl:mk_load(USize, Size, Imm)].
-spec bignum_sizeneed(non_neg_integer()) -> non_neg_integer().
diff --git a/lib/hipe/sparc/hipe_sparc_assemble.erl b/lib/hipe/sparc/hipe_sparc_assemble.erl
index 5424a6c965..0e27c78416 100644
--- a/lib/hipe/sparc/hipe_sparc_assemble.erl
+++ b/lib/hipe/sparc/hipe_sparc_assemble.erl
@@ -49,7 +49,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/test/bs_SUITE_data/bs_construct.erl b/lib/hipe/test/bs_SUITE_data/bs_construct.erl
index 9cc9ac848c..37a54c1981 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_construct.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_construct.erl
@@ -13,6 +13,7 @@ test() ->
ok = bs5(),
16#10000008 = bit_size(large_bin(1, 2, 3, 4)),
ok = bad_ones(),
+ ok = zero_width(),
ok.
%%--------------------------------------------------------------------
@@ -126,3 +127,18 @@ bad_ones() ->
Bin123 = <<1,2,3>>,
?FAIL(<<Bin123/float>>),
ok.
+
+%%--------------------------------------------------------------------
+%% Taken from the emulator bs_construct_SUITE - seg faulted till 18.1
+
+zero_width() ->
+ Z = id(0),
+ Small = id(42),
+ Big = id(1 bsl 128), % puts stuff on the heap
+ <<>> = <<Small:Z>>,
+ <<>> = <<Small:0>>,
+ <<>> = <<Big:Z>>,
+ <<>> = <<Big:0>>,
+ ok.
+
+id(X) -> X.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_match.erl b/lib/hipe/test/bs_SUITE_data/bs_match.erl
index 7bc93a316b..b241ea8d35 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_match.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_match.erl
@@ -1,8 +1,8 @@
%%% -*- erlang-indent-level: 2 -*-
%%%-------------------------------------------------------------------
%%% File : bs_match.erl
-%%% Author : Per Gustafsson <[email protected]>
-%%% Purpose : Performs simple matching and construction of binaries
+%%% Authors : Per Gustafsson <[email protected]>, Kostis Sagonas <[email protected]>
+%%% Purpose : Tests matching and construction of binaries
%%% TODO : Add binary and float tests
%%% Created : 20 Feb 2004
%%%-------------------------------------------------------------------
@@ -13,7 +13,7 @@
test() ->
Funs = [fun test_aligned/0, fun test_unaligned/0,
fun test_zero_tail/0, fun test_integer_matching/0,
- fun test_writable_bin/0],
+ fun test_writable_bin/0, fun test_match_huge_bin/0],
lists:foreach(fun (F) -> ok = F() end, Funs).
%%-------------------------------------------------------------------
@@ -175,6 +175,9 @@ test_dynamic_integer_matching(N) ->
<<12:N/integer-little, 0:S>> = <<12:N/integer-little, 0:S>>,
ok.
+%%-------------------------------------------------------------------
+%% Test writable bin -- added by Sverker Eriksson
+
test_writable_bin() ->
test_writable_bin(<<>>, 0),
ok.
@@ -185,3 +188,102 @@ test_writable_bin(Bin0, N) when N < 128 ->
Bin1 = <<Bin0/binary, N>>,
<<_/utf8, _/binary>> = Bin1,
test_writable_bin(Bin1, N+1).
+
+%%-------------------------------------------------------------------
+%% Test matching with a huge bin -- taken from bs_match_bin_SUITE
+
+test_match_huge_bin() ->
+ Bin = <<0:(1 bsl 27),13:8>>,
+ skip_huge_bin_1(1 bsl 27, Bin),
+ 16777216 = match_huge_bin_1(1 bsl 27, Bin),
+ %% Test overflowing the size of a binary field.
+ nomatch = overflow_huge_bin_skip_32(Bin),
+ nomatch = overflow_huge_bin_32(Bin),
+ nomatch = overflow_huge_bin_skip_64(Bin),
+ nomatch = overflow_huge_bin_64(Bin),
+ %% Size in variable
+ ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ok.
+
+overflow_huge_bin(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin(_, []) -> ok.
+
+overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin_unit128(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin_unit128(_, []) -> ok.
+
+skip_huge_bin_1(I, Bin) ->
+ <<_:I/binary-unit:1,13>> = Bin,
+ ok.
+
+match_huge_bin_1(I, Bin) ->
+ case Bin of
+ <<Val:I/binary-unit:1,13>> -> size(Val);
+ _ -> nomatch
+ end.
+
+overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32
+overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
+overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
+overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
+overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
+overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
+overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
+overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
+overflow_huge_bin_skip_32(_) -> nomatch.
+
+overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32
+overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25
+overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26
+overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27
+overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28
+overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29
+overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30
+overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31
+overflow_huge_bin_32(_) -> nomatch.
+
+overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64
+overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57
+overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58
+overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59
+overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60
+overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61
+overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62
+overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63
+overflow_huge_bin_skip_64(_) -> nomatch.
+
+overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64
+overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57
+overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58
+overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59
+overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60
+overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61
+overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62
+overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63
+overflow_huge_bin_64(_) -> nomatch.
+
+id(I) -> I.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index e507ae933f..123792e708 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.12
+HIPE_VSN = 3.14
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index 4ffa3d35ba..695ce16887 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -83,7 +83,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap