qstr mp_obj_code_get_name(const byte *code_info) { mp_decode_uint(&code_info); // skip code_info_size entry #if MICROPY_PERSISTENT_CODE return code_info[0] | (code_info[1] << 8); #else return mp_decode_uint(&code_info); #endif }
int is_expired_tuple(struct memcached_service *p, box_tuple_t *tuple) { uint64_t flush = p->flush; const char *pos = box_tuple_field(tuple, 1); uint64_t exptime = mp_decode_uint(&pos); uint64_t time = mp_decode_uint(&pos); return is_expired(exptime, time, flush); }
int64_t php_tp_response(struct tnt_response *r, char *buf, size_t size) { memset(r, 0, sizeof(*r)); const char *p = buf; /* len */ uint32_t len = size; /* header */ if (mp_typeof(*p) != MP_MAP) return -1; uint32_t n = mp_decode_map(&p); while (n-- > 0) { if (mp_typeof(*p) != MP_UINT) return -1; uint32_t key = mp_decode_uint(&p); if (mp_typeof(*p) != MP_UINT) return -1; switch (key) { case TNT_SYNC: r->sync = mp_decode_uint(&p); break; case TNT_CODE: r->code = mp_decode_uint(&p); break; default: return -1; } r->bitmap |= (1ULL << key); } /* body */ if (mp_typeof(*p) != MP_MAP) return -1; n = mp_decode_map(&p); while (n-- > 0) { uint32_t key = mp_decode_uint(&p); switch (key) { case TNT_ERROR: if (mp_typeof(*p) != MP_STR) return -1; uint32_t elen = 0; r->error = mp_decode_str(&p, &elen); r->error_len = elen; r->code &= ((1 << 15) - 1); break; case TNT_DATA: if (mp_typeof(*p) != MP_ARRAY) return -1; r->data = p; mp_next(&p); r->data_len = p - r->data; break; } r->bitmap |= (1ULL << key); } return p - buf; }
// ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { prelude->n_state = mp_decode_uint(ip); prelude->n_exc_stack = mp_decode_uint(ip); prelude->scope_flags = *(*ip)++; prelude->n_pos_args = *(*ip)++; prelude->n_kwonly_args = *(*ip)++; prelude->n_def_pos_args = *(*ip)++; *ip2 = *ip; prelude->code_info_size = mp_decode_uint(ip2); *ip += prelude->code_info_size; while (*(*ip)++ != 255) { } }
int args(box_function_ctx_t *ctx, const char *args, const char *args_end) { uint32_t arg_count = mp_decode_array(&args); if (arg_count < 1) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s", "invalid argument count"); } if (mp_typeof(*args) != MP_UINT) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s", "first tuple field must be uint"); } uint32_t num = mp_decode_uint(&args); char tuple_buf[512]; char *d = tuple_buf; d = mp_encode_array(d, 2); d = mp_encode_uint(d, num); d = mp_encode_str(d, "hello", strlen("hello")); assert(d <= tuple_buf + sizeof(tuple_buf)); box_tuple_format_t *fmt = box_tuple_format_default(); box_tuple_t *tuple = box_tuple_new(fmt, tuple_buf, d); if (tuple == NULL) return -1; return box_return_tuple(ctx, tuple); }
qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in); #if MICROPY_EMIT_NATIVE if (fun->base.type == &mp_type_fun_native) { // TODO native functions don't have name stored return MP_QSTR_; } #endif const byte *bc = fun->bytecode; mp_decode_uint(&bc); // skip n_state mp_decode_uint(&bc); // skip n_exc_stack bc++; // skip scope_params bc++; // skip n_pos_args bc++; // skip n_kwonly_args bc++; // skip n_def_pos_args return mp_obj_code_get_name(bc); }
static int test_format(void) { plan(282); header(); const size_t buf_size = 1024; char buf[buf_size]; size_t sz; const char *fmt; const char *p, *c, *e; uint32_t len = 0; fmt = "%d %u %i %ld %lu %li %lld %llu %lli" "%hd %hu %hi %hhd %hhu %hhi"; sz = mp_format(buf, buf_size, fmt, 1, 2, 3, (long)4, (long)5, (long)6, (long long)7, (long long)8, (long long)9, (short)10, (short)11, (short)12, (char)13, (char)14, (char)15); p = buf; for (unsigned i = 0; i < 15; i++) { ok(mp_typeof(*p) == MP_UINT, "Test type on step %d", i); ok(mp_decode_uint(&p) == i + 1, "Test value on step %d", i); } sz = mp_format(buf, buf_size, fmt, -1, -2, -3, (long)-4, (long)-5, (long)-6, (long long)-7, (long long)-8, (long long)-9, (short)-10, (unsigned short)-11, (short)-12, (signed char)-13, (unsigned char)-14, (signed char)-15); p = buf; for (int i = 0; i < 15; i++) { uint64_t expects[5] = { UINT_MAX - 1, ULONG_MAX - 4, ULLONG_MAX - 7, USHRT_MAX - 10, UCHAR_MAX - 13 }; if (i % 3 == 1) { ok(mp_typeof(*p) == MP_UINT, "Test type on step %d", i); ok(mp_decode_uint(&p) == expects[i / 3], "Test value on step %d", i); } else { ok(mp_typeof(*p) == MP_INT, "Test type on step %d", i); ok(mp_decode_int(&p) == - i - 1, "Test value on step %d", i); } } char data1[32]; char *data1_end = data1; data1_end = mp_encode_array(data1_end, 2); data1_end = mp_encode_str(data1_end, "ABC", 3); data1_end = mp_encode_uint(data1_end, 11); size_t data1_len = data1_end - data1; assert(data1_len <= sizeof(data1)); char data2[32]; char *data2_end = data2; data2_end = mp_encode_int(data2_end, -1234567890); data2_end = mp_encode_str(data2_end, "DEFGHIJKLMN", 11); data2_end = mp_encode_uint(data2_end, 321); size_t data2_len = data2_end - data2; assert(data2_len <= sizeof(data2)); fmt = "%d NIL [%d %b %b] this is test" "[%d %%%% [[ %d {%s %f %% %.*s %lf %.*s NIL}" "%p %d %.*p ]] %d%d%d]"; #define TEST_PARAMS 0, 1, true, false, -1, 2, \ "flt", 0.1, 6, "double#ignored", 0.2, 0, "ignore", \ data1, 3, data2_len, data2, 4, 5, 6 sz = mp_format(buf, buf_size, fmt, TEST_PARAMS); p = buf; e = buf + sz; c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 0, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_NIL, "type"); mp_decode_nil(&p); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_BOOL, "type"); ok(mp_decode_bool(&p) == true, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_BOOL, "type"); ok(mp_decode_bool(&p) == false, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_INT, "type"); ok(mp_decode_int(&p) == -1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 1, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_ARRAY, "type"); ok(mp_decode_array(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 2, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_MAP, "type"); ok(mp_decode_map(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 3, "decode"); ok(memcmp(c, "flt", 3) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_FLOAT, "type"); ok(fequal(mp_decode_float(&p), 0.1), "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 6, "decode"); ok(memcmp(c, "double", 6) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_DOUBLE, "type"); ok(dequal(mp_decode_double(&p), 0.2), "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 0, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_NIL, "type"); mp_decode_nil(&p); c = p; ok(mp_check(&c, e) == 0, "check"); ok(((size_t)(c - p) == data1_len) && memcmp(p, data1, data1_len) == 0, "compare"); p = c; c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 3, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_INT, "type"); ok(mp_decode_int(&p) == -1234567890, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_STR, "type"); c = mp_decode_str(&p, &len); ok(len == 11, "decode"); ok(memcmp(c, "DEFGHIJKLMN", 11) == 0, "compare"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 321, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 4, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 5, "decode"); c = p; ok(mp_check(&c, e) == 0, "check"); ok(mp_typeof(*p) == MP_UINT, "type"); ok(mp_decode_uint(&p) == 6, "decode"); ok(p == e, "nothing more"); ok(sz < 70, "no magic detected"); for (size_t lim = 0; lim <= 70; lim++) { memset(buf, 0, buf_size); size_t test_sz = mp_format(buf, lim, fmt, TEST_PARAMS); ok(test_sz == sz, "return value on step %d", (int)lim); bool all_zero = true; for(size_t z = lim; z < buf_size; z++) all_zero = all_zero && (buf[z] == 0); ok(all_zero, "buffer overflow on step %d", (int)lim); } #undef TEST_PARAMS footer(); return check_plan(); }
const char * _munpack_item(const char *p, size_t len, SV **res, HV *ext, int utf) { if (!len || !p) croak("Internal error: out of pointer"); const char *pe = p + len; switch(mp_typeof(*p)) { case MP_UINT: *res = newSViv( mp_decode_uint(&p) ); break; case MP_INT: *res = newSViv( mp_decode_int(&p) ); break; case MP_FLOAT: *res = newSVnv( mp_decode_float(&p) ); break; case MP_DOUBLE: *res = newSVnv( mp_decode_double(&p) ); break; case MP_STR: { const char *s; uint32_t len; s = mp_decode_str(&p, &len); *res = newSVpvn_flags(s, len, utf ? SVf_UTF8 : 0); break; } case MP_NIL: { mp_decode_nil(&p); *res = newSV(0); break; } case MP_BOOL: if (mp_decode_bool(&p)) { *res = newSViv(1); } else { *res = newSViv(0); } break; case MP_MAP: { uint32_t l, i; l = mp_decode_map(&p); HV * h = newHV(); sv_2mortal((SV *)h); for (i = 0; i < l; i++) { SV *k = 0; SV *v = 0; if (p >= pe) croak("Unexpected EOF msgunpack str"); p = _munpack_item(p, pe - p, &k, ext, utf); sv_2mortal(k); if (p >= pe) croak("Unexpected EOF msgunpack str"); p = _munpack_item(p, pe - p, &v, ext, utf); hv_store_ent(h, k, v, 0); } *res = newRV((SV *)h); break; } case MP_ARRAY: { uint32_t l, i; l = mp_decode_array(&p); AV *a = newAV(); sv_2mortal((SV *)a); for (i = 0; i < l; i++) { SV *item = 0; if (p >= pe) croak("Unexpected EOF msgunpack str"); p = _munpack_item(p, pe - p, &item, ext, utf); av_push(a, item); } *res = newRV((SV *)a); break; } case MP_EXT: { croak("Isn't defined yet"); } default: croak("Unexpected symbol 0x%02x", 0xFF & (int)(*p)); } return p; }
/* * For each UINT key in arguments create or increment counter in * box.space.test space. */ int multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end) { static const char *SPACE_NAME = "test"; static const char *INDEX_NAME = "primary"; uint32_t space_id = box_space_id_by_name(SPACE_NAME, strlen(SPACE_NAME)); uint32_t index_id = box_index_id_by_name(space_id, INDEX_NAME, strlen(INDEX_NAME)); if (space_id == BOX_ID_NIL || index_id == BOX_ID_NIL) { return box_error_set(__FILE__, __LINE__, ER_PROC_C, "Can't find index %s in space %s", INDEX_NAME, SPACE_NAME); } say_debug("space_id = %u, index_id = %u", space_id, index_id); uint32_t arg_count = mp_decode_array(&args); assert(!box_txn()); box_txn_begin(); assert(box_txn()); for (uint32_t i = 0; i < arg_count; i++) { /* Decode next argument */ if (mp_typeof(*args) != MP_UINT) return box_error_set(__FILE__, __LINE__, ER_PROC_C, "Expected uint keys"); uint32_t key = mp_decode_uint(&args); (void) key; /* Prepare MsgPack key for search */ char key_buf[16]; char *key_end = key_buf; key_end = mp_encode_array(key_end, 1); key_end = mp_encode_uint(key_end, key); assert(key_end < key_buf + sizeof(key_buf)); /* Get current value from space */ uint64_t counter = 0; box_tuple_t *tuple; if (box_index_get(space_id, index_id, key_buf, key_end, &tuple) != 0) { return -1; /* error */ } else if (tuple != NULL) { const char *field = box_tuple_field(tuple, 1); if (field == NULL || mp_typeof(*field) != MP_UINT) return box_error_set(__FILE__, __LINE__, ER_PROC_LUA, "Invalid tuple"); counter = mp_decode_uint(&field) + 1; } /* Replace value */ char tuple_buf[16]; char *tuple_end = tuple_buf; tuple_end = mp_encode_array(tuple_end, 2); tuple_end = mp_encode_uint(tuple_end, key); /* key */ tuple_end = mp_encode_uint(tuple_end, counter); /* counter */ assert(tuple_end <= tuple_buf + sizeof(tuple_buf)); if (box_replace(space_id, tuple_buf, tuple_end, NULL) != 0) return -1; } box_txn_commit(); assert(!box_txn()); return 0; }
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); } }
void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) { mp_showbc_code_start = ip; // get bytecode parameters mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); /*mp_uint_t scope_flags =*/ ip++; mp_uint_t n_pos_args = *ip++; mp_uint_t n_kwonly_args = *ip++; /*mp_uint_t n_def_pos_args =*/ ip++; const byte *code_info = ip; mp_uint_t code_info_size = mp_decode_uint(&code_info); ip += code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = code_info[0] | (code_info[1] << 8); qstr source_file = code_info[2] | (code_info[3] << 8); code_info += 4; #else qstr block_name = mp_decode_uint(&code_info); qstr source_file = mp_decode_uint(&code_info); #endif printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n", qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len); // raw bytecode dump printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size); for (mp_uint_t i = 0; i < len; i++) { if (i > 0 && i % 16 == 0) { printf("\n"); } printf(" %02x", mp_showbc_code_start[i]); } printf("\n"); // bytecode prelude: arg names (as qstr objects) printf("arg names:"); for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) { printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(const_table[i]))); } printf("\n"); printf("(N_STATE " UINT_FMT ")\n", n_state); printf("(N_EXC_STACK " UINT_FMT ")\n", n_exc_stack); // for printing line number info const byte *bytecode_start = ip; // bytecode prelude: initialise closed over variables { uint local_num; while ((local_num = *ip++) != 255) { printf("(INIT_CELL %u)\n", local_num); } len -= ip - mp_showbc_code_start; } // print out line number info { mp_int_t bc = bytecode_start - ip; mp_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte* ci = code_info; *ci;) { if ((ci[0] & 0x80) == 0) { // 0b0LLBBBBB encoding bc += ci[0] & 0x1f; source_line += ci[0] >> 5; ci += 1; } else { // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) bc += ci[0] & 0xf; source_line += ((ci[0] << 4) & 0x700) | ci[1]; ci += 2; } printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); }
static int opt_set(void *opts, const struct opt_def *def, const char **val, struct region *region, uint32_t errcode, uint32_t field_no) { int64_t ival; uint64_t uval; char *errmsg = tt_static_buf(); double dval; uint32_t str_len; const char *str; char *ptr; char *opt = ((char *) opts) + def->offset; switch (def->type) { case OPT_BOOL: if (mp_typeof(**val) != MP_BOOL) goto type_mismatch_err; store_bool(opt, mp_decode_bool(val)); break; case OPT_UINT32: if (mp_typeof(**val) != MP_UINT) goto type_mismatch_err; uval = mp_decode_uint(val); if (uval > UINT32_MAX) goto type_mismatch_err; store_u32(opt, uval); break; case OPT_INT64: if (mp_read_int64(val, &ival) != 0) goto type_mismatch_err; store_u64(opt, ival); break; case OPT_FLOAT: if (mp_read_double(val, &dval) != 0) goto type_mismatch_err; store_double(opt, dval); break; case OPT_STR: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); str_len = MIN(str_len, def->len - 1); memcpy(opt, str, str_len); opt[str_len] = '\0'; break; case OPT_STRPTR: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); if (str_len > 0) { ptr = (char *) region_alloc(region, str_len + 1); if (ptr == NULL) { diag_set(OutOfMemory, str_len + 1, "region", "opt string"); return -1; } memcpy(ptr, str, str_len); ptr[str_len] = '\0'; assert (strlen(ptr) == str_len); } else { ptr = NULL; } *(const char **)opt = ptr; break; case OPT_ENUM: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); if (def->to_enum == NULL) { ival = strnindex(def->enum_strs, str, str_len, def->enum_max); } else { ival = def->to_enum(str, str_len); } switch(def->enum_size) { case sizeof(uint8_t): store_u8(opt, (uint8_t)ival); break; case sizeof(uint16_t): store_u16(opt, (uint16_t)ival); break; case sizeof(uint32_t): store_u32(opt, (uint32_t)ival); break; case sizeof(uint64_t): store_u64(opt, (uint64_t)ival); break; default: unreachable(); }; break; case OPT_ARRAY: if (mp_typeof(**val) != MP_ARRAY) goto type_mismatch_err; ival = mp_decode_array(val); assert(def->to_array != NULL); if (def->to_array(val, ival, opt, errcode, field_no) != 0) return -1; break; case OPT_LEGACY: mp_next(val); break; default: unreachable(); } return 0; type_mismatch_err: snprintf(errmsg, TT_STATIC_BUF_LEN, "'%s' must be %s", def->name, opt_type_strs[def->type]); diag_set(ClientError, errcode, field_no, errmsg); return -1; }
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *ip, mp_uint_t len) { mp_showbc_code_start = ip; // get code info size const byte *code_info = ip; mp_uint_t code_info_size = mp_decode_uint(&code_info); ip += code_info_size; qstr block_name = mp_decode_uint(&code_info); qstr source_file = mp_decode_uint(&code_info); printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n", qstr_str(source_file), qstr_str(block_name), descr, code_info, len); // raw bytecode dump printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size); for (mp_uint_t i = 0; i < len; i++) { if (i > 0 && i % 16 == 0) { printf("\n"); } printf(" %02x", mp_showbc_code_start[i]); } printf("\n"); // bytecode prelude: arg names (as qstr objects) printf("arg names:"); for (mp_uint_t i = 0; i < n_total_args; i++) { printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(*(mp_obj_t*)ip))); ip += sizeof(mp_obj_t); } printf("\n"); // bytecode prelude: state size and exception stack size; 16 bit uints { uint n_state = mp_decode_uint(&ip); uint n_exc_stack = mp_decode_uint(&ip); printf("(N_STATE %u)\n", n_state); printf("(N_EXC_STACK %u)\n", n_exc_stack); } // bytecode prelude: initialise closed over variables { uint local_num; while ((local_num = *ip++) != 255) { printf("(INIT_CELL %u)\n", local_num); } len -= ip - mp_showbc_code_start; } // print out line number info { mp_int_t bc = (mp_showbc_code_start + code_info_size) - ip; // start counting from the prelude mp_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte* ci = code_info; *ci;) { if ((ci[0] & 0x80) == 0) { // 0b0LLBBBBB encoding bc += ci[0] & 0x1f; source_line += ci[0] >> 5; ci += 1; } else { // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) bc += ci[0] & 0xf; source_line += ((ci[0] << 4) & 0x700) | ci[1]; ci += 2; } printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); }
// On entry code_state should be allocated somewhere (stack/heap) and // contain the following valid entries: // - code_state->ip should contain the offset in bytes from the start of // the bytecode chunk to just after n_state and n_exc_stack // - code_state->n_state should be set to the state size (locals plus stack) void mp_setup_code_state(mp_code_state *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t 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. size_t n_state = code_state->n_state; // ip comes in as an offset into bytecode, so turn it into a true pointer code_state->ip = self->bytecode + (size_t)code_state->ip; // store pointer to constant table code_state->const_table = self->const_table; #if MICROPY_STACKLESS code_state->prev = NULL; #endif // get params size_t scope_flags = *code_state->ip++; size_t n_pos_args = *code_state->ip++; size_t n_kwonly_args = *code_state->ip++; size_t n_def_pos_args = *code_state->ip++; code_state->sp = &code_state->state[0] - 1; code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; // zero out the local stack to begin with memset(code_state->state, 0, n_state * sizeof(*code_state->state)); const mp_obj_t *kwargs = args + n_args; // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed) mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args]; // check positional arguments if (n_args > n_pos_args) { // given more than enough arguments if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) { fun_pos_args_mismatch(self, n_pos_args, n_args); } // put extra arguments in varargs tuple *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args); n_args = n_pos_args; } else { if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) { DEBUG_printf("passing empty tuple as *args\n"); *var_pos_kw_args-- = mp_const_empty_tuple; } // Apply processing and check below only if we don't have kwargs, // otherwise, kw handling code below has own extensive checks. if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) { if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) { // given enough arguments, but may need to use some default arguments for (size_t i = n_args; i < n_pos_args; i++) { code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)]; } } else { fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); } } } // copy positional args into state for (size_t i = 0; i < n_args; i++) { code_state->state[n_state - 1 - i] = args[i]; } // check keyword arguments if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { DEBUG_printf("Initial args: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); mp_obj_t dict = MP_OBJ_NULL; if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0? *var_pos_kw_args = dict; } // get pointer to arg_names array const mp_obj_t *arg_names = (const mp_obj_t*)code_state->const_table; for (size_t i = 0; i < n_kw; i++) { mp_obj_t wanted_arg_name = kwargs[2 * i]; for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) { if (wanted_arg_name == arg_names[j]) { if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); } code_state->state[n_state - 1 - j] = kwargs[2 * i + 1]; goto continue2; } } // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; } DEBUG_printf("Args with kws flattened: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); // fill in defaults for positional args mp_obj_t *d = &code_state->state[n_state - n_pos_args]; mp_obj_t *s = &self->extra_args[n_def_pos_args - 1]; for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) { if (*d == MP_OBJ_NULL) { *d = *s; } } DEBUG_printf("Args after filling default positional: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); // Check that all mandatory positional args are specified while (d < &code_state->state[n_state]) { if (*d++ == MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required positional argument #%d", &code_state->state[n_state] - d)); } } // Check that all mandatory keyword args are specified // Fill in default kw args if we have them for (size_t i = 0; i < n_kwonly_args; i++) { if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) { mp_map_elem_t *elem = NULL; if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { elem = mp_map_lookup(&((mp_obj_dict_t*)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP); } if (elem != NULL) { code_state->state[n_state - 1 - n_pos_args - i] = elem->value; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]))); } } } } else { // no keyword arguments given if (n_kwonly_args != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function missing keyword-only argument")); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); } } // get the ip and skip argument names const byte *ip = code_state->ip; // store pointer to code_info and jump over it { code_state->code_info = ip; const byte *ip2 = ip; size_t code_info_size = mp_decode_uint(&ip2); ip += code_info_size; } // bytecode prelude: initialise closed over variables size_t local_num; while ((local_num = *ip++) != 255) { code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); } // now that we skipped over the prelude, set the ip for the VM code_state->ip = ip; DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); dump_args(code_state->state, n_state); }
qstr mp_obj_code_get_name(const byte *code_info) { mp_decode_uint(&code_info); // skip code_info_size entry return mp_decode_uint(&code_info); }