<commit_before>/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2020-2020. 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%
 */

#include "beam_asm.hpp"

extern "C"
{
#include "bif.h"
#include "beam_common.h"
#include "code_ix.h"
#include "export.h"
}

/* Global configuration variables (under the `+J` prefix) */
#ifdef HAVE_LINUX_PERF_SUPPORT
int erts_jit_perf_support;
#endif

/*
 * Special Beam instructions.
 */

BeamInstr *beam_apply;
BeamInstr *beam_normal_exit;
BeamInstr *beam_exit;
BeamInstr *beam_export_trampoline;
BeamInstr *beam_bif_export_trap;
BeamInstr *beam_continue_exit;
BeamInstr *beam_save_calls;

/* NOTE These should be the only variables containing trace instructions.
**      Sometimes tests are for the instruction value, and sometimes
**      for the variable reference (one of these), and rogue references
**      will most likely cause chaos.
*/
BeamInstr *beam_return_to_trace;   /* OpCode(i_return_to_trace) */
BeamInstr *beam_return_trace;      /* OpCode(i_return_trace) */
BeamInstr *beam_exception_trace;   /* UGLY also OpCode(i_return_trace) */
BeamInstr *beam_return_time_trace; /* OpCode(i_return_time_trace) */

static JitAllocator *jit_allocator;

static BeamGlobalAssembler *bga;
static BeamModuleAssembler *bma;
static CpuInfo cpuinfo;

static void beamasm_init_gdb_jit_info(void);

/*
 * Enter all BIFs into the export table.
 *
 * Note that they will all call the error_handler until their modules have been
 * loaded, which may prevent the system from booting if BIFs from non-preloaded
 * modules are apply/3'd while loading code. Ordinary BIF calls will work fine
 * however since they won't go through export entries.
 */
static void install_bifs(void) {
    typedef Eterm (*bif_func_type)(Process *, Eterm *, const BeamInstr *);
    int i;

    ASSERT(beam_export_trampoline != NULL);
    ASSERT(beam_save_calls != NULL);

    for (i = 0; i < BIF_SIZE; i++) {
        BifEntry *entry;
        Export *ep;
        int j;

        entry = &bif_table[i];

        ep = erts_export_put(entry->module, entry->name, entry->arity);

        ep->info.op = op_i_func_info_IaaI;
        ep->info.mfa.module = entry->module;
        ep->info.mfa.function = entry->name;
        ep->info.mfa.arity = entry->arity;
        ep->bif_number = i;

        for (j = 0; j < ERTS_NUM_CODE_IX; j++) {
            erts_activate_export_trampoline(ep, j);
        }

        /* Set up a hidden export entry so we can trap to this BIF without
         * it being seen when tracing. */
        erts_init_trap_export(&BIF_TRAP_EXPORT(i),
                              entry->module,
                              entry->name,
                              entry->arity,
                              (bif_func_type)entry->f);
    }
}

static JitAllocator *pick_allocator() {
    void *test_ro, *test_rw;
    Error err;

    /* Default to allocating pages that are both writable and executable, if at
     * all possible. This is disabled in debug builds to help catch errors
     * where we write to the executable region. */
#ifndef DEBUG
    static JitAllocator single_allocator;

    err = single_allocator.alloc(&test_ro, &test_rw, 1);
    single_allocator.release(test_ro);

    if (err == ErrorCode::kErrorOk) {
        return &single_allocator;
    }
#endif

    /* Our platform most likely disallows directly writable+executable pages,
     * try dual-mapping instead
     *
     * `blockSize` is analogous to "carrier size," and we pick something much
     * larger than the default since dual-mapping implies having one file
     * descriptor per block on most platforms. We don't want to eat up one fd
     * for every 64KB. */
    static JitAllocator::CreateParams dual_params = {
            .options = JitAllocator::kOptionUseDualMapping,
            .blockSize = 8 << 20};
    static JitAllocator dual_allocator(&dual_params);

    err = dual_allocator.alloc(&test_ro, &test_rw, 1);
    dual_allocator.release(test_ro);

    if (err == ErrorCode::kErrorOk) {
        return &dual_allocator;
    }

    ERTS_ASSERT(!"Cannot allocate executable memory. The JIT will not work,"
                 "use the interpreter instead");
}

