mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); // get start of bytecode const byte *ip = self->bytecode; // bytecode prelude: state size and exception stack size size_t n_state = mp_decode_uint(&ip); size_t n_exc_stack = mp_decode_uint(&ip); // allocate state for locals and stack size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state; code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; } code_state->ip = (byte*)(ip - self->bytecode); // offset to after n_state/n_exc_stack code_state->n_state = n_state; mp_setup_code_state(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); return code_state; }
mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = self_in; // skip code-info block const byte *code_info = self->bytecode; mp_uint_t code_info_size = mp_decode_uint(&code_info); const byte *ip = self->bytecode + code_info_size; // bytecode prelude: skip arg names ip += (self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t); // bytecode prelude: state size and exception stack size mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); // allocate state for locals and stack mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state *code_state; code_state = m_new_obj_var_maybe(mp_code_state, byte, state_size); if (!code_state) { return NULL; } code_state->n_state = n_state; code_state->code_info = 0; // offset to code-info code_state->ip = (byte*)(ip - self->bytecode); // offset to prelude mp_setup_code_state(code_state, self_in, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); return code_state; }
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_obj_gen_wrap_t *self = self_in; mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun; assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc)); // skip code-info block const byte *code_info = self_fun->bytecode; mp_uint_t code_info_size = mp_decode_uint(&code_info); const byte *ip = self_fun->bytecode + code_info_size; // bytecode prelude: skip arg names ip += (self_fun->n_pos_args + self_fun->n_kwonly_args) * sizeof(mp_obj_t); // bytecode prelude: get state size and exception stack size mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; o->globals = self_fun->globals; o->code_state.n_state = n_state; o->code_state.ip = ip; mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args); return o; }
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_gen_wrap_t *self = self_in; mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun; assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc)); const byte *bytecode = self_fun->bytecode; // get code info size, and skip the line number table machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24); bytecode += code_info_size; // bytecode prelude: get state size and exception stack size machine_uint_t n_state = bytecode[0] | (bytecode[1] << 8); machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8); bytecode += 4; // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; o->globals = self_fun->globals; o->code_state.n_state = n_state; o->code_state.ip = bytecode; mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args); return o; }
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { // A generating function is just a bytecode function with type mp_type_gen_wrap mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in); // bytecode prelude: get state size and exception stack size size_t n_state = mp_decode_uint_value(self_fun->bytecode); size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode)); // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; o->globals = self_fun->globals; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); }
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw); DEBUG_printf("Input pos args: "); dump_args(args, n_args); DEBUG_printf("Input kw args: "); dump_args(args + n_args, n_kw * 2); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); // get start of bytecode const byte *ip = self->bytecode; // bytecode prelude: state size and exception stack size mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); #if VM_DETECT_STACK_OVERFLOW n_state += 1; #endif // allocate state for locals and stack mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state = NULL; if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } if (code_state == NULL) { code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } code_state->ip = (byte*)(ip - self->bytecode); // offset to after n_state/n_exc_stack code_state->n_state = n_state; mp_setup_code_state(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_globals_set(code_state->old_globals); #if VM_DETECT_STACK_OVERFLOW if (vm_return_kind == MP_VM_RETURN_NORMAL) { if (code_state->sp < code_state->state) { printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state); assert(0); } } // We can't check the case when an exception is returned in state[n_state - 1] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) { // Just check to see that we have at least 1 null object left in the state. bool overflow = true; for (mp_uint_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) { if (code_state->state[i] == MP_OBJ_NULL) { overflow = false; break; } } if (overflow) { printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state); assert(0); } } #endif mp_obj_t result; if (vm_return_kind == MP_VM_RETURN_NORMAL) { // return value is in *sp result = *code_state->sp; } else { // must be an exception because normal functions can't yield assert(vm_return_kind == MP_VM_RETURN_EXCEPTION); // return value is in fastn[0]==state[n_state - 1] result = code_state->state[n_state - 1]; } // free the state if it was allocated on the heap if (state_size != 0) { m_del_var(mp_code_state_t, byte, state_size, code_state); } if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; } else { // MP_VM_RETURN_EXCEPTION nlr_raise(result); } }
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw); DEBUG_printf("Input pos args: "); dump_args(args, n_args); DEBUG_printf("Input kw args: "); dump_args(args + n_args, n_kw * 2); mp_obj_fun_bc_t *self = self_in; DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); const byte *ip = self->bytecode; // get code info size, and skip line number table machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24); ip += code_info_size; // bytecode prelude: state size and exception stack size; 16 bit uints machine_uint_t n_state = ip[0] | (ip[1] << 8); machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8); ip += 4; #if VM_DETECT_STACK_OVERFLOW n_state += 1; #endif // allocate state for locals and stack uint state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state *code_state; if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var(mp_code_state, byte, state_size); } else { code_state = alloca(sizeof(mp_code_state) + state_size); } code_state->n_state = n_state; code_state->ip = ip; mp_setup_code_state(code_state, self_in, n_args, n_kw, args); // execute the byte code with the correct globals context mp_obj_dict_t *old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_globals_set(old_globals); #if VM_DETECT_STACK_OVERFLOW if (vm_return_kind == MP_VM_RETURN_NORMAL) { if (code_state->sp < code_state->state) { printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state); assert(0); } } // We can't check the case when an exception is returned in state[n_state - 1] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) { // Just check to see that we have at least 1 null object left in the state. bool overflow = true; for (uint i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) { if (code_state->state[i] == MP_OBJ_NULL) { overflow = false; break; } } if (overflow) { printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state); assert(0); } } #endif mp_obj_t result; switch (vm_return_kind) { case MP_VM_RETURN_NORMAL: // return value is in *sp result = *code_state->sp; break; case MP_VM_RETURN_EXCEPTION: // return value is in state[n_state - 1] result = code_state->state[n_state - 1]; break; case MP_VM_RETURN_YIELD: // byte-code shouldn't yield default: assert(0); result = mp_const_none; vm_return_kind = MP_VM_RETURN_NORMAL; break; } // free the state if it was allocated on the heap if (state_size > VM_MAX_STATE_ON_STACK) { m_del_var(mp_code_state, byte, state_size, code_state); } if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; } else { // MP_VM_RETURN_EXCEPTION nlr_raise(result); } }