// -*- 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%
//
//
// Define a regular expression that will match instructions that
// perform GC. That will allow beam_makeops to check for instructions
// that don't use $REFRESH_GEN_DEST() when they should.
//
GC_REGEXP=erts_garbage_collect|erts_gc|GcBifFunction;
// $Offset is relative to the start of the instruction (not to the
// location of the failure label reference). Since combined
// instructions may increment the instruction pointer (e.g. in
// 'increment') for some of the instructions in the group, we actually
// use a virtual start position common to all instructions in the
// group. To calculate the correct virtual position, we will need to
// add $IP_ADJUSTMENT to the offset. ($IP_ADJUSTMENT will usually be
// zero, except in a few bit syntax instructions.)
SET_I_REL(Offset) {
ASSERT(VALID_INSTR(*(I + ($Offset) + $IP_ADJUSTMENT)));
I += $Offset + $IP_ADJUSTMENT;
}
SET_CP_I_ABS(Target) {
c_p->i = $Target;
ASSERT(VALID_INSTR(*c_p->i));
}
SET_REL_I(Dst, Offset) {
$Dst = I + ($Offset);
ASSERT(VALID_INSTR(*$Dst));
}
FAIL(Fail) {
//| -no_prefetch
$SET_I_REL($Fail);
Goto(*I);
}
JUMP(Fail) {
//| -no_next
$SET_I_REL($Fail);
Goto(*I);
}
GC_TEST(Ns, Nh, Live) {
Uint need = $Nh + $Ns;
if (ERTS_UNLIKELY(E - HTOP < need)) {
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, $Live, FCALLS);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
SWAPIN;
}
HEAP_SPACE_VERIFIED($Nh);
}
GC_TEST_PRESERVE(NeedHeap, Live, PreserveTerm) {
Uint need = $NeedHeap;
if (ERTS_UNLIKELY(E - HTOP < need)) {
SWAPOUT;
reg[$Live] = $PreserveTerm;
PROCESS_MAIN_CHK_LOCKS(c_p);
FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, $Live+1, FCALLS);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
$PreserveTerm = reg[$Live];
SWAPIN;
}
HEAP_SPACE_VERIFIED($NeedHeap);
}
// Make sure that there are NeedStack + NeedHeap + 1 words available
// on the combined heap/stack segment, then allocates NeedHeap + 1
// words on the stack and saves CP.
AH(NeedStack, NeedHeap, Live) {
unsigned needed = $NeedStack + 1;
$GC_TEST(needed, $NeedHeap, $Live);
E -= needed;
*E = make_cp(c_p->cp);
c_p->cp = 0;
}
NEXT0() {
//| -no_next
SET_I((BeamInstr *) $NEXT_INSTRUCTION);
Goto(*I);
}
NEXT(Addr) {
//| -no_next
SET_I((BeamInstr *) $Addr);
Goto(*I);
}
FAIL_BODY() {
//| -no_prefetch
goto find_func_info;
}
FAIL_HEAD_OR_BODY(Fail) {
//| -no_prefetch
/*
* In a correctly working program, we expect failures in
* guards to be more likely than failures in bodies.
*/
if (ERTS_LIKELY($Fail)) {
$FAIL($Fail);
}
goto find_func_info;
}
BADARG(Fail) {
c_p->freason = BADARG;
$FAIL_HEAD_OR_BODY($Fail);
}
BADARITH0() {
c_p->freason = BADARITH;
goto find_func_info;
}
SYSTEM_LIMIT(Fail) {
c_p->freason = SYSTEM_LIMIT;
$FAIL_HEAD_OR_BODY($Fail);
}
BIF_ERROR_ARITY_1(Fail, BIF, Op1) {
//| -no_prefetch
if (ERTS_LIKELY($Fail)) {
$FAIL($Fail);
}
reg[0] = $Op1;
SWAPOUT;
I = handle_error(c_p, I, reg, &bif_export[$BIF]->info.mfa);
goto post_error_handling;
}
BIF_ERROR_ARITY_2(Fail, BIF, Op1, Op2) {
//| -no_prefetch
if (ERTS_LIKELY($Fail)) {
$FAIL($Fail);
}
reg[0] = $Op1;
reg[1] = $Op2;
SWAPOUT;
I = handle_error(c_p, I, reg, &bif_export[$BIF]->info.mfa);
goto post_error_handling;
}