void beamasm_init() {
    unsigned label = 1;

    ASSERT(bga == nullptr && bma == nullptr);

    struct operands {
        Eterm name;
        BeamInstr operand;
        BeamInstr **target;
    };

    std::vector<struct operands> operands = {
            {am_exit, op_error_action_code, &beam_exit},
            {am_continue_exit, op_continue_exit, &beam_continue_exit},
            {am_return_trace, op_return_trace, &beam_return_trace},
            {am_return_to_trace, op_i_return_to_trace, &beam_return_to_trace},
            {am_return_time_trace,
             op_i_return_time_trace,<commit_msg>jit: Fix build issue on Windows<commit_after>/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2020-2020. 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%
 */

#include "beam_asm.hpp"

extern "C"
{
#include "bif.h"
#include "beam_common.h"
#include "code_ix.h"
#include "export.h"
}

/* Global configuration variables (under the `+J` prefix) */
#ifdef HAVE_LINUX_PERF_SUPPORT
int erts_jit_perf_support;
#endif

/*
 * Special Beam instructions.
 */

BeamInstr *beam_apply;
BeamInstr *beam_normal_exit;
BeamInstr *beam_exit;
BeamInstr *beam_export_trampoline;
BeamInstr *beam_bif_export_trap;
BeamInstr *beam_continue_exit;
BeamInstr *beam_save_calls;

/* NOTE These should be the only variables containing trace instructions.
**      Sometimes tests are for the instruction value, and sometimes
**      for the variable reference (one of these), and rogue references
**      will most likely cause chaos.
*/
BeamInstr *beam_return_to_trace;   /* OpCode(i_return_to_trace) */
BeamInstr *beam_return_trace;      /* OpCode(i_return_trace) */
BeamInstr *beam_exception_trace;   /* UGLY also OpCode(i_return_trace) */
BeamInstr *beam_return_time_trace; /* OpCode(i_return_time_trace) */

static JitAllocator *jit_allocator;

static BeamGlobalAssembler *bga;
static BeamModuleAssembler *bma;
static CpuInfo cpuinfo;

static void beamasm_init_gdb_jit_info(void);

/*
 * Enter all BIFs into the export table.
 *
 * Note that they will all call the error_handler until their modules have been
 * loaded, which may prevent the system from booting if BIFs from non-preloaded
 * modules are apply/3'd while loading code. Ordinary BIF calls will work fine
 * however since they won't go through export entries.
 */
static void install_bifs(void) {
    typedef Eterm (*bif_func_type)(Process *, Eterm *, const BeamInstr *);
    int i;

    ASSERT(beam_export_trampoline != NULL);
    ASSERT(beam_save_calls != NULL);

    for (i = 0; i < BIF_SIZE; i++) {
        BifEntry *entry;
        Export *ep;
        int j;

        entry = &bif_table[i];

        ep = erts_export_put(entry->module, entry->name, entry->arity);

        ep->info.op = op_i_func_info_IaaI;
        ep->info.mfa.module = entry->module;
        ep->info.mfa.function = entry->name;
        ep->info.mfa.arity = entry->arity;
        ep->bif_number = i;

        for (j = 0; j < ERTS_NUM_CODE_IX; j++) {
            erts_activate_export_trampoline(ep, j);
        }

        /* Set up a hidden export entry so we can trap to this BIF without
         * it being seen when tracing. */
        erts_init_trap_export(&BIF_TRAP_EXPORT(i),
                              entry->module,
                              entry->name,
                              entry->arity,
                              (bif_func_type)entry->f);
    }
}

static JitAllocator *pick_allocator() {
    void *test_ro, *test_rw;
    Error err;

    /* Default to allocating pages that are both writable and executable, if at
     * all possible. This is disabled in debug builds to help catch errors
     * where we write to the executable region. */
#ifndef DEBUG
    static JitAllocator single_allocator;

    err = single_allocator.alloc(&test_ro, &test_rw, 1);
    single_allocator.release(test_ro);

    if (err == ErrorCode::kErrorOk) {
        return &single_allocator;
    }
#endif

    /* Our platform most likely disallows directly writable+executable pages,
     * try dual-mapping instead
     *
     * `blockSize` is analogous to "carrier size," and we pick something much
     * larger than the default since dual-mapping implies having one file
     * descriptor per block on most platforms. We don't want to eat up one fd
     * for every 64KB. */
    static JitAllocator::CreateParams dual_params = {
            /* .options = */ JitAllocator::kOptionUseDualMapping,
            /* .blockSize = */ 8 << 20};
    static JitAllocator dual_allocator(&dual_params);

    err = dual_allocator.alloc(&test_ro, &test_rw, 1);
    dual_allocator.release(test_ro);

    if (err == ErrorCode::kErrorOk) {
        return &dual_allocator;
    }

    ERTS_ASSERT(!"Cannot allocate executable memory. The JIT will not work,"
                 "use the interpreter instead");
}

void beamasm_init() {
    unsigned label = 1;

    ASSERT(bga == nullptr && bma == nullptr);

    struct operands {
        Eterm name;
        BeamInstr operand;
        BeamInstr **target;
    };

    std::vector<struct operands> operands = {
            {am_exit, op_error_action_code, &beam_exit},
            {am_continue_exit, op_continue_exit, &beam_continue_exit},
            {am_return_trace, op_return_trace, &beam_return_trace},
            {am_return_to_trace, op_i_return_to_trace, &beam_return_to_trace},
            {am_return_time_trace,
             op_i_return_time_trace,
{'fraction_non_alphanumeric': 0.09306466729147142, 'fraction_numerical': 0.004311152764761012, 'mean_word_length': 3.008640120210368, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '911323', 'n_tokens_mistral': 3404, 'n_tokens_neox': 3239, 'n_words': 986}