From 25fe3fb23c594d735cb6ebae120910e44f0cdae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 26 Jun 2019 15:49:48 +0200 Subject: Optimize continuation pointer management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BEAM instructions for calling a function don't save the continuation pointer (return address) on the stack, but to a special BEAM register called CP. It is the responsibility of the called function to save CP to the stack frame before calling other functions. In the earlier implementations of BEAM on Sparc, CP was located in a CPU register. That meant that the continuation pointer was never written to memory when calling simple functions that didn't call other functions at all or ended in a tail-call to another function. The modern BEAM no longer keeps CP in CPU register. Instead, it is kept in the `process` struct (in `p->cp`). That means the continuation pointer must be written to the memory on every call, and if the called function will call other functions, it will must read the continuation pointer from `p->cp` and store it on the stack. This commit eliminates the concept of the CP register and modifies the call instructions to directly store the continuation pointer on the stack. That makes allocation and trimming of stack frames slightly faster. A more important benefit is simplification of code that handles continuation pointers. Because all continuation pointers are now stored on the stack, the special case of handling `p->cp` disappears. Co-authored-by: John Högberg --- erts/emulator/beam/erl_nif.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'erts/emulator/beam/erl_nif.c') diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index ce43cb9e71..46f7e864fd 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -334,7 +334,7 @@ schedule(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirect_fp, ep = erts_nif_export_schedule(c_p, dirty_shadow_proc, c_p->current, - c_p->cp, + cp_val(c_p->stop[0]), BeamOpCodeAddr(op_call_nif), direct_fp, indirect_fp, mod, func_name, @@ -4117,7 +4117,6 @@ static struct erl_module_nif* create_lib(const ErlNifEntry* src) return lib; }; - BIF_RETTYPE load_nif_2(BIF_ALIST_2) { static const char bad_lib[] = "bad_lib"; @@ -4140,6 +4139,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) struct erl_module_nif* lib = NULL; struct erl_module_instance* this_mi; struct erl_module_instance* prev_mi; + BeamInstr* caller_cp; if (BIF_P->flags & F_HIPE_MODE) { ret = load_nif_error(BIF_P, "notsup", "Calling load_nif from HiPE compiled " @@ -4175,7 +4175,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ASSERT(BIF_P->current->module == am_erlang && BIF_P->current->function == am_load_nif && BIF_P->current->arity == 2); - caller = find_function_from_pc(BIF_P->cp); + caller_cp = cp_val(BIF_P->stop[0]); + caller = find_function_from_pc(caller_cp); ASSERT(caller != NULL); mod_atom = caller->module; ASSERT(is_atom(mod_atom)); -- cgit v1.2.3