microPython的源码解析之 emitinlinethumb.c

本文深入解析MicroPython的源码文件emitinlinethumb.c,介绍了函数表及其对应操作,涵盖了编译过程中的加载、存储、跳转、异常处理等关键步骤,并提供了执行逻辑流程图。通过对MicroPython最小内核的分析,帮助读者理解Python编译器的核心实现逻辑。
摘要由CSDN通过智能技术生成

MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.

microPython Python最小内核源码解析
以下是对代码中英文注释的翻译和补充,以及重新输出的代码:

#include <stdio.h>
#include <string.h>
#include <assert.h>

// 包含 MicroPython 发射(emit)相关的头文件
#include "py/emit.h"
#include "py/nativeglue.h"
#include "py/objfun.h"
#include "py/objstr.h"

// 调试信息打印,当启用详细调试模式时
#if MICROPY_DEBUG_VERBOSE // 打印调试信息
#define DEBUG_PRINT (1)
#define DEBUG_printf DEBUG_printf
#else // 不打印调试信息
#define DEBUG_printf(...) (void)0
#endif

// 各种架构下的 C 栈布局
#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN

// 原生函数的 C 栈布局:
//  0:                          nlr_buf_t [可选]
//                              return_value [可选字] 
//                              exc_handler_unwind [可选字]
//  emit->code_state_start:     mp_code_state_native_t
//  emit->stack_start:          Python 对象栈             | emit->n_state
//                              locals (reversed, L0 在末尾)    
//
// 原生生成器函数的 C 栈布局:
//  0=emit->stack_start:        nlr_buf_t
//                              return_value
//                              exc_handler_unwind [可选字]
//
//  viper 函数的 C 栈布局:
//  0:                          nlr_buf_t [可选]
//                              return_value [可选字]
//                              exc_handler_unwind [可选字]
//  emit->code_state_start:     fun_obj, old_globals [可选]
//  emit->stack_start:          Python 对象栈             | emit->n_state
//                              locals (reversed, L0 在末尾)    
//                              (L0-L2 可能在寄存器中)

// 原生发射器需要知道以下 C 结构体的大小和偏移(在目标平台上)
#if MICROPY_DYNAMIC_COMPILER
#define SIZEOF_NLR_BUF (2 + mp_dynamic_compiler.nlr_buf_num_regs + 1) // 保守估计,如果启用了 MICROPY_ENABLE_PYSTACK
#else
#define SIZEOF_NLR_BUF (sizeof(nlr_buf_t) / sizeof(uintptr_t))
#endif
#define SIZEOF_CODE_STATE (sizeof(mp_code_state_native_t) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_STATE (offsetof(mp_code_state_native_t, state) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_FUN_BC (offsetof(mp_code_state_native_t, fun_bc) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_native_t, ip) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_native_t, sp) / sizeof(uintptr_t))
#define OFFSETOF_CODE_STATE_N_STATE (offsetof(mp_code_state_native_t, n_state) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_CONTEXT (offsetof(mp_obj_fun_bc_t, context) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_CHILD_TABLE (offsetof(mp_obj_fun_bc_t, child_table) / sizeof(uintptr_t))
#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t))
#define OFFSETOF_MODULE_CONTEXT_QSTR_TABLE (offsetof(mp_module_context_t, constants.qstr_table) / sizeof(uintptr_t))
#define OFFSETOF_MODULE_CONTEXT_OBJ_TABLE (offsetof(mp_module_context_t, constants.obj_table) / sizeof(uintptr_t))
#define OFFSETOF_MODULE_CONTEXT_GLOBALS (offsetof(mp_module_context_t, module.globals) / sizeof(uintptr_t))

