aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/beam_emu.c11
-rw-r--r--erts/emulator/beam/bif.c16
-rw-r--r--erts/emulator/beam/bif.h6
-rw-r--r--erts/emulator/beam/erl_gc.c4
-rw-r--r--erts/emulator/beam/global.h1
5 files changed, 30 insertions, 8 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 16741aa2d7..88ac6cffb1 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1017,8 +1017,6 @@ static BeamInstr* call_error_handler(Process* p, BeamInstr* ip,
static BeamInstr* fixed_apply(Process* p, Eterm* reg, Uint arity) NOINLINE;
static BeamInstr* apply(Process* p, Eterm module, Eterm function,
Eterm args, Eterm* reg) NOINLINE;
-static int hibernate(Process* c_p, Eterm module, Eterm function,
- Eterm args, Eterm* reg) NOINLINE;
static BeamInstr* call_fun(Process* p, int arity,
Eterm* reg, Eterm args) NOINLINE;
static BeamInstr* apply_fun(Process* p, Eterm fun,
@@ -3393,6 +3391,9 @@ void process_main(void)
r(0) = c_p->def_arg_reg[0];
x(1) = c_p->def_arg_reg[1];
x(2) = c_p->def_arg_reg[2];
+ if (c_p->status == P_WAITING) {
+ goto do_schedule;
+ }
Dispatch();
}
reg[0] = r(0);
@@ -5191,7 +5192,7 @@ void process_main(void)
OpCase(i_hibernate): {
SWAPOUT;
- if (hibernate(c_p, r(0), x(1), x(2), reg)) {
+ if (erts_hibernate(c_p, r(0), x(1), x(2), reg)) {
goto do_schedule;
} else {
I = handle_error(c_p, I, reg, hibernate_3);
@@ -6178,8 +6179,8 @@ fixed_apply(Process* p, Eterm* reg, Uint arity)
return ep->address;
}
-static int
-hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg)
+int
+erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Eterm tmp;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index bb237e378a..5cf3f523b8 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1091,10 +1091,20 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
BIF_RETTYPE hibernate_3(BIF_ALIST_3)
{
/*
- * hibernate/3 is implemented as an instruction; therefore
- * this function will never be called.
+ * hibernate/3 is usually translated to an instruction; therefore
+ * this function is only called from HiPE or when the call could not
+ * be translated.
*/
- BIF_ERROR(BIF_P, BADARG);
+ Eterm reg[3];
+
+ if (erts_hibernate(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, reg)) {
+ /*
+ * If hibernate succeeded, TRAP. The process will be suspended
+ * if status is P_WAITING or continue (if any message was in the queue).
+ */
+ BIF_TRAP_CODE_PTR_(BIF_P, BIF_P->i);
+ }
+ return THE_NON_VALUE;
}
/**********************************************************************/
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index a84ee7bb23..615714f7f4 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -201,6 +201,12 @@ do { \
return THE_NON_VALUE; \
} while(0)
+#define BIF_TRAP_CODE_PTR_(p, Code_) do { \
+ *((UWord *) (UWord) ((p)->def_arg_reg + 3)) = (UWord) (Code_); \
+ (p)->freason = TRAP; \
+ return THE_NON_VALUE; \
+ } while(0)
+
extern Export bif_return_trap_export;
#ifdef DEBUG
#define ERTS_BIF_PREP_YIELD_RETURN_X(RET, P, VAL, DEBUG_VAL) \
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 2aa932e7d1..1a405e0c4d 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -33,6 +33,7 @@
#include "erl_gc.h"
#if HIPE
#include "hipe_stack.h"
+#include "hipe_mode_switch.h"
#endif
#define ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT 1
@@ -486,6 +487,9 @@ erts_garbage_collect_hibernate(Process* p)
htop = heap;
n = setup_rootset(p, p->arg_reg, p->arity, &rootset);
+#if HIPE
+ hipe_empty_nstack(p);
+#endif
src = (char *) p->heap;
src_size = (char *) p->htop - src;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index e8a9d5f32f..42aafe6ac6 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1664,6 +1664,7 @@ Uint erts_current_reductions(Process* current, Process *p);
int erts_print_system_version(int to, void *arg, Process *c_p);
+int erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg);
#define seq_trace_output(token, msg, type, receiver, process) \
seq_trace_output_generic((token), (msg), (type), (receiver), (process), NIL)
#define seq_trace_output_exit(token, msg, type, receiver, exitfrom) \