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 void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) { mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args); if (pn == NULL) { memory_error(parser); return; } pn->source_line = src_line; pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8); for (int i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } push_result_node(parser, (mp_parse_node_t)pn); }
STATIC void push_result_string(parser_t *parser, int src_line, const char *str, uint len) { mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, 2); if (pn == NULL) { memory_error(parser); return; } pn->source_line = src_line; pn->kind_num_nodes = RULE_string | (2 << 8); char *p = m_new(char, len); memcpy(p, str, len); pn->nodes[0] = (machine_int_t)p; pn->nodes[1] = len; push_result_node(parser, (mp_parse_node_t)pn); }
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. o = &MP_STATE_VM(mp_emergency_exception_obj); // We can't store any args. o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; } else { o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_args, args)); } o->base.type = type; o->traceback_data = NULL; return MP_OBJ_FROM_PTR(o); }
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); // Try to allocate memory for the exception, with fallback to emergency exception object mp_obj_exception_t *o_exc = m_new_obj_maybe(mp_obj_exception_t); if (o_exc == NULL) { o_exc = &MP_STATE_VM(mp_emergency_exception_obj); } // Populate the exception object o_exc->base.type = type; o_exc->traceback_data = NULL; mp_obj_tuple_t *o_tuple; if (n_args == 0) { // No args, can use the empty tuple straightaway o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; } else { // Try to allocate memory for the tuple containing the args o_tuple = m_new_obj_var_maybe(mp_obj_tuple_t, mp_obj_t, n_args); #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If we are called by mp_obj_new_exception_msg_varg then it will have // reserved room (after the traceback data) for a tuple with 1 element. // Otherwise we are free to use the whole buffer after the traceback data. if (o_tuple == NULL && mp_emergency_exception_buf_size >= EMG_TRACEBACK_ALLOC * sizeof(size_t) + sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t)) { o_tuple = (mp_obj_tuple_t*) ((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + EMG_TRACEBACK_ALLOC * sizeof(size_t)); } #endif if (o_tuple == NULL) { // No memory for a tuple, fallback to an empty tuple o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; } else { // Have memory for a tuple so populate it o_tuple->base.type = &mp_type_tuple; o_tuple->len = n_args; memcpy(o_tuple->items, args, n_args * sizeof(mp_obj_t)); } } // Store the tuple of args in the exception object o_exc->args = o_tuple; return MP_OBJ_FROM_PTR(o_exc); }
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_obj_type_t *type = type_in; if (n_kw != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in))); } mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. o = &mp_emergency_exception_obj; // We can't store any args. n_args = 0; o->args = mp_const_empty_tuple; } else { o->args = mp_obj_new_tuple(n_args, args); } o->base.type = type; o->traceback = MP_OBJ_NULL; return o; }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &mp_emergency_exception_obj; o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_const_empty_tuple; } else { o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_obj_new_tuple(1, NULL); if (fmt == NULL) { // no message assert(0); } else { // render exception message and store as .args[0] // TODO: optimize bufferbloat vstr_t *vstr = vstr_new(); va_list ap; va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); vstr_free(vstr); } } return o; }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &mp_emergency_exception_obj; o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_const_empty_tuple; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf; mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = str; byte *str_data = (byte *)&str[1]; uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size - str_data; va_list ap; va_start(ap, fmt); str->len = vsnprintf((char *)str_data, max_len, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->data = str_data; o->args = tuple; uint offset = &str_data[str->len] - mp_emergency_exception_buf; offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) { // We have room to store some traceback. mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset); list->base.type = &mp_type_list; list->items = (mp_obj_t)&list[1]; list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]); list->len = 0; o->traceback = list; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_obj_new_tuple(1, NULL); if (fmt == NULL) { // no message assert(0); } else { // render exception message and store as .args[0] // TODO: optimize bufferbloat vstr_t *vstr = vstr_new(); va_list ap; va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str(vstr->buf, vstr->len, false); vstr_free(vstr); } } return 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); } }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &MP_STATE_VM(mp_emergency_exception_obj); o->base.type = exc_type; o->traceback_data = NULL; o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)MP_STATE_VM(mp_emergency_exception_buf); mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = MP_OBJ_FROM_PTR(str); byte *str_data = (byte *)&str[1]; uint max_len = MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - str_data; vstr_t vstr; vstr_init_fixed_buf(&vstr, max_len, (char *)str_data); va_list ap; va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->len = vstr.len; str->data = str_data; o->args = tuple; uint offset = &str_data[str->len] - MP_STATE_VM(mp_emergency_exception_buf); offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(o->traceback_data[0]) * 3)) { // We have room to store some traceback. o->traceback_data = (size_t*)((byte *)MP_STATE_VM(mp_emergency_exception_buf) + offset); o->traceback_alloc = (MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]); o->traceback_len = 0; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback_data = NULL; o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(1, NULL)); assert(fmt != NULL); { if (strchr(fmt, '%') == NULL) { // no formatting substitutions, avoid allocating vstr. o->args->items[0] = mp_obj_new_str(fmt, strlen(fmt), false); } else { // render exception message and store as .args[0] va_list ap; vstr_t vstr; vstr_init(&vstr, 16); va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } } } return MP_OBJ_FROM_PTR(o); }