diff options
author | happi <[email protected]> | 2013-05-03 16:25:37 +0200 |
---|---|---|
committer | Patrik Nyblom <[email protected]> | 2013-06-04 17:59:48 +0200 |
commit | 6d366f0ae53669a17de96db0094ef62217b60f1b (patch) | |
tree | ed795e9521c0becd69714a2aab21968b9e8e4a59 | |
parent | f7f24a77e918eea712b435a5ae9b01de270d6d7d (diff) | |
download | otp-6d366f0ae53669a17de96db0094ef62217b60f1b.tar.gz otp-6d366f0ae53669a17de96db0094ef62217b60f1b.tar.bz2 otp-6d366f0ae53669a17de96db0094ef62217b60f1b.zip |
Make term_to_binary yield (trap).
-rw-r--r-- | erts/emulator/beam/atom.names | 2 | ||||
-rw-r--r-- | erts/emulator/beam/dist.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_gc.c | 9 | ||||
-rw-r--r-- | erts/emulator/beam/erl_init.c | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 5 | ||||
-rw-r--r-- | erts/emulator/beam/external.c | 517 | ||||
-rw-r--r-- | erts/emulator/beam/external.h | 2 | ||||
-rwxr-xr-x | erts/emulator/beam/global.h | 3 |
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); |