// 如果尚未定义,则将父参数设置为与子调用寄存器相同
#ifndef REG_PARENT_RET
#define REG_PARENT_RET REG_RET
#define REG_PARENT_ARG_1 REG_ARG_1
#define REG_PARENT_ARG_2 REG_ARG_2
#define REG_PARENT_ARG_3 REG_ARG_3
#define REG_PARENT_ARG_4 REG_ARG_4
#endif

// nlr_buf_t.ret_val 的字索引
#define NLR_BUF_IDX_RET_VAL (1)

// viper 函数是否需要访问 fun_obj
#define NEED_FUN_OBJ(emit) ((emit)->scope->exc_stack_size > 0 \
    || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS)))

// 原生/viper 函数是否需要用异常处理器包装
#define NEED_GLOBAL_EXC_HANDLER(emit) ((emit)->scope->exc_stack_size > 0 \
    || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_REFGLOBALS)))

// 是否需要一个槽来存储 LOCAL_IDX_EXC_HANDLER_UNWIND
#define NEED_EXC_HANDLER_UNWIND(emit) ((emit)->scope->exc_stack_size > 0)

// 是否可以使用寄存器来存储局部变量(只有在没有异常处理器的情况下才为真,因为否则 nlr_jump 会将寄存器恢复到函数开始时的状态,局部变量的更新将会丢失)
#define CAN_USE_REGS_FOR_LOCALS(emit) ((emit)->scope->exc_stack_size == 0 && !(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR))

// 本地 C 栈中各种变量的索引
#define LOCAL_IDX_EXC_VAL(emit) (NLR_BUF_IDX_RET_VAL)
#define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1)
#define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (SIZEOF_NLR_BUF + 1) // 这需要一个独立的变量,不在 nlr_buf_t 中
#define LOCAL_IDX_RET_VAL(emit) (SIZEOF_NLR_BUF) // 当 NEED_GLOBAL_EXC_HANDLER 为真时需要
#define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_FUN_BC)
#define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)
#define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)
#define LOCAL_IDX_LOCAL_VAR(emit, local_num) ((emit)->stack_start + (emit)->n_state - 1 - (local_num))

#if MICROPY_PERSISTENT_CODE_SAVE

// 当启用保存原生代码到 .mpy 文件的能力时:
//  - Qstrs 通过 qstr_table 间接访问,REG_LOCAL_3 始终指向 qstr_table。
//  - 在生成器中不使用寄存器来存储局部变量,REG_LOCAL_2 指向生成器状态。
//  - 最多有 2 个寄存器保存局部变量(参见 CAN_USE_REGS_FOR_LOCALS 了解何时可能)。

#define REG_GENERATOR_STATE (REG_LOCAL_2)
#define REG_QSTR_TABLE (REG_LOCAL_3)
#define MAX_REGS_FOR_LOCAL_VARS (2)

static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {
   REG_LOCAL_1, REG_LOCAL_2};

#else

// 当未启用保存原生代码到 .mpy 文件的能力时:
//  - Qstrs 值直接写入机器代码。
//  - 在生成器中不使用寄存器来存储局部变量,REG_LOCAL_3 指向生成器状态。
//  - 最多有 3 个寄存器保存局部变量(参见 CAN_USE_REGS_FOR_LOCALS 了解何时可能)。

#define REG_GENERATOR_STATE (REG_LOCAL_3)
#define MAX_REGS_FOR_LOCAL_VARS (3)

static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {
   REG_LOCAL_1, REG_LOCAL_2, REG_LOCAL_3};

#endif

#define REG_LOCAL_LAST (reg_local_table[MAX_REGS_FOR_LOCAL_VARS - 1])

#define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do {
      \
        *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \
} while (0)

// 堆栈信息类型
typedef enum {
   
    STACK_VALUE,
    STACK_REG,
    STACK_IMM,
} stack_info_kind_t;

