aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/beam_bif_load.c53
-rw-r--r--erts/emulator/beam/beam_bp.c106
-rw-r--r--erts/emulator/beam/beam_debug.c44
-rw-r--r--erts/emulator/beam/beam_emu.c39
-rw-r--r--erts/emulator/beam/beam_load.c48
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_bif_info.c6
-rw-r--r--erts/emulator/beam/erl_bif_os.c75
-rw-r--r--erts/emulator/beam/erl_bif_port.c175
-rw-r--r--erts/emulator/beam/erl_process.c6
-rw-r--r--erts/emulator/beam/erl_unicode.c97
-rw-r--r--erts/emulator/beam/erl_vm.h11
-rw-r--r--erts/emulator/beam/global.h2
-rw-r--r--erts/emulator/beam/instrs.tab18
-rw-r--r--erts/emulator/beam/macros.tab2
-rw-r--r--erts/emulator/beam/module.h2
-rw-r--r--erts/emulator/beam/ops.tab268
-rw-r--r--erts/emulator/beam/sys.h59
18 files changed, 650 insertions, 362 deletions
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 00822d1415..87367b44ab 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -768,36 +768,45 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
ErtsCodeIndex code_ix;
Module* modp;
+ if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
if (!erts_try_seize_code_write_permission(BIF_P)) {
ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2],
BIF_P, BIF_ARG_1, BIF_ARG_2);
}
- /* ToDo: Use code_ix staging instead of thread blocking */
-
- erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- erts_thr_progress_block();
-
code_ix = erts_active_code_ix();
modp = erts_get_module(BIF_ARG_1, code_ix);
- if (!modp || !modp->on_load || !modp->on_load->code_hdr) {
- error:
- erts_thr_progress_unblock();
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ if (!modp || !modp->on_load || !modp->on_load->code_hdr
+ || !modp->on_load->code_hdr->on_load_function_ptr) {
+
erts_release_code_write_permission();
BIF_ERROR(BIF_P, BADARG);
}
- if (modp->on_load->code_hdr->on_load_function_ptr == NULL) {
- goto error;
- }
- if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) {
- goto error;
- }
if (BIF_ARG_2 == am_true) {
+ struct m mods[1];
+ int is_blocking = 0;
int i, num_exps;
+ erts_start_staging_code_ix(0);
+ code_ix = erts_staging_code_ix();
+ modp = erts_get_module(BIF_ARG_1, code_ix);
+
+ ASSERT(modp && modp->on_load && modp->on_load->code_hdr
+ && modp->on_load->code_hdr->on_load_function_ptr);
+
+ if (erts_is_default_trace_enabled()
+ || IF_HIPE(hipe_need_blocking(modp))) {
+
+ erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ erts_thr_progress_block();
+ is_blocking = 1;
+ }
+
/*
* Make the code with the on_load function current.
*/
@@ -831,11 +840,13 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
}
}
modp->curr.code_hdr->on_load_function_ptr = NULL;
- set_default_trace_pattern(BIF_ARG_1);
- #ifdef HIPE
- hipe_redirect_to_module(modp);
- #endif
- } else if (BIF_ARG_2 == am_false) {
+
+ mods[0].modp = modp;
+ mods[0].module = BIF_ARG_1;
+ mods[0].exception = THE_NON_VALUE;
+ return staging_epilogue(BIF_P, 1, am_true, is_blocking, mods, 1, 0);
+ }
+ else if (BIF_ARG_2 == am_false) {
int i, num_exps;
/*
@@ -855,8 +866,6 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
ep->beam[1] = 0;
}
}
- erts_thr_progress_unblock();
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_release_code_write_permission();
BIF_RET(am_true);
}
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index c81380c14d..fe1e15701b 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -419,9 +419,11 @@ erts_install_breakpoints(BpFunctions* f)
for (i = 0; i < n; i++) {
ErtsCodeInfo* ci = f->matching[i].ci;
- BeamInstr *pc = erts_codeinfo_to_code(ci);
GenericBp* g = ci->u.gen_bp;
- if (*pc != br && g) {
+ BeamInstr volatile *pc = erts_codeinfo_to_code(ci);
+ BeamInstr instr = *pc;
+
+ if (!BeamIsOpCode(instr, op_i_generic_breakpoint) && g) {
Module* modp = f->matching[i].mod;
/*
@@ -435,11 +437,16 @@ erts_install_breakpoints(BpFunctions* f)
/*
* The following write is not protected by any lock. We
* assume that the hardware guarantees that a write of an
- * aligned word-size (or half-word) writes is atomic
- * (i.e. that other processes executing this code will not
- * see a half pointer).
+ * aligned word-size writes is atomic (i.e. that other
+ * processes executing this code will not see a half
+ * pointer).
+ *
+ * The contents of *pc is marked 'volatile' to ensure that
+ * the compiler will do a single full-word write, and not
+ * try any fancy optimizations to write a half word.
*/
- *pc = br;
+ instr = BeamSetCodeAddr(instr, br);
+ *pc = instr;
modp->curr.num_breakpoints++;
}
}
@@ -634,6 +641,49 @@ erts_clear_export_break(Module* modp, ErtsCodeInfo *ci)
ASSERT(ci->u.gen_bp == NULL);
}
+/*
+ * If c_p->cp is a trace return instruction, we set cp
+ * to be the place where we again start to execute code.
+ *
+ * cp is used by match spec {caller} to get the calling
+ * function, and if we don't do this fixup it will be
+ * 'undefined'. This has the odd side effect of {caller}
+ * not really being which function is the caller, but
+ * rather which function we are about to return to.
+ */
+static void fixup_cp_before_trace(Process *c_p, int *return_to_trace)
+{
+ Eterm *cpp, *E = c_p->stop;
+ BeamInstr w = *c_p->cp;
+ if (BeamIsOpCode(w, op_return_trace)) {
+ cpp = &E[2];
+ } else if (BeamIsOpCode(w, op_i_return_to_trace)) {
+ *return_to_trace = 1;
+ cpp = &E[0];
+ } else if (BeamIsOpCode(w, op_i_return_time_trace)) {
+ cpp = &E[0];
+ } else {
+ cpp = NULL;
+ }
+ if (cpp) {
+ for (;;) {
+ BeamInstr w = *cp_val(*cpp);
+ if (BeamIsOpCode(w, op_return_trace)) {
+ cpp += 3;
+ } else if (BeamIsOpCode(w, op_i_return_to_trace)) {
+ *return_to_trace = 1;
+ cpp += 1;
+ } else if (BeamIsOpCode(w, op_i_return_time_trace)) {
+ cpp += 2;
+ } else {
+ break;
+ }
+ }
+ c_p->cp = (BeamInstr *) cp_val(*cpp);
+ ASSERT(is_CP(*cpp));
+ }
+}
+
BeamInstr
erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg)
{
@@ -744,6 +794,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
GenericBp* g;
GenericBpData* bp = NULL;
Uint bp_flags = 0;
+ int return_to_trace = 0;
ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
@@ -759,6 +810,8 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
*/
if (!applying) {
p->cp = I;
+ } else {
+ fixup_cp_before_trace(p, &return_to_trace);
}
if (bp_flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE) &&
IS_TRACED_FL(p, F_TRACE_CALLS)) {
@@ -937,49 +990,18 @@ static ErtsTracer
do_call_trace(Process* c_p, ErtsCodeInfo* info, Eterm* reg,
int local, Binary* ms, ErtsTracer tracer)
{
- Eterm* cpp;
int return_to_trace = 0;
- BeamInstr w;
BeamInstr *cp_save = c_p->cp;
Uint32 flags;
Uint need = 0;
Eterm* E = c_p->stop;
- w = *c_p->cp;
- if (BeamIsOpCode(w, op_return_trace)) {
- cpp = &E[2];
- } else if (BeamIsOpCode(w, op_i_return_to_trace)) {
- return_to_trace = 1;
- cpp = &E[0];
- } else if (BeamIsOpCode(w, op_i_return_time_trace)) {
- cpp = &E[0];
- } else {
- cpp = NULL;
- }
- if (cpp) {
- for (;;) {
- BeamInstr w = *cp_val(*cpp);
- if (BeamIsOpCode(w, op_return_trace)) {
- cpp += 3;
- } else if (BeamIsOpCode(w, op_i_return_to_trace)) {
- return_to_trace = 1;
- cpp += 1;
- } else if (BeamIsOpCode(w, op_i_return_time_trace)) {
- cpp += 2;
- } else {
- break;
- }
- }
- cp_save = c_p->cp;
- c_p->cp = (BeamInstr *) cp_val(*cpp);
- ASSERT(is_CP(*cpp));
- }
- ERTS_UNREQ_PROC_MAIN_LOCK(c_p);
+ fixup_cp_before_trace(c_p, &return_to_trace);
+
flags = erts_call_trace(c_p, info, ms, reg, local, &tracer);
- ERTS_REQ_PROC_MAIN_LOCK(c_p);
- if (cpp) {
- c_p->cp = cp_save;
- }
+
+ /* restore cp after potential fixup */
+ c_p->cp = cp_save;
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) {
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index 0f332da63f..70078c8c59 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -201,7 +201,7 @@ void debug_dump_code(BeamInstr *I, int num)
for (i = 0; i < NUM_SPECIFIC_OPS; i++) {
if (BeamIsOpCode(instr, i) && opc[i].name[0] != '\0') {
code_ptr += print_op(ERTS_PRINT_DSBUF, (void *) dsbufp,
- i, opc[i].sz-1, code_ptr+1) + 1;
+ i, opc[i].sz-1, code_ptr) + 1;
break;
}
}
@@ -321,7 +321,7 @@ erts_debug_disassemble_1(BIF_ALIST_1)
for (i = 0; i < NUM_SPECIFIC_OPS; i++) {
if (BeamIsOpCode(instr, i) && opc[i].name[0] != '\0') {
code_ptr += print_op(ERTS_PRINT_DSBUF, (void *) dsbufp,
- i, opc[i].sz-1, code_ptr+1) + 1;
+ i, opc[i].sz-1, code_ptr) + 1;
break;
}
}
@@ -405,8 +405,11 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
* Avoid copying because instructions containing bignum operands
* are bigger than actually declared.
*/
- ap = (BeamInstr *) addr;
+ addr++;
+ ap = addr;
} else {
+ BeamInstr instr_word = addr++[0];
+
/*
* Copy all arguments to a local buffer for the unpacking.
*/
@@ -431,23 +434,22 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
case 'q':
*ap++ = *--sp;
break;
- case 'i': /* Initialize packing accumulator. */
- *ap++ = packed;
- break;
- case 's':
- *ap++ = packed & 0x3ff;
- packed >>= 10;
+#ifdef ARCH_64
+ case '1': /* Tightest shift */
+ *ap++ = (packed & BEAM_TIGHTEST_MASK) << 3;
+ packed >>= BEAM_TIGHTEST_SHIFT;
break;
- case '0': /* Tight shift */
+#endif
+ case '2': /* Tight shift */
*ap++ = packed & BEAM_TIGHT_MASK;
packed >>= BEAM_TIGHT_SHIFT;
break;
- case '6': /* Shift 16 steps */
+ case '3': /* Loose shift */
*ap++ = packed & BEAM_LOOSE_MASK;
packed >>= BEAM_LOOSE_SHIFT;
break;
#ifdef ARCH_64
- case 'w': /* Shift 32 steps */
+ case '4': /* Shift 32 steps */
*ap++ = packed & BEAM_WIDE_MASK;
packed >>= BEAM_WIDE_SHIFT;
break;
@@ -458,8 +460,18 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
case 'P':
packed = *--sp;
break;
+#if defined(ARCH_64) && defined(CODE_MODEL_SMALL)
+ case '#': /* -1 */
+ case '$': /* -2 */
+ case '%': /* -3 */
+ case '&': /* -4 */
+ case '\'': /* -5 */
+ case '(': /* -6 */
+ packed = (packed << BEAM_WIDE_SHIFT) | BeamExtraData(instr_word);
+ break;
+#endif
default:
- ASSERT(0);
+ erts_exit(ERTS_ERROR_EXIT, "beam_debug: invalid packing op: %c\n", *prog);
}
}
ap = args;
@@ -744,7 +756,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0]));
break;
case LOADER_Y_REG:
- erts_print(to, to_arg, " x(%d)", loader_y_reg_index(ap[0]));
+ erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0]) - CP_SIZE);
break;
default:
erts_print(to, to_arg, " %T", (Eterm) ap[0]);
@@ -765,7 +777,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0]));
break;
case LOADER_Y_REG:
- erts_print(to, to_arg, " x(%d)", loader_y_reg_index(ap[0]));
+ erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0]) - CP_SIZE);
break;
default:
erts_print(to, to_arg, " %T", (Eterm) ap[0]);
@@ -788,7 +800,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0]));
break;
case LOADER_Y_REG:
- erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0]));
+ erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0]) - CP_SIZE);
break;
default:
erts_print(to, to_arg, " %T", (Eterm) ap[0]);
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 9a77c63390..aa94fbf536 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -50,14 +50,16 @@
#if defined(NO_JUMP_TABLE)
# define OpCase(OpCode) case op_##OpCode
# define CountCase(OpCode) case op_count_##OpCode
-# define IsOpCode(InstrWord, OpCode) ((InstrWord) == (BeamInstr)op_##OpCode)
-# define Goto(Rel) {Go = (Rel); goto emulator_loop;}
+# define IsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == (BeamInstr)op_##OpCode)
+# define Goto(Rel) {Go = BeamCodeAddr(Rel); goto emulator_loop;}
+# define GotoPF(Rel) Goto(Rel)
#else
# define OpCase(OpCode) lb_##OpCode
# define CountCase(OpCode) lb_count_##OpCode
-# define IsOpCode(InstrWord, OpCode) ((InstrWord) == (BeamInstr)&&lb_##OpCode)
-# define Goto(Rel) goto *((void *)Rel)
-# define LabelAddr(Label) &&Label
+# define IsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == (BeamInstr)&&lb_##OpCode)
+# define Goto(Rel) goto *((void *)BeamCodeAddr(Rel))
+# define GotoPF(Rel) goto *((void *)Rel)
+# define LabelAddr(Label) &&Label
#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
@@ -131,11 +133,11 @@ do { \
/* We don't check the range if an ordinary switch is used */
#ifdef NO_JUMP_TABLE
-#define VALID_INSTR(IP) ((UWord)(IP) < (NUMBER_OF_OPCODES*2+10))
+# define VALID_INSTR(IP) (BeamCodeAddr(IP) < (NUMBER_OF_OPCODES*2+10))
#else
-#define VALID_INSTR(IP) \
- ((SWord)LabelAddr(emulator_loop) <= (SWord)(IP) && \
- (SWord)(IP) < (SWord)LabelAddr(end_emulator_loop))
+# define VALID_INSTR(IP) \
+ ((BeamInstr)LabelAddr(emulator_loop) <= BeamCodeAddr(IP) && \
+ BeamCodeAddr(IP) < (BeamInstr)LabelAddr(end_emulator_loop))
#endif /* NO_JUMP_TABLE */
#define SET_CP(p, ip) \
@@ -234,15 +236,18 @@ void** beam_ops;
#define fb(N) ((Sint)(Sint32)(N))
#define jb(N) ((Sint)(Sint32)(N))
#define tb(N) (N)
-#define xb(N) (*(Eterm *) (((unsigned char *)reg) + (N)))
-#define yb(N) (*(Eterm *) (((unsigned char *)E) + (N)))
+#define xb(N) (*ADD_BYTE_OFFSET(reg, N))
+#define yb(N) (*ADD_BYTE_OFFSET(E, N))
#define Sb(N) (*REG_TARGET_PTR(N))
#define lb(N) (*(double *) (((unsigned char *)&(freg[0].fd)) + (N)))
#define Qb(N) (N)
#define Ib(N) (N)
+
#define x(N) reg[N]
#define y(N) E[N]
#define r(N) x(N)
+#define Q(N) (N*sizeof(Eterm *))
+#define l(N) (freg[N].fd)
/*
* Check that we haven't used the reductions and jump to function pointed to by
@@ -1006,6 +1011,18 @@ init_emulator_finish(void)
int i;
Export* ep;
+#if defined(ARCH_64) && defined(CODE_MODEL_SMALL)
+ for (i = 0; i < NUMBER_OF_OPCODES; i++) {
+ BeamInstr instr = BeamOpCodeAddr(i);
+ if (instr >= (1ull << 32)) {
+ erts_exit(ERTS_ERROR_EXIT,
+ "This run-time was supposed be compiled with all code below 2Gb,\n"
+ "but the instruction '%s' is located at %016lx.\n",
+ opc[i].name, instr);
+ }
+ }
+#endif
+
beam_apply[0] = BeamOpCodeAddr(op_i_apply);
beam_apply[1] = BeamOpCodeAddr(op_normal_exit);
beam_exit[0] = BeamOpCodeAddr(op_error_action_code);
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 9835b1c096..bbccd0b79d 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -806,11 +806,6 @@ erts_finish_loading(Binary* magic, Process* c_p,
struct erl_module_instance* inst_p;
Uint size;
- /*
- * No other process may run since we will update the export
- * table which is not protected by any locks.
- */
-
ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_write_permission() ||
erts_thr_progress_is_blocking());
/*
@@ -2578,23 +2573,31 @@ load_code(LoaderState* stp)
sp++;
}
break;
- case 'i': /* Initialize packing accumulator. */
- packed = code[--ci];
+#ifdef ARCH_64
+ case '1': /* Tightest shift (always 10 bits) */
+ ci--;
+ ASSERT((code[ci] & ~0x1FF8ull) == 0); /* Fits in 10 bits */
+ packed = (packed << BEAM_TIGHTEST_SHIFT);
+ packed |= code[ci] >> 3;
+ if (packed_label) {
+ packed_label->packed++;
+ }
break;
- case '0': /* Tight shift */
+#endif
+ case '2': /* Tight shift (10 or 16 bits) */
packed = (packed << BEAM_TIGHT_SHIFT) | code[--ci];
if (packed_label) {
packed_label->packed++;
}
break;
- case '6': /* Shift 16 steps */
+ case '3': /* Loose shift (16 bits) */
packed = (packed << BEAM_LOOSE_SHIFT) | code[--ci];
if (packed_label) {
packed_label->packed++;
}
break;
#ifdef ARCH_64
- case 'w': /* Shift 32 steps */
+ case '4': /* Wide shift (32 bits) */
{
Uint w = code[--ci];
@@ -2646,8 +2649,31 @@ load_code(LoaderState* stp)
sp++;
packed = 0;
break;
+#if defined(ARCH_64) && defined(CODE_MODEL_SMALL)
+ case '#': /* -1 */
+ case '$': /* -2 */
+ case '%': /* -3 */
+ case '&': /* -4 */
+ case '\'': /* -5 */
+ case '(': /* -6 */
+ /* Pack accumulator contents into instruction word. */
+ {
+ Sint pos = ci - (*prog - '#' + 1);
+ /* Are the high 32 bits of the instruction word zero? */
+ ASSERT((code[pos] & ~((1ull << BEAM_WIDE_SHIFT)-1)) == 0);
+ code[pos] |= packed << BEAM_WIDE_SHIFT;
+ if (packed_label) {
+ ASSERT(packed_label->packed == 1);
+ packed_label->pos = pos;
+ packed_label->packed = 2;
+ packed_label = 0;
+ }
+ packed >>= BEAM_WIDE_SHIFT;
+ }
+ break;
+#endif
default:
- ASSERT(0);
+ erts_exit(ERTS_ERROR_EXIT, "beam_load: invalid packing op: %c\n", *prog);
}
}
ASSERT(sp == stack); /* Incorrect program? */
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index bf5487d31e..878b971b07 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -259,6 +259,7 @@ type MREF_TAB_BKTS STANDARD SYSTEM magic_ref_table_buckets
type MREF_TAB LONG_LIVED SYSTEM magic_ref_table
type MINDIRECTION FIXED_SIZE SYSTEM magic_indirection
type BINARY_FIND SHORT_LIVED PROCESSES binary_find
+type OPEN_PORT_ENV TEMPORARY SYSTEM open_port_env
type THR_Q_EL STANDARD SYSTEM thr_q_element
type THR_Q_EL_SL FIXED_SIZE SYSTEM sl_thr_q_element
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 17c936f041..27bbf70c0b 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -3674,6 +3674,12 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
Eterm *hp = HAlloc(BIF_P, hsz);
BIF_RET(uword_to_big(size, hp));
}
+ } else if (ERTS_IS_ATOM_STR("scheduler_dump", BIF_ARG_1)) {
+#if defined(ERTS_HAVE_TRY_CATCH) && defined(ERTS_SYS_SUSPEND_SIGNAL)
+ BIF_RET(am_true);
+#else
+ BIF_RET(am_false);
+#endif
}
}
else if (is_tuple(BIF_ARG_1)) {
diff --git a/erts/emulator/beam/erl_bif_os.c b/erts/emulator/beam/erl_bif_os.c
index 5cd172c26f..910325a2f4 100644
--- a/erts/emulator/beam/erl_bif_os.c
+++ b/erts/emulator/beam/erl_bif_os.c
@@ -37,6 +37,8 @@
#include "dist.h"
#include "erl_version.h"
+static int check_env_name(char *name);
+
/*
* Return the pid for the Erlang process in the host OS.
*/
@@ -101,8 +103,10 @@ BIF_RETTYPE os_getenv_1(BIF_ALIST_1)
key_str = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE,
ERTS_ALC_T_TMP,1,0,&len);
- if (!key_str) {
- BIF_ERROR(p, BADARG);
+ if (!check_env_name(key_str)) {
+ if (key_str && key_str != &buf[0])
+ erts_free(ERTS_ALC_T_TMP, key_str);
+ BIF_ERROR(p, BADARG);
}
if (key_str != &buf[0])
@@ -143,25 +147,20 @@ BIF_RETTYPE os_putenv_2(BIF_ALIST_2)
{
char def_buf_key[STATIC_BUF_SIZE];
char def_buf_value[STATIC_BUF_SIZE];
- char *key_buf, *value_buf;
+ char *key_buf = NULL, *value_buf = NULL;
key_buf = erts_convert_filename_to_native(BIF_ARG_1,def_buf_key,
STATIC_BUF_SIZE,
ERTS_ALC_T_TMP,0,0,NULL);
- if (!key_buf) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ if (!check_env_name(key_buf))
+ goto badarg;
+
value_buf = erts_convert_filename_to_native(BIF_ARG_2,def_buf_value,
STATIC_BUF_SIZE,
ERTS_ALC_T_TMP,1,0,
NULL);
- if (!value_buf) {
- if (key_buf != def_buf_key) {
- erts_free(ERTS_ALC_T_TMP, key_buf);
- }
- BIF_ERROR(BIF_P, BADARG);
- }
-
+ if (!value_buf)
+ goto badarg;
if (erts_sys_putenv(key_buf, value_buf)) {
if (key_buf != def_buf_key) {
@@ -179,6 +178,13 @@ BIF_RETTYPE os_putenv_2(BIF_ALIST_2)
erts_free(ERTS_ALC_T_TMP, value_buf);
}
BIF_RET(am_true);
+
+badarg:
+ if (key_buf && key_buf != def_buf_key)
+ erts_free(ERTS_ALC_T_TMP, key_buf);
+ if (value_buf && value_buf != def_buf_value)
+ erts_free(ERTS_ALC_T_TMP, value_buf);
+ BIF_ERROR(BIF_P, BADARG);
}
BIF_RETTYPE os_unsetenv_1(BIF_ALIST_1)
@@ -188,20 +194,21 @@ BIF_RETTYPE os_unsetenv_1(BIF_ALIST_1)
key_buf = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE,
ERTS_ALC_T_TMP,0,0,NULL);
- if (!key_buf) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ if (!check_env_name(key_buf))
+ goto badarg;
+
+ if (erts_sys_unsetenv(key_buf))
+ goto badarg;
- if (erts_sys_unsetenv(key_buf)) {
- if (key_buf != buf) {
- erts_free(ERTS_ALC_T_TMP, key_buf);
- }
- BIF_ERROR(BIF_P, BADARG);
- }
if (key_buf != buf) {
erts_free(ERTS_ALC_T_TMP, key_buf);
}
BIF_RET(am_true);
+
+badarg:
+ if (key_buf && key_buf != buf)
+ erts_free(ERTS_ALC_T_TMP, key_buf);
+ BIF_ERROR(BIF_P, BADARG);
}
BIF_RETTYPE os_set_signal_2(BIF_ALIST_2) {
@@ -217,3 +224,27 @@ BIF_RETTYPE os_set_signal_2(BIF_ALIST_2) {
error:
BIF_ERROR(BIF_P, BADARG);
}
+
+static int
+check_env_name(char *raw_name)
+{
+ byte *c = (byte *) raw_name;
+ int encoding;
+
+ if (!c)
+ return 0;
+
+ encoding = erts_get_native_filename_encoding();
+
+ if (erts_raw_env_char_is_7bit_ascii_char('\0', c, encoding))
+ return 0; /* Do not allow empty name... */
+
+ /* Verify no '=' characters in variable name... */
+ do {
+ if (erts_raw_env_char_is_7bit_ascii_char('=', c, encoding))
+ return 0;
+ c = erts_raw_env_next_char(c, encoding);
+ } while (!erts_raw_env_char_is_7bit_ascii_char('\0', c, encoding));
+
+ return 1; /* Seems ok... */
+}
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 3b8e70d44a..c4a4dd5863 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -45,7 +45,7 @@
#include "dtrace-wrapper.h"
static Port *open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump);
-static byte* convert_environment(Process* p, Eterm env);
+static char* convert_environment(Eterm env);
static char **convert_args(Eterm);
static void free_args(char **);
@@ -718,11 +718,11 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
goto badarg;
}
} else if (option == am_env) {
- byte* bytes;
- if ((bytes = convert_environment(p, *tp)) == NULL) {
+ if (opts.envir) /* ignore previous env option... */
+ erts_free(ERTS_ALC_T_OPEN_PORT_ENV, opts.envir);
+ opts.envir = convert_environment(*tp);
+ if (!opts.envir)
goto badarg;
- }
- opts.envir = (char *) bytes;
} else if (option == am_args) {
char **av;
char **oav = opts.argv;
@@ -956,6 +956,8 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
erts_atomic32_read_bor_relb(&port->state, sflgs);
do_return:
+ if (opts.envir)
+ erts_free(ERTS_ALC_T_OPEN_PORT_ENV, opts.envir);
if (name_buf)
erts_free(ERTS_ALC_T_TMP, (void *) name_buf);
if (opts.argv) {
@@ -1021,74 +1023,129 @@ static void free_args(char **av)
}
erts_free(ERTS_ALC_T_TMP, av);
}
-
-static byte* convert_environment(Process* p, Eterm env)
+#ifdef DEBUG
+#define ERTS_CONV_ENV_BUF_EXTRA 2
+#else
+#define ERTS_CONV_ENV_BUF_EXTRA 1024
+#endif
+
+static char* convert_environment(Eterm env)
{
- Eterm all;
- Eterm* temp_heap;
- Eterm* hp;
- Uint heap_size;
- Sint n;
- Sint size;
+ /*
+ * Returns environment buffer in memory allocated
+ * as ERTS_ALC_T_OPEN_PORT_ENV. Caller *needs*
+ * to deallocate...
+ */
+
+ Sint size, alloc_size;
byte* bytes;
int encoding = erts_get_native_filename_encoding();
- if ((n = erts_list_length(env)) < 0) {
- return NULL;
- }
- heap_size = 2*(5*n+1);
- temp_heap = hp = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, heap_size*sizeof(Eterm));
- bytes = NULL; /* Indicating error */
+ alloc_size = ERTS_CONV_ENV_BUF_EXTRA;
+ bytes = erts_alloc(ERTS_ALC_T_OPEN_PORT_ENV,
+ alloc_size);
+ size = 0;
- /*
- * All errors below are handled by jumping to 'done', to ensure that the memory
- * gets deallocated. Do NOT return directly from this function.
- */
+ /* ERTS_CONV_ENV_BUF_EXTRA >= for end delimiter... */
+ ERTS_CT_ASSERT(ERTS_CONV_ENV_BUF_EXTRA >= 2);
- all = CONS(hp, make_small(0), NIL);
- hp += 2;
+ while (is_list(env)) {
+ Sint var_sz, val_sz, need;
+ byte *str, *limit;
+ Eterm tmp, *tp, *consp;
- while(is_list(env)) {
- Eterm tmp;
- Eterm* tp;
+ consp = list_val(env);
+ tmp = CAR(consp);
+ if (is_not_tuple_arity(tmp, 2))
+ goto error;
- tmp = CAR(list_val(env));
- if (is_not_tuple_arity(tmp, 2)) {
- goto done;
- }
tp = tuple_val(tmp);
- tmp = CONS(hp, make_small(0), NIL);
- hp += 2;
- if (tp[2] != am_false) {
- tmp = CONS(hp, tp[2], tmp);
- hp += 2;
- }
- tmp = CONS(hp, make_small('='), tmp);
- hp += 2;
- tmp = CONS(hp, tp[1], tmp);
- hp += 2;
- all = CONS(hp, tmp, all);
- hp += 2;
- env = CDR(list_val(env));
- }
- if (is_not_nil(env)) {
- goto done;
- }
- if ((size = erts_native_filename_need(all, encoding, 1)) < 0) {
- goto done;
+ /* Check encoding of env variable... */
+ if (is_not_list(tp[1]))
+ goto error;
+ var_sz = erts_native_filename_need(tp[1], encoding);
+ if (var_sz <= 0)
+ goto error;
+ /* Check encoding of value... */
+ if (tp[2] == am_false || is_nil(tp[2]))
+ val_sz = 0;
+ else if (is_not_list(tp[2]))
+ goto error;
+ else {
+ val_sz = erts_native_filename_need(tp[2], encoding);
+ if (val_sz < 0)
+ goto error;
+ }
+
+ /* Ensure enough memory... */
+ need = size;
+ need += var_sz + val_sz;
+ /* '=' and '\0' */
+ need += 2 * erts_raw_env_7bit_ascii_char_need(encoding);
+ if (need > alloc_size) {
+ alloc_size = (need - alloc_size) + alloc_size;
+ alloc_size += ERTS_CONV_ENV_BUF_EXTRA;
+ bytes = erts_realloc(ERTS_ALC_T_OPEN_PORT_ENV,
+ bytes, alloc_size);
+ }
+
+ /* Write environment variable name... */
+ str = bytes + size;
+ erts_native_filename_put(tp[1], encoding, str);
+ /* empty variable name is not allowed... */
+ if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding))
+ goto error;
+
+ /*
+ * Drop null characters at the end and verify that we do
+ * not have any '=' characters in the name...
+ */
+ limit = str + var_sz;
+ while (str < limit) {
+ if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding))
+ break;
+ if (erts_raw_env_char_is_7bit_ascii_char('=', str, encoding))
+ goto error;
+ str = erts_raw_env_next_char(str, encoding);
+ }
+
+ /* Write the equals sign... */
+ str = erts_raw_env_7bit_ascii_char_put('=', str, encoding);
+
+ /* Write the value... */
+ if (val_sz > 0) {
+ limit = str + val_sz;
+ erts_native_filename_put(tp[2], encoding, str);
+ while (str < limit) {
+ if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding))
+ break;
+ str = erts_raw_env_next_char(str, encoding);
+ }
+ }
+
+ /* Delimit... */
+ str = erts_raw_env_7bit_ascii_char_put('\0', str, encoding);
+
+ size = str - bytes;
+ ASSERT(size <= alloc_size);
+
+ env = CDR(consp);
}
- /*
- * Put the result in a binary (no risk for a memory leak that way).
- */
- (void) erts_new_heap_binary(p, NULL, size, &bytes);
- erts_native_filename_put(all,encoding,bytes);
+ /* End delimit... */
+ (void) erts_raw_env_7bit_ascii_char_put('\0', &bytes[size], encoding);
+
+ if (is_nil(env))
+ return (char *) bytes;
+
+error:
+
+ if (bytes)
+ erts_free(ERTS_ALC_T_OPEN_PORT_ENV, bytes);
- done:
- erts_free(ERTS_ALC_T_TMP, temp_heap);
- return bytes;
+ return (char *) NULL; /* error... */
}
/* ------------ decode_packet() and friends: */
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 61fdf86a56..3d12b3bc21 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -12476,9 +12476,9 @@ send_exit_signal(Process *c_p, /* current process if and only
if ((state & ERTS_PSFLG_TRAP_EXIT)
&& (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) {
- /* have to release the status lock in order to send the exit message */
- erts_proc_unlock(rp, *rp_locks & ERTS_PROC_LOCKS_XSIG_SEND);
- *rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
+ /* have to release the status and trace lock in order to send the exit message */
+ erts_proc_unlock(rp, *rp_locks & (ERTS_PROC_LOCKS_XSIG_SEND|ERTS_PROC_LOCK_TRACE));
+ *rp_locks &= ~(ERTS_PROC_LOCKS_XSIG_SEND|ERTS_PROC_LOCK_TRACE);
if (have_seqtrace(token) && token_update)
seq_trace_update_send(token_update);
if (is_value(exit_tuple))
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index efd2ca3db2..b7a5c45fea 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -1988,7 +1988,7 @@ char *erts_convert_filename_to_encoding(Eterm name, char *statbuf, size_t statbu
is_list(name) ||
(allow_empty && is_nil(name))) {
Sint need;
- if ((need = erts_native_filename_need(name, encoding, 0)) < 0) {
+ if ((need = erts_native_filename_need(name, encoding)) < 0) {
return NULL;
}
if (encoding == ERL_FILENAME_WIN_WCHAR) {
@@ -2152,7 +2152,7 @@ Eterm erts_convert_native_to_filename(Process *p, byte *bytes)
}
-Sint erts_native_filename_need(Eterm ioterm, int encoding, int allow_null)
+Sint erts_native_filename_need(Eterm ioterm, int encoding)
{
Eterm *objp;
Eterm obj;
@@ -2195,21 +2195,19 @@ Sint erts_native_filename_need(Eterm ioterm, int encoding, int allow_null)
default:
need = -1;
}
- if (!allow_null) {
- /*
- * Do not allow null in
- * the middle of filenames
- */
- if (need > 0) {
- byte *name = ap->name;
- int len = ap->len;
- for (i = 0; i < len; i++) {
- if (name[i] == 0)
- seen_null = 1;
- else if (seen_null) {
- need = -1;
- break;
- }
+ /*
+ * Do not allow null in
+ * the middle of filenames
+ */
+ if (need > 0) {
+ byte *name = ap->name;
+ int len = ap->len;
+ for (i = 0; i < len; i++) {
+ if (name[i] == 0)
+ seen_null = 1;
+ else if (seen_null) {
+ need = -1;
+ break;
}
}
}
@@ -2243,17 +2241,15 @@ L_Again: /* Restart with sublist, old listend was pushed on stack */
if (is_small(obj)) { /* Always small */
for(;;) {
Uint x = unsigned_val(obj);
- if (!allow_null) {
- /*
- * Do not allow null in
- * the middle of filenames
- */
- if (x == 0)
- seen_null = 1;
- else if (seen_null) {
- DESTROY_ESTACK(stack);
- return ((Sint) -1);
- }
+ /*
+ * Do not allow null in
+ * the middle of filenames
+ */
+ if (x == 0)
+ seen_null = 1;
+ else if (seen_null) {
+ DESTROY_ESTACK(stack);
+ return ((Sint) -1);
}
switch (encoding) {
case ERL_FILENAME_LATIN1:
@@ -2528,6 +2524,38 @@ void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars)
}
/*
+ * *** Requirements on Raw Filename Format ***
+ *
+ * These requirements are due to the 'filename' module
+ * in stdlib. This since it is documented that it
+ * should be able to operate on raw filenames as well
+ * as ordinary filenames.
+ *
+ * A raw filename *must* be a byte sequence where:
+ * 1. Codepoints 0-127 (7-bit ascii) *must* be encoded
+ * as a byte with the corresponding value. That is,
+ * the most significant bit in the byte encoding the
+ * codepoint is never set.
+ * 2. Codepoints greater than 127 *must* be encoded
+ * with the most significant bit set in *every* byte
+ * encoding it.
+ *
+ * Latin1 and UTF-8 meet these requirements while
+ * UTF-16 and UTF-32 don't.
+ *
+ * On Windows filenames are natively stored as malformed
+ * UTF-16LE (lonely surrogates may appear). A more correct
+ * description than UTF-16 would be an array of 16-bit
+ * words... In order to meet the requirements of the
+ * raw file format we convert the malformed UTF-16LE to
+ * malformed UTF-8 which meet the requirements.
+ *
+ * Note that these requirements are today only OTP
+ * internal (erts-stdlib internal) requirements that
+ * could be changed.
+ */
+
+/*
* This internal bif converts a filename to whatever format is suitable for the file driver
* It also adds zero termination so that prim_file needn't bother with the character encoding
* of the file driver
@@ -2538,6 +2566,12 @@ BIF_RETTYPE prim_file_internal_name2native_1(BIF_ALIST_1)
Sint need;
Eterm bin_term;
byte* bin_p;
+
+ /*
+ * See comment on "Requirements on Raw Filename Format"
+ * above.
+ */
+
/* Prim file explicitly does not allow atoms, although we could
very well cope with it. Instead of letting 'file' handle them,
it would probably be more efficient to handle them here. Subject to
@@ -2609,7 +2643,7 @@ BIF_RETTYPE prim_file_internal_name2native_1(BIF_ALIST_1)
} /* binary */
- if ((need = erts_native_filename_need(BIF_ARG_1, encoding, 0)) < 0) {
+ if ((need = erts_native_filename_need(BIF_ARG_1, encoding)) < 0) {
BIF_ERROR(BIF_P,BADARG);
}
if (encoding == ERL_FILENAME_WIN_WCHAR) {
@@ -2644,6 +2678,11 @@ BIF_RETTYPE prim_file_internal_native2name_1(BIF_ALIST_1)
Eterm ret;
int mac = 0;
+ /*
+ * See comment on "Requirements on Raw Filename Format"
+ * above.
+ */
+
if (is_not_binary(BIF_ARG_1)) {
BIF_ERROR(BIF_P,BADARG);
}
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index 661538eadd..76980b5871 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -209,6 +209,15 @@ extern void** beam_ops;
# define BeamOpCodeAddr(OpCode) ((BeamInstr)beam_ops[(OpCode)])
#endif
-#define BeamIsOpCode(InstrWord, OpCode) ((InstrWord) == BeamOpCodeAddr(OpCode))
+#if defined(ARCH_64) && defined(CODE_MODEL_SMALL)
+# define BeamCodeAddr(InstrWord) ((BeamInstr)(Uint32)(InstrWord))
+# define BeamSetCodeAddr(InstrWord, Addr) (((InstrWord) & ~((1ull << 32)-1)) | (Addr))
+# define BeamExtraData(InstrWord) ((InstrWord) >> 32)
+#else
+# define BeamCodeAddr(InstrWord) ((BeamInstr)(InstrWord))
+# define BeamSetCodeAddr(InstrWord, Addr) (Addr)
+#endif
+
+#define BeamIsOpCode(InstrWord, OpCode) (BeamCodeAddr(InstrWord) == BeamOpCodeAddr(OpCode))
#endif /* __ERL_VM_H__ */
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 604172857a..09aeba00fa 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1238,7 +1238,7 @@ void erts_init_unicode(void);
Sint erts_unicode_set_loop_limit(Sint limit);
void erts_native_filename_put(Eterm ioterm, int encoding, byte *p) ;
-Sint erts_native_filename_need(Eterm ioterm, int encoding, int allow_null);
+Sint erts_native_filename_need(Eterm ioterm, int encoding);
void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars);
int erts_analyze_utf8(byte *source, Uint size,
byte **err_pos, Uint *num_chars, int *left);
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 07cc4bd527..20d356a81d 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -857,8 +857,7 @@ catch(Y, Fail) {
}
catch_end(Y) {
- c_p->catches--;
- make_blank($Y);
+ $try_end($Y);
if (is_non_value(r(0))) {
c_p->fvalue = NIL;
if (x(1) == am_throw) {
@@ -888,12 +887,15 @@ catch_end(Y) {
try_end(Y) {
c_p->catches--;
make_blank($Y);
- if (is_non_value(r(0))) {
- c_p->fvalue = NIL;
- r(0) = x(1);
- x(1) = x(2);
- x(2) = x(3);
- }
+}
+
+try_case(Y) {
+ $try_end($Y);
+ ASSERT(is_non_value(r(0)));
+ c_p->fvalue = NIL;
+ r(0) = x(1);
+ x(1) = x(2);
+ x(2) = x(3);
}
try_case_end(Src) {
diff --git a/erts/emulator/beam/macros.tab b/erts/emulator/beam/macros.tab
index 0d175a7ec6..e0b5f56b53 100644
--- a/erts/emulator/beam/macros.tab
+++ b/erts/emulator/beam/macros.tab
@@ -38,7 +38,7 @@ REFRESH_GEN_DEST() {
// zero, except in a few bit syntax instructions.)
SET_I_REL(Offset) {
- ASSERT(VALID_INSTR(*(I + ($Offset))));
+ ASSERT(VALID_INSTR(*(I + ($Offset) + $IP_ADJUSTMENT)));
I += $Offset + $IP_ADJUSTMENT;
}
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index 9a81e6035b..a3f1ce1705 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -45,7 +45,7 @@ typedef struct erl_module {
int seen; /* Used by finish_loading() */
struct erl_module_instance curr;
- struct erl_module_instance old; /* protected by "old_code" rwlock */
+ struct erl_module_instance old; /* active protected by "old_code" rwlock */
struct erl_module_instance* on_load;
} Module;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 75ff40606b..7a2c39b3a8 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -99,21 +99,21 @@ line Loc | func_info M F A => func_info M F A | line Loc
line I
-allocate t t
-allocate_heap t I t
+allocate t t?
+allocate_heap t I t?
%cold
deallocate Q
%hot
init y
-allocate_zero t t
-allocate_heap_zero t I t
+allocate_zero t t?
+allocate_heap_zero t I t?
trim N Remaining => i_trim N
i_trim t
-test_heap I t
+test_heap I t?
allocate_heap S u==0 R => allocate S R
allocate_heap_zero S u==0 R => allocate_zero S R
@@ -158,19 +158,19 @@ is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \
select_tuple_arity S=d Fail=f Size=u Rest=* => \
gen_select_tuple_arity(S, Fail, Size, Rest)
-i_select_val_bins xy f I
+i_select_val_bins xy f? I
-i_select_val_lins xy f I
+i_select_val_lins xy f? I
-i_select_val2 xy f c c
+i_select_val2 xy f? c c
-i_select_tuple_arity xy f I
+i_select_tuple_arity xy f? I
-i_select_tuple_arity2 xy f A A
+i_select_tuple_arity2 xy f? A A
-i_jump_on_val_zero xy f I
+i_jump_on_val_zero xy f? I
-i_jump_on_val xy f I W
+i_jump_on_val xy f? I W
get_list xy xy xy
@@ -188,7 +188,8 @@ catch_end y
# Try/catch.
try Y F => catch Y F
-try_case Y => try_end Y
+
+try_case y
try_end y
%cold
@@ -213,9 +214,9 @@ i_get_tuple_element2y x P y y
i_get_tuple_element3 x P x
%cold
-is_number f x
-is_number f y
+is_number f? xy
%hot
+
is_number Fail=f i =>
is_number Fail=f na => jump Fail
is_number Fail Literal=q => move Literal x | is_number Fail x
@@ -446,37 +447,37 @@ is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C
is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C
is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C
-i_is_eq_exact_immed f rxy c
+i_is_eq_exact_immed f? rxy c
-i_is_eq_exact_literal f xy c
+i_is_eq_exact_literal f? xy c
-i_is_ne_exact_immed f xy c
+i_is_ne_exact_immed f? xy c
-i_is_ne_exact_literal f xy c
+i_is_ne_exact_literal f? xy c
is_eq_exact Lbl Y=y X=x => is_eq_exact Lbl X Y
-is_eq_exact f x xy
-is_eq_exact f y y
+is_eq_exact f? x xy
+is_eq_exact f? y y
-is_ne_exact f S S
+is_ne_exact f? S S
-is_lt f x x
-is_lt f x c
-is_lt f c x
+is_lt f? x x
+is_lt f? x c
+is_lt f? c x
%cold
-is_lt f s s
+is_lt f? s s
%hot
-is_ge f x x
-is_ge f x c
-is_ge f c x
+is_ge f? x x
+is_ge f? x c
+is_ge f? c x
%cold
-is_ge f s s
+is_ge f? s s
%hot
-is_eq f s s
+is_eq f? s s
-is_ne f s s
+is_ne f? s s
#
# Putting things.
@@ -583,7 +584,7 @@ is_tagged_tuple Fail Literal=q Arity Atom => \
move Literal x | is_tagged_tuple Fail x Arity Atom
is_tagged_tuple Fail=f c Arity Atom => jump Fail
-is_tagged_tuple f rxy A a
+is_tagged_tuple f? rxy A a
# Test tuple & arity (head)
@@ -591,14 +592,14 @@ is_tuple Fail Literal=q => move Literal x | is_tuple Fail x
is_tuple Fail=f c => jump Fail
is_tuple Fail=f S=xy | test_arity Fail=f S=xy Arity => is_tuple_of_arity Fail S Arity
-is_tuple_of_arity f rxy A
+is_tuple_of_arity f? rxy A
-is_tuple f rxy
+is_tuple f? rxy
test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity
test_arity Fail=f c Arity => jump Fail
-test_arity f xy A
+test_arity f? xy A
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P3 D3=x | \
@@ -619,16 +620,16 @@ is_integer Fail Literal=q => move Literal x | is_integer Fail x
is_integer Fail=f S=x | allocate Need Regs => is_integer_allocate Fail S Need Regs
-is_integer_allocate f x t t
+is_integer_allocate f? x t t
-is_integer f xy
+is_integer f? xy
is_list Fail=f n =>
is_list Fail Literal=q => move Literal x | is_list Fail x
is_list Fail=f c => jump Fail
-is_list f x
+is_list f? x
%cold
-is_list f y
+is_list f? y
%hot
is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs
@@ -638,21 +639,21 @@ is_nonempty_list F=f x==0 | test_heap I1 I2 => is_nonempty_list_test_heap F I1 I
is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \
is_nonempty_list_get_list Fail S D1 D2
-is_nonempty_list_allocate f rx t t
-is_nonempty_list_test_heap f I t
-is_nonempty_list_get_list f rx x x
-is_nonempty_list f xy
+is_nonempty_list_allocate f? rx t t
+is_nonempty_list_test_heap f? I t
+is_nonempty_list_get_list f? rx x x
+is_nonempty_list f? xy
-is_atom f x
+is_atom f? x
%cold
-is_atom f y
+is_atom f? y
%hot
is_atom Fail=f a =>
is_atom Fail=f niq => jump Fail
-is_float f x
+is_float f? x
%cold
-is_float f y
+is_float f? y
%hot
is_float Fail=f nai => jump Fail
is_float Fail Literal=q => move Literal x | is_float Fail x
@@ -660,13 +661,13 @@ is_float Fail Literal=q => move Literal x | is_float Fail x
is_nil Fail=f n =>
is_nil Fail=f qia => jump Fail
-is_nil f xy
+is_nil f? xy
is_binary Fail Literal=q => move Literal x | is_binary Fail x
is_binary Fail=f c => jump Fail
-is_binary f x
+is_binary f? x
%cold
-is_binary f y
+is_binary f? y
%hot
# XXX Deprecated.
@@ -674,27 +675,27 @@ is_bitstr Fail Term => is_bitstring Fail Term
is_bitstring Fail Literal=q => move Literal x | is_bitstring Fail x
is_bitstring Fail=f c => jump Fail
-is_bitstring f x
+is_bitstring f? x
%cold
-is_bitstring f y
+is_bitstring f? y
%hot
is_reference Fail=f cq => jump Fail
-is_reference f x
+is_reference f? x
%cold
-is_reference f y
+is_reference f? y
%hot
is_pid Fail=f cq => jump Fail
-is_pid f x
+is_pid f? x
%cold
-is_pid f y
+is_pid f? y
%hot
is_port Fail=f cq => jump Fail
-is_port f x
+is_port f? x
%cold
-is_port f y
+is_port f? y
%hot
is_boolean Fail=f a==am_true =>
@@ -702,19 +703,19 @@ is_boolean Fail=f a==am_false =>
is_boolean Fail=f ac => jump Fail
%cold
-is_boolean f xy
+is_boolean f? xy
%hot
is_function2 Fail=f acq Arity => jump Fail
is_function2 Fail=f Fun a => jump Fail
-is_function2 f S s
+is_function2 f? S s
# Allocating & initializing.
allocate Need Regs | init Y => allocate_init Need Regs Y
init Y1 | init Y2 => init2 Y1 Y2
-allocate_init t t y
+allocate_init t t? y
#################################################################
# External function and bif calls.
@@ -1004,13 +1005,13 @@ node y
# Note: 'I' is sufficient because this instruction will only be used
# if the arity fits in 24 bits.
-i_fast_element xy j I d
+i_fast_element xy j? I d
-i_element xy j s d
+i_element xy j? s d
-bif1 f b s d
+bif1 f? b s d
bif1_body b s d
-i_bif2 f b s s d
+i_bif2 f? b s s d
i_bif2_body b s s d
#
@@ -1062,7 +1063,7 @@ make_fun2 OldIndex=u => gen_make_fun2(OldIndex)
i_make_fun W t
%hot
-is_function f xy
+is_function f? xy
is_function Fail=f c => jump Fail
func_info M F A => i_func_info u M F A
@@ -1091,24 +1092,24 @@ i_bs_match_string x f W W
bs_get_integer2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-i_bs_get_integer_small_imm x W f t x
-i_bs_get_integer_imm x W t f t x
-i_bs_get_integer f t t x s x
-i_bs_get_integer_8 x f x
-i_bs_get_integer_16 x f x
+i_bs_get_integer_small_imm x W f? t x
+i_bs_get_integer_imm x W t f? t x
+i_bs_get_integer f? t t x s x
+i_bs_get_integer_8 x f? x
+i_bs_get_integer_16 x f? x
%if ARCH_64
-i_bs_get_integer_32 x f x
+i_bs_get_integer_32 x f? x
%endif
# Fetching binaries from binaries.
bs_get_binary2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-i_bs_get_binary_imm2 f x t W t x
-i_bs_get_binary2 f x t s t x
-i_bs_get_binary_all2 f x t t x
-i_bs_get_binary_all_reuse x f t
+i_bs_get_binary_imm2 f? x t W t x
+i_bs_get_binary2 f x t? s t x
+i_bs_get_binary_all2 f? x t t x
+i_bs_get_binary_all_reuse x f? t
# Fetching float from binaries.
bs_get_float2 Fail=f Ms=x Live=u Sz=s Unit=u Flags=u Dst=d => \
@@ -1116,29 +1117,32 @@ bs_get_float2 Fail=f Ms=x Live=u Sz=s Unit=u Flags=u Dst=d => \
bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail
-i_bs_get_float2 f x t s t x
+i_bs_get_float2 f? x t s t x
# Miscellanous
bs_skip_bits2 Fail=f Ms=x Sz=sq Unit=u Flags=u => \
gen_skip_bits2(Fail, Ms, Sz, Unit, Flags)
-i_bs_skip_bits_imm2 f x W
-i_bs_skip_bits2 f x xy t
-i_bs_skip_bits_all2 f x t
+i_bs_skip_bits_imm2 f? x W
+i_bs_skip_bits2 f? x xy t
+i_bs_skip_bits_all2 f? x t
bs_test_tail2 Fail=f Ms=x Bits=u==0 => bs_test_zero_tail2 Fail Ms
bs_test_tail2 Fail=f Ms=x Bits=u => bs_test_tail_imm2 Fail Ms Bits
-bs_test_zero_tail2 f x
-bs_test_tail_imm2 f x W
+bs_test_zero_tail2 f? x
+bs_test_tail_imm2 f? x W
bs_test_unit F Ms Unit=u==8 => bs_test_unit8 F Ms
-bs_test_unit f x t
-bs_test_unit8 f x
+bs_test_unit f? x t
+bs_test_unit8 f? x
# An y register operand for bs_context_to_binary is rare,
# but can happen because of inlining.
+bs_context_to_binary Y=y | line L | badmatch Y => \
+ move Y x | bs_context_to_binary x | line L | badmatch x
+
bs_context_to_binary Y=y => move Y x | bs_context_to_binary x
bs_context_to_binary x
@@ -1147,14 +1151,14 @@ bs_context_to_binary x
# Utf8/utf16/utf32 support. (R12B-5)
#
bs_get_utf8 Fail=f Ms=x u u Dst=d => i_bs_get_utf8 Ms Fail Dst
-i_bs_get_utf8 x f x
+i_bs_get_utf8 x f? x
bs_skip_utf8 Fail=f Ms=x u u => i_bs_get_utf8 Ms Fail x
bs_get_utf16 Fail=f Ms=x u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
bs_skip_utf16 Fail=f Ms=x u Flags=u => i_bs_get_utf16 Ms Fail Flags x
-i_bs_get_utf16 x f t x
+i_bs_get_utf16 x f? t x
bs_get_utf32 Fail=f Ms=x Live=u Flags=u Dst=d => \
bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \
@@ -1183,13 +1187,13 @@ bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \
bs_init2 Fail Sz Words Regs Flags Dst => \
i_bs_init_fail_heap Sz Words Fail Regs Dst
-i_bs_init_fail xy j t x
+i_bs_init_fail xy j? t? x
-i_bs_init_fail_heap s I j t x
+i_bs_init_fail_heap s I j? t? x
-i_bs_init W t x
+i_bs_init W t? x
-i_bs_init_heap W I t x
+i_bs_init_heap W I t? x
bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail
@@ -1202,16 +1206,16 @@ bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \
bs_init_bits Fail Sz Words Regs Flags Dst => \
i_bs_init_bits_fail_heap Sz Words Fail Regs Dst
-i_bs_init_bits_fail xy j t x
+i_bs_init_bits_fail xy j? t? x
-i_bs_init_bits_fail_heap s I j t x
+i_bs_init_bits_fail_heap s I j? t? x
-i_bs_init_bits W t x
-i_bs_init_bits_heap W I t x
+i_bs_init_bits W t? x
+i_bs_init_bits_heap W I t? x
bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D
-bs_add j s s t x
+bs_add j? s s t? x
bs_append Fail Size Extra Live Unit Bin Flags Dst => \
move Bin x | i_bs_append Fail Extra Live Unit Size Dst
@@ -1221,8 +1225,8 @@ bs_private_append Fail Size Unit Bin Flags Dst => \
bs_init_writable
-i_bs_append j I t t s x
-i_bs_private_append j t s S x
+i_bs_append j? I t? t s x
+i_bs_private_append j? t s S x
#
# Storing integers into binaries.
@@ -1231,8 +1235,8 @@ i_bs_private_append j t s S x
bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \
gen_put_integer(Fail, Sz, Unit, Flags, Src)
-i_new_bs_put_integer j s t s
-i_new_bs_put_integer_imm j W t s
+i_new_bs_put_integer j? s t s
+i_new_bs_put_integer_imm j? W t s
#
# Utf8/utf16/utf32 support. (R12B-5)
@@ -1248,14 +1252,14 @@ i_bs_utf16_size s x
bs_put_utf8 Fail u Src=s => i_bs_put_utf8 Fail Src
-i_bs_put_utf8 j s
+i_bs_put_utf8 j? s
-bs_put_utf16 j t s
+bs_put_utf16 j? t s
bs_put_utf32 Fail=j Flags=u Src=s => \
i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src
-i_bs_validate_unicode j s
+i_bs_validate_unicode j? s
#
# Storing floats into binaries.
@@ -1265,8 +1269,8 @@ bs_put_float Fail Sz=q Unit Flags Val => badarg Fail
bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \
gen_put_float(Fail, Sz, Unit, Flags, Src)
-i_new_bs_put_float j s t s
-i_new_bs_put_float_imm j W t s
+i_new_bs_put_float j? s t s
+i_new_bs_put_float_imm j? W t s
#
# Storing binaries into binaries.
@@ -1275,9 +1279,9 @@ i_new_bs_put_float_imm j W t s
bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \
gen_put_binary(Fail, Sz, Unit, Flags, Src)
-i_new_bs_put_binary j s t s
-i_new_bs_put_binary_imm j W s
-i_new_bs_put_binary_all j s t
+i_new_bs_put_binary j? s t s
+i_new_bs_put_binary_imm j? W s
+i_new_bs_put_binary_all j? s t
#
# Warning: The i_bs_put_string and i_new_bs_put_string instructions
@@ -1391,12 +1395,12 @@ new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \
new_map d t I
i_new_small_map_lit d t q
update_map_assoc s d t I
-update_map_exact j s d t I
+update_map_exact j? s d t I
is_map Fail Lit=q | literal_is_map(Lit) =>
is_map Fail cq => jump Fail
-is_map f xy
+is_map f? xy
## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements
@@ -1410,14 +1414,14 @@ get_map_elements Fail Src=xy Size=u==2 Rest=* => \
get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \
gen_get_map_elements(Fail, Src, Size, Rest)
-i_get_map_elements f s I
+i_get_map_elements f? s I
i_get_map_element Fail Src=xy Key=y Dst => \
move Key x | i_get_map_element Fail Src x Dst
-i_get_map_element_hash f xy c I xy
+i_get_map_element_hash f? xy c I xy
-i_get_map_element f xy x xy
+i_get_map_element f? xy x xy
#
# Convert the plus operations to a generic plus instruction.
@@ -1485,32 +1489,32 @@ gc_bif1 Fail I u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src I Dst
i_increment rxy W t d
-i_plus x xy j t d
-i_plus s s j t d
+i_plus x xy j? t d
+i_plus s s j? t d
-i_minus x x j t d
-i_minus s s j t d
+i_minus x x j? t d
+i_minus s s j? t d
-i_times j t s s d
+i_times j? t s s d
-i_m_div j t s s d
-i_int_div j t s s d
+i_m_div j? t s s d
+i_int_div j? t s s d
-i_rem x x j t d
-i_rem s s j t d
+i_rem x x j? t d
+i_rem s s j? t d
-i_bsl s s j t d
-i_bsr s s j t d
+i_bsl s s j? t d
+i_bsr s s j? t d
-i_band x c j t d
-i_band s s j t d
+i_band x c j? t d
+i_band s s j? t d
-i_bor j I s s d
-i_bxor j I s s d
+i_bor j? I s s d
+i_bxor j? I s s d
i_int_bnot Fail Src=c Live Dst => move Src x | i_int_bnot Fail x Live Dst
-i_int_bnot j S t d
+i_int_bnot j? S t d
#
# Old guard BIFs that creates heap fragments are no longer allowed.
@@ -1534,9 +1538,9 @@ gc_bif2 Fail I Bif S1 S2 Dst => \
gc_bif3 Fail I Bif S1 S2 S3 Dst => \
gen_guard_bif3(Fail, I, Bif, S1, S2, S3, Dst)
-i_gc_bif1 j W s t d
+i_gc_bif1 j? W s t? d
-i_gc_bif2 j W t s s d
+i_gc_bif2 j? W t? s s d
ii_gc_bif3/7
@@ -1545,7 +1549,7 @@ ii_gc_bif3/7
ii_gc_bif3 Fail Bif Live S1 S2 S3 Dst => \
move S1 x | i_gc_bif3 Fail Bif Live S2 S3 Dst
-i_gc_bif3 j W t s s d
+i_gc_bif3 j? W t? s s d
#
# The following instruction is specially handled in beam_load.c
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 9106091ca6..bf7d310568 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -824,11 +824,16 @@ int erts_sys_unsetenv(char *key);
char *erts_read_env(char *key);
void erts_free_read_env(void *value);
-#if defined(ERTS_THR_HAVE_SIG_FUNCS) && !defined(ETHR_UNUSABLE_SIGUSRX)
+#if defined(ERTS_THR_HAVE_SIG_FUNCS) && \
+ (!defined(ETHR_UNUSABLE_SIGUSRX) || defined(SIGRTMIN))
extern void sys_thr_resume(erts_tid_t tid);
extern void sys_thr_suspend(erts_tid_t tid);
-#define ERTS_SYS_SUSPEND_SIGNAL SIGUSR2
-#endif
+#ifdef SIGRTMIN
+#define ERTS_SYS_SUSPEND_SIGNAL (SIGRTMIN+1)
+#else
+#define ERTS_SYS_SUSPEND_SIGNAL (SIGUSR2)
+#endif /* SIGRTMIN */
+#endif /* HAVE_SIG_FUNCS */
/* utils.c */
@@ -1170,4 +1175,52 @@ int erts_get_printable_characters(void);
void erts_init_sys_common_misc(void);
+ERTS_GLB_INLINE Sint erts_raw_env_7bit_ascii_char_need(int encoding);
+ERTS_GLB_INLINE byte *erts_raw_env_7bit_ascii_char_put(byte c, byte *p,
+ int encoding);
+ERTS_GLB_INLINE int erts_raw_env_char_is_7bit_ascii_char(byte c, byte *p,
+ int encoding);
+ERTS_GLB_INLINE byte *erts_raw_env_next_char(byte *p, int encoding);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE Sint
+erts_raw_env_7bit_ascii_char_need(int encoding)
+{
+ return (encoding == ERL_FILENAME_WIN_WCHAR) ? 2 : 1;
+}
+
+ERTS_GLB_INLINE byte *
+erts_raw_env_7bit_ascii_char_put(byte c,
+ byte *p,
+ int encoding)
+{
+ *(p++) = c;
+ if (encoding == ERL_FILENAME_WIN_WCHAR)
+ *(p++) = 0;
+ return p;
+}
+
+ERTS_GLB_INLINE int
+erts_raw_env_char_is_7bit_ascii_char(byte c,
+ byte *p,
+ int encoding)
+{
+ if (encoding == ERL_FILENAME_WIN_WCHAR)
+ return (p[0] == c) & (p[1] == 0);
+ else
+ return p[0] == c;
+}
+
+ERTS_GLB_INLINE byte *
+erts_raw_env_next_char(byte *p, int encoding)
+{
+ if (encoding == ERL_FILENAME_WIN_WCHAR)
+ return p + 2;
+ else
+ return p + 1;
+}
+
+#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
+
#endif