aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/external.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/external.c')
-rw-r--r--erts/emulator/beam/external.c135
1 files changed, 92 insertions, 43 deletions
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index a4cc3435c3..656de7c49a 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -529,7 +529,7 @@ Uint erts_encode_ext_size(Eterm term)
Uint erts_encode_ext_size_2(Eterm term, unsigned dflags)
{
- return encode_size_struct2(NULL, term, TERM_TO_BINARY_DFLAGS|dflags)
+ return encode_size_struct2(NULL, term, dflags)
+ 1 /* VERSION_MAGIC */;
}
@@ -1068,7 +1068,7 @@ static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1)
BIF_RET(res);
}
}
-
+
BIF_RETTYPE term_to_binary_1(BIF_ALIST_1)
{
Eterm res = erts_term_to_binary_int(BIF_P, BIF_ARG_1, 0, TERM_TO_BINARY_DFLAGS, NULL);
@@ -1099,10 +1099,10 @@ BIF_RETTYPE term_to_binary_2(BIF_ALIST_2)
if (tp[1] == am_minor_version && is_small(tp[2])) {
switch (signed_val(tp[2])) {
case 0:
- flags = TERM_TO_BINARY_DFLAGS;
+ flags = TERM_TO_BINARY_DFLAGS & ~DFLAG_NEW_FLOATS;
break;
case 1:
- flags = TERM_TO_BINARY_DFLAGS|DFLAG_NEW_FLOATS;
+ flags = TERM_TO_BINARY_DFLAGS;
break;
default:
goto error;
@@ -1169,6 +1169,7 @@ typedef struct {
Eterm* hp_end;
int remaining_n;
char* remaining_bytes;
+ Eterm* maps_head;
} B2TDecodeContext;
typedef struct {
@@ -1486,6 +1487,7 @@ static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* con
ctx->u.dc.hp_start = HAlloc(p, ctx->heap_size);
ctx->u.dc.hp = ctx->u.dc.hp_start;
ctx->u.dc.hp_end = ctx->u.dc.hp_start + ctx->heap_size;
+ ctx->u.dc.maps_head = NULL;
ctx->state = B2TDecode;
/*fall through*/
case B2TDecode:
@@ -1603,9 +1605,9 @@ external_size_2(BIF_ALIST_2)
if (tp[1] == am_minor_version && is_small(tp[2])) {
switch (signed_val(tp[2])) {
case 0:
+ flags &= ~DFLAG_NEW_FLOATS;
break;
case 1:
- flags |= DFLAG_NEW_FLOATS;
break;
default:
goto error;
@@ -2560,29 +2562,25 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
{
map_t *mp = (map_t*)map_val(obj);
Uint size = map_get_size(mp);
- Eterm *mptr;
*ep++ = MAP_EXT;
put_int32(size, ep); ep += 4;
- /* Push values first */
if (size > 0) {
- mptr = map_get_values(mp);
+ Eterm *kptr = map_get_keys(mp);
+ Eterm *vptr = map_get_values(mp);
+
for (i = size-1; i >= 1; i--) {
WSTACK_PUSH(s, ENC_TERM);
- WSTACK_PUSH(s, (UWord) mptr[i]);
+ WSTACK_PUSH(s, (UWord) vptr[i]);
+ WSTACK_PUSH(s, ENC_TERM);
+ WSTACK_PUSH(s, (UWord) kptr[i]);
}
WSTACK_PUSH(s, ENC_TERM);
- WSTACK_PUSH(s, (UWord) mptr[0]);
+ WSTACK_PUSH(s, (UWord) vptr[0]);
- mptr = map_get_keys(mp);
- for (i = size-1; i >= 1; i--) {
- WSTACK_PUSH(s, ENC_TERM);
- WSTACK_PUSH(s, (UWord) mptr[i]);
- }
-
- obj = mptr[0];
+ obj = kptr[0];
goto L_jump_start;
}
}
@@ -2878,7 +2876,7 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap,
int n;
ErtsAtomEncoding char_enc;
register Eterm* hp; /* Please don't take the address of hp */
- Eterm *maps_head = NULL; /* for validation of maps */
+ Eterm *maps_head; /* for validation of maps */
Eterm* next;
SWord reds;
@@ -2888,6 +2886,7 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap,
next = ctx->u.dc.next;
ep = ctx->u.dc.ep;
hpp = &ctx->u.dc.hp;
+ maps_head = ctx->u.dc.maps_head;
if (ctx->state != B2TDecode) {
int n_limit = reds;
@@ -2968,6 +2967,7 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap,
reds = ERTS_SWORD_MAX;
next = objp;
*next = (Eterm) (UWord) NULL;
+ maps_head = NULL;
}
hp = *hpp;
@@ -3514,16 +3514,16 @@ dec_term_atom_common:
keys = make_tuple(hp);
*hp++ = make_arityval(size);
- kptr = hp;
hp += size;
+ kptr = hp - 1;
mp = (map_t*)hp;
hp += MAP_HEADER_SIZE;
- vptr = hp;
hp += size;
+ vptr = hp - 1;
- /* kptr, first word for keys
- * vptr, first word for values
+ /* kptr, last word for keys
+ * vptr, last word for values
*/
/*
@@ -3538,27 +3538,12 @@ dec_term_atom_common:
mp->keys = keys;
*objp = make_map(mp);
- /* We assume the map is wellformed, meaning:
- * - ascending key order
- * - unique keys
- */
-
- objp = vptr + size - 1;
- n = size;
-
- while (n-- > 0) {
- *objp = (Eterm) COMPRESS_POINTER(next);
- next = objp;
- objp--;
- }
-
- objp = kptr + size - 1;
- n = size;
-
- while (n-- > 0) {
- *objp = (Eterm) COMPRESS_POINTER(next);
- next = objp;
- objp--;
+ for (n = size; n; n--) {
+ *vptr = (Eterm) COMPRESS_POINTER(next);
+ *kptr = (Eterm) COMPRESS_POINTER(vptr);
+ next = kptr;
+ vptr--;
+ kptr--;
}
}
break;
@@ -3780,6 +3765,7 @@ dec_term_atom_common:
ctx->u.dc.ep = ep;
ctx->u.dc.next = next;
ctx->u.dc.hp = hp;
+ ctx->u.dc.maps_head = maps_head;
ctx->reds = 0;
return NULL;
}
@@ -4454,3 +4440,66 @@ error:
#undef SKIP2
#undef CHKSIZE
}
+
+
+#ifdef HIPE
+BIF_RETTYPE hipe_wrapper_term_to_binary_1(BIF_ALIST_1);
+BIF_RETTYPE hipe_wrapper_term_to_binary_2(BIF_ALIST_2);
+BIF_RETTYPE hipe_wrapper_erts_internal_binary_to_term_1(BIF_ALIST_1);
+BIF_RETTYPE hipe_wrapper_erts_internal_binary_to_term_2(BIF_ALIST_2);
+
+/* Hipe wrappers used by native code for BIFs that disable GC while trapping.
+ *
+ * Problem:
+ * When native code calls a BIF that traps, hipe_mode_switch will push a
+ * "trap frame" on the Erlang stack in order to find its way back from beam_emu
+ * back to native caller when finally done. If GC is disabled and stack/heap
+ * is full there is no place to push the "trap frame".
+ *
+ * Solution:
+ * We reserve space on stack for the "trap frame" here before the BIF is called.
+ * If the BIF does not trap, the space is reclaimed here before returning.
+ * If the BIF traps, hipe_push_beam_trap_frame() will detect that a "trap frame"
+ * already is reserved and use it.
+ */
+BIF_RETTYPE hipe_wrapper_term_to_binary_1(BIF_ALIST_1)
+{
+ Eterm res;
+ hipe_reserve_beam_trap_frame(BIF_P, BIF__ARGS, 1);
+ res = term_to_binary_1(BIF_P, BIF__ARGS);
+ if (is_value(res) || BIF_P->freason != TRAP) {
+ hipe_unreserve_beam_trap_frame(BIF_P);
+ }
+ return res;
+}
+BIF_RETTYPE hipe_wrapper_term_to_binary_2(BIF_ALIST_2)
+{
+ Eterm res;
+ hipe_reserve_beam_trap_frame(BIF_P, BIF__ARGS, 2);
+ res = term_to_binary_2(BIF_P, BIF__ARGS);
+ if (is_value(res) || BIF_P->freason != TRAP) {
+ hipe_unreserve_beam_trap_frame(BIF_P);
+ }
+ return res;
+}
+BIF_RETTYPE hipe_wrapper_erts_internal_binary_to_term_1(BIF_ALIST_1)
+{
+ Eterm res;
+ hipe_reserve_beam_trap_frame(BIF_P, BIF__ARGS, 1);
+ res = erts_internal_binary_to_term_1(BIF_P, BIF__ARGS);
+ if (is_value(res) || BIF_P->freason != TRAP) {
+ hipe_unreserve_beam_trap_frame(BIF_P);
+ }
+ return res;
+}
+BIF_RETTYPE hipe_wrapper_erts_internal_binary_to_term_2(BIF_ALIST_2)
+{
+ Eterm res;
+ hipe_reserve_beam_trap_frame(BIF_P, BIF__ARGS, 2);
+ res = erts_internal_binary_to_term_2(BIF_P, BIF__ARGS);
+ if (is_value(res) || BIF_P->freason != TRAP) {
+ hipe_unreserve_beam_trap_frame(BIF_P);
+ }
+ return res;
+}
+#endif /*HIPE*/