// 这些枚举必须是不同的,并且最低 4 位必须对应正确的 MP_NATIVE_TYPE_xxx 值
typedef enum {
   
    VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ,
    VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL,
    VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT,
    VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT,
    VTYPE_PTR = 0x00 | MP_NATIVE_TYPE_PTR,
    VTYPE_PTR8 = 0x00 | MP_NATIVE_TYPE_PTR8,
    VTYPE_PTR16 = 0x00 | MP_NATIVE_TYPE_PTR16,
    VTYPE_PTR32 = 0x00 | MP_NATIVE_TYPE_PTR32,

    VTYPE_PTR_NONE = 0x50 | MP_NATIVE_TYPE_PTR,

    VTYPE_UNBOUND = 0x60 | MP_NATIVE_TYPE_OBJ,
    VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ,
} vtype_kind_t;

// 将 vtype 转换为 qstr
static qstr vtype_to_qstr(vtype_kind_t vtype) {
   
    switch (vtype) {
   
        case VTYPE_PYOBJ:
            return MP_QSTR_object;
        case VTYPE_BOOL:
            return MP_QSTR_bool;
        case VTYPE_INT:
            return MP_QSTR_int;
        case VTYPE_UINT:
            return MP_QSTR_uint;
        case VTYPE_PTR:
            return MP_QSTR_ptr;
        case VTYPE_PTR8:
            return MP_QSTR_ptr8;
        case VTYPE_PTR16:
            return MP_QSTR_ptr16;
        case VTYPE_PTR32:
            return MP_QSTR_ptr32;
        case VTYPE_PTR_NONE:
        default:
            return MP_QSTR_None;
    }
}

// 堆栈信息结构体
typedef struct _stack_info_t {
   
    vtype_kind_t vtype; // 值类型
    stack_info_kind_t kind; // 堆栈信息类型
    union {
   
        int u_reg;
        mp_int_t u_imm;
    } data; // 数据
} stack_info_t;

// 异常栈条目结构体
typedef struct _exc_stack_entry_t {
   
    uint16_t label : 15; // 标签
    uint16_t is_finally : 1; // 是否为 finally 块
    uint16_t unwind_label : 15; // 展开标签
    uint16_t is_active : 1; // 是否激活
} exc_stack_entry_t;

// 发射器结构体
struct _emit_t {
   
    mp_emit_common_t *emit_common; // 通用发射器
    mp_obj_t *error_slot; // 错误槽
    uint *label_slot; // 标签槽
    uint exit_label; // 退出标签
    int pass; // 遍历次数

    bool do_viper_types; // 是否使用 viper 类型

    mp_uint_t local_vtype_alloc; // 本地变量类型分配
    vtype_kind_t *local_vtype; // 本地变量类型

    mp_uint_t stack_info_alloc; // 堆栈信息分配
    stack_info_t *stack_info; // 堆栈信息
    vtype_kind_t saved_stack_vtype; // 保存的堆栈值类型

    size_t exc_stack_alloc; // 异常栈分配
    size_t exc_stack_size; // 异常栈大小
    exc_stack_entry_t *exc_stack; // 异常栈

    int prelude_offset; // 前奏偏移
    int prelude_ptr_index; // 前奏指针索引
    int start_offset; // 开始偏移
    int n_state; // 状态数量
    uint16_t code_state_start; // 代码状态起始
    uint16_t stack_start; // 栈起始
    int stack_size; // 栈大小
    uint16_t n_info; // 信息数量
    uint16_t n_cell; // 单元格数量

    scope_t *scope; // 作用域

    ASM_T *as; // 汇编对象
};

// 从对象中加载寄存器
static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj);
// 进入原生全局异常处理
static void emit_native_global_exc_entry(emit_t *emit);
// 退出原生全局异常处理
static void emit_native_global_exc_exit(emit_t *emit);
// 加载常量对象
static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj);

