// -*- c -*-
//
// %CopyrightBegin%
//
// Copyright Ericsson AB 2017. 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// %CopyrightEnd%
//
return_trace() {
ErtsCodeMFA* mfa = (ErtsCodeMFA *)(E[0]);
SWAPOUT; /* Needed for shared heap */
ERTS_UNREQ_PROC_MAIN_LOCK(c_p);
erts_trace_return(c_p, mfa, r(0), ERTS_TRACER_FROM_ETERM(E+1)/* tracer */);
ERTS_REQ_PROC_MAIN_LOCK(c_p);
SWAPIN;
c_p->cp = NULL;
SET_I((BeamInstr *) cp_val(E[2]));
E += 3;
Goto(*I);
//| -no_next
}
i_generic_breakpoint() {
BeamInstr real_I;
HEAVY_SWAPOUT;
real_I = erts_generic_breakpoint(c_p, erts_code_to_codeinfo(I), reg);
HEAVY_SWAPIN;
ASSERT(VALID_INSTR(real_I));
Goto(real_I);
//| -no_next
}
i_return_time_trace() {
BeamInstr *pc = (BeamInstr *) (UWord) E[0];
SWAPOUT;
erts_trace_time_return(c_p, erts_code_to_codeinfo(pc));
SWAPIN;
c_p->cp = NULL;
SET_I((BeamInstr *) cp_val(E[1]));
E += 2;
Goto(*I);
//| -no_next
}
i_return_to_trace() {
if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO)) {
Uint *cpp = (Uint*) E;
for(;;) {
ASSERT(is_CP(*cpp));
if (IsOpCode(*cp_val(*cpp), return_trace)) {
do
++cpp;
while (is_not_CP(*cpp));
cpp += 2;
} else if (IsOpCode(*cp_val(*cpp), i_return_to_trace)) {
do
++cpp;
while (is_not_CP(*cpp));
} else {
break;
}
}
SWAPOUT; /* Needed for shared heap */
ERTS_UNREQ_PROC_MAIN_LOCK(c_p);
erts_trace_return_to(c_p, cp_val(*cpp));
ERTS_REQ_PROC_MAIN_LOCK(c_p);
SWAPIN;
}
c_p->cp = NULL;
SET_I((BeamInstr *) cp_val(E[0]));
E += 1;
Goto(*I);
//| -no_next
}
i_yield() {
/* This is safe as long as REDS_IN(c_p) is never stored
* in c_p->arg_reg[0]. It is currently stored in c_p->def_arg_reg[5].
*/
c_p->arg_reg[0] = am_true;
c_p->arity = 1; /* One living register (the 'true' return value) */
SWAPOUT;
$SET_CP_I_ABS($NEXT_INSTRUCTION);
c_p->current = NULL;
goto do_schedule;
//| -no_next
}
i_hibernate() {
HEAVY_SWAPOUT;
if (erts_hibernate(c_p, reg)) {
FCALLS = c_p->fcalls;
c_p->flags &= ~F_HIBERNATE_SCHED;
goto do_schedule;
} else {
HEAVY_SWAPIN;
I = handle_error(c_p, I, reg, &bif_export[BIF_hibernate_3]->info.mfa);
goto post_error_handling;
}
//| -no_next
}
// This is optimised as an instruction because
// it has to be very very fast.
i_perf_counter() {
ErtsSysPerfCounter ts;
ts = erts_sys_perf_counter();
if (IS_SSMALL(ts)) {
r(0) = make_small((Sint)ts);
} else {
$GC_TEST(0, ERTS_SINT64_HEAP_SIZE(ts), 0);
r(0) = make_big(HTOP);
#if defined(ARCH_32)
if (ts >= (((Uint64) 1) << 32)) {
*HTOP = make_pos_bignum_header(2);
BIG_DIGIT(HTOP, 0) = (Uint) (ts & ((Uint) 0xffffffff));
BIG_DIGIT(HTOP, 1) = (Uint) ((ts >> 32) & ((Uint) 0xffffffff));
HTOP += 3;
}
else
#endif
{
*HTOP = make_pos_bignum_header(1);
BIG_DIGIT(HTOP, 0) = (Uint) ts;
HTOP += 2;
}
}
}
i_debug_breakpoint() {
HEAVY_SWAPOUT;
I = call_error_handler(c_p, erts_code_to_codemfa(I), reg, am_breakpoint);
HEAVY_SWAPIN;
if (I) {
Goto(*I);
}
goto handle_error;
//| -no_next
}
//
// Special jump instruction used for tracing. Takes an absolute
// failure address.
//
trace_jump(Fail) {
//| -no_next
SET_I((BeamInstr *) $Fail);
Goto(*I);
}