summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/beam_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/beam_common.c')
-rw-r--r--erts/emulator/beam/beam_common.c576
1 files changed, 299 insertions, 277 deletions
diff --git a/erts/emulator/beam/beam_common.c b/erts/emulator/beam/beam_common.c
index 36f9d49629..2055f60e91 100644
--- a/erts/emulator/beam/beam_common.c
+++ b/erts/emulator/beam/beam_common.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2021. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2022. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
#include "dist.h"
#include "beam_catches.h"
#include "beam_common.h"
+#include "erl_global_literals.h"
#ifdef USE_VM_PROBES
#include "dtrace-wrapper.h"
@@ -233,7 +234,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
if (ERTS_PROC_IS_EXITING(c_p)) {
sys_strcpy(fun_buf, "<exiting>");
} else {
- ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i);
+ const ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i);
if (cmfa) {
dtrace_fun_decode(c_p, cmfa, NULL, fun_buf);
} else {
@@ -394,6 +395,7 @@ Eterm error_atom[NUMBER_EXIT_CODES] = {
am_notsup, /* 17 */
am_badmap, /* 18 */
am_badkey, /* 19 */
+ am_badrecord, /* 20 */
};
/* Returns the return address at E[0] in printable form, skipping tracing in
@@ -402,21 +404,24 @@ Eterm error_atom[NUMBER_EXIT_CODES] = {
* This is needed to generate correct stacktraces when throwing errors from
* instructions that return like an ordinary function, such as call_nif. */
ErtsCodePtr erts_printable_return_address(Process* p, Eterm *E) {
- Eterm *ptr = E;
+ Eterm *stack_bottom = STACK_START(p);
+ Eterm *scanner = E;
- ASSERT(is_CP(*ptr));
+ ASSERT(is_CP(scanner[0]));
- while (ptr < STACK_START(p)) {
- ErtsCodePtr cp = cp_val(*ptr);
+ while (scanner < stack_bottom) {
+ ErtsCodePtr return_address;
- if (BeamIsReturnTrace(cp)) {
- ptr += 3;
- } else if (BeamIsReturnTimeTrace(cp)) {
- ptr += 2;
- } else if (BeamIsReturnToTrace(cp)) {
- ptr += 1;
+ erts_inspect_frame(scanner, &return_address);
+
+ if (BeamIsReturnTrace(return_address)) {
+ scanner += CP_SIZE + 2;
+ } else if (BeamIsReturnTimeTrace(return_address)) {
+ scanner += CP_SIZE + 1;
+ } else if (BeamIsReturnToTrace(return_address)) {
+ scanner += CP_SIZE;
} else {
- return cp;
+ return return_address;
}
}
@@ -519,18 +524,20 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg,
&& !(c_p->freason & EXF_PANIC)) {
ErtsCodePtr new_pc;
/* The Beam handler code (catch_end or try_end) checks reg[0]
- for THE_NON_VALUE to see if the previous code finished
- abnormally. If so, reg[1], reg[2] and reg[3] should hold the
- exception class, term and trace, respectively. (If the
- handler is just a trap to native code, these registers will
- be ignored.) */
+ * for THE_NON_VALUE to see if the previous code finished
+ * abnormally. If so, reg[1], reg[2] and reg[3] should hold
+ * the term, trace, and exception class, respectively. Note
+ * that the handler code will only need to move the class
+ * to reg[0] to have all registers correctly set up for the
+ * code that follows.
+ */
reg[0] = THE_NON_VALUE;
- reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)];
- reg[2] = Value;
- reg[3] = c_p->ftrace;
+ reg[1] = Value;
+ reg[2] = c_p->ftrace;
+ reg[3] = exception_tag[GET_EXC_CLASS(c_p->freason)];
if ((new_pc = next_catch(c_p, reg))) {
-#if defined(BEAMASM) && defined(NATIVE_ERLANG_STACK)
+#if defined(BEAMASM) && (defined(NATIVE_ERLANG_STACK) || defined(__aarch64__))
/* In order to make use of native call and return
* instructions, when beamasm uses the native stack it
* doesn't include the CP in the current stack frame,
@@ -539,7 +546,11 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg,
*
* Therefore, we need to bump the stack pointer as if this were an
* ordinary return. */
- ASSERT(is_CP(c_p->stop[0]));
+
+ if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) {
+ FRAME_POINTER(c_p) = (Eterm*)cp_val(c_p->stop[0]);
+ }
+
c_p->stop += CP_SIZE;
#else
/* To avoid keeping stale references. */
@@ -566,8 +577,10 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg,
static ErtsCodePtr
next_catch(Process* c_p, Eterm *reg) {
int active_catches = c_p->catches > 0;
+ ErtsCodePtr return_to_trace_address = NULL;
int have_return_to_trace = 0;
- Eterm *ptr, *prev, *return_to_trace_ptr = NULL;
+ Eterm *ptr, *prev;
+ ErtsCodePtr handler;
ptr = prev = c_p->stop;
ASSERT(ptr <= STACK_START(c_p));
@@ -583,53 +596,82 @@ next_catch(Process* c_p, Eterm *reg) {
}
while (ptr < STACK_START(c_p)) {
- if (is_catch(*ptr)) {
- if (active_catches) goto found_catch;
- ptr++;
- }
- else if (is_CP(*ptr)) {
- prev = ptr;
- if (BeamIsReturnTrace(cp_val(*prev))) {
- if (cp_val(*prev) == beam_exception_trace) {
- ErtsCodeMFA *mfa = (ErtsCodeMFA*)cp_val(ptr[1]);
- erts_trace_exception(c_p, mfa,
- reg[1], reg[2],
- ERTS_TRACER_FROM_ETERM(ptr+2));
- }
- /* Skip MFA, tracer, and CP. */
- ptr += 3;
- } else if (BeamIsReturnToTrace(cp_val(*prev))) {
- have_return_to_trace = !0; /* Record next cp */
- return_to_trace_ptr = NULL;
- /* Skip CP. */
- ptr += 1;
- } else if (BeamIsReturnTimeTrace(cp_val(*prev))) {
- /* Skip prev_info and CP. */
- ptr += 2;
- } else {
- if (have_return_to_trace) {
- /* Record this cp as possible return_to trace cp */
- have_return_to_trace = 0;
- return_to_trace_ptr = ptr;
- } else return_to_trace_ptr = NULL;
- ptr++;
- }
- } else ptr++;
+ Eterm val = ptr[0];
+
+ if (is_catch(val)) {
+ if (active_catches) {
+ goto found_catch;
+ }
+
+ ptr++;
+ } else if (is_CP(val)) {
+ ErtsCodePtr return_address;
+ const Eterm *frame;
+
+ prev = ptr;
+ frame = erts_inspect_frame(ptr, &return_address);
+
+ if (BeamIsReturnTrace(return_address)) {
+ if (return_address == beam_exception_trace) {
+ ErtsTracer *tracer;
+ ErtsCodeMFA *mfa;
+
+ mfa = (ErtsCodeMFA*)cp_val(frame[0]);
+ tracer = ERTS_TRACER_FROM_ETERM(&frame[1]);
+
+ ASSERT_MFA(mfa);
+ erts_trace_exception(c_p, mfa, reg[3], reg[1], tracer);
+ }
+
+ ptr += CP_SIZE + 2;
+ } else if (BeamIsReturnTimeTrace(return_address)) {
+ ptr += CP_SIZE + 1;
+ } else if (BeamIsReturnToTrace(return_address)) {
+ have_return_to_trace = 1; /* Record next cp */
+ return_to_trace_address = NULL;
+
+ ptr += CP_SIZE;
+ } else {
+ /* This is an ordinary call frame: if the previous frame was a
+ * return_to trace we should record this CP as a return_to
+ * candidate. */
+ if (have_return_to_trace) {
+ return_to_trace_address = return_address;
+ have_return_to_trace = 0;
+ } else {
+ return_to_trace_address = NULL;
+ }
+
+ ptr += CP_SIZE;
+ }
+ } else {
+ ptr++;
+ }
}
+
return NULL;
found_catch:
ASSERT(ptr < STACK_START(c_p));
c_p->stop = prev;
- if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_ptr) {
- /* The stackframe closest to the catch contained an
- * return_to_trace entry, so since the execution now
- * continues after the catch, a return_to trace message
- * would be appropriate.
- */
- erts_trace_return_to(c_p, cp_val(*return_to_trace_ptr));
+
+ if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_address) {
+ /* The stackframe closest to the catch contained an
+ * return_to_trace entry, so since the execution now
+ * continues after the catch, a return_to trace message
+ * would be appropriate.
+ */
+ erts_trace_return_to(c_p, return_to_trace_address);
}
- return catch_pc(*ptr);
+
+ /* Clear the try_tag or catch_tag in the stack frame so that we
+ * don't have to do it in the JITted code for the try_case
+ * instruction. (Unfortunately, a catch_end will still need to
+ * clear the catch_tag because it is executed even when no
+ * exception has occurred.) */
+ handler = catch_pc(*ptr);
+ *ptr = NIL;
+ return handler;
}
/*
@@ -712,6 +754,7 @@ expand_error_value(Process* c_p, Uint freason, Eterm Value) {
case (GET_EXC_INDEX(EXC_BADARITY)):
case (GET_EXC_INDEX(EXC_BADMAP)):
case (GET_EXC_INDEX(EXC_BADKEY)):
+ case (GET_EXC_INDEX(EXC_BADRECORD)):
/* Some common exceptions: value -> {atom, value} */
ASSERT(is_value(Value));
hp = HAlloc(c_p, 3);
@@ -753,35 +796,39 @@ gather_stacktrace(Process* p, struct StackTrace* s, int depth)
while (ptr < STACK_START(p) && depth > 0) {
if (is_CP(*ptr)) {
- ErtsCodePtr cp = cp_val(*ptr);
-
- if (BeamIsReturnTrace(cp)) {
- ptr += 3;
- } else if (BeamIsReturnTimeTrace(cp)) {
- ptr += 2;
- } else if (BeamIsReturnToTrace(cp)) {
- ptr += 1;
+ ErtsCodePtr return_address;
+
+ erts_inspect_frame(ptr, &return_address);
+
+ if (BeamIsReturnTrace(return_address)) {
+ ptr += CP_SIZE + 2;
+ } else if (BeamIsReturnTimeTrace(return_address)) {
+ ptr += CP_SIZE + 1;
+ } else if (BeamIsReturnToTrace(return_address)) {
+ ptr += CP_SIZE;
} else {
- if (cp != prev) {
- void *adjusted_cp;
+ if (return_address != prev) {
+ ErtsCodePtr adjusted_address;
/* Record non-duplicates only */
- prev = cp;
+ prev = return_address;
+
#ifdef BEAMASM
- /*
- * Some instructions (e.g. call) are shorter than one word,
- * so we will need to subtract one byte from the pointer
- * to avoid ending up before the start of the instruction.
- */
- adjusted_cp = ((char *) cp) - 1;
+ /* Some instructions (e.g. call) are shorter than one word,
+ * so we will need to subtract one byte from the pointer
+ * to avoid ending up before the start of the
+ * instruction. */
+ adjusted_address = ((char*)return_address) - 1;
#else
- /* Subtract one word from the pointer. */
- adjusted_cp = ((char *) cp) - sizeof(UWord);
+ /* Subtract one word from the pointer. */
+ adjusted_address = ((char*)return_address) - sizeof(UWord);
#endif
- s->trace[s->depth++] = adjusted_cp;
+
+ s->trace[s->depth++] = adjusted_address;
depth--;
}
- ptr++;
+
+ ptr += CP_SIZE;
}
} else {
ptr++;
@@ -796,7 +843,7 @@ gather_stacktrace(Process* p, struct StackTrace* s, int depth)
*
* There is an issue with line number information. Line number
* information is associated with the address *before* an operation
- * that may fail or be stored stored on the stack. But continuation
+ * that may fail or be stored on the stack. But continuation
* pointers point after its call instruction, not before. To avoid
* finding the wrong line number, we'll need to adjust them so that
* they point at the beginning of the call instruction or inside the
@@ -952,10 +999,13 @@ save_stacktrace(Process* c_p, ErtsCodePtr pc, Eterm* reg,
args = make_arglist(c_p, reg, bif_mfa->arity);
} else {
+ if (c_p->freason & EXF_HAS_EXT_INFO && is_map(c_p->fvalue)) {
+ error_info = c_p->fvalue;
+ }
non_bif_stacktrace:
-
s->current = c_p->current;
+
/*
* For a function_clause error, the arguments are in the beam
* registers and c_p->current is set.
@@ -1065,7 +1115,7 @@ static Eterm *get_freason_ptr_from_exc(Eterm exc) {
if (exc == NIL) {
/*
- * Is is not exactly clear when exc can be NIL. Probably only
+ * It is not exactly clear when exc can be NIL. Probably only
* when the exception has been generated from native code.
* Return a pointer to an Eterm that can be safely written and
* ignored.
@@ -1351,7 +1401,7 @@ apply_bif_error_adjustment(Process *p, Export *ep,
* error handling code.
*/
if (need == 0) {
- need = 1; /* i_apply_only */
+ need = CP_SIZE; /* i_apply_only */
}
if (HeapWordsLeft(p) < need) {
@@ -1365,7 +1415,17 @@ apply_bif_error_adjustment(Process *p, Export *ep,
* Push the continuation pointer for the current function to the stack.
*/
p->stop -= need;
- p->stop[0] = make_cp(I);
+
+ switch (erts_frame_layout) {
+ case ERTS_FRAME_LAYOUT_RA:
+ p->stop[0] = make_cp(I);
+ break;
+ case ERTS_FRAME_LAYOUT_FP_RA:
+ p->stop[0] = make_cp(FRAME_POINTER(p));
+ p->stop[1] = make_cp(I);
+ FRAME_POINTER(p) = &p->stop[0];
+ break;
+ }
} else {
/*
* Called from an i_apply_last_* instruction.
@@ -1377,7 +1437,17 @@ apply_bif_error_adjustment(Process *p, Export *ep,
* and then add a dummy stackframe for the i_apply_last* instruction
* to discard.
*/
- p->stop[0] = make_cp(I);
+ switch (erts_frame_layout) {
+ case ERTS_FRAME_LAYOUT_RA:
+ p->stop[0] = make_cp(I);
+ break;
+ case ERTS_FRAME_LAYOUT_FP_RA:
+ p->stop[0] = make_cp(FRAME_POINTER(p));
+ p->stop[1] = make_cp(I);
+ FRAME_POINTER(p) = &p->stop[0];
+ break;
+ }
+
p->stop -= need;
}
}
@@ -1596,10 +1666,21 @@ erts_hibernate(Process* c_p, Eterm* reg)
c_p->arg_reg[0] = module;
c_p->arg_reg[1] = function;
c_p->arg_reg[2] = args;
- c_p->stop = c_p->hend - CP_SIZE; /* Keep first continuation pointer */
- ASSERT(c_p->stop[0] == make_cp(beam_normal_exit));
+ c_p->stop = c_p->hend - CP_SIZE; /* Keep first continuation pointer */
+
+ switch(erts_frame_layout) {
+ case ERTS_FRAME_LAYOUT_RA:
+ ASSERT(c_p->stop[0] == make_cp(beam_normal_exit));
+ break;
+ case ERTS_FRAME_LAYOUT_FP_RA:
+ FRAME_POINTER(c_p) = &c_p->stop[0];
+ ASSERT(c_p->stop[0] == make_cp(NULL));
+ ASSERT(c_p->stop[1] == make_cp(beam_normal_exit));
+ break;
+ }
+
c_p->catches = 0;
- c_p->i = beam_apply;
+ c_p->i = beam_run_process;
/*
* If there are no waiting messages, garbage collect and
@@ -1628,171 +1709,133 @@ ErtsCodePtr
call_fun(Process* p, /* Current process. */
int arity, /* Number of arguments for Fun. */
Eterm* reg, /* Contents of registers. */
- Eterm args, /* THE_NON_VALUE or pre-built list of arguments. */
- Export **epp) /* Export entry, if any. */
+ Eterm args) /* THE_NON_VALUE or pre-built list of arguments. */
{
- Eterm fun = reg[arity];
- Eterm hdr;
- int i;
- Eterm* hp;
+ ErtsCodeIndex code_ix;
+ ErtsCodePtr code_ptr;
+ ErlFunThing *funp;
+ Eterm fun;
+
+ fun = reg[arity];
- if (!is_boxed(fun)) {
- goto badfun;
+ if (is_not_any_fun(fun)) {
+ p->current = NULL;
+ p->freason = EXC_BADFUN;
+ p->fvalue = fun;
+ return NULL;
}
- hdr = *boxed_val(fun);
- if (is_fun_header(hdr)) {
- ErlFunThing* funp = (ErlFunThing *) fun_val(fun);
- ErlFunEntry* fe = funp->fe;
- ErtsCodePtr code_ptr = fe->address;
- Eterm* var_ptr;
- unsigned num_free = funp->num_free;
- const ErtsCodeMFA *mfa = erts_code_to_codemfa(code_ptr);
- int actual_arity = mfa->arity;
+ funp = (ErlFunThing*)fun_val(fun);
- if (actual_arity == arity+num_free) {
- DTRACE_LOCAL_CALL(p, mfa);
- if (num_free == 0) {
- return code_ptr;
- } else {
- var_ptr = funp->env;
- reg += arity;
- i = 0;
- do {
- reg[i] = var_ptr[i];
- i++;
- } while (i < num_free);
- reg[i] = fun;
- return code_ptr;
- }
- return code_ptr;
- } else {
- /*
- * Something wrong here. First build a list of the arguments.
- */
+ code_ix = erts_active_code_ix();
+ code_ptr = (funp->entry.disp)->addresses[code_ix];
- if (is_non_value(args)) {
- Uint sz = 2 * arity;
- args = NIL;
- if (HeapWordsLeft(p) < sz) {
- erts_garbage_collect(p, sz, reg, arity+1);
- fun = reg[arity];
- }
- hp = HEAP_TOP(p);
- HEAP_TOP(p) += sz;
- for (i = arity-1; i >= 0; i--) {
- args = CONS(hp, reg[i], args);
- hp += 2;
- }
- }
+ if (ERTS_LIKELY(code_ptr != beam_unloaded_fun && funp->arity == arity)) {
+ for (int i = 0, num_free = funp->num_free; i < num_free; i++) {
+ reg[i + arity] = funp->env[i];
+ }
- if (actual_arity >= 0) {
- /*
- * There is a fun defined, but the call has the wrong arity.
- */
- hp = HAlloc(p, 3);
- p->freason = EXC_BADARITY;
- p->fvalue = TUPLE2(hp, fun, args);
- return NULL;
- } else {
- Export* ep;
- Module* modp;
- Eterm module;
- ErtsCodeIndex code_ix = erts_active_code_ix();
-
- /*
- * No arity. There is no module loaded that defines the fun,
- * either because the fun is newly created from the external
- * representation (the module has never been loaded),
- * or the module defining the fun has been unloaded.
- */
-
- module = fe->module;
-
- ERTS_THR_READ_MEMORY_BARRIER;
- if (fe->pend_purge_address) {
- /*
- * The system is currently trying to purge the
- * module containing this fun. Suspend the process
- * and let it try again when the purge operation is
- * done (may succeed or not).
- */
- ep = erts_suspend_process_on_pending_purge_lambda(p, fe);
- ASSERT(ep);
- }
- else {
- if ((modp = erts_get_module(module, code_ix)) != NULL
- && modp->curr.code_hdr != NULL) {
- /*
- * There is a module loaded, but obviously the fun is not
- * defined in it. We must not call the error_handler
- * (or we will get into an infinite loop).
- */
- goto badfun;
- }
+#ifdef USE_VM_CALL_PROBES
+ if (is_local_fun(funp)) {
+ DTRACE_LOCAL_CALL(p, erts_code_to_codemfa(code_ptr));
+ } else {
+ Export *ep = funp->entry.exp;
+ ASSERT(is_external_fun(funp) && funp->next == NULL);
+ DTRACE_GLOBAL_CALL(p, &ep->info.mfa);
+ }
+#endif
- /*
- * No current code for this module. Call the error_handler module
- * to attempt loading the module.
- */
-
- ep = erts_find_function(erts_proc_get_error_handler(p),
- am_undefined_lambda, 3, code_ix);
- if (ep == NULL) { /* No error handler */
- p->current = NULL;
- p->freason = EXC_UNDEF;
- return NULL;
- }
- }
- reg[0] = module;
- reg[1] = fun;
- reg[2] = args;
- reg[3] = NIL;
- *epp = ep;
- return ep->addresses[code_ix];
- }
- }
- } else if (is_export_header(hdr)) {
- Export *ep;
- int actual_arity;
+ return code_ptr;
+ } else {
+ /* Something wrong here. First build a list of the arguments. */
+ if (is_non_value(args)) {
+ Uint sz = 2 * arity;
+ Eterm *hp;
- ep = *((Export **) (export_val(fun) + 1));
- actual_arity = ep->info.mfa.arity;
+ args = NIL;
- if (arity == actual_arity) {
- DTRACE_GLOBAL_CALL(p, &ep->info.mfa);
- *epp = ep;
- return ep->addresses[erts_active_code_ix()];
- } else {
- /*
- * Wrong arity. First build a list of the arguments.
- */
+ if (HeapWordsLeft(p) < sz) {
+ erts_garbage_collect(p, sz, reg, arity+1);
- if (is_non_value(args)) {
- args = NIL;
- hp = HAlloc(p, arity*2);
- for (i = arity-1; i >= 0; i--) {
- args = CONS(hp, reg[i], args);
- hp += 2;
- }
- }
+ fun = reg[arity];
+ funp = (ErlFunThing*)fun_val(fun);
+ }
- hp = HAlloc(p, 3);
- p->freason = EXC_BADARITY;
- p->fvalue = TUPLE2(hp, fun, args);
- return NULL;
- }
- } else {
- badfun:
- p->current = NULL;
- p->freason = EXC_BADFUN;
- p->fvalue = fun;
- return NULL;
+ hp = HEAP_TOP(p);
+ HEAP_TOP(p) += sz;
+
+ for (int i = arity - 1; i >= 0; i--) {
+ args = CONS(hp, reg[i], args);
+ hp += 2;
+ }
+ }
+
+ if (funp->arity != arity) {
+ /* There is a fun defined, but the call has the wrong arity. */
+ Eterm *hp = HAlloc(p, 3);
+ p->freason = EXC_BADARITY;
+ p->fvalue = TUPLE2(hp, fun, args);
+ return NULL;
+ } else {
+ ErlFunEntry *fe;
+ Eterm module;
+ Module *modp;
+ Export *ep;
+
+ /* There is no module loaded that defines the fun, either because
+ * the fun is newly created from the external representation (the
+ * module has never been loaded), or the module defining the fun
+ * has been unloaded. */
+ ASSERT(is_local_fun(funp) && code_ptr == beam_unloaded_fun);
+ fe = funp->entry.fun;
+ module = fe->module;
+
+ ERTS_THR_READ_MEMORY_BARRIER;
+ if (fe->pend_purge_address) {
+ /* The system is currently trying to purge the
+ * module containing this fun. Suspend the process
+ * and let it try again when the purge operation is
+ * done (may succeed or not). */
+ ep = erts_suspend_process_on_pending_purge_lambda(p, fe);
+ } else {
+ if ((modp = erts_get_module(module, code_ix)) != NULL
+ && modp->curr.code_hdr != NULL) {
+ /* There is a module loaded, but obviously the fun is
+ * not defined in it. We must not call the error_handler
+ * (or we will get into an infinite loop). */
+ p->current = NULL;
+ p->freason = EXC_BADFUN;
+ p->fvalue = fun;
+ return NULL;
+ }
+
+ /* No current code for this module. Call the error_handler
+ * module to attempt loading the module. */
+
+ ep = erts_find_function(erts_proc_get_error_handler(p),
+ am_undefined_lambda, 3, code_ix);
+ if (ep == NULL) {
+ /* No error handler */
+ p->current = NULL;
+ p->freason = EXC_UNDEF;
+ return NULL;
+ }
+ }
+
+ ASSERT(ep);
+
+ reg[0] = module;
+ reg[1] = fun;
+ reg[2] = args;
+ reg[3] = NIL;
+
+ return ep->dispatch.addresses[code_ix];
+ }
}
}
ErtsCodePtr
-apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg, Export **epp)
+apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg)
{
int arity;
Eterm tmp;
@@ -1819,41 +1862,17 @@ apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg, Export **epp)
return NULL;
}
reg[arity] = fun;
- return call_fun(p, arity, reg, args, epp);
-}
-
-ErlFunThing*
-new_fun_thing(Process* p, ErlFunEntry* fe, int num_free)
-{
- const ErtsCodeMFA *mfa;
- ErlFunThing* funp;
-
- mfa = erts_code_to_codemfa(fe->address);
- funp = (ErlFunThing*) p->htop;
- p->htop += ERL_FUN_SIZE + num_free;
- erts_refc_inc(&fe->refc, 2);
-
- funp->thing_word = HEADER_FUN;
- funp->next = MSO(p).first;
- MSO(p).first = (struct erl_off_heap_header*) funp;
- funp->fe = fe;
- funp->num_free = num_free;
- funp->creator = p->common.id;
- funp->arity = mfa->arity - num_free;
-
- return funp;
+ return call_fun(p, arity, reg, args);
}
int
is_function2(Eterm Term, Uint arity)
{
- if (is_fun(Term)) {
- ErlFunThing* funp = (ErlFunThing *) fun_val(Term);
- return funp->arity == arity;
- } else if (is_export(Term)) {
- Export* exp = (Export *) (export_val(Term)[1]);
- return exp->info.mfa.arity == arity;
+ if (is_any_fun(Term)) {
+ ErlFunThing *funp = (ErlFunThing*)fun_val(Term);
+ return funp->arity == arity;
}
+
return 0;
}
@@ -1985,11 +2004,14 @@ erts_gc_new_map(Process* p, Eterm* reg, Uint live,
}
thp = p->htop;
- mhp = thp + 1 + n/2;
+ mhp = thp + (n == 0 ? 0 : 1) + n/2;
E = p->stop;
- keys = make_tuple(thp);
- *thp++ = make_arityval(n/2);
-
+ if (n == 0) {
+ keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE;
+ } else {
+ keys = make_tuple(thp);
+ *thp++ = make_arityval(n/2);
+ }
mp = (flatmap_t *)mhp; mhp += MAP_HEADER_FLATMAP_SZ;
mp->thing_word = MAP_HEADER_FLATMAP;
mp->size = n/2;
@@ -2159,7 +2181,7 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live,
old_keys++, old_vals++, num_old--;
} else { /* Replace or insert new */
GET_TERM(new_p[1], *hp++);
- if (c > 0) { /* If new new key */
+ if (c > 0) { /* If new key */
*kp++ = new_key;
} else { /* If replacement */
*kp++ = key;