emit_t *EXPORT_FUN(new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) {
   
    // 创建并初始化新的发射器
    emit_t *emit = m_new0(emit_t, 1);
    emit->emit_common = emit_common;
    emit->error_slot = error_slot;
    emit->label_slot = label_slot;
    emit->stack_info_alloc = 8;
    emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
    emit->exc_stack_alloc = 8;
    emit->exc_stack = m_new(exc_stack_entry_t, emit->exc_stack_alloc);
    emit->as = m_new0(ASM_T, 1);
    mp_asm_base_init(&emit->as->base, max_num_labels);
    return emit;
}

// 释放发射器资源
void EXPORT_FUN(free)(emit_t * emit) {
   
    mp_asm_base_deinit(&emit->as->base, false);
    m_del_obj(ASM_T, emit->as);
    m_del(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc);
    m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);
    m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);
    m_del_obj(emit_t, emit);
}

// 调用带有立即数参数的函数
static void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg);

// 将寄存器移动到常量
static void emit_native_mov_reg_const(emit_t *emit, int reg_dest, int const_val) {
   
    ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_FUN_TABLE, const_val);
}

// 将本地变量从寄存器移动到状态
static void emit_native_mov_state_reg(emit_t *emit, int local_num, int reg_src) {
   
    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
   
        ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, REG_GENERATOR_STATE, local_num);
    } else {
   
        ASM_MOV_LOCAL_REG(emit->as, local_num, reg_src);
    }
}

// 将状态从寄存器移动到本地变量
static void emit_native_mov_reg_state(emit_t *emit, int reg_dest, int local_num) {
   
    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
   
        ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_GENERATOR_STATE, local_num);
    } else {
   
        ASM_MOV_REG_LOCAL(emit->as, reg_dest, local_num);
    }
}

// 将状态地址从寄存器移动到本地变量
static void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local_num) {
   
    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
   
        ASM_MOV_REG_IMM(emit->as, reg_dest, local_num * ASM_WORD_SIZE);
        ASM_ADD_REG_REG(emit->as, reg_dest, REG_GENERATOR_STATE);
    } else {
   
        ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, local_num);
    }
}

// 将 qstr 从寄存器移动到本地变量
static void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) {
   
    #if MICROPY_PERSISTENT_CODE_SAVE
    ASM_LOAD16_REG_REG_OFFSET(emit->as, arg_reg, REG_QSTR_TABLE, mp_emit_common_use_qstr(emit->emit_common, qst));
    #else
    ASM_MOV_REG_IMM(emit->as, arg_reg, qst);
    #endif
}

// 将 qstr 对象从寄存器移动到本地变量
static void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) {
   
    #if MICROPY_PERSISTENT_CODE_SAVE
    emit_load_reg_with_object(emit, reg_dest, MP_OBJ_NEW_QSTR(qst));
    #else
    ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst));
    #endif
}

// 通过寄存器移动状态中的立即数
#define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \
    do {
      \
        ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \
        emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
    } while (false)

