aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorhappi <[email protected]>2013-05-03 16:25:37 +0200
committerPatrik Nyblom <[email protected]>2013-06-04 17:59:48 +0200
commit6d366f0ae53669a17de96db0094ef62217b60f1b (patch)
treeed795e9521c0becd69714a2aab21968b9e8e4a59 /erts
parentf7f24a77e918eea712b435a5ae9b01de270d6d7d (diff)
downloadotp-6d366f0ae53669a17de96db0094ef62217b60f1b.tar.gz
otp-6d366f0ae53669a17de96db0094ef62217b60f1b.tar.bz2
otp-6d366f0ae53669a17de96db0094ef62217b60f1b.zip
Make term_to_binary yield (trap).
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/atom.names2
-rw-r--r--erts/emulator/beam/dist.c4
-rw-r--r--erts/emulator/beam/erl_gc.c9
-rw-r--r--erts/emulator/beam/erl_init.c1
-rw-r--r--erts/emulator/beam/erl_process.c4
-rw-r--r--erts/emulator/beam/erl_process.h5
-rw-r--r--erts/emulator/beam/external.c517
-rw-r--r--erts/emulator/beam/external.h2
-rwxr-xr-xerts/emulator/beam/global.h3
9 files changed, 414 insertions, 133 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 7d86e486f1..bf1480ea06 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -197,6 +197,7 @@ atom elib_malloc
atom emulator
atom enable_trace
atom enabled
+atom enc_term_cont
atom endian
atom env
atom eof
@@ -530,6 +531,7 @@ atom system_version
atom system_architecture
atom SYSTEM='SYSTEM'
atom table
+atom term_to_binary_of_size
atom this
atom thread_pool_size
atom threads
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 44f4eb9d43..a7b3d4cb2f 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -1740,10 +1740,10 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy)
/* Encode internal version of dist header */
obuf->extp = erts_encode_ext_dist_header_setup(obuf->ext_endp, acmp);
/* Encode control message */
- erts_encode_dist_ext(ctl, &obuf->ext_endp, flags, acmp);
+ erts_encode_dist_ext(c_p, ctl, &obuf->ext_endp, flags, acmp);
if (is_value(msg)) {
/* Encode message */
- erts_encode_dist_ext(msg, &obuf->ext_endp, flags, acmp);
+ erts_encode_dist_ext(c_p, msg, &obuf->ext_endp, flags, acmp);
}
ASSERT(obuf->extp < obuf->ext_endp);
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 0d12e658d9..2c219ee87c 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -1964,6 +1964,15 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset)
++n;
}
+ // Check if a suspended bif has live working data.
+ // How do we know n is small enough to fit in roots[32?]?
+ if (p->extra_root != NULL) {
+ printf("GC with extra_root 0x%xl\n", p->extra_root);
+ roots[n].v = p->extra_root;
+ roots[n].sz = p->extra_root_sz;
+ ++n;
+ }
+
ASSERT((is_nil(p->seq_trace_token) ||
is_tuple(follow_moved(p->seq_trace_token)) ||
is_atom(p->seq_trace_token)));
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index b3a3c3d403..2fb73aed96 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -340,6 +340,7 @@ erl_init(int ncpu,
erts_init_bif_binary();
erts_init_bif_re();
erts_init_unicode(); /* after RE to get access to PCRE unicode */
+ erts_init_external();
erts_delay_trap = erts_export_put(am_erlang, am_delay_trap, 2);
erts_late_init_process();
#if HAVE_ERTS_MSEG
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 88eb224f84..7724033245 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -7513,6 +7513,10 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->heap_sz = sz;
p->catches = 0;
+ p->extra_root = NULL;
+ p->extra_root_sz = 0;
+ p->extra_root_allocator = 0;
+
p->bin_vheap_sz = p->min_vheap_size;
p->bin_old_vheap_sz = p->min_vheap_size;
p->bin_old_vheap = 0;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 865ac6c43f..fca83dba8f 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -792,6 +792,11 @@ struct process {
ErlMessageQueue msg; /* Message queue */
+ Eterm *extra_root; /* Extra root set, used e.g. by yielding bifs. */
+ Uint extra_root_sz; /* Size of extra root set. */
+ ErtsAlcType_t extra_root_allocator; /* Type of memory allocator used,
+ used for freeing extra_root if process dies. */
+
union {
ErtsBifTimer *bif_timers; /* Bif timers aiming at this process */
void *terminate;
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 8420cfae24..c90074528c 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -81,7 +81,52 @@
*
*/
+
+typedef struct {
+ UWord *start;
+ Eterm *sp;
+ UWord *end;
+ UWord *wsp;
+
+ ErtsAtomCacheMap *acmp;
+ Eterm obj;
+ byte *bytes, *ep;
+ Uint32 dflags;
+ struct erl_off_heap_header** off_heap;
+} enc_work_area;
+
+#define PRINT_EWA(ewa) \
+do { \
+ Uint *_msp = ewa->start; \
+ printf("start: 0x%lx\n\r", (Uint)ewa->start); \
+ printf("sp: 0x%lx\n\r", (Uint)ewa->sp); \
+ printf("end: 0x%lx\n\r", (Uint)ewa->end); \
+ printf("wsp: 0x%lx\n\r", (Uint)ewa->wsp); \
+ printf("acmp: 0x%lx\n\r", (Uint)ewa->acmp); \
+ printf("obj: 0x%lx\n\r", (Uint)ewa->obj); \
+ printf("ep: 0x%lx\n\r", (Uint)ewa->ep); \
+ printf("bytes: 0x%lx\n\r", (Uint)ewa->bytes); \
+ printf("dflags: %d\n\r", (int)ewa->dflags); \
+ printf("off_heap: 0x%lx\n\r", (Uint)ewa->off_heap); \
+ printf("Estack:"); \
+ while(_msp < ewa->sp) printf("0x%lx ",(long int)*_msp++); \
+ _msp = ewa->end-1; \
+ printf("\n\rWstack:"); \
+ while(_msp > ewa->wsp) printf("%d ",(int)*_msp--); \
+ printf("\n\r\n\n"); \
+} while(0)
+
+static Export term_to_binary_trap_export;
+static Export enc_term_trap_export;
+
+static BIF_RETTYPE term_to_binary_of_size_2(BIF_ALIST_2);
+static BIF_RETTYPE enc_term_trap_3(BIF_ALIST_3);
+static BIF_RETTYPE term_to_binary_of_size(Process *, Eterm, Eterm);
+static BIF_RETTYPE enc_term_cont(Process *, Eterm);
+static BIF_RETTYPE enc_term_trap(Process *, Eterm, Eterm, Eterm);
static byte* enc_term(ErtsAtomCacheMap *, Eterm, byte*, Uint32, struct erl_off_heap_header** off_heap);
+static Eterm erl_enc_term(Process *, ErtsAtomCacheMap *, Eterm, byte*, Uint32, struct erl_off_heap_header** off_heap, Eterm args, byte* bytes, Eterm bin);
+static byte* enc_small(Eterm, byte*);
static Uint is_external_string(Eterm obj, int* p_is_string);
static byte* enc_atom(ErtsAtomCacheMap *, Eterm, byte*, Uint32);
static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint32);
@@ -90,6 +135,15 @@ static byte* dec_atom(ErtsDistExternal *, byte*, Eterm*);
static byte* dec_pid(ErtsDistExternal *, Eterm**, byte*, ErlOffHeap*, Eterm*);
static Sint decoded_size(byte *ep, byte* endp, int internal_tags);
+void erts_init_external(void) {
+ erts_init_trap_export(&term_to_binary_trap_export,
+ am_erlang, am_term_to_binary_of_size, 2,
+ &term_to_binary_of_size_2);
+ erts_init_trap_export(&enc_term_trap_export,
+ am_erlang, am_enc_term_cont, 3,
+ &enc_term_trap_3);
+ return;
+}
static Uint encode_size_struct2(ErtsAtomCacheMap *, Eterm, unsigned);
@@ -498,18 +552,15 @@ Uint erts_encode_ext_size_ets(Eterm term)
}
-void erts_encode_dist_ext(Eterm term, byte **ext, Uint32 flags, ErtsAtomCacheMap *acmp)
+void erts_encode_dist_ext(Process *p, Eterm term, byte **ext, Uint32 flags, ErtsAtomCacheMap *acmp)
{
byte *ep = *ext;
#ifndef ERTS_DEBUG_USE_DIST_SEP
if (!(flags & DFLAG_DIST_HDR_ATOM_CACHE))
#endif
*ep++ = VERSION_MAGIC;
+ // TODO: handle process arg and scheduling
ep = enc_term(acmp, term, ep, flags, NULL);
- if (!ep)
- erl_exit(ERTS_ABORT_EXIT,
- "%s:%d:erts_encode_dist_ext(): Internal data structure error\n",
- __FILE__, __LINE__);
*ext = ep;
}
@@ -517,16 +568,17 @@ void erts_encode_ext(Eterm term, byte **ext)
{
byte *ep = *ext;
*ep++ = VERSION_MAGIC;
+ // TODO: get process pointer from all uses of erts_encode_ext,
+ // and make them handle yielding.
ep = enc_term(NULL, term, ep, TERM_TO_BINARY_DFLAGS, NULL);
- if (!ep)
- erl_exit(ERTS_ABORT_EXIT,
- "%s:%d:erts_encode_ext(): Internal data structure error\n",
- __FILE__, __LINE__);
*ext = ep;
}
byte* erts_encode_ext_ets(Eterm term, byte *ep, struct erl_off_heap_header** off_heap)
{
+ // TODO: get process pointer from all uses of erts_encode_ext_ets,
+ // and make them handle yielding.
+
return enc_term(NULL, term, ep, TERM_TO_BINARY_DFLAGS|DFLAG_INTERNAL_TAGS,
off_heap);
}
@@ -1335,37 +1387,87 @@ external_size_2(BIF_ALIST_2)
}
}
+
Eterm
erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags)
{
Uint size;
- Eterm bin;
- size_t real_size;
- byte* endp;
+ Eterm options, *hp;
+ /* Save C-level options in an Erlang over trap. */
size = encode_size_struct2(NULL, Term, flags) + 1 /* VERSION_MAGIC */;
+ hp = HAlloc(p, 4); /* Size of a 3-tuple */
+ options = TUPLE3(hp, make_small(level), make_small(flags), make_small(size));
+
+ BUMP_REDS(p, (size >> 8));
+ if (p->fcalls < 1) {
+ BIF_TRAP2(&term_to_binary_trap_export, p, Term, options);
+ }
+
+ return term_to_binary_of_size(p, Term, options);
+}
+
+BIF_RETTYPE term_to_binary_of_size_2(BIF_ALIST_2)
+{
+ return term_to_binary_of_size(BIF_P, BIF_ARG_1, BIF_ARG_2);
+}
+
+
+static BIF_RETTYPE term_to_binary_of_size(Process *p, Eterm arg1, Eterm arg2)
+{
+ Uint size;
+ Uint32 flags;
+ Eterm bin, *ptr;
+ byte* bytes;
+
+ ptr = tuple_val(arg2);
+ flags = unsigned_val(ptr[2]);
+ size = unsigned_val(ptr[3]);
+
+ bin = new_binary(p, (byte *)NULL, size);
+ bytes = binary_bytes(bin);
+ bytes[0] = VERSION_MAGIC;
+ return erl_enc_term(p, NULL, arg1, bytes+1, flags, NULL, arg2, bytes, bin);
+}
+
+static BIF_RETTYPE term_to_binary_cont(Process *p, Eterm res, Eterm args, Eterm bin)
+{
+ Eterm *ptr;
+ size_t real_size;
+ byte *bytes, *endp, *ep;
+ int level;
+ Uint size;
+ enc_work_area *ewa;
+ Binary *bin2;
+
+
+ bin2 = ((ProcBin *) binary_val(res))->val;
+ ewa = ((enc_work_area *)ERTS_MAGIC_BIN_DATA(bin2));
+ ep = ewa->ep;
+ bytes = ewa->bytes;
+ if (!ep)
+ erl_exit(ERTS_ABORT_EXIT,
+ "%s:%d:enc_term: Internal data structure error\n",
+ __FILE__, __LINE__);
+
+ ptr = tuple_val(args);
+ level = signed_val(ptr[1]);
+ size = unsigned_val(ptr[3]);
+
+ bin2 = ((ProcBin *) binary_val(res))->val;
+ ewa = ((enc_work_area *)ERTS_MAGIC_BIN_DATA(bin2));
+ endp = ewa->ep;
+
+ real_size = endp - bytes;
+ if (real_size > size) {
+ erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n",
+ __FILE__, __LINE__, endp - (bytes + size));
+ }
if (level != 0) {
- byte buf[256];
- byte* bytes = buf;
byte* out_bytes;
uLongf dest_len;
- if (sizeof(buf) < size) {
- bytes = erts_alloc(ERTS_ALC_T_TMP, size);
- }
-
- if ((endp = enc_term(NULL, Term, bytes, flags, NULL))
- == NULL) {
- erl_exit(1, "%s, line %d: bad term: %x\n",
- __FILE__, __LINE__, Term);
- }
- real_size = endp - bytes;
- if (real_size > size) {
- erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n",
- __FILE__, __LINE__, real_size - size);
- }
-
/*
* We don't want to compress if compression actually increases the size.
* Therefore, don't give zlib more out buffer than the size of the
@@ -1379,7 +1481,7 @@ erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags)
} else {
dest_len = real_size - 5;
}
- bin = new_binary(p, NULL, real_size+1);
+ bin = erts_realloc_binary(bin, real_size+1);
out_bytes = binary_bytes(bin);
out_bytes[0] = VERSION_MAGIC;
if (erl_zlib_compress2(out_bytes+6, &dest_len, bytes, real_size, level) != Z_OK) {
@@ -1390,30 +1492,47 @@ erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags)
put_int32(real_size, out_bytes+2);
bin = erts_realloc_binary(bin, dest_len+6);
}
- if (bytes != buf) {
- erts_free(ERTS_ALC_T_TMP, bytes);
- }
- return bin;
+
} else {
- byte* bytes;
-
- bin = new_binary(p, (byte *)NULL, size);
- bytes = binary_bytes(bin);
- bytes[0] = VERSION_MAGIC;
- if ((endp = enc_term(NULL, Term, bytes+1, flags, NULL))
- == NULL) {
- erl_exit(1, "%s, line %d: bad term: %x\n",
- __FILE__, __LINE__, Term);
- }
- real_size = endp - bytes;
- if (real_size > size) {
- erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n",
- __FILE__, __LINE__, endp - (bytes + size));
- }
- return erts_realloc_binary(bin, real_size);
+ bin = erts_realloc_binary(bin, real_size);
+ }
+ return bin;
+}
+
+
+static byte*
+enc_small(Eterm obj, byte *ep)
+{
+ Uint n;
+ Sint val = signed_val(obj);
+
+ if ((Uint)val < 256) {
+ *ep++ = SMALL_INTEGER_EXT;
+ put_int8(val, ep);
+ ep++;
+ } else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) {
+ *ep++ = INTEGER_EXT;
+ put_int32(val, ep);
+ ep += 4;
+ } else {
+ DeclareTmpHeapNoproc(tmp_big,2);
+ Eterm big;
+ UseTmpHeapNoproc(2);
+ big = small_to_big(val, tmp_big);
+ *ep++ = SMALL_BIG_EXT;
+ n = big_bytes(big);
+ ASSERT(n < 256);
+ put_int8(n, ep);
+ ep += 1;
+ *ep++ = big_sign(big);
+ ep = big_to_bytes(big, ep);
+ UnUseTmpHeapNoproc(2);
}
+
+ return ep;
}
+
/*
* This function fills ext with the external format of atom.
* If it's an old atom we just supply an index, otherwise
@@ -1676,13 +1795,166 @@ dec_pid(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Ete
#define ENC_TERM ((Eterm) 0)
#define ENC_ONE_CONS ((Eterm) 1)
#define ENC_PATCH_FUN_SIZE ((Eterm) 2)
-#define ENC_LAST_ARRAY_ELEMENT ((Eterm) 3)
+/* While doing term_to_binary we keep two stacks.
+ One stack contains erlang terms to handle, this stack is passed to the GC
+ as a root set through process.extra_rootset.
+ The other stack contains "work orders" (integers (0, 1, or 2)), this stack
+ the GC can't handle.
+ Both stacks are stored in one memory area which can be reallocated and
+ deallocated if the process dies during a yield.
+ */
+#define ALLOC_EWASTACK(ewa) \
+ ewa->start = (Eterm *)erts_alloc(ERTS_ALC_T_ESTACK, DEF_WSTACK_SIZE*sizeof(UWord)*2); \
+ ewa->sp = ewa->start; \
+ ewa->end = ewa->start + DEF_WSTACK_SIZE*2; \
+ ewa->wsp = ewa->end - 1;
+
+
+#define DESTROY_EWASTACK(ewa) \
+do { \
+ if(ewa->start != NULL) { \
+ erts_free(ERTS_ALC_T_ESTACK, ewa->start); \
+ ewa->start=NULL; \
+ } \
+} while(0)
+
+#define GROW_IF_NEEDED(ewa) \
+ if (ewa->sp == ewa->wsp) { \
+ int size = (ewa->end - ewa->wsp) -1; \
+ erl_grow_wstack(&ewa->start, &ewa->sp, &ewa->end); \
+ ewa->wsp = ewa->end-1; \
+ while(size) *ewa->wsp-- = ewa->sp[size--]; \
+ }
+
+#define EWASTACK_PUSH(ewa, x) \
+do { \
+ GROW_IF_NEEDED(ewa) \
+ *ewa->sp++ = (x); \
+} while(0)
+
+#define EWASTACK_WPUSH(ewa, x) \
+do { \
+ GROW_IF_NEEDED(ewa) \
+ *ewa->wsp-- = (x); \
+} while(0)
+
+#define EWASTACK_COUNT(ewa) (ewa->sp - ewa->start)
+#define EWASTACK_WCOUNT(ewa) (ewa->end - ewa->wsp)
+#define EWASTACK_WISEMPTY(ewa) (ewa->wsp == (ewa->end-1))
+#define EWASTACK_POP(ewa) (*(--ewa->sp))
+#define EWASTACK_WPOP(ewa) (*(++ewa->wsp))
+
+#define SAVE_TO_EWA \
+do { \
+ ewa->acmp = acmp; \
+ ewa->obj = obj; \
+ ewa->ep = ep; \
+ ewa->dflags = dflags; \
+ ewa->off_heap = off_heap; \
+} while(0)
+
+#define GET_FROM_EWA \
+do { \
+ acmp = ewa->acmp; \
+ obj = ewa->obj; \
+ ep = ewa->ep; \
+ dflags = ewa->dflags; \
+ off_heap = ewa->off_heap; \
+} while(0)
+
+
+static void cleanup_my_data_ttb(Binary *bp)
+{
+ enc_work_area *ewa;
+ ewa = (enc_work_area *)ERTS_MAGIC_BIN_DATA(bp);
+ DESTROY_EWASTACK(ewa);
+ return;
+}
+
+
+
+#define SET_UP_EWA \
+ bin = erts_create_magic_binary(sizeof(enc_work_area), cleanup_my_data_ttb); \
+ ewa = (enc_work_area *)ERTS_MAGIC_BIN_DATA(bin); \
+ ALLOC_EWASTACK(ewa);\
+ SAVE_TO_EWA;
+
+#define CHECK_ENC_TERM() \
+ if (!ep) \
+ erl_exit(ERTS_ABORT_EXIT, \
+ "%s:%d:enc_term: Internal data structure error\n", \
+ __FILE__, __LINE__);
+
+
+/* Yielding entry point to enc_term. */
+Eterm
+erl_enc_term(Process *p, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
+ struct erl_off_heap_header** off_heap, Eterm args, byte* bytes, Eterm resbin)
+{
+ Eterm *hp, mbin, res;
+ enc_work_area *ewa;
+ Binary *bin;
+ SET_UP_EWA;
+ ewa->bytes = bytes;
+
+ hp = HAlloc(p, PROC_BIN_SIZE);
+ mbin = erts_mk_magic_binary_term(&hp, &MSO(p), bin);
+
+ res = enc_term_cont(p, mbin);
+ if(res == THE_NON_VALUE) {
+ // Yield
+ p->extra_root = ewa->start;
+ p->extra_root_sz = (Uint) EWASTACK_COUNT(ewa);
+ p->extra_root_allocator = ERTS_ALC_T_ESTACK;
+ BIF_TRAP3(&enc_term_trap_export, p, mbin, args, resbin);
+ }
+
+ return term_to_binary_cont(p, res, args, resbin);
+}
+
+BIF_RETTYPE enc_term_trap_3(BIF_ALIST_3)
+{
+ return enc_term_trap(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+}
+
+BIF_RETTYPE enc_term_trap(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
+{
+ Eterm res;
+ res = enc_term_cont(p, arg1);
+ if(res == THE_NON_VALUE) {
+ // Yield
+ BIF_TRAP3(&enc_term_trap_export, p, arg1, arg2, arg3);
+ }
+
+ return term_to_binary_cont(p, res, arg2, arg3);
+}
+
+/* Non-yielding entry point to enc_term */
static byte*
enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
struct erl_off_heap_header** off_heap)
{
- DECLARE_WSTACK(s);
+ Eterm *buf, *start_buf, mbin, res;
+ ErlOffHeap fake_off_heap;
+ enc_work_area *ewa;
+ Binary *bin;
+ SET_UP_EWA;
+ start_buf = buf = (Eterm *) erts_alloc(ERTS_ALC_T_BINARY_BUFFER, PROC_BIN_SIZE);
+ fake_off_heap.first=NULL;
+ mbin = erts_mk_magic_binary_term(&buf, &fake_off_heap, bin);
+ res = enc_term_cont(NULL, mbin);
+ bin = ((ProcBin *) binary_val(res))->val;
+ ewa = ((enc_work_area *)ERTS_MAGIC_BIN_DATA(bin));
+ ep = ewa->ep;
+ CHECK_ENC_TERM();
+ erts_free(ERTS_ALC_T_BINARY_BUFFER, start_buf);
+ return ep;
+}
+
+
+BIF_RETTYPE enc_term_cont(Process *p, Eterm arg1)
+{
Uint n;
Uint i;
Uint j;
@@ -1692,66 +1964,74 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
#if HALFWORD_HEAP
UWord wobj;
#endif
-
-
- goto L_jump_start;
+ enc_work_area *ewa;
+ ErtsAtomCacheMap *acmp;
+ Eterm obj;
+ byte* ep;
+ Uint32 dflags;
+ struct erl_off_heap_header** off_heap;
+
+ int reds;
+ Binary *bin = ((ProcBin *) binary_val(arg1))->val;
+ ewa = (enc_work_area *) ERTS_MAGIC_BIN_DATA(bin);
+ GET_FROM_EWA;
+
+ /* TODO: We could store the old values in ewa and restore them here... */
+ if(p != NULL) {
+ p->extra_root = NULL;
+ p->extra_root_sz = 0;
+ }
+ reds = (p == NULL) ? 0 : p->fcalls;
+ if (EWASTACK_WISEMPTY(ewa)) goto L_jump_start;
+ else goto outer_loop;
outer_loop:
- while (!WSTACK_ISEMPTY(s)) {
+ while (!EWASTACK_WISEMPTY(ewa)) {
+ if ((p != NULL) && (--reds < 1)) {
+ p->fcalls = reds;
+ SAVE_TO_EWA;
+ p->extra_root = ewa->start;
+ p->extra_root_sz = (Uint) EWASTACK_COUNT(ewa);
+ p->extra_root_allocator = ERTS_ALC_T_ESTACK;
+ return THE_NON_VALUE;
+ }
+
+ switch (val = EWASTACK_WPOP(ewa)) {
+ case ENC_TERM:
#if HALFWORD_HEAP
- obj = (Eterm) (wobj = WSTACK_POP(s));
+ obj = (Eterm) (wobj = EWASTACK_POP(ewa));
#else
- obj = WSTACK_POP(s);
+ obj = EWASTACK_POP(ewa);
#endif
- switch (val = WSTACK_POP(s)) {
- case ENC_TERM:
+
break;
case ENC_ONE_CONS:
encode_one_cons:
{
- Eterm* cons = list_val(obj);
+ Eterm* cons;
Eterm tl;
+#if HALFWORD_HEAP
+ obj = (Eterm) (wobj = EWASTACK_POP(ewa));
+#else
+ obj = EWASTACK_POP(ewa);
+#endif
+ cons = list_val(obj);
obj = CAR(cons);
tl = CDR(cons);
- WSTACK_PUSH(s, is_list(tl) ? ENC_ONE_CONS : ENC_TERM);
- WSTACK_PUSH(s, tl);
+ EWASTACK_WPUSH(ewa, is_list(tl) ? ENC_ONE_CONS : ENC_TERM);
+ EWASTACK_PUSH(ewa, tl);
}
break;
case ENC_PATCH_FUN_SIZE:
{
-#if HALFWORD_HEAP
- byte* size_p = (byte *) wobj;
-#else
- byte* size_p = (byte *) obj;
-#endif
+ byte* size_p = (byte *) EWASTACK_WPOP(ewa);
put_int32(ep - size_p, size_p);
}
goto outer_loop;
- case ENC_LAST_ARRAY_ELEMENT:
- {
-#if HALFWORD_HEAP
- Eterm* ptr = (Eterm *) wobj;
-#else
- Eterm* ptr = (Eterm *) obj;
-#endif
- obj = *ptr;
- }
- break;
- default: /* ENC_LAST_ARRAY_ELEMENT+1 and upwards */
- {
-#if HALFWORD_HEAP
- Eterm* ptr = (Eterm *) wobj;
-#else
- Eterm* ptr = (Eterm *) obj;
-#endif
- obj = *ptr++;
- WSTACK_PUSH(s, val-1);
- WSTACK_PUSH(s, (UWord) ptr);
- }
- break;
}
+
L_jump_start:
switch(tag_val_def(obj)) {
case NIL_DEF:
@@ -1763,34 +2043,7 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
break;
case SMALL_DEF:
- {
- /* From R14B we no longer restrict INTEGER_EXT to 28 bits,
- * as done earlier for backward compatibility reasons. */
- Sint val = signed_val(obj);
-
- if ((Uint)val < 256) {
- *ep++ = SMALL_INTEGER_EXT;
- put_int8(val, ep);
- ep++;
- } else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) {
- *ep++ = INTEGER_EXT;
- put_int32(val, ep);
- ep += 4;
- } else {
- DeclareTmpHeapNoproc(tmp_big,2);
- Eterm big;
- UseTmpHeapNoproc(2);
- big = small_to_big(val, tmp_big);
- *ep++ = SMALL_BIG_EXT;
- n = big_bytes(big);
- ASSERT(n < 256);
- put_int8(n, ep);
- ep += 1;
- *ep++ = big_sign(big);
- ep = big_to_bytes(big, ep);
- UnUseTmpHeapNoproc(2);
- }
- }
+ ep = enc_small(obj, ep);
break;
case BIG_DEF:
@@ -1877,6 +2130,7 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
*ep++ = LIST_EXT;
put_int32(i, ep);
ep += 4;
+ EWASTACK_PUSH(ewa, obj);
goto encode_one_cons;
}
}
@@ -1895,9 +2149,10 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
put_int32(i, ep);
ep += 4;
}
- if (i > 0) {
- WSTACK_PUSH(s, ENC_LAST_ARRAY_ELEMENT+i-1);
- WSTACK_PUSH(s, (UWord) ptr);
+ while (i > 0) {
+ EWASTACK_WPUSH(ewa, ENC_TERM);
+ EWASTACK_PUSH(ewa, (UWord) ptr[i-1]);
+ i--;
}
break;
@@ -2013,11 +2268,12 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
case EXPORT_DEF:
{
Export* exp = *((Export **) (export_val(obj) + 1));
+
if ((dflags & DFLAG_EXPORT_PTR_TAG) != 0) {
*ep++ = EXPORT_EXT;
ep = enc_atom(acmp, exp->code[0], ep, dflags);
ep = enc_atom(acmp, exp->code[1], ep, dflags);
- ep = enc_term(acmp, make_small(exp->code[2]), ep, dflags, off_heap);
+ ep = enc_small(make_small(exp->code[2]), ep);
} else {
/* Tag, arity */
*ep++ = SMALL_TUPLE_EXT;
@@ -2041,8 +2297,8 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
int ei;
*ep++ = NEW_FUN_EXT;
- WSTACK_PUSH(s, ENC_PATCH_FUN_SIZE);
- WSTACK_PUSH(s, (UWord) ep); /* Position for patching in size */
+ EWASTACK_WPUSH(ewa, ENC_PATCH_FUN_SIZE);
+ EWASTACK_WPUSH(ewa, (UWord) ep); /* Position for patching in size */
ep += 4;
*ep = funp->arity;
ep += 1;
@@ -2053,14 +2309,14 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
put_int32(funp->num_free, ep);
ep += 4;
ep = enc_atom(acmp, funp->fe->module, ep, dflags);
- ep = enc_term(acmp, make_small(funp->fe->old_index), ep, dflags, off_heap);
- ep = enc_term(acmp, make_small(funp->fe->old_uniq), ep, dflags, off_heap);
+ ep = enc_small(make_small(funp->fe->old_index), ep);
+ ep = enc_small(make_small(funp->fe->old_uniq), ep);
ep = enc_pid(acmp, funp->creator, ep, dflags);
fun_env:
for (ei = funp->num_free-1; ei > 0; ei--) {
- WSTACK_PUSH(s, ENC_TERM);
- WSTACK_PUSH(s, (UWord) funp->env[ei]);
+ EWASTACK_WPUSH(ewa, ENC_TERM);
+ EWASTACK_PUSH(ewa, (UWord) funp->env[ei]);
}
if (funp->num_free != 0) {
obj = funp->env[0];
@@ -2103,8 +2359,9 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags,
break;
}
}
- DESTROY_WSTACK(s);
- return ep;
+ SAVE_TO_EWA;
+ // DESTROY_EWASTACK(ewa);
+ return arg1;
}
static
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index e37d47919e..cef773374e 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -160,7 +160,7 @@ Uint erts_encode_ext_dist_header_size(ErtsAtomCacheMap *);
byte *erts_encode_ext_dist_header_setup(byte *, ErtsAtomCacheMap *);
byte *erts_encode_ext_dist_header_finalize(byte *, ErtsAtomCache *, Uint32);
Uint erts_encode_dist_ext_size(Eterm, Uint32, ErtsAtomCacheMap *);
-void erts_encode_dist_ext(Eterm, byte **, Uint32, ErtsAtomCacheMap *);
+void erts_encode_dist_ext(Process *, Eterm, byte **, Uint32, ErtsAtomCacheMap *);
Uint erts_encode_ext_size(Eterm);
Uint erts_encode_ext_size_2(Eterm, unsigned);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index d5e727bcba..af245790d9 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -771,6 +771,9 @@ Sint erts_re_set_loop_limit(Sint limit);
void erts_init_bif_binary(void);
Sint erts_binary_set_loop_limit(Sint limit);
+/* external.c */
+void erts_init_external(void);
+
/* erl_unicode.c */
void erts_init_unicode(void);
Sint erts_unicode_set_loop_limit(Sint limit);