aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/erl_map.c66
-rw-r--r--erts/emulator/beam/erl_process.h13
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c27
-rw-r--r--erts/emulator/test/map_SUITE.erl66
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin10876 -> 11072 bytes
-rw-r--r--erts/preloaded/src/erts_internal.erl12
-rw-r--r--lib/hipe/llvm/hipe_llvm.erl40
-rw-r--r--lib/hipe/main/hipe.erl4
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl12
10 files changed, 136 insertions, 105 deletions
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index a6510ace81..ce2cffa498 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -671,3 +671,4 @@ bif math:floor/1
bif math:ceil/1
bif math:fmod/2
bif os:set_signal/2
+bif erts_internal:maps_to_list/2
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 9062e44b10..a80f5d6a16 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -91,7 +91,7 @@ static BIF_RETTYPE hashmap_merge(Process *p, Eterm nodeA, Eterm nodeB, int swap_
static Export hashmap_merge_trap_export;
static BIF_RETTYPE maps_merge_trap_1(BIF_ALIST_1);
static Uint hashmap_subtree_size(Eterm node);
-static Eterm hashmap_to_list(Process *p, Eterm map);
+static Eterm hashmap_to_list(Process *p, Eterm map, Sint n);
static Eterm hashmap_keys(Process *p, Eterm map);
static Eterm hashmap_values(Process *p, Eterm map);
static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm node, Eterm *value);
@@ -161,13 +161,58 @@ BIF_RETTYPE maps_to_list_1(BIF_ALIST_1) {
BIF_RET(res);
} else if (is_hashmap(BIF_ARG_1)) {
- return hashmap_to_list(BIF_P, BIF_ARG_1);
+ return hashmap_to_list(BIF_P, BIF_ARG_1, -1);
}
BIF_P->fvalue = BIF_ARG_1;
BIF_ERROR(BIF_P, BADMAP);
}
+/* erts_internal:maps_to_list/2
+ *
+ * This function should be removed once iterators are in place.
+ * Never document it.
+ * Never encourage its usage.
+ *
+ * A negative value in ARG 2 means the entire map.
+ */
+
+BIF_RETTYPE erts_internal_maps_to_list_2(BIF_ALIST_2) {
+ Sint m;
+ if (term_to_Sint(BIF_ARG_2, &m)) {
+ if (is_flatmap(BIF_ARG_1)) {
+ Uint n;
+ Eterm* hp;
+ Eterm *ks,*vs, res, tup;
+ flatmap_t *mp = (flatmap_t*)flatmap_val(BIF_ARG_1);
+
+ ks = flatmap_get_keys(mp);
+ vs = flatmap_get_values(mp);
+ n = flatmap_get_size(mp);
+
+ if (m >= 0) {
+ n = m < n ? m : n;
+ }
+
+ hp = HAlloc(BIF_P, (2 + 3) * n);
+ res = NIL;
+
+ while(n--) {
+ tup = TUPLE2(hp, ks[n], vs[n]); hp += 3;
+ res = CONS(hp, tup, res); hp += 2;
+ }
+
+ BIF_RET(res);
+ } else if (is_hashmap(BIF_ARG_1)) {
+ return hashmap_to_list(BIF_P, BIF_ARG_1, m);
+ }
+ BIF_P->fvalue = BIF_ARG_1;
+ BIF_ERROR(BIF_P, BADMAP);
+ }
+ BIF_ERROR(BIF_P, BADARG);
+}
+
+
/* maps:find/2
* return value if key *matches* a key in the map
*/
@@ -1917,15 +1962,22 @@ BIF_RETTYPE maps_values_1(BIF_ALIST_1) {
BIF_ERROR(BIF_P, BADMAP);
}
-static Eterm hashmap_to_list(Process *p, Eterm node) {
+static Eterm hashmap_to_list(Process *p, Eterm node, Sint m) {
DECLARE_WSTACK(stack);
Eterm *hp, *kv;
- Eterm res = NIL;
+ Eterm tup, res = NIL;
+ Uint n = hashmap_size(node);
- hp = HAlloc(p, hashmap_size(node) * (2 + 3));
+ if (m >= 0) {
+ n = m < n ? m : n;
+ }
+
+ hp = HAlloc(p, n * (2 + 3));
hashmap_iterator_init(&stack, node, 0);
- while ((kv=hashmap_iterator_next(&stack)) != NULL) {
- Eterm tup = TUPLE2(hp, CAR(kv), CDR(kv));
+ while (n--) {
+ kv = hashmap_iterator_next(&stack);
+ ASSERT(kv != NULL);
+ tup = TUPLE2(hp, CAR(kv), CDR(kv));
hp += 3;
res = CONS(hp, tup, res);
hp += 2;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index ce0989883c..8bf372dad5 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -958,9 +958,11 @@ struct process {
Eterm* stop; /* Stack top */
Eterm* heap; /* Heap start */
Eterm* hend; /* Heap end */
+ Eterm* abandoned_heap;
Uint heap_sz; /* Size of heap in words */
Uint min_heap_size; /* Minimum size of heap (in words). */
Uint min_vheap_size; /* Minimum size of virtual heap (in words). */
+ Uint max_heap_size; /* Maximum size of heap (in words). */
#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
volatile unsigned long fp_exception;
@@ -973,16 +975,6 @@ struct process {
#endif
/*
- * Moved to after "struct hipe_process_state hipe", as a temporary fix for
- * LLVM hard-coding offsetof(struct process, hipe.nstack) (sic!)
- * (see void X86FrameLowering::adjustForHiPEPrologue(...) in
- * lib/Target/X86/X86FrameLowering.cpp).
- *
- * Used to be below "Eterm* hend".
- */
- Eterm* abandoned_heap;
-
- /*
* Saved x registers.
*/
Uint arity; /* Number of live argument registers (only valid
@@ -1061,7 +1053,6 @@ struct process {
Eterm *old_hend; /* Heap pointers for generational GC. */
Eterm *old_htop;
Eterm *old_heap;
- Uint max_heap_size; /* Maximum size of heap (in words). */
Uint16 gen_gcs; /* Number of (minor) generational GCs. */
Uint16 max_gen_gcs; /* Max minor gen GCs before fullsweep. */
ErlOffHeap off_heap; /* Off-heap data updated by copy_struct(). */
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index 0706f8d2c9..f11223d8b0 100644
--- a/erts/emulator/hipe/hipe_mode_switch.c
+++ b/erts/emulator/hipe/hipe_mode_switch.c
@@ -174,33 +174,6 @@ void hipe_mode_switch_init(void)
make_catch(beam_catches_cons(hipe_beam_pc_throw, BEAM_CATCHES_NIL));
hipe_mfa_info_table_init();
-
-#if (defined(__i386__) || defined(__x86_64__)) && defined(__linux__)
- /* Verify that the offset of c-p->hipe does not change.
- The ErLLVM hipe backend depends on it being in a specific
- position. Kostis et al has promised to fix this in upstream
- llvm by OTP 20, so it should be possible to remove these asserts
- after that. */
- ERTS_CT_ASSERT(sizeof(ErtsPTabElementCommon) ==
- (sizeof(Eterm) + /* id */
- sizeof(((ErtsPTabElementCommon*)0)->refc) +
- sizeof(ErtsTracer) + /* tracer */
- sizeof(Uint) + /* trace_flags */
- sizeof(erts_smp_atomic_t) + /* timer */
- sizeof(((ErtsPTabElementCommon*)0)->u)));
-
- ERTS_CT_ASSERT(offsetof(Process, hipe) ==
- (sizeof(ErtsPTabElementCommon) + /* common */
- sizeof(Eterm*) + /* htop */
- sizeof(Eterm*) + /* stop */
- sizeof(Eterm*) + /* heap */
- sizeof(Eterm*) + /* hend */
- sizeof(Uint) + /* heap_sz */
- sizeof(Uint) + /* min_heap_size */
- sizeof(Uint) + /* min_vheap_size */
- sizeof(volatile unsigned long))); /* fp_exception */
-#endif
-
}
void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure)
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index dfa1629112..02f3c89318 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -52,6 +52,7 @@
t_bif_map_values/1,
t_bif_map_to_list/1,
t_bif_map_from_list/1,
+ t_bif_erts_internal_maps_to_list/1,
%% erlang
t_erlang_hash/1,
@@ -118,6 +119,7 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
t_bif_map_update,
t_bif_map_values,
t_bif_map_to_list, t_bif_map_from_list,
+ t_bif_erts_internal_maps_to_list,
%% erlang
t_erlang_hash, t_map_encode_decode,
@@ -2362,23 +2364,55 @@ t_bif_map_from_list(Config) when is_list(Config) ->
{'EXIT', {badarg,_}} = (catch maps:from_list(id(42))),
ok.
-t_bif_build_and_check(Config) when is_list(Config) ->
- ok = check_build_and_remove(750,[
- fun(K) -> [K,K] end,
- fun(K) -> [float(K),K] end,
- fun(K) -> K end,
- fun(K) -> {1,K} end,
- fun(K) -> {K} end,
- fun(K) -> [K|K] end,
- fun(K) -> [K,1,2,3,4] end,
- fun(K) -> {K,atom} end,
- fun(K) -> float(K) end,
- fun(K) -> integer_to_list(K) end,
- fun(K) -> list_to_atom(integer_to_list(K)) end,
- fun(K) -> [K,{K,[K,{K,[K]}]}] end,
- fun(K) -> <<K:32>> end
- ]),
+t_bif_erts_internal_maps_to_list(Config) when is_list(Config) ->
+ %% small maps
+ [] = erts_internal:maps_to_list(#{},-1),
+ [] = erts_internal:maps_to_list(#{},-2),
+ [] = erts_internal:maps_to_list(#{},10),
+ [{a,1},{b,2}] = lists:sort(erts_internal:maps_to_list(#{a=>1,b=>2}, 2)),
+ [{a,1},{b,2}] = lists:sort(erts_internal:maps_to_list(#{a=>1,b=>2}, -1)),
+ [{_,_}] = erts_internal:maps_to_list(#{a=>1,b=>2}, 1),
+ [{a,1},{b,2},{c,3}] = lists:sort(erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},-2)),
+ [{a,1},{b,2},{c,3}] = lists:sort(erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},3)),
+ [{a,1},{b,2},{c,3}] = lists:sort(erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},5)),
+ [{_,_},{_,_}] = erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},2),
+ [{_,_}] = erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},1),
+ [] = erts_internal:maps_to_list(#{c=>3,a=>1,b=>2},0),
+
+ %% big maps
+ M = maps:from_list([{I,ok}||I <- lists:seq(1,500)]),
+ [] = erts_internal:maps_to_list(M,0),
+ [{_,_}] = erts_internal:maps_to_list(M,1),
+ [{_,_},{_,_}] = erts_internal:maps_to_list(M,2),
+ Ls1 = erts_internal:maps_to_list(M,10),
+ 10 = length(Ls1),
+ Ls2 = erts_internal:maps_to_list(M,20),
+ 20 = length(Ls2),
+ Ls3 = erts_internal:maps_to_list(M,120),
+ 120 = length(Ls3),
+ Ls4 = erts_internal:maps_to_list(M,-1),
+ 500 = length(Ls4),
+ %% error cases
+ {'EXIT', {{badmap,[{a,b},b]},_}} = (catch erts_internal:maps_to_list(id([{a,b},b]),id(1))),
+ {'EXIT', {badarg,_}} = (catch erts_internal:maps_to_list(id(#{}),id(a))),
+ {'EXIT', {badarg,_}} = (catch erts_internal:maps_to_list(id(#{1=>2}),id(<<>>))),
+ ok.
+
+t_bif_build_and_check(Config) when is_list(Config) ->
+ ok = check_build_and_remove(750,[fun(K) -> [K,K] end,
+ fun(K) -> [float(K),K] end,
+ fun(K) -> K end,
+ fun(K) -> {1,K} end,
+ fun(K) -> {K} end,
+ fun(K) -> [K|K] end,
+ fun(K) -> [K,1,2,3,4] end,
+ fun(K) -> {K,atom} end,
+ fun(K) -> float(K) end,
+ fun(K) -> integer_to_list(K) end,
+ fun(K) -> list_to_atom(integer_to_list(K)) end,
+ fun(K) -> [K,{K,[K,{K,[K]}]}] end,
+ fun(K) -> <<K:32>> end]),
ok.
check_build_and_remove(_,[]) -> ok;
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index fe99cc769b..c0ff53f503 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index a27cb2ba38..bcc779e6f6 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -31,7 +31,8 @@
-export([await_port_send_result/3]).
-export([cmp_term/2]).
--export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1]).
+-export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1,
+ maps_to_list/2]).
-export([open_port/2, port_command/3, port_connect/2, port_close/1,
port_control/3, port_call/3, port_info/1, port_info/2]).
@@ -369,6 +370,15 @@ map_hashmap_children(_M) ->
Multi :: boolean(),
Res :: term().
+%% return a list of key value pairs, at most of length N
+-spec maps_to_list(M,N) -> Pairs when
+ M :: map(),
+ N :: integer(),
+ Pairs :: list().
+
+maps_to_list(_M, _N) ->
+ erlang:nif_error(undefined).
+
%% erlang:demonitor(Ref, [flush]) traps to
%% erts_internal:flush_monitor_messages(Ref, Res) when
%% it needs to flush monitor messages.
diff --git a/lib/hipe/llvm/hipe_llvm.erl b/lib/hipe/llvm/hipe_llvm.erl
index b22f8fb320..641d3fda0a 100644
--- a/lib/hipe/llvm/hipe_llvm.erl
+++ b/lib/hipe/llvm/hipe_llvm.erl
@@ -862,7 +862,7 @@ pp_ins(Dev, Ver, I) ->
true -> write(Dev, "volatile ");
false -> ok
end,
- pp_dereference_type(Dev, Ver, load_p_type(I)),
+ pp_dereference_type(Dev, load_p_type(I)),
write(Dev, [" ", load_pointer(I), " "]),
case load_alignment(I) of
[] -> ok;
@@ -898,7 +898,7 @@ pp_ins(Dev, Ver, I) ->
true -> write(Dev, "inbounds ");
false -> ok
end,
- pp_dereference_type(Dev, Ver, getelementptr_p_type(I)),
+ pp_dereference_type(Dev, getelementptr_p_type(I)),
write(Dev, [" ", getelementptr_value(I)]),
pp_typed_idxs(Dev, getelementptr_typed_idxs(I)),
write(Dev, "\n");
@@ -959,10 +959,8 @@ pp_ins(Dev, Ver, I) ->
pp_args(Dev, fun_def_arglist(I)),
write(Dev, ") "),
pp_options(Dev, fun_def_fn_attrs(I)),
- case Ver >= {3,7} of false -> ok; true ->
- write(Dev, "personality i32 (i32, i64, i8*,i8*)* "
- "@__gcc_personality_v0 ")
- end,
+ write(Dev, "personality i32 (i32, i64, i8*,i8*)* "
+ "@__gcc_personality_v0 "),
case fun_def_align(I) of
[] -> ok;
N -> write(Dev, ["align ", N])
@@ -997,12 +995,7 @@ pp_ins(Dev, Ver, I) ->
pp_type(Dev, const_decl_type(I)),
write(Dev, [" ", const_decl_value(I), "\n"]);
#llvm_landingpad{} ->
- write(Dev, "landingpad { i8*, i32 } "),
- case Ver < {3,7} of false -> ok; true ->
- write(Dev, "personality i32 (i32, i64, i8*,i8*)* "
- "@__gcc_personality_v0 ")
- end,
- write(Dev, "cleanup\n");
+ write(Dev, "landingpad { i8*, i32 } cleanup\n");
#llvm_asm{} ->
write(Dev, [asm_instruction(I), "\n"]);
#llvm_adj_stack{} ->
@@ -1011,15 +1004,7 @@ pp_ins(Dev, Ver, I) ->
pp_type(Dev, adj_stack_type(I)),
write(Dev, [" ", adj_stack_offset(I),")\n"]);
#llvm_meta{} ->
- write(Dev, ["!", meta_id(I), " = "]),
- Named = case string:to_integer(meta_id(I)) of
- {_, ""} -> false;
- _ -> true
- end,
- case Ver < {3,6} andalso not Named of
- true -> write(Dev, "metadata !{metadata ");
- false -> write(Dev, "!{ ")
- end,
+ write(Dev, ["!", meta_id(I), " = !{ "]),
write(Dev, string:join([if is_list(Op) -> ["!\"", Op, "\""];
is_integer(Op) -> ["i32 ", integer_to_list(Op)];
is_record(Op, llvm_meta) ->
@@ -1030,15 +1015,10 @@ pp_ins(Dev, Ver, I) ->
exit({?MODULE, pp_ins, {"Unknown LLVM instruction", Other}})
end.
-%% @doc Print the type of a dereference in an LLVM instruction using syntax
-%% parsable by the specified LLVM version.
-pp_dereference_type(Dev, Ver, Type) ->
- case Ver >= {3,7} of
- false -> ok;
- true ->
- pp_type(Dev, pointer_type(Type)),
- write(Dev, ", ")
- end,
+%% @doc Print the type of a dereference in an LLVM instruction.
+pp_dereference_type(Dev, Type) ->
+ pp_type(Dev, pointer_type(Type)),
+ write(Dev, ", "),
pp_type(Dev, Type).
%% @doc Pretty-print a list of types
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 06facae5c1..fff397b060 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -655,7 +655,7 @@ run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
case proplists:get_bool(to_llvm, Opts0) andalso
not llvm_support_available() of
true ->
- ?error_msg("No LLVM version 3.4 or greater "
+ ?error_msg("No LLVM version 3.9 or greater "
"found in $PATH; aborting "
"native code compilation.\n", []),
?EXIT(cant_find_required_llvm_version);
@@ -1585,7 +1585,7 @@ check_options(Opts) ->
-spec llvm_support_available() -> boolean().
llvm_support_available() ->
- get_llvm_version() >= {3,4}.
+ get_llvm_version() >= {3,9}.
-type llvm_version() :: {Major :: integer(), Minor :: integer()}.
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 6ddba8121a..aabccfc5d9 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -473,19 +473,9 @@ print_length(Term, _D, _RF, _Enc, _Str) ->
print_length_map(_Map, 1, _RF, _Enc, _Str) ->
{"#{...}", 6};
print_length_map(Map, D, RF, Enc, Str) when is_map(Map) ->
- Pairs = print_length_map_pairs(maps_to_list(Map, D), D, RF, Enc, Str),
+ Pairs = print_length_map_pairs(erts_internal:maps_to_list(Map, D), D, RF, Enc, Str),
{{map, Pairs}, list_length(Pairs, 3)}.
-maps_to_list(Map, D) when D < 0; map_size(Map) =< D ->
- maps:to_list(Map);
-maps_to_list(Map, D) ->
- F = fun(_K, _V, {N, L}) when N =:= D ->
- throw(L);
- (K, V, {N, L}) ->
- {N+1, [{K, V} | L]}
- end,
- lists:reverse(catch maps:fold(F, {0, []}, Map)).
-
print_length_map_pairs([], _D, _RF, _Enc, _Str) ->
[];
print_length_map_pairs(_Pairs, 1, _RF, _Enc, _Str) ->