py/emitnative: Add support for archs that cannot read executable data.

In which case place the native function prelude in a bytes object, linked
from the const_table of that function.  An architecture should define
N_PRELUDE_AS_BYTES_OBJ to 1 before including py/emitnative.c to emit
correct machine code, then enable MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ
so the runtime can correctly handle the prelude being in a bytes object.
This commit is contained in:
Damien George 2019-09-10 13:47:24 +10:00
parent 3504edc804
commit 306ec5369a
2 changed files with 36 additions and 0 deletions

View File

@ -48,6 +48,7 @@
#include "py/emit.h"
#include "py/bc.h"
#include "py/objstr.h"
#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
@ -92,6 +93,7 @@
#define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_t, ip) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_t, sp) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t))
// If not already defined, set parent args to same as child call registers
@ -333,7 +335,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
emit->pass = pass;
emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER;
emit->stack_size = 0;
#if N_PRELUDE_AS_BYTES_OBJ
emit->const_table_cur_obj = emit->do_viper_types ? 0 : 1; // reserve first obj for prelude bytes obj
#else
emit->const_table_cur_obj = 0;
#endif
emit->const_table_cur_raw_code = 0;
#if MICROPY_PERSISTENT_CODE_SAVE
emit->qstr_link_cur = 0;
@ -483,7 +489,12 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
emit->code_state_start = 0;
emit->stack_start = SIZEOF_CODE_STATE;
#if N_PRELUDE_AS_BYTES_OBJ
// Load index of prelude bytes object in const_table
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)(emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1));
#else
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset);
#endif
mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset);
ASM_ENTRY(emit->as, SIZEOF_NLR_BUF);
@ -528,8 +539,17 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
// Set code_state.ip (offset from start of this function to prelude info)
#if N_PRELUDE_AS_BYTES_OBJ
// Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1);
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t));
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE);
ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1);
emit_native_mov_state_reg(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, REG_LOCAL_3);
#else
// TODO this encoding may change size in the final pass, need to make it fixed
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1);
#endif
// Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)
emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1);
@ -634,6 +654,16 @@ STATIC void emit_native_end_pass(emit_t *emit) {
}
}
emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start;
#if N_PRELUDE_AS_BYTES_OBJ
// Prelude bytes object is after qstr arg names and mp_fun_table
size_t table_off = emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1;
if (emit->pass == MP_PASS_EMIT) {
void *buf = emit->as->base.code_base + emit->prelude_offset;
size_t n = emit->as->base.code_offset - emit->prelude_offset;
emit->const_table[table_off] = (uintptr_t)mp_obj_new_bytes(buf, n);
}
#endif
}
ASM_END_PASS(emit->as);

View File

@ -30,6 +30,7 @@
#include "py/runtime.h"
#include "py/bc.h"
#include "py/objstr.h"
#include "py/objgenerator.h"
#include "py/objfun.h"
#include "py/stackctrl.h"
@ -88,6 +89,11 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
// Determine start of prelude, and extract n_state from it
uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0];
#if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ
// Prelude is in bytes object in const_table, at index prelude_offset
mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]);
prelude_offset = (const byte*)prelude_bytes->data - self_fun->bytecode;
#endif
const uint8_t *ip = self_fun->bytecode + prelude_offset;
size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args;
MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args);