// 开始一个新的作用域遍历
static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
   
    DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);

    emit->pass = pass;
    emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER;
    emit->stack_size = 0;
    emit->scope = scope;

    // 为本地变量分配类型跟踪内存
    if (emit->local_vtype_alloc < scope->num_locals) {
   
        emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals);
        emit->local_vtype_alloc = scope->num_locals;
    }

    // 设置参数的默认类型
    mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args;
    if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
   
        num_args += 1;
    }
    if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) {
   
        num_args += 1;
    }
    for (mp_uint_t i = 0; i < num_args; i++) {
   
        emit->local_vtype[i] = VTYPE_PYOBJ;
    }

    // 为参数设置 viper 类型
    if (emit->do_viper_types) {
   
        for (int i = 0; i < emit->scope->id_info_len; ++i) {
   
            id_info_t *id = &emit->scope->id_info[i];
            if (id->flags & ID_FLAG_IS_PARAM) {
   
                assert(id->local_num < emit->local_vtype_alloc);
                emit->local_vtype[id->local_num] = id->flags >> ID_FLAG_VIPER_TYPE_POS;
            }
        }
    }

    // 本地变量开始时未绑定,类型未知
    for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) {
   
        emit->local_vtype[i] = emit->do_viper_types ? VTYPE_UNBOUND : VTYPE_PYOBJ;
    }

    // 堆栈上的值开始时未绑定
    for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) {
   
        emit->stack_info[i].kind = STACK_VALUE;
        emit->stack_info[i].vtype = VTYPE_UNBOUND;
    }

    mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);

    // 生成函数入口代码

    // 计算代码状态的起始位置(mp_code_state_native_t 或 viper 的简化版本)
    emit->code_state_start = 0;
    if (NEED_GLOBAL_EXC_HANDLER(emit)) {
   
        emit->code_state_start = SIZEOF_NLR_BUF; // 为 nlr_buf_t 保留
        emit->code_state_start += 1;  // 为 return_value 保留
        if (NEED_EXC_HANDLER_UNWIND(emit)) {
   
            emit->code_state_start += 1;
        }
    }

    size_t fun_table_off = mp_emit_common_use_const_obj(emit->emit_common, MP_OBJ_FROM_PTR(&mp_fun_table));

    if (emit->do_viper_types) {
   
        // 计算状态大小(局部变量加上堆栈)
        // n_state 计算所有堆栈和局部变量,即使在寄存器中的也算
        emit->n_state = scope->num_locals + scope->stack_size;
        int num_locals_in_regs = 0;
        if (CAN_USE_REGS_FOR_LOCALS(emit)) {
   
            num_locals_in_regs = scope->num_locals;
            if (num_locals_in_regs > MAX_REGS_FOR_LOCAL_VARS) {
   
                num_locals_in_regs = MAX_REGS_FOR_LOCAL_VARS;
            }
            // 需要一个寄存器用于 REG_LOCAL_LAST(见下文)
            if (scope->num_pos_args >= MAX_REGS_FOR_LOCAL_VARS + 1) {
   
                --num_locals_in_regs;
            }
        }

        // 计算局部变量和 Python 堆栈在 C 栈中的起始位置
        if (NEED_GLOBAL_EXC_HANDLER(emit)) {
   
            // 为函数对象和旧全局变量保留 2 个字
            emit->stack_start = emit->code_state_start + 2;
        } else if (scope->scope_flags & MP_SCOPE_FLAG_HASCONSTS) {
   
            // 为函数对象保留 1 个字,用于访问常量表
            emit->stack_start = emit->code_state_start + 1;
        } else {
   
            emit->stack_start = emit->code_state_start + 0;
        }

        // 函数入口
        ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs);

        #if N_X86
        asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
        #endif

        // 将 REG_FUN_TABLE 载入 mp_fun_table 指针,该指针在 const_table 中找到
        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
        #if MICROPY_PERSISTENT_CODE_SAVE
        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
        #endif
        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, fun_table_off);

        // 将函数对象(作为第一个参数传递)存储到堆栈上,如果需要的话
        if (NEED_FUN_OBJ(emit)) {
   
            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
        }

        // 将 n_args 放入 REG_ARG_1,n_kw 放入 REG_ARG_2,args 数组放入 REG_LOCAL_LAST
        #if N_X86
        asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1);
        asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2);
        asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_LAST);
        #else
        ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2);
        ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3);
        ASM_MOV_REG_REG(emit->as, REG_LOCAL_LAST, REG_PARENT_ARG_4);
        #endif

        // 检查参数数量是否与此函数匹配,如果不匹配则调用 mp_arg_check_num_sig
        ASM_JUMP_IF_REG_NONZERO(emit->as, REG_ARG_2, *emit->label_slot + 4, true);
        ASM_MOV_REG_IMM(emit->as, REG_ARG_3, scope->num_pos_args);
        ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_3, *emit->label_slot + 5);
        mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 4);
        ASM_MOV_REG_IMM(emit->as, REG_ARG_3, MP_OBJ_FUN_MAKE_SIG(scope->num_pos_args, scope->num_pos_args, false));
        ASM_CALL_IND(emit->as, MP_F_ARG_CHECK_NUM_SIG);
        mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 5);

        // 将参数存储到局部变量中(寄存器或堆栈),如果需要则转换为本地类型
        for (int i = 0; i < emit->scope->num_pos_args; i++) {
   
            int r = REG_ARG_1;
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_LOCAL_LAST, i);
            if (emit->local_vtype[i] != VTYPE_PYOBJ) {
   
                emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, emit->local_vtype[i], REG_ARG_2);
                r = REG_RET;
            }
            // REG_LOCAL_LAST 指向 args 数组,因此如果还需要它,请不要覆盖它
            if (i < MAX_REGS_FOR_LOCAL_VARS && CAN_USE_REGS_FOR_LOCALS(emit) && (i != MAX_REGS_FOR_LOCAL_VARS - 1 || emit->scope->num_pos_args == MAX_REGS_FOR_LOCAL_VARS)) {
   
                ASM_MOV_REG_REG(emit->as, reg_local_table[i], r);
            } else {
   
                emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, i), r);
            }
        }
        // 如果这个寄存器不能再写入,则从堆栈中获取局部变量并放回 REG_LOCAL_LAST
        if (emit->scope->num_pos_args >= MAX_REGS_FOR_LOCAL_VARS + 1 && CAN_USE_REGS_FOR_LOCALS(emit)) {
   
            ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_LAST, LOCAL_IDX_LOCAL_VAR(emit, MAX_REGS_FOR_LOCAL_VARS - 1));
        }

        emit_native_global_exc_entry(emit);

    } else {
   
        // 计算状态大小(局部变量加上堆栈)
        emit->n_state = scope->num_locals + scope->stack_size;

        // 在第一个机器字中存储一个索引,用于函数的前奏。
        // 这在运行时由 mp_obj_fun_native_get_prelude_ptr() 使用。
        mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_ptr_index);

        if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
   
            mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset);
            ASM_ENTRY(emit->as, emit->code_state_start);

            // 为 REG_GENERATOR_STATE 指向的状态重置状态大小
            emit->code_state_start = 0;
            emit->stack_start = SIZEOF_CODE_STATE;

            // 将代码状态的地址放入 REG_GENERATOR_STATE
            #if N_X86
            asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE);
            #else
            ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1);
            #endif

            // 将抛出值放入 LOCAL_IDX_EXC_VAL 槽,用于 yield/yield-from
            #if N_X86
            asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
            #endif
            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2);

            // 将 REG_FUN_TABLE 载入 mp_fun_table 指针,该指针在 const_table 中找到
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit));
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONTEXT);
            #if MICROPY_PERSISTENT_CODE_SAVE
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
            #endif
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, fun_table_off);
        } else {
   
            // 本地变量和堆栈在 code_state 结构之后开始
            emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE;

            // 为 code_state 结构分配 C 栈空间,其中包括状态
            ASM_ENTRY(emit->as, emit->stack_start + emit->n_state);

            // 准备传入的参数以调用 mp_setup_code_state

            #if N_X86
            asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
            asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
            asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3);
            asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4);
            #endif

            // 将 REG_FUN_TABLE 载入 mp_fun_table 指针,该指针在 const_table 中找到
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
            #if MICROPY_PERSISTENT_CODE_SAVE
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
            #endif
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, fun_table_off);

            // 设置 code_state.fun_bc
            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);

            // 设置 code_state.n_state(仅在小端目标上有效,因为 n_state 是 uint16_t)
            emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_N_STATE, emit->n_state, REG_ARG_1);

            // 将 code_state 的地址放入第一个参数
            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start);

            // 如果需要,复制接下来的 3 个参数
            #if REG_ARG_2 != REG_PARENT_ARG_2
            ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2);
            #endif
            #if REG_ARG_3 != REG_PARENT_ARG_3
            ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3);
            #endif
            #if REG_ARG_4 != REG_PARENT_ARG_4
            ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4);
            #endif

            // 调用 mp_setup_code_state 准备 code_state 结构
            #if N_THUMB
            asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);
            #elif N_ARM
            asm_arm_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4);
            #else
            ASM_CALL_IND(emit->as, MP_F_SETUP_CODE_STATE);
            #endif
        }

        emit_native_global_exc_entry(emit);

        // 仅当没有异常处理器时,将一些局部变量缓存到寄存器中
        if (CAN_USE_REGS_FOR_LOCALS(emit)) {
   
            for (int i = 0; i < MAX_REGS_FOR_LOCAL_VARS && i < scope->num_locals; ++i) {
   
                ASM_MOV_REG_LOCAL(emit->as, reg_local_table[i], LOCAL_IDX_LOCAL_VAR(emit, i));
            }
        }

        // 设置闭包变量的类型
        for (mp_uint_t i = 0; i < scope->id_info_len; i++) {
   
            id_info_t *id = &scope->id_info[i];
            if (id->kind == ID_INFO_KIND_CELL) {
   
                emit->local_vtype[id->local_num] = VTYPE_PYOBJ;
            }
        }
    }
}

// 将字节写入代码信息
static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) {
   
    mp_asm_base_data(&emit->as->base, 1, val);
}

// 将 qstr 写入代码信息
static inline void emit_native_write_code_info_qstr(emit_t *emit, qstr qst) {
   
    mp_encode_uint(&emit->as->base, mp_asm_base_get_cur_to_write_bytes, mp_emit_common_use_qstr(emit->emit_common, qst));
}

// 结束一个作用域遍历
static bool emit_native_end_pass(emit_t *emit) {
   
    emit_native_global_exc_exit(emit);

    if (!emit->do_viper_types) {
   
        emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base);
        emit->prelude_ptr_index = emit->emit_common->ct_cur_child;

        size_t n_state = emit->n_state;
        size_t n_exc_stack = 0; // 原生代码不需要异常栈
        MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit);

        size_t n_info = emit->n_info;
        size_t n_cell = emit->n_cell;
        MP_BC_PRELUDE_SIZE_ENCODE(n_info, n_cell, emit_native_write_code_info_byte, emit);

        // 字节码前奏:源信息(函数和参数 qstrs)
        size_t info_start = mp_asm_base_get_code_pos(&emit->as->base);
        emit_native_write_code_info_qstr(emit, emit->scope->simple_name);
        for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
   
            qstr qst = MP_QSTR__star_;
            for (int j = 0; j < emit->scope->id_info_len; ++j) {
   
                id_info_t *id = &emit->scope->id_info[j];
                if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
   
                    qst = id->qst;
                    break;
                }
            }
            emit_native_write_code_info_qstr(emit, qst);
        }
        emit->n_info = mp_asm_base_get_code_pos(&emit->as->base) - info_start;

        // 字节码前奏:初始化闭包变量
        size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base);
        for (int i = 0; i < emit->scope->id_info_len; i++) {
   
            id_info_t *id = &emit->scope->id_info[i];
            if (id->kind == ID_INFO_KIND_CELL) {
   
                assert(id->local_num <= 255);
                mp_asm_base_data(&emit->as->base, 1, id->local_num); // 写入应转换为单元格的局部变量
            }
        }
        emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start;

    }

    ASM_END_PASS(emit->as);

    // 检查堆栈大小是否恢复到零
    assert(emit->stack_size == 0);
    assert(emit->exc_stack_size == 0);

    if (emit->pass == MP_PASS_EMIT) {
   
        void *f = mp_asm_base_get_code(&emit->as->base);
        mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base);

        mp_raw_code_t **children = emit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值