diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 64 | ||||
| -rw-r--r-- | src/backtrace.c | 70 | ||||
| -rw-r--r-- | src/cdump.c | 468 | ||||
| -rw-r--r-- | src/class.c | 326 | ||||
| -rw-r--r-- | src/codedump.c | 307 | ||||
| -rw-r--r-- | src/debug.c | 125 | ||||
| -rw-r--r-- | src/dump.c | 441 | ||||
| -rw-r--r-- | src/error.c | 84 | ||||
| -rw-r--r-- | src/etc.c | 28 | ||||
| -rw-r--r-- | src/fmt_fp.c | 708 | ||||
| -rw-r--r-- | src/gc.c | 28 | ||||
| -rw-r--r-- | src/hash.c | 3 | ||||
| -rw-r--r-- | src/kernel.c | 27 | ||||
| -rw-r--r-- | src/load.c | 24 | ||||
| -rw-r--r-- | src/numeric.c | 465 | ||||
| -rw-r--r-- | src/object.c | 106 | ||||
| -rw-r--r-- | src/proc.c | 27 | ||||
| -rw-r--r-- | src/range.c | 71 | ||||
| -rw-r--r-- | src/readflt.c | 119 | ||||
| -rw-r--r-- | src/readint.c | 30 | ||||
| -rw-r--r-- | src/string.c | 416 | ||||
| -rw-r--r-- | src/symbol.c | 157 | ||||
| -rw-r--r-- | src/variable.c | 16 | ||||
| -rw-r--r-- | src/vm.c | 346 |
24 files changed, 2264 insertions, 2192 deletions
diff --git a/src/array.c b/src/array.c index e83f7e2d8..c100591eb 100644 --- a/src/array.c +++ b/src/array.c @@ -29,7 +29,7 @@ ary_new_capa(mrb_state *mrb, mrb_int capa) } blen = capa * sizeof(mrb_value); - a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); + a = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class); if (capa <= MRB_ARY_EMBED_LEN_MAX) { ARY_SET_EMBED_LEN(a, 0); } @@ -578,7 +578,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self) return val; } -MRB_API mrb_value +static mrb_value mrb_ary_shift_m(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); @@ -591,6 +591,7 @@ mrb_ary_shift_m(mrb_state *mrb, mrb_value self) }; ary_modify_check(mrb, a); if (len == 0 || n == 0) return mrb_ary_new(mrb); + if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array shift"); if (n > len) n = len; val = mrb_ary_new_from_values(mrb, n, ARY_PTR(a)); if (ARY_SHARED_P(a)) { @@ -693,19 +694,6 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) return self; } -MRB_API mrb_value -mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n) -{ - struct RArray *a = mrb_ary_ptr(ary); - mrb_int len = ARY_LEN(a); - - /* range check */ - if (n < 0) n += len; - if (n < 0 || len <= n) return mrb_nil_value(); - - return ARY_PTR(a)[n]; -} - MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) { @@ -754,13 +742,16 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val /* range check */ if (head < 0) { head += alen; - if (head < 0) { - mrb_raise(mrb, E_INDEX_ERROR, "index is out of array"); - } + if (head < 0) goto out_of_range; + } + if (head > ARY_MAX_SIZE - len) { + out_of_range: + mrb_raisef(mrb, E_INDEX_ERROR, "index %i is out of array", head); } tail = head + len; if (alen < len || alen < tail) { len = alen - head; + tail = head + len; } /* size check */ @@ -786,12 +777,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val argv = &rpl; } if (head >= alen) { - if (head > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head); - } + if (head > ARY_MAX_SIZE - argc) goto out_of_range; len = head + argc; if (len > ARY_CAPA(a)) { - ary_expand_capa(mrb, a, head + argc); + ary_expand_capa(mrb, a, len); } ary_fill_with_nil(ARY_PTR(a) + alen, head - alen); if (argc > 0) { @@ -803,7 +792,8 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val mrb_int newlen; if (alen - len > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len); + head = alen + argc - len; + goto out_of_range; } newlen = alen + argc - len; if (newlen > ARY_CAPA(a)) { @@ -812,7 +802,6 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val if (len != argc) { mrb_value *ptr = ARY_PTR(a); - tail = head + len; value_move(ptr + head + argc, ptr + tail, alen - tail); ARY_SET_LEN(a, newlen); } @@ -843,7 +832,7 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg); } ary_make_shared(mrb, a); - b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); + b = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class); b->as.heap.ptr = a->as.heap.ptr + beg; b->as.heap.len = len; b->as.heap.aux.shared = a->as.heap.aux.shared; @@ -1095,7 +1084,7 @@ mrb_ary_index_m(mrb_state *mrb, mrb_value self) for (i = 0; i < RARRAY_LEN(self); i++) { if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { - return mrb_fixnum_value(i); + return mrb_int_value(mrb, i); } } return mrb_nil_value(); @@ -1109,7 +1098,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) for (i = RARRAY_LEN(self) - 1; i >= 0; i--) { if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { - return mrb_fixnum_value(i); + return mrb_int_value(mrb, i); } if (i > (len = RARRAY_LEN(self))) { i = len; @@ -1148,7 +1137,7 @@ mrb_ary_size(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - return mrb_fixnum_value(ARY_LEN(a)); + return mrb_int_value(mrb, ARY_LEN(a)); } MRB_API mrb_value @@ -1190,15 +1179,16 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) } MRB_API mrb_value -mrb_ary_entry(mrb_value ary, mrb_int offset) +mrb_ary_entry(mrb_value ary, mrb_int n) { - if (offset < 0) { - offset += RARRAY_LEN(ary); - } - if (offset < 0 || RARRAY_LEN(ary) <= offset) { - return mrb_nil_value(); - } - return RARRAY_PTR(ary)[offset]; + struct RArray *a = mrb_ary_ptr(ary); + mrb_int len = ARY_LEN(a); + + /* range check */ + if (n < 0) n += len; + if (n < 0 || len <= n) return mrb_nil_value(); + + return ARY_PTR(a)[n]; } static mrb_value @@ -1292,6 +1282,7 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1) { mrb_value ary2 = mrb_get_arg1(mrb); + mrb->c->ci->mid = 0; if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); if (!mrb_array_p(ary2)) { return mrb_false_value(); @@ -1306,6 +1297,7 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) { mrb_value ary2 = mrb_get_arg1(mrb); + mrb->c->ci->mid = 0; if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); if (!mrb_array_p(ary2)) { return mrb_nil_value(); diff --git a/src/backtrace.c b/src/backtrace.c index 6e7e66f8c..d6648cc43 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -32,44 +32,64 @@ mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace); static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *data) { - ptrdiff_t i; - int n = 0; - if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ - for (i=ciidx; i >= 0; i--) { + for (ptrdiff_t i=ciidx; i >= 0; i--) { struct backtrace_location loc; mrb_callinfo *ci; - const mrb_irep *irep; + const mrb_irep *irep = 0; const mrb_code *pc; uint32_t idx; ci = &mrb->c->cibase[i]; - if (!ci->proc) continue; - if (MRB_PROC_CFUNC_P(ci->proc)) continue; - - irep = ci->proc->body.irep; - if (!irep) continue; - - if (mrb->c->cibase[i].pc) { - pc = &mrb->c->cibase[i].pc[-1]; + if (!ci->proc || MRB_PROC_CFUNC_P(ci->proc)) { + if (!ci->mid) continue; + loc.lineno = -1; + idx = 0; } else { - continue; + irep = ci->proc->body.irep; + if (!irep) continue; + if (mrb->c->cibase[i].pc) { + pc = &mrb->c->cibase[i].pc[-1]; + } + else { + continue; + } + idx = (uint32_t)(pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, idx); + } + loc.method_id = ci->mid; + if (loc.lineno == -1) { + for (ptrdiff_t j=i-1; j >= 0; j--) { + ci = &mrb->c->cibase[j]; + + if (!ci->proc) continue; + if (MRB_PROC_CFUNC_P(ci->proc)) continue; + + irep = ci->proc->body.irep; + if (!irep) continue; + + if (mrb->c->cibase[j].pc) { + pc = &mrb->c->cibase[j].pc[-1]; + } + else { + continue; + } + + idx = (uint32_t)(pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, idx); + if (loc.lineno > 0) break; + } } - - idx = (uint32_t)(pc - irep->iseq); - loc.lineno = mrb_debug_get_line(mrb, irep, idx); - if (n++ == 0 && loc.lineno == -1 && ci->acc < 0) continue; loc.filename = mrb_debug_get_filename(mrb, irep, idx); if (!loc.filename) { loc.filename = "(unknown)"; } - loc.method_id = ci->mid; func(mrb, &loc, data); } } @@ -82,22 +102,24 @@ print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace) mrb_int i; mrb_int n = RARRAY_LEN(backtrace); mrb_value *loc, mesg; - FILE *stream = stderr; if (n != 0) { - fprintf(stream, "trace (most recent call last):\n"); + if (n > 1) { + fprintf(stderr, "trace (most recent call last):\n"); + } for (i=n-1,loc=&RARRAY_PTR(backtrace)[i]; i>0; i--,loc--) { if (mrb_string_p(*loc)) { - fprintf(stream, "\t[%d] %.*s\n", + fprintf(stderr, "\t[%d] %.*s\n", (int)i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); } } if (mrb_string_p(*loc)) { - fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); + fprintf(stderr, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); } } mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc)); - fprintf(stream, "%.*s\n", (int)RSTRING_LEN(mesg), RSTRING_PTR(mesg)); + fwrite(RSTRING_PTR(mesg), RSTRING_LEN(mesg), 1, stderr); + fputc('\n', stderr); } /* mrb_print_backtrace diff --git a/src/cdump.c b/src/cdump.c new file mode 100644 index 000000000..ecc27d9a1 --- /dev/null +++ b/src/cdump.c @@ -0,0 +1,468 @@ +/* +** dump.c - mruby binary dumper (mrbc binary format) +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/string.h> +#include <mruby/dump.h> +#include <mruby/irep.h> +#include <mruby/debug.h> + +#include <string.h> + +#ifndef MRB_NO_STDIO + +#ifndef MRB_NO_FLOAT +#include <mruby/endian.h> +#define MRB_FLOAT_FMT "%.17g" +#endif + +static int +cdump_pool(mrb_state *mrb, const mrb_pool_value *p, FILE *fp) +{ + if (p->tt & IREP_TT_NFLAG) { /* number */ + switch (p->tt) { +#ifdef MRB_64BIT + case IREP_TT_INT64: + if (p->u.i64 < INT32_MIN || INT32_MAX < p->u.i64) { + fprintf(fp, "{IREP_TT_INT64, {.i64=%" PRId64 "}},\n", p->u.i64); + } + else { + fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", (int32_t)p->u.i64); + } + break; +#endif + case IREP_TT_INT32: + fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", p->u.i32); + break; + case IREP_TT_FLOAT: +#ifndef MRB_NO_FLOAT + if (p->u.f == 0) { + fprintf(fp, "{IREP_TT_FLOAT, {.f=%#.1f}},\n", p->u.f); + } + else { + fprintf(fp, "{IREP_TT_FLOAT, {.f=" MRB_FLOAT_FMT "}},\n", p->u.f); + } +#endif + break; + case IREP_TT_BIGINT: + { + const char *s = p->u.str; + int len = s[0]+2; + fputs("{IREP_TT_BIGINT, {\"", fp); + for (int i=0; i<len; i++) { + fprintf(fp, "\\x%02x", (int)s[i]&0xff); + } + fputs("\"}},\n", fp); + } + break; + } + } + else { /* string */ + int i, len = p->tt>>2; + const char *s = p->u.str; + fprintf(fp, "{IREP_TT_STR|(%d<<2), {\"", len); + for (i=0; i<len; i++) { + fprintf(fp, "\\x%02x", (int)s[i]&0xff); + } + fputs("\"}},\n", fp); + } + return MRB_DUMP_OK; +} + +static mrb_bool +sym_name_word_p(const char *name, mrb_int len) +{ + if (len == 0) return FALSE; + if (name[0] != '_' && !ISALPHA(name[0])) return FALSE; + for (int i = 1; i < len; i++) { + if (name[i] != '_' && !ISALNUM(name[i])) return FALSE; + } + return TRUE; +} + +static mrb_bool +sym_name_with_equal_p(const char *name, mrb_int len) +{ + return len >= 2 && name[len-1] == '=' && sym_name_word_p(name, len-1); +} + +static mrb_bool +sym_name_with_question_mark_p(const char *name, mrb_int len) +{ + return len >= 2 && name[len-1] == '?' && sym_name_word_p(name, len-1); +} + +static mrb_bool +sym_name_with_bang_p(const char *name, mrb_int len) +{ + return len >= 2 && name[len-1] == '!' && sym_name_word_p(name, len-1); +} + +static mrb_bool +sym_name_ivar_p(const char *name, mrb_int len) +{ + return len >= 2 && name[0] == '@' && sym_name_word_p(name+1, len-1); +} + +static mrb_bool +sym_name_cvar_p(const char *name, mrb_int len) +{ + return len >= 3 && name[0] == '@' && sym_name_ivar_p(name+1, len-1); +} + +#define OPERATOR_SYMBOL(sym_name, name) {name, sym_name, sizeof(sym_name)-1} +struct operator_symbol { + const char *name; + const char *sym_name; + uint16_t sym_name_len; +}; +static const struct operator_symbol operator_table[] = { + OPERATOR_SYMBOL("!", "not"), + OPERATOR_SYMBOL("%", "mod"), + OPERATOR_SYMBOL("&", "and"), + OPERATOR_SYMBOL("*", "mul"), + OPERATOR_SYMBOL("+", "add"), + OPERATOR_SYMBOL("-", "sub"), + OPERATOR_SYMBOL("/", "div"), + OPERATOR_SYMBOL("<", "lt"), + OPERATOR_SYMBOL(">", "gt"), + OPERATOR_SYMBOL("^", "xor"), + OPERATOR_SYMBOL("`", "tick"), + OPERATOR_SYMBOL("|", "or"), + OPERATOR_SYMBOL("~", "neg"), + OPERATOR_SYMBOL("!=", "neq"), + OPERATOR_SYMBOL("!~", "nmatch"), + OPERATOR_SYMBOL("&&", "andand"), + OPERATOR_SYMBOL("**", "pow"), + OPERATOR_SYMBOL("+@", "plus"), + OPERATOR_SYMBOL("-@", "minus"), + OPERATOR_SYMBOL("<<", "lshift"), + OPERATOR_SYMBOL("<=", "le"), + OPERATOR_SYMBOL("==", "eq"), + OPERATOR_SYMBOL("=~", "match"), + OPERATOR_SYMBOL(">=", "ge"), + OPERATOR_SYMBOL(">>", "rshift"), + OPERATOR_SYMBOL("[]", "aref"), + OPERATOR_SYMBOL("||", "oror"), + OPERATOR_SYMBOL("<=>", "cmp"), + OPERATOR_SYMBOL("===", "eqq"), + OPERATOR_SYMBOL("[]=", "aset"), +}; + +static const char* +sym_operator_name(const char *sym_name, mrb_int len) +{ + mrb_sym table_size = sizeof(operator_table)/sizeof(struct operator_symbol); + if (operator_table[table_size-1].sym_name_len < len) return NULL; + + mrb_sym start, idx; + int cmp; + const struct operator_symbol *op_sym; + for (start = 0; table_size != 0; table_size/=2) { + idx = start+table_size/2; + op_sym = &operator_table[idx]; + cmp = (int)len-(int)op_sym->sym_name_len; + if (cmp == 0) { + cmp = memcmp(sym_name, op_sym->sym_name, len); + if (cmp == 0) return op_sym->name; + } + if (0 < cmp) { + start = ++idx; + --table_size; + } + } + return NULL; +} + +static const char* +sym_var_name(mrb_state *mrb, const char *initname, const char *key, int n) +{ + char buf[32]; + mrb_value s = mrb_str_new_cstr(mrb, initname); + mrb_str_cat_lit(mrb, s, "_"); + mrb_str_cat_cstr(mrb, s, key); + mrb_str_cat_lit(mrb, s, "_"); + snprintf(buf, sizeof(buf), "%d", n); + mrb_str_cat_cstr(mrb, s, buf); + return RSTRING_PTR(s); +} + +static int +cdump_sym(mrb_state *mrb, mrb_sym sym, const char *var_name, int idx, mrb_value init_syms_code, FILE *fp) +{ + if (sym == 0) return MRB_DUMP_INVALID_ARGUMENT; + + mrb_int len; + const char *name = mrb_sym_name_len(mrb, sym, &len), *op_name; + if (!name) return MRB_DUMP_INVALID_ARGUMENT; + if (sym_name_word_p(name, len)) { + fprintf(fp, "MRB_SYM(%s)", name); + } + else if (sym_name_with_equal_p(name, len)) { + fprintf(fp, "MRB_SYM_E(%.*s)", (int)(len-1), name); + } + else if (sym_name_with_question_mark_p(name, len)) { + fprintf(fp, "MRB_SYM_Q(%.*s)", (int)(len-1), name); + } + else if (sym_name_with_bang_p(name, len)) { + fprintf(fp, "MRB_SYM_B(%.*s)", (int)(len-1), name); + } + else if (sym_name_ivar_p(name, len)) { + fprintf(fp, "MRB_IVSYM(%s)", name+1); + } + else if (sym_name_cvar_p(name, len)) { + fprintf(fp, "MRB_CVSYM(%s)", name+2); + } + else if ((op_name = sym_operator_name(name, len))) { + fprintf(fp, "MRB_OPSYM(%s)", op_name); + } + else { + char buf[32]; + mrb_value name_obj = mrb_str_new(mrb, name, len); + mrb_str_cat_lit(mrb, init_syms_code, " "); + mrb_str_cat_cstr(mrb, init_syms_code, var_name); + snprintf(buf, sizeof(buf), "[%d] = ", idx); + mrb_str_cat_cstr(mrb, init_syms_code, buf); + mrb_str_cat_lit(mrb, init_syms_code, "mrb_intern_lit(mrb, "); + mrb_str_cat_str(mrb, init_syms_code, mrb_str_dump(mrb, name_obj)); + mrb_str_cat_lit(mrb, init_syms_code, ");\n"); + fputs("0", fp); + } + fputs(", ", fp); + return MRB_DUMP_OK; +} + +static int +cdump_syms(mrb_state *mrb, const char *name, const char *key, int n, int syms_len, const mrb_sym *syms, mrb_value init_syms_code, FILE *fp) +{ + int ai = mrb_gc_arena_save(mrb); + mrb_int code_len = RSTRING_LEN(init_syms_code); + const char *var_name = sym_var_name(mrb, name, key, n); + fprintf(fp, "mrb_DEFINE_SYMS_VAR(%s, %d, (", var_name, syms_len); + for (int i=0; i<syms_len; i++) { + cdump_sym(mrb, syms[i], var_name, i, init_syms_code, fp); + } + fputs("), ", fp); + if (code_len == RSTRING_LEN(init_syms_code)) fputs("const", fp); + fputs(");\n", fp); + mrb_gc_arena_restore(mrb, ai); + return MRB_DUMP_OK; +} + +//Handle the simple/common case of debug_info: +// - 1 file associated with a single irep +// - mrb_debug_line_ary format only +static int +simple_debug_info(mrb_irep_debug_info *info) +{ + if (!info || info->flen != 1) { + return 0; + } + return 1; +} + +//Adds debug information to c-structs and +//adds filenames in init_syms_code block +static int +cdump_debug(mrb_state *mrb, const char *name, int n, mrb_irep_debug_info *info, + mrb_value init_syms_code, FILE *fp) +{ + char buffer[256]; + const char *filename; + mrb_int file_len; + int len, i; + const char *line_type = "mrb_debug_line_ary"; + + if (!simple_debug_info(info)) + return MRB_DUMP_INVALID_IREP; + + len = info->files[0]->line_entry_count; + + filename = mrb_sym_name_len(mrb, info->files[0]->filename_sym, &file_len); + snprintf(buffer, sizeof(buffer), " %s_debug_file_%d.filename_sym = mrb_intern_lit(mrb,\"", + name, n); + mrb_str_cat_cstr(mrb, init_syms_code, buffer); + mrb_str_cat_cstr(mrb, init_syms_code, filename); + mrb_str_cat_cstr(mrb, init_syms_code, "\");\n"); + + switch (info->files[0]->line_type) { + case mrb_debug_line_ary: + fprintf(fp, "static uint16_t %s_debug_lines_%d[%d] = {", name, n, len); + for (i=0; i<len; i++) { + if (i%10 == 0) fputs("\n", fp); + fprintf(fp, "0x%04x,", info->files[0]->lines.ary[i]); + } + fputs("};\n", fp); + break; + + case mrb_debug_line_flat_map: + line_type = "mrb_debug_line_flat_map"; + fprintf(fp, "static struct mrb_irep_debug_info_line %s_debug_lines_%d[%d] = {", name, n, len); + for (i=0; i<len; i++) { + mrb_irep_debug_info_line *fmap = &info->files[0]->lines.flat_map[i]; + fprintf(fp, "\t{.start_pos=0x%04x,.line=%d},\n", fmap->start_pos, fmap->line); + } + fputs("};\n", fp); + break; + + case mrb_debug_line_packed_map: + line_type = "mrb_debug_line_packed_map"; + fprintf(fp, "static char %s_debug_lines_%d[] = \"", name, n); + uint8_t *pmap = info->files[0]->lines.packed_map; + for (i=0; i<len; i++) { + fprintf(fp, "\\x%02x", pmap[i]&0xff); + } + fputs("\";\n", fp); + break; + } + fprintf(fp, "static mrb_irep_debug_info_file %s_debug_file_%d = {\n", name, n); + fprintf(fp, "%d, %d, %d, %s, {%s_debug_lines_%d}};\n", + info->files[0]->start_pos, + info->files[0]->filename_sym, + info->files[0]->line_entry_count, + line_type, + name,n); + fprintf(fp, "static mrb_irep_debug_info_file *%s_debug_file_%d_ = &%s_debug_file_%d;\n", name, n, name, n); + + fprintf(fp, "static mrb_irep_debug_info %s_debug_%d = {\n", name, n); + fprintf(fp, "%d, %d, &%s_debug_file_%d_};\n", info->pc_count, info->flen, name, n); + + return MRB_DUMP_OK; +} + +static int +cdump_irep_struct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *name, int n, mrb_value init_syms_code, int *mp) +{ + int i, len; + int max = *mp; + int debug_available = 0; + + /* dump reps */ + if (irep->reps) { + for (i=0,len=irep->rlen; i<len; i++) { + *mp += len; + if (cdump_irep_struct(mrb, irep->reps[i], flags, fp, name, max+i, init_syms_code, mp) != MRB_DUMP_OK) + return MRB_DUMP_INVALID_ARGUMENT; + } + fprintf(fp, "static const mrb_irep *%s_reps_%d[%d] = {\n", name, n, len); + for (i=0,len=irep->rlen; i<len; i++) { + fprintf(fp, " &%s_irep_%d,\n", name, max+i); + } + fputs("};\n", fp); + } + /* dump pool */ + if (irep->pool) { + len=irep->plen; + fprintf(fp, "static const mrb_pool_value %s_pool_%d[%d] = {\n", name, n, len); + for (i=0; i<len; i++) { + if (cdump_pool(mrb, &irep->pool[i], fp) != MRB_DUMP_OK) + return MRB_DUMP_INVALID_ARGUMENT; + } + fputs("};\n", fp); + } + /* dump syms */ + if (irep->syms) { + cdump_syms(mrb, name, "syms", n, irep->slen, irep->syms, init_syms_code, fp); + } + /* dump iseq */ + len=irep->ilen+sizeof(struct mrb_irep_catch_handler)*irep->clen; + fprintf(fp, "static const mrb_code %s_iseq_%d[%d] = {", name, n, len); + for (i=0; i<len; i++) { + if (i%20 == 0) fputs("\n", fp); + fprintf(fp, "0x%02x,", irep->iseq[i]); + } + fputs("};\n", fp); + /* dump lv */ + if (irep->lv) { + cdump_syms(mrb, name, "lv", n, irep->nlocals-1, irep->lv, init_syms_code, fp); + } + /* dump debug */ + if (flags & MRB_DUMP_DEBUG_INFO) { + if(cdump_debug(mrb, name, n, irep->debug_info, + init_syms_code, fp) == MRB_DUMP_OK) { + debug_available = 1; + } + } + + + /* dump irep */ + fprintf(fp, "static const mrb_irep %s_irep_%d = {\n", name, n); + fprintf(fp, " %d,%d,%d,\n", irep->nlocals, irep->nregs, irep->clen); + fprintf(fp, " MRB_IREP_STATIC,%s_iseq_%d,\n", name, n); + if (irep->pool) { + fprintf(fp, " %s_pool_%d,", name, n); + } + else { + fputs( " NULL,", fp); + } + if (irep->syms) { + fprintf(fp, "%s_syms_%d,", name, n); + } + else { + fputs( "NULL,", fp); + } + if (irep->reps) { + fprintf(fp, "%s_reps_%d,\n", name, n); + } + else { + fputs( "NULL,\n", fp); + } + if (irep->lv) { + fprintf(fp, " %s_lv_%d,\n", name, n); + } + else { + fputs( " NULL,\t\t\t\t\t/* lv */\n", fp); + } + if(debug_available) { + fprintf(fp, " &%s_debug_%d,\n", name, n); + } + else { + fputs(" NULL,\t\t\t\t\t/* debug_info */\n", fp); + } + fprintf(fp, " %d,%d,%d,%d,0\n};\n", irep->ilen, irep->plen, irep->slen, irep->rlen); + + return MRB_DUMP_OK; +} + +int +mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname) +{ + if (fp == NULL || initname == NULL || initname[0] == '\0') { + return MRB_DUMP_INVALID_ARGUMENT; + } + if (fprintf(fp, "#include <mruby.h>\n" + "#include <mruby/irep.h>\n" + "#include <mruby/debug.h>\n" + "#include <mruby/proc.h>\n" + "#include <mruby/presym.h>\n" + "\n") < 0) { + return MRB_DUMP_WRITE_FAULT; + } + fputs("#define mrb_BRACED(...) {__VA_ARGS__}\n", fp); + fputs("#define mrb_DEFINE_SYMS_VAR(name, len, syms, qualifier) \\\n", fp); + fputs(" static qualifier mrb_sym name[len] = mrb_BRACED syms\n", fp); + fputs("\n", fp); + mrb_value init_syms_code = mrb_str_new_capa(mrb, 0); + int max = 1; + int n = cdump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max); + if (n != MRB_DUMP_OK) return n; + fprintf(fp, + "%s\n" + "const struct RProc %s[] = {{\n", + (flags & MRB_DUMP_STATIC) ? "static" + : "#ifdef __cplusplus\n" + "extern\n" + "#endif", + initname); + fprintf(fp, "NULL,NULL,MRB_TT_PROC,MRB_GC_RED,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname); + fputs("static void\n", fp); + fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname); + fputs("{\n", fp); + fputs(RSTRING_PTR(init_syms_code), fp); + fputs("}\n", fp); + return MRB_DUMP_OK; +} +#endif diff --git a/src/class.c b/src/class.c index dfd25b371..fdf63794b 100644 --- a/src/class.c +++ b/src/class.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stdarg.h> #include <mruby.h> #include <mruby/array.h> #include <mruby/hash.h> @@ -341,7 +340,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) struct RClass *sc, *c; if (o->c->tt == MRB_TT_SCLASS) return; - sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); + sc = MRB_OBJ_ALLOC(mrb, MRB_TT_SCLASS, mrb->class_class); sc->flags |= MRB_FL_CLASS_IS_INHERITED; sc->mt = mt_new(mrb); sc->iv = 0; @@ -800,18 +799,12 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -static mrb_value -to_ary(mrb_state *mrb, mrb_value val) -{ - mrb_check_type(mrb, val, MRB_TT_ARRAY); - return val; -} - -static mrb_value -to_hash(mrb_state *mrb, mrb_value val) +static void +ensure_class_type(mrb_state *mrb, mrb_value val) { - mrb_check_type(mrb, val, MRB_TT_HASH); - return val; + if (!class_ptr_p(val)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", val); + } } #define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss) @@ -859,6 +852,17 @@ mrb_get_arg1(mrb_state *mrb) return array_argv[0]; } +MRB_API mrb_bool +mrb_block_given_p(mrb_state *mrb) +{ + const mrb_callinfo *ci = mrb->c->ci; + int argc = ci->argc; + int idx = (argc < 0) ? 2 : argc + 1; + mrb_value b = ci->stack[idx]; + + return !mrb_nil_p(b); +} + void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); /* @@ -873,52 +877,57 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: Class/Module [mrb_value] + C: Class/Module [mrb_value] when ! follows, the value may be nil S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [const char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [const char*] NUL terminated string; z! gives NULL for nil a: Array [const mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - c: Class/Module [strcut RClass*] + c: Class/Module [strcut RClass*] c! gives NULL for nil f: Integer/Float [mrb_float] i: Integer/Float [mrb_int] b: boolean [mrb_bool] n: String/Symbol [mrb_sym] d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil - I: inline struct [void*] + I: inline struct [void*,struct RClass] I! gives NULL for nil &: block [mrb_value] &! raises exception if no block given *: rest argument [const mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given ':': keyword args [mrb_kwargs const] Get keyword arguments + + format modifiers: + + string note + ---------------------------------------------------------------------------------------------- + !: Switch to the alternate mode; The behaviour changes depending on the specifier + +: Request a not frozen object; However, except nil value */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...) { const char *fmt = format; char c; - mrb_int i = 0; + int i = 0; va_list ap; - mrb_int argc = mrb->c->ci->argc; - mrb_value *array_argv = mrb->c->ci->stack+1; + int argc = mrb->c->ci->argc; + const mrb_value *argv = mrb->c->ci->stack+1; mrb_bool argv_on_stack = argc >= 0; mrb_bool opt = FALSE; mrb_bool opt_skip = TRUE; - mrb_bool given = TRUE; + const mrb_value *pickarg = NULL; /* arguments currently being processed */ mrb_value kdict; mrb_bool reqkarg = FALSE; int argc_min = 0, argc_max = 0; if (!argv_on_stack) { - struct RArray *a = mrb_ary_ptr(*array_argv); - array_argv = ARY_PTR(a); + struct RArray *a = mrb_ary_ptr(*argv); + argv = ARY_PTR(a); argc = ARY_LEN(a); } va_start(ap, format); -#define ARGV array_argv - while ((c = *fmt++)) { switch (c) { case '|': @@ -930,6 +939,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE; goto check_exit; case '!': + case '+': break; case ':': reqkarg = TRUE; @@ -945,9 +955,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } check_exit: - if (reqkarg && argc > argc_min && mrb_hash_p(kdict = ARGV[argc - 1])) { + if (reqkarg && argc > argc_min && mrb_hash_p(kdict = argv[argc - 1])) { mrb_hash_check_kdict(mrb, kdict); - argc --; + argc--; } else { kdict = mrb_nil_value(); @@ -956,16 +966,45 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) opt = FALSE; i = 0; while ((c = *format++)) { - mrb_value *argv = ARGV; - mrb_bool altmode; + mrb_bool altmode = FALSE; + mrb_bool needmodify = FALSE; + + for (; *format; format++) { + switch (*format) { + case '!': + if (altmode) goto modifier_exit; /* not accept for multiple '!' */ + altmode = TRUE; + break; + case '+': + if (needmodify) goto modifier_exit; /* not accept for multiple '+' */ + needmodify = TRUE; + break; + default: + goto modifier_exit; + } + } + modifier_exit: switch (c) { case '|': case '*': case '&': case '?': case ':': + if (needmodify) { + bad_needmodify: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong `%c+` modified specifer`", c); + } break; default: - if (argc <= i) { + if (i < argc) { + pickarg = &argv[i++]; + if (needmodify && !mrb_nil_p(*pickarg)) { + if (mrb_immediate_p(*pickarg)) { + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", *pickarg); + } + mrb_check_frozen(mrb, mrb_obj_ptr(*pickarg)); + } + } + else { if (opt) { - given = FALSE; + pickarg = NULL; } else { mrb_argnum_error(mrb, argc, argc_min, argc_max); @@ -974,38 +1013,26 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; } - if (*format == '!') { - format ++; - altmode = TRUE; - } - else { - altmode = FALSE; - } - switch (c) { case 'o': - { - mrb_value *p; - - p = va_arg(ap, mrb_value*); - if (i < argc) { - *p = argv[i++]; - } - } - break; case 'C': + case 'S': + case 'A': + case 'H': { mrb_value *p; p = va_arg(ap, mrb_value*); - if (i < argc) { - mrb_value ss; - - ss = argv[i++]; - if (!class_ptr_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); + if (pickarg) { + if (!(altmode && mrb_nil_p(*pickarg))) { + switch (c) { + case 'C': ensure_class_type(mrb, *pickarg); break; + case 'S': mrb_ensure_string_type(mrb, *pickarg); break; + case 'A': mrb_ensure_array_type(mrb, *pickarg); break; + case 'H': mrb_ensure_hash_type(mrb, *pickarg); break; + } } - *p = ss; + *p = *pickarg; } } break; @@ -1014,114 +1041,72 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) struct RClass **p; p = va_arg(ap, struct RClass**); - if (i < argc) { - mrb_value ss; - - ss = argv[i++]; - if (!class_ptr_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); - } - *p = mrb_class_ptr(ss); - } - } - break; - case 'S': - { - mrb_value *p; - - p = va_arg(ap, mrb_value*); - if (i < argc) { - *p = argv[i++]; - if (!(altmode && mrb_nil_p(*p))) { - mrb_to_str(mrb, *p); + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { + *p = NULL; } - } - } - break; - case 'A': - { - mrb_value *p; - - p = va_arg(ap, mrb_value*); - if (i < argc) { - *p = argv[i++]; - if (!(altmode && mrb_nil_p(*p))) { - *p = to_ary(mrb, *p); - } - } - } - break; - case 'H': - { - mrb_value *p; - - p = va_arg(ap, mrb_value*); - if (i < argc) { - *p = argv[i++]; - if (!(altmode && mrb_nil_p(*p))) { - *p = to_hash(mrb, *p); + else { + ensure_class_type(mrb, *pickarg); + *p = mrb_class_ptr(*pickarg); } } } break; case 's': { - mrb_value ss; const char **ps = 0; mrb_int *pl = 0; ps = va_arg(ap, const char**); pl = va_arg(ap, mrb_int*); - if (i < argc) { - ss = argv[i++]; - if (altmode && mrb_nil_p(ss)) { + if (needmodify) goto bad_needmodify; + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { *ps = NULL; *pl = 0; } else { - mrb_to_str(mrb, ss); - *ps = RSTRING_PTR(ss); - *pl = RSTRING_LEN(ss); + mrb_ensure_string_type(mrb, *pickarg); + *ps = RSTRING_PTR(*pickarg); + *pl = RSTRING_LEN(*pickarg); } } } break; case 'z': { - mrb_value ss; const char **ps; ps = va_arg(ap, const char**); - if (i < argc) { - ss = argv[i++]; - if (altmode && mrb_nil_p(ss)) { + if (needmodify) goto bad_needmodify; + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { *ps = NULL; } else { - mrb_to_str(mrb, ss); - *ps = RSTRING_CSTR(mrb, ss); + mrb_ensure_string_type(mrb, *pickarg); + *ps = RSTRING_CSTR(mrb, *pickarg); } } } break; case 'a': { - mrb_value aa; struct RArray *a; const mrb_value **pb; mrb_int *pl; pb = va_arg(ap, const mrb_value**); pl = va_arg(ap, mrb_int*); - if (i < argc) { - aa = argv[i++]; - if (altmode && mrb_nil_p(aa)) { + if (needmodify) goto bad_needmodify; + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { *pb = 0; *pl = 0; } else { - aa = to_ary(mrb, aa); - a = mrb_ary_ptr(aa); + mrb_ensure_array_type(mrb, *pickarg); + a = mrb_ary_ptr(*pickarg); *pb = ARY_PTR(a); *pl = ARY_LEN(a); } @@ -1131,16 +1116,23 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) case 'I': { void* *p; - mrb_value ss; + struct RClass *klass; p = va_arg(ap, void**); - if (i < argc) { - ss = argv[i++]; - if (!mrb_istruct_p(ss)) - { - mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss); + klass = va_arg(ap, struct RClass*); + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { + *p = NULL; + } + else { + if (!mrb_obj_is_kind_of(mrb, *pickarg, klass)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not a %C", *pickarg, klass); + } + if (!mrb_istruct_p(*pickarg)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", *pickarg); + } + *p = mrb_istruct_ptr(*pickarg); } - *p = mrb_istruct_ptr(ss); } } break; @@ -1150,8 +1142,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_float *p; p = va_arg(ap, mrb_float*); - if (i < argc) { - *p = mrb_to_flo(mrb, argv[i++]); + if (pickarg) { + *p = mrb_as_float(mrb, *pickarg); } } break; @@ -1161,8 +1153,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_int *p; p = va_arg(ap, mrb_int*); - if (i < argc) { - *p = mrb_integer(mrb_to_int(mrb, argv[i++])); + if (pickarg) { + *p = mrb_as_int(mrb, *pickarg); } } break; @@ -1170,9 +1162,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_bool *boolp = va_arg(ap, mrb_bool*); - if (i < argc) { - mrb_value b = argv[i++]; - *boolp = mrb_test(b); + if (pickarg) { + *boolp = mrb_test(*pickarg); } } break; @@ -1181,11 +1172,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_sym *symp; symp = va_arg(ap, mrb_sym*); - if (i < argc) { - mrb_value ss; - - ss = argv[i++]; - *symp = to_sym(mrb, ss); + if (pickarg) { + *symp = to_sym(mrb, *pickarg); } } break; @@ -1196,13 +1184,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) datap = va_arg(ap, void**); type = va_arg(ap, struct mrb_data_type const*); - if (i < argc) { - mrb_value dd = argv[i++]; - if (altmode && mrb_nil_p(dd)) { + if (pickarg) { + if (altmode && mrb_nil_p(*pickarg)) { *datap = 0; } else { - *datap = mrb_data_get_ptr(mrb, dd, type); + *datap = mrb_data_get_ptr(mrb, *pickarg, type); } } } @@ -1234,7 +1221,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool *p; p = va_arg(ap, mrb_bool*); - *p = given; + *p = pickarg ? TRUE : FALSE; } break; @@ -1288,7 +1275,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large"); } - for (j = required; j > 0; j --, kname ++, values ++) { + for (j = required; j > 0; j--, kname++, values++) { mrb_value k = mrb_symbol_value(*kname); if (!mrb_hash_key_p(mrb, ksrc, k)) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %n", *kname); @@ -1297,7 +1284,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_gc_protect(mrb, *values); } - for (j = kwnum - required; j > 0; j --, kname ++, values ++) { + for (j = kwnum - required; j > 0; j--, kname++, values++) { mrb_value k = mrb_symbol_value(*kname); if (mrb_hash_key_p(mrb, ksrc, k)) { *values = mrb_hash_delete_key(mrb, ksrc, k); @@ -1328,8 +1315,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } -#undef ARGV - if (!c && argc > i) { mrb_argnum_error(mrb, argc, argc_min, argc_max); } @@ -1344,7 +1329,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super) { struct RClass *c; - c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); + c = MRB_OBJ_ALLOC(mrb, MRB_TT_CLASS, mrb->class_class); if (super) { c->super = super; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); @@ -1367,7 +1352,7 @@ boot_initmod(mrb_state *mrb, struct RClass *mod) static struct RClass* include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) { - struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); + struct RClass *ic = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, mrb->class_class); if (m->tt == MRB_TT_ICLASS) { m = m->c; } @@ -1435,7 +1420,7 @@ fix_include_module(mrb_state *mrb, struct RBasic *obj, void *data) { struct RClass **m = (struct RClass**)data; - if (obj->tt == MRB_TT_ICLASS && obj->c == m[0] && (obj->flags & MRB_FL_CLASS_IS_ORIGIN) == 0) { + if (obj->tt == MRB_TT_ICLASS && obj->c == m[0] && !MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) { struct RClass *ic = (struct RClass*)obj; include_module_at(mrb, ic, ic, m[1], 1); } @@ -1498,7 +1483,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) else { c0 = c; } - origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c0); + origin = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, c0); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->super = c->super; c->super = origin; @@ -1713,7 +1698,11 @@ mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, m static void mc_clear(mrb_state *mrb) { - memset(mrb->cache, 0, MRB_METHOD_CACHE_SIZE*sizeof(mrb->cache[0])); + static const struct mrb_cache_entry ce_zero ={0}; + + for (int i=0; i<MRB_METHOD_CACHE_SIZE; i++) { + mrb->cache[i] = ce_zero; + } } void @@ -2169,7 +2158,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super) MRB_API struct RClass* mrb_module_new(mrb_state *mrb) { - struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); + struct RClass *m = MRB_OBJ_ALLOC(mrb, MRB_TT_MODULE, mrb->module_class); boot_initmod(mrb, m); return m; } @@ -2197,6 +2186,7 @@ mrb_obj_class(mrb_state *mrb, mrb_value obj) MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) { + if (a == b) return; mrb_method_t m = mrb_method_search(mrb, c, b); if (!MRB_METHOD_CFUNC_P(m)) { @@ -2207,7 +2197,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) } else if (p->color != MRB_GC_RED) { struct RClass *tc = MRB_PROC_TARGET_CLASS(p); - struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); + struct REnv *e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL); e->mid = b; if (tc) { @@ -2216,6 +2206,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) } p->e.env = e; p->flags |= MRB_PROC_ENVSET; + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); } } mrb_define_method_raw(mrb, c, a, m); @@ -2269,6 +2260,8 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) } } +void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid); + static mrb_value mrb_mod_alias(mrb_state *mrb, mrb_value mod) { @@ -2277,6 +2270,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); + mrb_method_added(mrb, c, new_name); return mod; } @@ -2389,7 +2383,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) } /* const get with class path string */ - path = mrb_ensure_string_type(mrb, path); + mrb_ensure_string_type(mrb, path); ptr = RSTRING_PTR(path); len = RSTRING_LEN(path); off = 0; @@ -2445,6 +2439,7 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) mrb_sym sym; mrb_get_args(mrb, "n", &sym); + mrb->c->ci->mid = 0; if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym); @@ -2492,6 +2487,22 @@ mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); } +void +mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid) +{ + mrb_sym added; + mrb_value recv = mrb_obj_value(c); + + if (c->tt == MRB_TT_SCLASS) { + added = MRB_SYM(singleton_method_added); + recv = mrb_iv_get(mrb, recv, MRB_SYM(__attached__)); + } + else { + added = MRB_SYM(method_added); + } + mrb_funcall_id(mrb, recv, added, 1, mrb_symbol_value(mid)); +} + mrb_value mrb_mod_define_method_m(mrb_state *mrb, struct RClass *c) { @@ -2516,11 +2527,12 @@ mrb_mod_define_method_m(mrb_state *mrb, struct RClass *c) if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class); mrb_proc_copy(p, mrb_proc_ptr(blk)); p->flags |= MRB_PROC_STRICT; MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, c, mid, m); + mrb_method_added(mrb, c, mid); return mrb_symbol_value(mid); } @@ -2879,6 +2891,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.5 */ mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */ + mrb_define_method(mrb, bob, "singleton_method_added", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE()); @@ -2919,13 +2932,14 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); + mrb_define_method(mrb, bob, "method_added", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "prepend_features"); mrb_undef_method(mrb, cls, "extend_object"); mrb_undef_method(mrb, cls, "module_function"); - mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class); + mrb->top_self = MRB_OBJ_ALLOC(mrb, MRB_TT_OBJECT, mrb->object_class); mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE()); mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE()); mrb_define_singleton_method(mrb, mrb->top_self, "define_method", top_define_method, MRB_ARGS_ARG(1,1)); diff --git a/src/codedump.c b/src/codedump.c index f382bb7eb..431771ca9 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -57,7 +57,7 @@ print_header(mrb_state *mrb, const mrb_irep *irep, uint32_t i) printf("%03d ", (int)i); } -#define CASE(insn,ops) case insn: FETCH_ ## ops (); +#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn static void codedump(mrb_state *mrb, const mrb_irep *irep) @@ -68,7 +68,7 @@ codedump(mrb_state *mrb, const mrb_irep *irep) const char *file = NULL, *next_file; if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d ilen=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); if (irep->lv) { @@ -128,23 +128,21 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_header(mrb, irep, (uint32_t)i); ins = READ_B(); switch (ins) { - CASE(OP_NOP, Z); + CASE(OP_NOP, Z): printf("OP_NOP\n"); break; - CASE(OP_MOVE, BB); + CASE(OP_MOVE, BB): printf("OP_MOVE\tR%d\tR%d\t", a, b); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_LOADL16, BS); - goto op_loadl; - CASE(OP_LOADL, BB); - op_loadl: + + CASE(OP_LOADL, BB): switch (irep->pool[b].tt) { - case IREP_TT_FLOAT: #ifndef MRB_NO_FLOAT + case IREP_TT_FLOAT: printf("OP_LOADL\tR%d\tL(%d)\t; %f", a, b, (double)irep->pool[b].u.f); -#endif break; +#endif case IREP_TT_INT32: printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId32, a, b, irep->pool[b].u.i32); break; @@ -159,160 +157,160 @@ codedump(mrb_state *mrb, const mrb_irep *irep) } print_lv_a(mrb, irep, a); break; - CASE(OP_LOADI, BB); + CASE(OP_LOADI, BB): printf("OP_LOADI\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADINEG, BB); + CASE(OP_LOADINEG, BB): printf("OP_LOADI\tR%d\t-%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADI16, BS); + CASE(OP_LOADI16, BS): printf("OP_LOADI16\tR%d\t%d\t", a, (int)(int16_t)b); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADI32, BSS); + CASE(OP_LOADI32, BSS): printf("OP_LOADI32\tR%d\t%d\t", a, (int32_t)(((uint32_t)b<<16)+c)); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADI__1, B); + CASE(OP_LOADI__1, B): printf("OP_LOADI__1\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADI_0, B); goto L_LOADI; - CASE(OP_LOADI_1, B); goto L_LOADI; - CASE(OP_LOADI_2, B); goto L_LOADI; - CASE(OP_LOADI_3, B); goto L_LOADI; - CASE(OP_LOADI_4, B); goto L_LOADI; - CASE(OP_LOADI_5, B); goto L_LOADI; - CASE(OP_LOADI_6, B); goto L_LOADI; - CASE(OP_LOADI_7, B); + CASE(OP_LOADI_0, B): goto L_LOADI; + CASE(OP_LOADI_1, B): goto L_LOADI; + CASE(OP_LOADI_2, B): goto L_LOADI; + CASE(OP_LOADI_3, B): goto L_LOADI; + CASE(OP_LOADI_4, B): goto L_LOADI; + CASE(OP_LOADI_5, B): goto L_LOADI; + CASE(OP_LOADI_6, B): goto L_LOADI; + CASE(OP_LOADI_7, B): L_LOADI: printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADSYM16, BS); - goto op_loadsym; - CASE(OP_LOADSYM, BB); - op_loadsym: + CASE(OP_LOADSYM, BB): printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADNIL, B); + CASE(OP_LOADNIL, B): printf("OP_LOADNIL\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADSELF, B); + CASE(OP_LOADSELF, B): printf("OP_LOADSELF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADT, B); + CASE(OP_LOADT, B): printf("OP_LOADT\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_LOADF, B); + CASE(OP_LOADF, B): printf("OP_LOADF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETGV, BB); - printf("OP_GETGV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETGV, BB): + printf("OP_GETGV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETGV, BB); - printf("OP_SETGV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETGV, BB): + printf("OP_SETGV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETSV, BB); - printf("OP_GETSV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETSV, BB): + printf("OP_GETSV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETSV, BB); - printf("OP_SETSV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETSV, BB): + printf("OP_SETSV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETCONST, BB); - printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETCONST, BB): + printf("OP_GETCONST\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETCONST, BB); - printf("OP_SETCONST\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETCONST, BB): + printf("OP_SETCONST\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETMCNST, BB); - printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETMCNST, BB): + printf("OP_GETMCNST\tR%d\tR%d::%s\t", a, a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETMCNST, BB); - printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETMCNST, BB): + printf("OP_SETMCNST\tR%d::%s\tR%d\t", a+1, mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETIV, BB); - printf("OP_GETIV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETIV, BB): + printf("OP_GETIV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETIV, BB); - printf("OP_SETIV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETIV, BB): + printf("OP_SETIV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_GETUPVAR, BBB); - printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c); + CASE(OP_GETUPVAR, BBB): + printf("OP_GETUPVAR\tR%d\t%d\t%d\t", a, b, c); print_lv_a(mrb, irep, a); break; - CASE(OP_SETUPVAR, BBB); - printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); + CASE(OP_SETUPVAR, BBB): + printf("OP_SETUPVAR\tR%d\t%d\t%d\t", a, b, c); print_lv_a(mrb, irep, a); break; - CASE(OP_GETCV, BB); - printf("OP_GETCV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b])); + CASE(OP_GETCV, BB): + printf("OP_GETCV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_SETCV, BB); - printf("OP_SETCV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); + CASE(OP_SETCV, BB): + printf("OP_SETCV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; - CASE(OP_JMP, S); + CASE(OP_JMP, S): i = pc - irep->iseq; printf("OP_JMP\t\t%03d\n", (int)i+(int16_t)a); break; - CASE(OP_JMPUW, S); + CASE(OP_JMPUW, S): i = pc - irep->iseq; printf("OP_JMPUW\t\t%03d\n", (int)i+(int16_t)a); break; - CASE(OP_JMPIF, BS); + CASE(OP_JMPIF, BS): i = pc - irep->iseq; printf("OP_JMPIF\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; - CASE(OP_JMPNOT, BS); + CASE(OP_JMPNOT, BS): i = pc - irep->iseq; printf("OP_JMPNOT\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; - CASE(OP_JMPNIL, BS); + CASE(OP_JMPNIL, BS): i = pc - irep->iseq; printf("OP_JMPNIL\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; - CASE(OP_SENDV, BB); + CASE(OP_SENDV, BB): printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; - CASE(OP_SENDVB, BB); + CASE(OP_SENDVB, BB): printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; - CASE(OP_SEND, BBB); + CASE(OP_SEND, BBB): printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); break; - CASE(OP_SENDB, BBB); + CASE(OP_SENDB, BBB): printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); break; - CASE(OP_CALL, Z); + CASE(OP_SENDVK, BB): + printf("OP_SENDVK\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); + break; + CASE(OP_CALL, Z): printf("OP_CALL\n"); break; - CASE(OP_SUPER, BB); + CASE(OP_SUPER, BB): printf("OP_SUPER\tR%d\t%d\n", a, b); break; - CASE(OP_ARGARY, BS); - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a, + CASE(OP_ARGARY, BS): + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)\t", a, (b>>11)&0x3f, (b>>10)&0x1, (b>>5)&0x1f, @@ -320,7 +318,7 @@ codedump(mrb_state *mrb, const mrb_irep *irep) (b>>0)&0xf); print_lv_a(mrb, irep, a); break; - CASE(OP_ENTER, W); + CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", MRB_ASPEC_REQ(a), MRB_ASPEC_OPT(a), @@ -330,31 +328,31 @@ codedump(mrb_state *mrb, const mrb_irep *irep) MRB_ASPEC_KDICT(a), MRB_ASPEC_BLOCK(a)); break; - CASE(OP_KEY_P, BB); + CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_KEYEND, Z); + CASE(OP_KEYEND, Z): printf("OP_KEYEND\n"); break; - CASE(OP_KARG, BB); + CASE(OP_KARG, BB): printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_RETURN, B); + CASE(OP_RETURN, B): printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_RETURN_BLK, B); + CASE(OP_RETURN_BLK, B): printf("OP_RETURN_BLK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_BREAK, B); + CASE(OP_BREAK, B): printf("OP_BREAK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_BLKPUSH, BS); - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, + CASE(OP_BLKPUSH, BS): + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)\t", a, (b>>11)&0x3f, (b>>10)&0x1, (b>>5)&0x1f, @@ -362,112 +360,108 @@ codedump(mrb_state *mrb, const mrb_irep *irep) (b>>0)&0xf); print_lv_a(mrb, irep, a); break; - CASE(OP_LAMBDA, BB); - printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); - break; - CASE(OP_BLOCK, BB); - printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); - break; - CASE(OP_METHOD, BB); - printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); - break; - CASE(OP_LAMBDA16, BS); + CASE(OP_LAMBDA, BB): printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); break; - CASE(OP_BLOCK16, BS); + CASE(OP_BLOCK, BB): printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); break; - CASE(OP_METHOD16, BS); + CASE(OP_METHOD, BB): printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]); break; - CASE(OP_RANGE_INC, B); + CASE(OP_RANGE_INC, B): printf("OP_RANGE_INC\tR%d\n", a); break; - CASE(OP_RANGE_EXC, B); + CASE(OP_RANGE_EXC, B): printf("OP_RANGE_EXC\tR%d\n", a); break; - CASE(OP_DEF, BB); + CASE(OP_DEF, BB): printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; - CASE(OP_UNDEF, B); + CASE(OP_UNDEF, B): printf("OP_UNDEF\t:%s\n", mrb_sym_dump(mrb, irep->syms[a])); break; - CASE(OP_ALIAS, BB); + CASE(OP_ALIAS, BB): printf("OP_ALIAS\t:%s\t%s\n", mrb_sym_dump(mrb, irep->syms[a]), mrb_sym_dump(mrb, irep->syms[b])); break; - CASE(OP_ADD, B); + CASE(OP_ADD, B): printf("OP_ADD\tR%d\tR%d\n", a, a+1); break; - CASE(OP_ADDI, BB); - printf("OP_ADDI\tR%d\t%d\n", a, b); + CASE(OP_ADDI, BB): + printf("OP_ADDI\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - CASE(OP_SUB, B); + CASE(OP_SUB, B): printf("OP_SUB\tR%d\tR%d\n", a, a+1); break; - CASE(OP_SUBI, BB); - printf("OP_SUBI\tR%d\t%d\n", a, b); + CASE(OP_SUBI, BB): + printf("OP_SUBI\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - CASE(OP_MUL, B); + CASE(OP_MUL, B): printf("OP_MUL\tR%d\tR%d\n", a, a+1); break; - CASE(OP_DIV, B); + CASE(OP_DIV, B): printf("OP_DIV\tR%d\tR%d\n", a, a+1); break; - CASE(OP_LT, B); + CASE(OP_LT, B): printf("OP_LT\t\tR%d\tR%d\n", a, a+1); break; - CASE(OP_LE, B); + CASE(OP_LE, B): printf("OP_LE\t\tR%d\tR%d\n", a, a+1); break; - CASE(OP_GT, B); + CASE(OP_GT, B): printf("OP_GT\t\tR%d\tR%d\n", a, a+1); break; - CASE(OP_GE, B); + CASE(OP_GE, B): printf("OP_GE\t\tR%d\tR%d\n", a, a+1); break; - CASE(OP_EQ, B); + CASE(OP_EQ, B): printf("OP_EQ\t\tR%d\tR%d\n", a, a+1); break; - CASE(OP_ARRAY, BB); + CASE(OP_ARRAY, BB): printf("OP_ARRAY\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_ARRAY2, BBB); + CASE(OP_ARRAY2, BBB): printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_ARYCAT, B); - printf("OP_ARYCAT\tR%d\t", a); + CASE(OP_ARYCAT, B): + printf("OP_ARYCAT\tR%d\tR%d\t", a, a+1); print_lv_a(mrb, irep, a); break; - CASE(OP_ARYPUSH, B); - printf("OP_ARYPUSH\tR%d\t", a); + CASE(OP_ARYPUSH, BB): + printf("OP_ARYPUSH\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_ARYDUP, B); + CASE(OP_ARYDUP, B): printf("OP_ARYDUP\tR%d\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_AREF, BBB); + CASE(OP_AREF, BBB): printf("OP_AREF\tR%d\tR%d\t%d", a, b, c); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_ASET, BBB); + CASE(OP_ASET, BBB): printf("OP_ASET\tR%d\tR%d\t%d", a, b, c); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_APOST, BBB); + CASE(OP_APOST, BBB): printf("OP_APOST\tR%d\t%d\t%d", a, b, c); print_lv_a(mrb, irep, a); break; - CASE(OP_INTERN, B); - printf("OP_INTERN\tR%d", a); + CASE(OP_INTERN, B): + printf("OP_INTERN\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SYMBOL, BB): + mrb_assert((irep->pool[b].tt&IREP_TT_NFLAG)==0); + printf("OP_SYMBOL\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str); print_lv_a(mrb, irep, a); break; - CASE(OP_STRING16, BS); - goto op_string; - CASE(OP_STRING, BB); - op_string: + CASE(OP_STRING, BB): + mrb_assert((irep->pool[b].tt&IREP_TT_NFLAG)==0); if ((irep->pool[b].tt & IREP_TT_NFLAG) == 0) { printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str); } @@ -476,48 +470,48 @@ codedump(mrb_state *mrb, const mrb_irep *irep) } print_lv_a(mrb, irep, a); break; - CASE(OP_STRCAT, B); - printf("OP_STRCAT\tR%d\t", a); + CASE(OP_STRCAT, B): + printf("OP_STRCAT\tR%d\tR%d\n", a, a+1); print_lv_a(mrb, irep, a); break; - CASE(OP_HASH, BB); + CASE(OP_HASH, BB): printf("OP_HASH\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_HASHADD, BB); + CASE(OP_HASHADD, BB): printf("OP_HASHADD\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; - CASE(OP_HASHCAT, B); + CASE(OP_HASHCAT, B): printf("OP_HASHCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_OCLASS, B); + CASE(OP_OCLASS, B): printf("OP_OCLASS\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_CLASS, BB); + CASE(OP_CLASS, BB): printf("OP_CLASS\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_MODULE, BB); + CASE(OP_MODULE, BB): printf("OP_MODULE\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_EXEC, BB); + CASE(OP_EXEC, BB): printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, (void*)irep->reps[b]); print_lv_a(mrb, irep, a); break; - CASE(OP_SCLASS, B); + CASE(OP_SCLASS, B): printf("OP_SCLASS\tR%d\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_TCLASS, B); + CASE(OP_TCLASS, B): printf("OP_TCLASS\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_ERR, B); + CASE(OP_ERR, B): if ((irep->pool[a].tt & IREP_TT_NFLAG) == 0) { printf("OP_ERR\t%s\n", irep->pool[a].u.str); } @@ -525,27 +519,52 @@ codedump(mrb_state *mrb, const mrb_irep *irep) printf("OP_ERR\tL(%d)\n", a); } break; - CASE(OP_EXCEPT, B); + CASE(OP_EXCEPT, B): printf("OP_EXCEPT\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_RESCUE, BB); + CASE(OP_RESCUE, BB): printf("OP_RESCUE\tR%d\tR%d", a, b); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_RAISEIF, B); + CASE(OP_RAISEIF, B): printf("OP_RAISEIF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; - CASE(OP_DEBUG, BBB); + CASE(OP_DEBUG, BBB): printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); break; - CASE(OP_STOP, Z); + CASE(OP_STOP, Z): printf("OP_STOP\n"); break; + CASE(OP_EXT1, Z): + ins = READ_B(); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT2, Z): + ins = READ_B(); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT3, Z): + ins = READ_B(); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: printf("OP_unknown (0x%x)\n", ins); break; diff --git a/src/debug.c b/src/debug.c index c03c91cf5..e570e8068 100644 --- a/src/debug.c +++ b/src/debug.c @@ -35,19 +35,46 @@ get_file(mrb_irep_debug_info *info, uint32_t pc) return *ret; } -static mrb_debug_line_type -select_line_type(const uint16_t *lines, size_t lines_len) +size_t +mrb_packed_int_len(uint32_t num) { - size_t line_count = 0; - int prev_line = -1; - size_t i; - for (i = 0; i < lines_len; ++i) { - if (lines[i] != prev_line) { - ++line_count; - } - } - return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count) - ? mrb_debug_line_ary : mrb_debug_line_flat_map; + size_t llen = 0; + + do { + llen++; + } while (num >>= 7); + return llen; +} + +size_t +mrb_packed_int_encode(uint32_t num, uint8_t *p, uint8_t *pend) +{ + size_t llen = 0; + + do { + uint8_t byte = num & 0x7f; + num >>= 7; + if (num != 0) byte |= 0x80; + if (p < pend) *p++ = byte; + llen++; + } while (num != 0); + + return llen; +} + +uint32_t +mrb_packed_int_decode(uint8_t *p, uint8_t **newpos) +{ + size_t i = 0, shift = 0; + uint32_t n = 0; + + do { + n |= ((uint32_t)(p[i] & 0x7f)) << shift; + i++; + shift += 7; + } while (shift < sizeof(uint32_t) * 8 && (p[i - 1] & 0x80)); + if (newpos) *newpos = p + i; + return n; } MRB_API char const* @@ -102,6 +129,19 @@ mrb_debug_get_line(mrb_state *mrb, const mrb_irep *irep, uint32_t pc) return ret->line; } + + case mrb_debug_line_packed_map: { + uint8_t *p = f->lines.packed_map; + uint8_t *pend = p + f->line_entry_count; + uint32_t pos = 0, line = 0, line_diff; + while (p < pend) { + pos += mrb_packed_int_decode(p, &p); + line_diff = mrb_packed_int_decode(p, &p); + if (pc < pos) break; + line += line_diff; + } + return line; + } } } } @@ -144,10 +184,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, } f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); - d->files = (mrb_irep_debug_info_file**)( - d->files - ? mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1)) - : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*))); + d->files = (mrb_irep_debug_info_file**)mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1)); d->files[d->flen++] = f; file_pc_count = end_pos - start_pos; @@ -157,42 +194,32 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, fn_len = strlen(filename); f->filename_sym = mrb_intern(mrb, filename, fn_len); - - f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); + f->line_type = mrb_debug_line_packed_map; f->lines.ptr = NULL; - switch (f->line_type) { - case mrb_debug_line_ary: - f->line_entry_count = file_pc_count; - f->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); - for (i = 0; i < file_pc_count; ++i) { - f->lines.ary[i] = lines[start_pos + i]; - } - break; - - case mrb_debug_line_flat_map: { - uint16_t prev_line = 0; - mrb_irep_debug_info_line m; - f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); - f->line_entry_count = 0; - for (i = 0; i < file_pc_count; ++i) { - if (lines[start_pos + i] == prev_line) { continue; } - - f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( - mrb, f->lines.flat_map, - sizeof(mrb_irep_debug_info_line) * (f->line_entry_count + 1)); - m.start_pos = start_pos + i; - m.line = lines[start_pos + i]; - f->lines.flat_map[f->line_entry_count] = m; - - /* update */ - ++f->line_entry_count; - prev_line = lines[start_pos + i]; - } - } break; - - default: mrb_assert(0); break; + uint16_t prev_line = 0; + uint32_t prev_pc = 0; + size_t packed_size = 0; + uint8_t *p, *pend; + + for (i = 0; i < file_pc_count; ++i) { + if (lines[start_pos + i] == prev_line) continue; + packed_size += mrb_packed_int_len(start_pos+i-prev_pc); + prev_pc = start_pos+i; + packed_size += mrb_packed_int_len(lines[start_pos+i]-prev_line); + prev_line = lines[start_pos + i]; + } + p = f->lines.packed_map = (uint8_t*)mrb_malloc(mrb, packed_size); + pend = p + packed_size; + prev_line = 0; prev_pc = 0; + for (i = 0; i < file_pc_count; ++i) { + if (lines[start_pos + i] == prev_line) continue; + p += mrb_packed_int_encode(start_pos+i-prev_pc, p, pend); + prev_pc = start_pos + i; + p += mrb_packed_int_encode(lines[start_pos + i]-prev_line, p, pend); + prev_line = lines[start_pos + i]; } + f->line_entry_count = (uint32_t)packed_size; return f; } diff --git a/src/dump.c b/src/dump.c index 91edf17d3..4327cb375 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1,20 +1,18 @@ /* -** dump.c - mruby binary dumper (mrbc binary format) +** cdump.c - mruby binary dumper (in C) ** ** See Copyright Notice in mruby.h */ -#include <string.h> -#include <limits.h> -#include <math.h> +#include <mruby.h> #include <mruby/dump.h> #include <mruby/string.h> #include <mruby/irep.h> #include <mruby/debug.h> +#include <string.h> #ifndef MRB_NO_FLOAT #include <mruby/endian.h> -#define MRB_FLOAT_FMT "%.17g" #endif static size_t get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep); @@ -414,6 +412,10 @@ get_debug_record_size(mrb_state *mrb, const mrb_irep *irep) ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count); break; + case mrb_debug_line_packed_map: + ret += (size_t)(file->line_entry_count); + break; + default: mrb_assert(0); break; } } @@ -508,6 +510,11 @@ write_debug_record_1(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, mrb_sym } } break; + case mrb_debug_line_packed_map: { + memcpy(cur, file->lines.packed_map, file->line_entry_count); + cur += file->line_entry_count; + } break; + default: mrb_assert(0); break; } } @@ -929,428 +936,4 @@ mrb_dump_irep_cfunc(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *f return result; } -static int -dump_pool(mrb_state *mrb, const mrb_pool_value *p, FILE *fp) -{ - if (p->tt & IREP_TT_NFLAG) { /* number */ - switch (p->tt) { -#ifdef MRB_64BIT - case IREP_TT_INT64: - if (p->u.i64 < INT32_MIN || INT32_MAX < p->u.i64) { - fprintf(fp, "{IREP_TT_INT64, {.i64=%" PRId64 "}},\n", p->u.i64); - } - else { - fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", (int32_t)p->u.i64); - } - break; -#endif - case IREP_TT_INT32: - fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", p->u.i32); - break; - case IREP_TT_FLOAT: -#ifndef MRB_NO_FLOAT - if (p->u.f == 0) { - fprintf(fp, "{IREP_TT_FLOAT, {.f=%#.1f}},\n", p->u.f); - } - else { - fprintf(fp, "{IREP_TT_FLOAT, {.f=" MRB_FLOAT_FMT "}},\n", p->u.f); - } -#endif - break; - case IREP_TT_BIGINT: - { - const char *s = p->u.str; - int len = s[0]+2; - fputs("{IREP_TT_BIGINT, {\"", fp); - for (int i=0; i<len; i++) { - fprintf(fp, "\\x%02x", (int)s[i]&0xff); - } - fputs("\"}},\n", fp); - } - break; - } - } - else { /* string */ - int i, len = p->tt>>2; - const char *s = p->u.str; - fprintf(fp, "{IREP_TT_STR|(%d<<2), {\"", len); - for (i=0; i<len; i++) { - fprintf(fp, "\\x%02x", (int)s[i]&0xff); - } - fputs("\"}},\n", fp); - } - return MRB_DUMP_OK; -} - -static mrb_bool -sym_name_word_p(const char *name, mrb_int len) -{ - if (len == 0) return FALSE; - if (name[0] != '_' && !ISALPHA(name[0])) return FALSE; - for (int i = 1; i < len; i++) { - if (name[i] != '_' && !ISALNUM(name[i])) return FALSE; - } - return TRUE; -} - -static mrb_bool -sym_name_with_equal_p(const char *name, mrb_int len) -{ - return len >= 2 && name[len-1] == '=' && sym_name_word_p(name, len-1); -} - -static mrb_bool -sym_name_with_question_mark_p(const char *name, mrb_int len) -{ - return len >= 2 && name[len-1] == '?' && sym_name_word_p(name, len-1); -} - -static mrb_bool -sym_name_with_bang_p(const char *name, mrb_int len) -{ - return len >= 2 && name[len-1] == '!' && sym_name_word_p(name, len-1); -} - -static mrb_bool -sym_name_ivar_p(const char *name, mrb_int len) -{ - return len >= 2 && name[0] == '@' && sym_name_word_p(name+1, len-1); -} - -static mrb_bool -sym_name_cvar_p(const char *name, mrb_int len) -{ - return len >= 3 && name[0] == '@' && sym_name_ivar_p(name+1, len-1); -} - -#define OPERATOR_SYMBOL(sym_name, name) {name, sym_name, sizeof(sym_name)-1} -struct operator_symbol { - const char *name; - const char *sym_name; - uint16_t sym_name_len; -}; -static const struct operator_symbol operator_table[] = { - OPERATOR_SYMBOL("!", "not"), - OPERATOR_SYMBOL("%", "mod"), - OPERATOR_SYMBOL("&", "and"), - OPERATOR_SYMBOL("*", "mul"), - OPERATOR_SYMBOL("+", "add"), - OPERATOR_SYMBOL("-", "sub"), - OPERATOR_SYMBOL("/", "div"), - OPERATOR_SYMBOL("<", "lt"), - OPERATOR_SYMBOL(">", "gt"), - OPERATOR_SYMBOL("^", "xor"), - OPERATOR_SYMBOL("`", "tick"), - OPERATOR_SYMBOL("|", "or"), - OPERATOR_SYMBOL("~", "neg"), - OPERATOR_SYMBOL("!=", "neq"), - OPERATOR_SYMBOL("!~", "nmatch"), - OPERATOR_SYMBOL("&&", "andand"), - OPERATOR_SYMBOL("**", "pow"), - OPERATOR_SYMBOL("+@", "plus"), - OPERATOR_SYMBOL("-@", "minus"), - OPERATOR_SYMBOL("<<", "lshift"), - OPERATOR_SYMBOL("<=", "le"), - OPERATOR_SYMBOL("==", "eq"), - OPERATOR_SYMBOL("=~", "match"), - OPERATOR_SYMBOL(">=", "ge"), - OPERATOR_SYMBOL(">>", "rshift"), - OPERATOR_SYMBOL("[]", "aref"), - OPERATOR_SYMBOL("||", "oror"), - OPERATOR_SYMBOL("<=>", "cmp"), - OPERATOR_SYMBOL("===", "eqq"), - OPERATOR_SYMBOL("[]=", "aset"), -}; - -static const char* -sym_operator_name(const char *sym_name, mrb_int len) -{ - mrb_sym table_size = sizeof(operator_table)/sizeof(struct operator_symbol); - if (operator_table[table_size-1].sym_name_len < len) return NULL; - - mrb_sym start, idx; - int cmp; - const struct operator_symbol *op_sym; - for (start = 0; table_size != 0; table_size/=2) { - idx = start+table_size/2; - op_sym = &operator_table[idx]; - cmp = (int)len-(int)op_sym->sym_name_len; - if (cmp == 0) { - cmp = memcmp(sym_name, op_sym->sym_name, len); - if (cmp == 0) return op_sym->name; - } - if (0 < cmp) { - start = ++idx; - --table_size; - } - } - return NULL; -} - -static const char* -sym_var_name(mrb_state *mrb, const char *initname, const char *key, int n) -{ - char buf[32]; - mrb_value s = mrb_str_new_cstr(mrb, initname); - mrb_str_cat_lit(mrb, s, "_"); - mrb_str_cat_cstr(mrb, s, key); - mrb_str_cat_lit(mrb, s, "_"); - snprintf(buf, sizeof(buf), "%d", n); - mrb_str_cat_cstr(mrb, s, buf); - return RSTRING_PTR(s); -} - -static int -dump_sym(mrb_state *mrb, mrb_sym sym, const char *var_name, int idx, mrb_value init_syms_code, FILE *fp) -{ - if (sym == 0) return MRB_DUMP_INVALID_ARGUMENT; - - mrb_int len; - const char *name = mrb_sym_name_len(mrb, sym, &len), *op_name; - if (!name) return MRB_DUMP_INVALID_ARGUMENT; - if (sym_name_word_p(name, len)) { - fprintf(fp, "MRB_SYM(%s)", name); - } - else if (sym_name_with_equal_p(name, len)) { - fprintf(fp, "MRB_SYM_E(%.*s)", (int)(len-1), name); - } - else if (sym_name_with_question_mark_p(name, len)) { - fprintf(fp, "MRB_SYM_Q(%.*s)", (int)(len-1), name); - } - else if (sym_name_with_bang_p(name, len)) { - fprintf(fp, "MRB_SYM_B(%.*s)", (int)(len-1), name); - } - else if (sym_name_ivar_p(name, len)) { - fprintf(fp, "MRB_IVSYM(%s)", name+1); - } - else if (sym_name_cvar_p(name, len)) { - fprintf(fp, "MRB_CVSYM(%s)", name+2); - } - else if ((op_name = sym_operator_name(name, len))) { - fprintf(fp, "MRB_OPSYM(%s)", op_name); - } - else { - char buf[32]; - mrb_value name_obj = mrb_str_new(mrb, name, len); - mrb_str_cat_lit(mrb, init_syms_code, " "); - mrb_str_cat_cstr(mrb, init_syms_code, var_name); - snprintf(buf, sizeof(buf), "[%d] = ", idx); - mrb_str_cat_cstr(mrb, init_syms_code, buf); - mrb_str_cat_lit(mrb, init_syms_code, "mrb_intern_lit(mrb, "); - mrb_str_cat_str(mrb, init_syms_code, mrb_str_dump(mrb, name_obj)); - mrb_str_cat_lit(mrb, init_syms_code, ");\n"); - fputs("0", fp); - } - fputs(", ", fp); - return MRB_DUMP_OK; -} - -static int -dump_syms(mrb_state *mrb, const char *name, const char *key, int n, int syms_len, const mrb_sym *syms, mrb_value init_syms_code, FILE *fp) -{ - int ai = mrb_gc_arena_save(mrb); - mrb_int code_len = RSTRING_LEN(init_syms_code); - const char *var_name = sym_var_name(mrb, name, key, n); - fprintf(fp, "mrb_DEFINE_SYMS_VAR(%s, %d, (", var_name, syms_len); - for (int i=0; i<syms_len; i++) { - dump_sym(mrb, syms[i], var_name, i, init_syms_code, fp); - } - fputs("), ", fp); - if (code_len == RSTRING_LEN(init_syms_code)) fputs("const", fp); - fputs(");\n", fp); - mrb_gc_arena_restore(mrb, ai); - return MRB_DUMP_OK; -} - -//Handle the simple/common case of debug_info: -// - 1 file associated with a single irep -// - mrb_debug_line_ary format only -static int -simple_debug_info(mrb_irep_debug_info *info) -{ - if (!info || - info->flen != 1 || - info->files[0]->line_type != mrb_debug_line_ary) { - return 0; - } - return 1; -} - -//Adds debug information to c-structs and -//adds filenames in init_syms_code block -static int -dump_debug(mrb_state *mrb, const char *name, int n, mrb_irep_debug_info *info, - mrb_value init_syms_code, FILE *fp) -{ - char buffer[256]; - const char *filename; - mrb_int file_len; - int len, i; - - if (!simple_debug_info(info)) - return MRB_DUMP_INVALID_IREP; - - len = info->files[0]->line_entry_count; - - filename = mrb_sym_name_len(mrb, info->files[0]->filename_sym, &file_len); - snprintf(buffer, sizeof(buffer), " %s_debug_file_%d.filename_sym = mrb_intern_lit(mrb,\"", - name, n); - mrb_str_cat_cstr(mrb, init_syms_code, buffer); - mrb_str_cat_cstr(mrb, init_syms_code, filename); - mrb_str_cat_cstr(mrb, init_syms_code, "\");\n"); - - fprintf(fp, "static uint16_t %s_debug_lines_%d[%d] = {", name, n, len); - for (i=0; i<len; i++) { - if (i%10 == 0) fputs("\n", fp); - fprintf(fp, "0x%04x,", info->files[0]->lines.ary[i]); - } - fputs("};\n", fp); - - fprintf(fp, "static mrb_irep_debug_info_file %s_debug_file_%d = {\n", name, n); - fprintf(fp, "%d, %d, %d, mrb_debug_line_ary, {%s_debug_lines_%d}};\n", - info->files[0]->start_pos, - info->files[0]->filename_sym, - info->files[0]->line_entry_count, - name,n); - fprintf(fp, "static mrb_irep_debug_info_file *%s_debug_file_%d_ = &%s_debug_file_%d;\n", name, n, name, n); - - fprintf(fp, "static mrb_irep_debug_info %s_debug_%d = {\n", name, n); - fprintf(fp, "%d, %d, &%s_debug_file_%d_};\n", info->pc_count, info->flen, name, n); - - return MRB_DUMP_OK; -} - -static int -dump_irep_struct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *name, int n, mrb_value init_syms_code, int *mp) -{ - int i, len; - int max = *mp; - int debug_available = 0; - - /* dump reps */ - if (irep->reps) { - for (i=0,len=irep->rlen; i<len; i++) { - *mp += len; - if (dump_irep_struct(mrb, irep->reps[i], flags, fp, name, max+i, init_syms_code, mp) != MRB_DUMP_OK) - return MRB_DUMP_INVALID_ARGUMENT; - } - fprintf(fp, "static const mrb_irep *%s_reps_%d[%d] = {\n", name, n, len); - for (i=0,len=irep->rlen; i<len; i++) { - fprintf(fp, " &%s_irep_%d,\n", name, max+i); - } - fputs("};\n", fp); - } - /* dump pool */ - if (irep->pool) { - len=irep->plen; - fprintf(fp, "static const mrb_pool_value %s_pool_%d[%d] = {\n", name, n, len); - for (i=0; i<len; i++) { - if (dump_pool(mrb, &irep->pool[i], fp) != MRB_DUMP_OK) - return MRB_DUMP_INVALID_ARGUMENT; - } - fputs("};\n", fp); - } - /* dump syms */ - if (irep->syms) { - dump_syms(mrb, name, "syms", n, irep->slen, irep->syms, init_syms_code, fp); - } - /* dump iseq */ - len=irep->ilen+sizeof(struct mrb_irep_catch_handler)*irep->clen; - fprintf(fp, "static const mrb_code %s_iseq_%d[%d] = {", name, n, len); - for (i=0; i<len; i++) { - if (i%20 == 0) fputs("\n", fp); - fprintf(fp, "0x%02x,", irep->iseq[i]); - } - fputs("};\n", fp); - /* dump lv */ - if (irep->lv) { - dump_syms(mrb, name, "lv", n, irep->nlocals-1, irep->lv, init_syms_code, fp); - } - /* dump debug */ - if (flags & MRB_DUMP_DEBUG_INFO) { - if(dump_debug(mrb, name, n, irep->debug_info, - init_syms_code, fp) == MRB_DUMP_OK) { - debug_available = 1; - } - } - - - /* dump irep */ - fprintf(fp, "static const mrb_irep %s_irep_%d = {\n", name, n); - fprintf(fp, " %d,%d,%d,\n", irep->nlocals, irep->nregs, irep->clen); - fprintf(fp, " MRB_IREP_STATIC,%s_iseq_%d,\n", name, n); - if (irep->pool) { - fprintf(fp, " %s_pool_%d,", name, n); - } - else { - fputs( " NULL,", fp); - } - if (irep->syms) { - fprintf(fp, "%s_syms_%d,", name, n); - } - else { - fputs( "NULL,", fp); - } - if (irep->reps) { - fprintf(fp, "%s_reps_%d,\n", name, n); - } - else { - fputs( "NULL,\n", fp); - } - if (irep->lv) { - fprintf(fp, " %s_lv_%d,\n", name, n); - } - else { - fputs( " NULL,\t\t\t\t\t/* lv */\n", fp); - } - if(debug_available) { - fprintf(fp, " &%s_debug_%d,\n", name, n); - } - else { - fputs(" NULL,\t\t\t\t\t/* debug_info */\n", fp); - } - fprintf(fp, " %d,%d,%d,%d,0\n};\n", irep->ilen, irep->plen, irep->slen, irep->rlen); - - return MRB_DUMP_OK; -} - -int -mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname) -{ - if (fp == NULL || initname == NULL || initname[0] == '\0') { - return MRB_DUMP_INVALID_ARGUMENT; - } - if (fprintf(fp, "#include <mruby.h>\n" - "#include <mruby/irep.h>\n" - "#include <mruby/debug.h>\n" - "#include <mruby/proc.h>\n" - "#include <mruby/presym.h>\n" - "\n") < 0) { - return MRB_DUMP_WRITE_FAULT; - } - fputs("#define mrb_BRACED(...) {__VA_ARGS__}\n", fp); - fputs("#define mrb_DEFINE_SYMS_VAR(name, len, syms, qualifier) \\\n", fp); - fputs(" static qualifier mrb_sym name[len] = mrb_BRACED syms\n", fp); - fputs("\n", fp); - mrb_value init_syms_code = mrb_str_new_capa(mrb, 0); - int max = 1; - int n = dump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max); - if (n != MRB_DUMP_OK) return n; - fprintf(fp, - "%s\n" - "const struct RProc %s[] = {{\n", - (flags & MRB_DUMP_STATIC) ? "static" - : "#ifdef __cplusplus\n" - "extern\n" - "#endif", - initname); - fprintf(fp, "NULL,NULL,MRB_TT_PROC,MRB_GC_RED,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname); - fputs("static void\n", fp); - fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname); - fputs("{\n", fp); - fputs(RSTRING_PTR(init_syms_code), fp); - fputs("}\n", fp); - return MRB_DUMP_OK; -} - #endif /* MRB_NO_STDIO */ diff --git a/src/error.c b/src/error.c index 5d9b367bd..5ceff2436 100644 --- a/src/error.c +++ b/src/error.c @@ -5,7 +5,6 @@ */ #include <errno.h> -#include <stdarg.h> #include <stdlib.h> #include <mruby.h> #include <mruby/array.h> @@ -19,17 +18,20 @@ #include <mruby/presym.h> MRB_API mrb_value -mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) +mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { - mrb_value arg = mrb_str_new(mrb, ptr, len); - return mrb_obj_new(mrb, c, 1, &arg); + mrb_ensure_string_type(mrb, str); + + struct RBasic* e = mrb_obj_alloc(mrb, MRB_TT_EXCEPTION, c); + mrb_value exc = mrb_obj_value(e); + mrb_iv_set(mrb, exc, MRB_SYM(mesg), str); + return exc; } MRB_API mrb_value -mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) +mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) { - mrb_to_str(mrb, str); - return mrb_obj_new(mrb, c, 1, &str); + return mrb_exc_new_str(mrb, c, mrb_str_new(mrb, ptr, len)); } /* @@ -287,7 +289,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) #else i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); #endif - obj = mrb_fixnum_value(i); + obj = mrb_int_value(mrb, i); goto L_cat_obj; #ifndef MRB_NO_FLOAT case 'f': @@ -302,6 +304,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) obj = mrb_str_new(mrb, chars, len); goto L_cat_obj; } + L_cat_plain: mrb_str_cat(mrb, result, b, e - b - 1); mrb_str_cat(mrb, result, chars, len); b = ++p; @@ -325,10 +328,15 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) obj = va_arg(ap, mrb_value); L_cat_obj: str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj); - chars = RSTRING_PTR(str); - len = RSTRING_LEN(str); - inspect = FALSE; - goto L_cat; + if (mrb_type(str) != MRB_TT_STRING) { + chars = "void (no string conversion)"; + len = strlen(chars); + } + else { + chars = RSTRING_PTR(str); + len = RSTRING_LEN(str); + } + goto L_cat_plain; case 'C': cls = va_arg(ap, struct RClass*); L_cat_class: @@ -352,7 +360,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) L_cat_current: chars = p; len = 1; - goto L_cat; + goto L_cat_plain; default: mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p); } @@ -381,41 +389,37 @@ mrb_format(mrb_state *mrb, const char *format, ...) return str; } -static mrb_noreturn void -raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv) +static mrb_value +error_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap) { - mrb_value mesg; - - mesg = mrb_vformat(mrb, fmt, ap); - if (argv == NULL) { - argv = &mesg; - } - else { - argv[0] = mesg; - } - mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv)); + mrb_value mesg = mrb_vformat(mrb, fmt, ap); + return mrb_exc_new_str(mrb, c, mesg); } MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...) { - va_list args; + va_list ap; + mrb_value exc; - va_start(args, fmt); - raise_va(mrb, c, fmt, args, 0, NULL); - va_end(args); + va_start(ap, fmt); + exc = error_va(mrb, c, fmt, ap); + va_end(ap); + + mrb_exc_raise(mrb, exc); } MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...) { - mrb_value argv[2]; - va_list args; + va_list ap; + mrb_value exc; - va_start(args, fmt); - argv[1] = mrb_symbol_value(id); - raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv); - va_end(args); + va_start(ap, fmt); + exc = error_va(mrb, E_NAME_ERROR, fmt, ap); + va_end(ap); + mrb_iv_set(mrb, exc, MRB_IVSYM(name), mrb_symbol_value(id)); + mrb_exc_raise(mrb, exc); } MRB_API void @@ -524,16 +528,14 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...) { - mrb_value exc; - mrb_value argv[3]; va_list ap; + mrb_value exc; va_start(ap, fmt); - argv[0] = mrb_vformat(mrb, fmt, ap); - argv[1] = mrb_symbol_value(id); - argv[2] = args; + exc = error_va(mrb, E_NOMETHOD_ERROR, fmt, ap); va_end(ap); - exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv); + mrb_iv_set(mrb, exc, MRB_IVSYM(name), mrb_symbol_value(id)); + mrb_iv_set(mrb, exc, MRB_IVSYM(args), args); mrb_exc_raise(mrb, exc); } @@ -15,7 +15,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb { struct RData *data; - data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass); + data = MRB_OBJ_ALLOC(mrb, MRB_TT_DATA, klass); data->data = ptr; data->type = type; @@ -158,11 +158,35 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) { union mrb_value_ v; +#ifdef MRB_WORDBOX_NO_FLOAT_TRUNCATE v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.fp->f = f; MRB_SET_FROZEN_FLAG(v.bp); +#elif defined(MRB_64BIT) && defined(MRB_USE_FLOAT32) + v.w = 0; + v.f = f; + v.w = ((v.w<<2) & ~3) | 2; +#else + v.f = f; + v.w = (v.w & ~3) | 2; +#endif return v.value; } + + +#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE +MRB_API mrb_float +mrb_word_boxing_value_float(mrb_value v) +{ + union mrb_value_ u; + u.value = v; + u.w = u.w & ~3; +#if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32) + u.w >>= 2; +#endif + return u.f; +} +#endif #endif /* MRB_NO_FLOAT */ MRB_API mrb_value @@ -185,7 +209,7 @@ MRB_API mrb_value mrb_xxx_boxing_cptr_value(mrb_state *mrb, void *p) { mrb_value v; - struct RCptr *cptr = (struct RCptr*)mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class); + struct RCptr *cptr = MRB_OBJ_ALLOC(mrb, MRB_TT_CPTR, mrb->object_class); SET_OBJ_VALUE(v, cptr); cptr->p = p; diff --git a/src/fmt_fp.c b/src/fmt_fp.c index d3fe97ce3..bcb9ccc24 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,463 +1,363 @@ #include <mruby.h> -#if !defined(MRB_NO_FLOAT) -#if defined(MRB_NO_STDIO) || defined(_WIN32) || defined(_WIN64) -/* - -Most code in this file originates from musl (src/stdio/vfprintf.c) -which, just like mruby itself, is licensed under the MIT license. - -Copyright (c) 2005-2014 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include <limits.h> #include <string.h> -#include <math.h> -#include <float.h> -#include <ctype.h> -#include <mruby/string.h> +#ifndef MRB_NO_FLOAT +/*********************************************************************** -struct fmt_args; + Routine for converting a single-precision + floating point number into a string. -typedef void output_func(struct fmt_args *f, const char *s, size_t l); + The code in this function was inspired from Fred Bayer's pdouble.c. + Since pdouble.c was released as Public Domain, I'm releasing this + code as public domain as well. -struct fmt_args { - mrb_state *mrb; - output_func *output; - void *opaque; -}; + Dave Hylands -struct mrb_cstr { - char *buf; - size_t len; -}; + The original code can be found in https://github.com/dhylands/format-float +***********************************************************************/ -#define MAX(a,b) ((a)>(b) ? (a) : (b)) -#define MIN(a,b) ((a)<(b) ? (a) : (b)) +/*********************************************************************** -/* Convenient bit representation for modifier flags, which all fall - * within 31 codepoints of the space character. */ + I modified the routine for mruby: -#define ALT_FORM (1U<<('#'-' ')) -#define ZERO_PAD (1U<<('0'-' ')) -#define LEFT_ADJ (1U<<('-'-' ')) -#define PAD_POS (1U<<(' '-' ')) -#define MARK_POS (1U<<('+'-' ')) + * support `double` + * support `#` (alt_form) modifier -#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS) + My modifications in this file are also placed in the public domain. -static output_func strcat_value; -static output_func strcat_cstr; + Matz (Yukihiro Matsumoto) -static void -strcat_value(struct fmt_args *f, const char *s, size_t l) -{ - mrb_value str = *(mrb_value*)f->opaque; - mrb_str_cat(f->mrb, str, s, l); -} +***********************************************************************/ -static void -strcat_cstr(struct fmt_args *f, const char *s, size_t l) -{ - struct mrb_cstr *cstr = (struct mrb_cstr*)f->opaque; +#include <math.h> - if (l > cstr->len) { - mrb_state *mrb = f->mrb; +#ifdef MRB_USE_FLOAT32 - mrb_raise(mrb, E_ARGUMENT_ERROR, "string buffer too small"); - } +// 1 sign bit, 8 exponent bits, and 23 mantissa bits. +// exponent values 0 and 255 are reserved, exponent can be 1 to 254. +// exponent is stored with a bias of 127. +// The min and max floats are on the order of 1x10^37 and 1x10^-37 - memcpy(cstr->buf, s, l); +#define FLT_DECEXP 32 +#define FLT_ROUND_TO_ONE 0.9999995F +#define FLT_MIN_BUF_SIZE 6 // -9e+99 - cstr->buf += l; - cstr->len -= l; -} +#else -static void -out(struct fmt_args *f, const char *s, size_t l) -{ - f->output(f, s, l); -} +// 1 sign bit, 11 exponent bits, and 52 mantissa bits. -#define PAD_SIZE 256 -static void -pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint32_t fl) -{ - char pad[PAD_SIZE]; - if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; - l = w - l; - memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l); - for (; l >= PAD_SIZE; l -= PAD_SIZE) - out(f, pad, PAD_SIZE); - out(f, pad, l); -} +#define FLT_DECEXP 256 +#define FLT_ROUND_TO_ONE 0.999999999995 +#define FLT_MIN_BUF_SIZE 7 // -9e+199 -static const char xdigits[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; +#endif /* MRB_USE_FLOAT32 */ -static char* -fmt_u(uint32_t x, char *s) -{ - for (; x; x /= 10) *--s = '0' + x % 10; - return s; -} - -/* Do not override this check. The floating-point printing code below - * depends on the float.h constants being right. If they are wrong, it - * may overflow the stack. */ -#if LDBL_MANT_DIG == 53 -typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; +static const mrb_float g_pos_pow[] = { +#ifndef MRB_USE_FLOAT32 + 1e256, 1e128, 1e64, #endif + 1e32, 1e16, 1e8, 1e4, 1e2, 1e1 +}; +static const mrb_float g_neg_pow[] = { +#ifndef MRB_USE_FLOAT32 + 1e-256, 1e-128, 1e-64, +#endif + 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1 +}; -static int -fmt_fp(struct fmt_args *f, long double y, ptrdiff_t w, ptrdiff_t p, uint32_t fl, int t) -{ - uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion - + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion - uint32_t *a, *d, *r, *z; - uint32_t i; - int e2=0, e, j; - ptrdiff_t l; - char buf[9+LDBL_MANT_DIG/4], *s; - const char *prefix="-0X+0X 0X-0x+0x 0x"; - ptrdiff_t pl; - char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; - - pl=1; - if (signbit(y)) { - y=-y; - } else if (fl & MARK_POS) { - prefix+=3; - } else if (fl & PAD_POS) { - prefix+=6; - } else prefix++, pl=0; - - if (!isfinite(y)) { - const char *ss = (t&32)?"inf":"INF"; - if (y!=y) ss=(t&32)?"nan":"NAN"; - pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); - out(f, prefix, pl); - out(f, ss, 3); - pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); - return (int)MAX(w, 3+pl); +/* + * mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign) + * + * fmt: should be one of 'e', 'E', 'f', 'F', 'g', or 'G'. (|0x80 for '#') + * prec: is the precision (as specified in printf) + * sign: should be '\0', '+', or ' ' ('\0' is the normal one - only print + * a sign if ```f``` is negative. Anything else is printed as the + * sign character for positive numbers. + */ + +int +mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign) { + char *s = buf; + int buf_remaining = buf_size - 1; + int alt_form = 0; + + if ((uint8_t)fmt & 0x80) { + fmt &= 0x7f; /* turn off alt_form flag */ + alt_form = 1; } + if (buf_size <= FLT_MIN_BUF_SIZE) { + // Smallest exp notion is -9e+99 (-9e+199) which is 6 (7) chars plus terminating + // null. - y = frexp((double)y, &e2) * 2; - if (y) e2--; - - if ((t|32)=='a') { - long double round = 8.0; - ptrdiff_t re; - - if (t&32) prefix += 9; - pl += 2; + if (buf_size >= 2) { + *s++ = '?'; + } + if (buf_size >= 1) { + *s++ = '\0'; + } + return buf_size >= 2; + } + if (signbit(f)) { + *s++ = '-'; + f = -f; + } else if (sign) { + *s++ = sign; + } + buf_remaining -= (s - buf); // Adjust for sign + + { + char uc = fmt & 0x20; + if (isinf(f)) { + *s++ = 'I' ^ uc; + *s++ = 'N' ^ uc; + *s++ = 'F' ^ uc; + goto ret; + } else if (isnan(f)) { + *s++ = 'N' ^ uc; + *s++ = 'A' ^ uc; + *s++ = 'N' ^ uc; + ret: + *s = '\0'; + return s - buf; + } + } - if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; - else re=LDBL_MANT_DIG/4-1-p; + if (prec < 0) { + prec = 6; + } + char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt + fmt |= 0x20; // Force fmt to be lowercase + char org_fmt = fmt; + if (fmt == 'g' && prec == 0) { + prec = 1; + } + int e, e1; + int dec = 0; + char e_sign = '\0'; + int num_digits = 0; + const mrb_float *pos_pow = g_pos_pow; + const mrb_float *neg_pow = g_neg_pow; + + if (f == 0.0) { + e = 0; + if (fmt == 'e') { + e_sign = '+'; + } else if (fmt == 'f') { + num_digits = prec + 1; + } + } else if (f < 1.0) { // f < 1.0 + char first_dig = '0'; + if (f >= FLT_ROUND_TO_ONE) { + first_dig = '1'; + } - if (re) { - while (re--) round*=16; - if (*prefix=='-') { - y=-y; - y-=round; - y+=round; - y=-y; + // Build negative exponent + for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*neg_pow > f) { + e += e1; + f *= *pos_pow; } - else { - y+=round; - y-=round; + } + char e_sign_char = '-'; + if (f < 1.0) { + if (f >= FLT_ROUND_TO_ONE) { + f = 1.0; + if (e == 0) { + e_sign_char = '+'; + } + } else { + e++; + f *= 10.0; } } - estr=fmt_u(e2<0 ? -e2 : e2, ebuf); - if (estr==ebuf) *--estr='0'; - *--estr = (e2<0 ? '-' : '+'); - *--estr = t+('p'-'a'); - - s=buf; - do { - int x=(int)y; - *s++=xdigits[x]|(t&32); - y=16*(y-x); - if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; - } while (y); - - if (p && s-buf-2 < p) - l = (p+2) + (ebuf-estr); - else - l = (s-buf) + (ebuf-estr); - - pad(f, ' ', w, pl+l, fl); - out(f, prefix, pl); - pad(f, '0', w, pl+l, fl^ZERO_PAD); - out(f, buf, s-buf); - pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); - out(f, estr, ebuf-estr); - pad(f, ' ', w, pl+l, fl^LEFT_ADJ); - return (int)MAX(w, pl+l); - } - if (p<0) p=6; - - if (y) y *= 268435456.0, e2-=28; + // If the user specified 'g' format, and e is <= 4, then we'll switch + // to the fixed format ('f') - if (e2<0) a=r=z=big; - else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; + if (fmt == 'f' || (fmt == 'g' && e <= 4)) { + fmt = 'f'; + dec = -1; + *s++ = first_dig; - do { - *z = (uint32_t)y; - y = 1000000000*(y-*z++); - } while (y); - - while (e2>0) { - uint32_t carry=0; - int sh=MIN(29,e2); - for (d=z-1; d>=a; d--) { - uint64_t x = ((uint64_t)*d<<sh)+carry; - *d = x % 1000000000; - carry = (uint32_t)(x / 1000000000); + if (org_fmt == 'g') { + prec += (e - 1); + } + // truncate precision to prevent buffer overflow + if (prec + 2 > buf_remaining) { + prec = buf_remaining - 2; + } + num_digits = prec; + if (num_digits || alt_form) { + *s++ = '.'; + while (--e && num_digits) { + *s++ = '0'; + num_digits--; + } + } + } else { + // For e & g formats, we'll be printing the exponent, so set the + // sign. + e_sign = e_sign_char; + dec = 0; + + if (prec > (buf_remaining - FLT_MIN_BUF_SIZE)) { + prec = buf_remaining - FLT_MIN_BUF_SIZE; + if (fmt == 'g') { + prec++; + } + } } - if (carry) *--a = carry; - while (z>a && !z[-1]) z--; - e2-=sh; - } - while (e2<0) { - uint32_t carry=0, *b; - int sh=MIN(9,-e2), need=1+((int)p+LDBL_MANT_DIG/3+8)/9; - for (d=a; d<z; d++) { - uint32_t rm = *d & ((1<<sh)-1); - *d = (*d>>sh) + carry; - carry = (1000000000>>sh) * rm; + } else { + // Build positive exponent + for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*pos_pow <= f) { + e += e1; + f *= *neg_pow; + } } - if (!*a) a++; - if (carry) *z++ = carry; - /* Avoid (slow!) computation past requested precision */ - b = (t|32)=='f' ? r : a; - if (z-b > need) z = b+need; - e2+=sh; - } - if (a<z) for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++); - else e=0; - - /* Perform rounding: j is precision after the radix (possibly neg) */ - j = (int)p - ((t|32)!='f')*e - ((t|32)=='g' && p); - if (j < 9*(z-r-1)) { - uint32_t x; - /* We avoid C's broken division of negative numbers */ - d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); - j += 9*LDBL_MAX_EXP; - j %= 9; - for (i=10, j++; j<9; i*=10, j++); - x = *d % i; - /* Are there any significant digits past j? */ - if (x || d+1!=z) { - long double round = 2/LDBL_EPSILON; - long double small; - if (*d/i & 1) round += 2; - if (x<i/2) small=0.5; - else if (x==i/2 && d+1==z) small=1.0; - else small=1.5; - if (pl && *prefix=='-') round*=-1, small*=-1; - *d -= x; - /* Decide whether to round by probing round+small */ - if (round+small != round) { - *d = *d + i; - while (*d > 999999999) { - *d--=0; - if (d<a) *--a=0; - (*d)++; + // If the user specified fixed format (fmt == 'f') and e makes the + // number too big to fit into the available buffer, then we'll + // switch to the 'e' format. + + if (fmt == 'f') { + if (e >= buf_remaining) { + fmt = 'e'; + } else if ((e + prec + 2) > buf_remaining) { + prec = buf_remaining - e - 2; + if (prec < 0) { + // This means no decimal point, so we can add one back + // for the decimal. + prec++; } - for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++); } } - if (z>d+1) z=d+1; - } - for (; z>a && !z[-1]; z--); - - if ((t|32)=='g') { - if (!p) p++; - if (p>e && e>=-4) { - t--; - p-=e+1; - } - else { - t-=2; - p--; - } - if (!(fl&ALT_FORM)) { - /* Count trailing zeros in last place */ - if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); - else j=9; - if ((t|32)=='f') - p = MIN(p,MAX(0,9*(z-r-1)-j)); - else - p = MIN(p,MAX(0,9*(z-r-1)+e-j)); + if (fmt == 'e' && prec > (buf_remaining - 6)) { + prec = buf_remaining - 6; } - } - l = 1 + p + (p || (fl&ALT_FORM)); - if ((t|32)=='f') { - if (e>0) l+=e; - } - else { - estr=fmt_u(e<0 ? -e : e, ebuf); - while(ebuf-estr<2) *--estr='0'; - *--estr = (e<0 ? '-' : '+'); - *--estr = t; - l += ebuf-estr; - } + // If the user specified 'g' format, and e is < prec, then we'll switch + // to the fixed format. - pad(f, ' ', w, pl+l, fl); - out(f, prefix, pl); - pad(f, '0', w, pl+l, fl^ZERO_PAD); - - if ((t|32)=='f') { - if (a>r) a=r; - for (d=a; d<=r; d++) { - char *ss = fmt_u(*d, buf+9); - if (d!=a) while (ss>buf) *--ss='0'; - else if (ss==buf+9) *--ss='0'; - out(f, ss, buf+9-ss); + if (fmt == 'g' && e < prec) { + fmt = 'f'; + prec -= (e + 1); } - if (p || (fl&ALT_FORM)) out(f, ".", 1); - for (; d<z && p>0; d++, p-=9) { - char *ss = fmt_u(*d, buf+9); - while (ss>buf) *--ss='0'; - out(f, ss, MIN(9,p)); + if (fmt == 'f') { + dec = e; + num_digits = prec + e + 1; + } else { + e_sign = '+'; } - pad(f, '0', p+9, 9, 0); } - else { - if (z<=a) z=a+1; - for (d=a; d<z && p>=0; d++) { - char *ss = fmt_u(*d, buf+9); - if (ss==buf+9) *--ss='0'; - if (d!=a) while (ss>buf) *--ss='0'; - else { - out(f, ss++, 1); - if (p>0||(fl&ALT_FORM)) out(f, ".", 1); - } - out(f, ss, MIN(buf+9-ss, p)); - p -= (int)(buf+9-ss); - } - pad(f, '0', p+18, 18, 0); - out(f, estr, ebuf-estr); + if (prec < 0) { + // This can happen when the prec is trimmed to prevent buffer overflow + prec = 0; } - pad(f, ' ', w, pl+l, fl^LEFT_ADJ); - - return (int)MAX(w, pl+l); -} - -static int -fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) -{ - ptrdiff_t w, p; - uint32_t fl; - - if (*fmt != '%') { - return -1; - } - ++fmt; - - /* Read modifier flags */ - for (fl=0; (unsigned)*fmt-' '<32 && (FLAGMASK&(1U<<(*fmt-' '))); fmt++) - fl |= 1U<<(*fmt-' '); - - /* - and 0 flags are mutually exclusive */ - if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; - - for (w = 0; ISDIGIT(*fmt); ++fmt) { - w = 10 * w + (*fmt - '0'); + // We now have f as a floating point number between >= 1 and < 10 + // (or equal to zero), and e contains the absolute value of the power of + // 10 exponent. and (dec + 1) == the number of dgits before the decimal. + + // For e, prec is # digits after the decimal + // For f, prec is # digits after the decimal + // For g, prec is the max number of significant digits + // + // For e & g there will be a single digit before the decimal + // for f there will be e digits before the decimal + + if (fmt == 'e') { + num_digits = prec + 1; + } else if (fmt == 'g') { + if (prec == 0) { + prec = 1; + } + num_digits = prec; } - if (*fmt == '.') { - ++fmt; - for (p = 0; ISDIGIT(*fmt); ++fmt) { - p = 10 * p + (*fmt - '0'); + // Print the digits of the mantissa + for (int i = 0; i < num_digits; ++i, --dec) { + int8_t d = (int8_t)((int)f)%10; + *s++ = '0' + d; + if (dec == 0 && (prec > 0 || alt_form)) { + *s++ = '.'; } - } - else { - p = -1; + f -= (mrb_float)d; + f *= 10.0; } - switch (*fmt) { - case 'e': case 'f': case 'g': case 'a': - case 'E': case 'F': case 'G': case 'A': - return fmt_fp(f, flo, w, p, fl, *fmt); - default: - return -1; + // Round + if (f >= 5.0) { + char *rs = s; + rs--; + while (1) { + if (*rs == '.') { + rs--; + continue; + } + if (*rs < '0' || *rs > '9') { + // + or - + rs++; // So we sit on the digit to the right of the sign + break; + } + if (*rs < '9') { + (*rs)++; + break; + } + *rs = '0'; + if (rs == buf) { + break; + } + rs--; + } + if (*rs == '0') { + // We need to insert a 1 + if (rs[1] == '.' && fmt != 'f') { + // We're going to round 9.99 to 10.00 + // Move the decimal point + rs[0] = '.'; + rs[1] = '0'; + if (e_sign == '-') { + e--; + } else { + e++; + } + } + s++; + char *ss = s; + while (ss > rs) { + *ss = ss[-1]; + ss--; + } + *rs = '1'; + if (f < 1.0 && fmt == 'f') { + // We rounded up to 1.0 + prec--; + } + } } -} -MRB_API mrb_value -mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) -{ - struct fmt_args f; - mrb_value str = mrb_str_new_capa(mrb, 24); - - f.mrb = mrb; - f.output = strcat_value; - f.opaque = (void*)&str; - if (fmt_core(&f, fmt, mrb_float(flo)) < 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); + if (org_fmt == 'g' && prec > 0 && !alt_form) { + // Remove trailing zeros and a trailing decimal point + while (s[-1] == '0') { + s--; + } + if (s[-1] == '.') { + s--; + } } - return str; -} - -MRB_API int -mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval) -{ - struct fmt_args f; - struct mrb_cstr cstr; - - cstr.buf = buf; - cstr.len = len - 1; /* reserve NUL terminator */ - f.mrb = mrb; - f.output = strcat_cstr; - f.opaque = (void*)&cstr; - if (fmt_core(&f, fmt, fval) < 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); + // Append the exponent + if (e_sign) { + *s++ = e_char; + *s++ = e_sign; + if (e >= 100) { + *s++ = '0' + (e / 100); + e %= 100; + } + *s++ = '0' + (e / 10); + *s++ = '0' + (e % 10); } - *cstr.buf = '\0'; - return (int)(cstr.buf - buf); -} -#else /* MRB_NO_STDIO || _WIN32 || _WIN64 */ -#include <stdio.h> - -MRB_API mrb_value -mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) -{ - char buf[25]; - - snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); - return mrb_str_new_cstr(mrb, buf); -} + *s = '\0'; -MRB_API int -mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval) -{ - return snprintf(buf, len, fmt, fval); + return s - buf; } -#endif /* MRB_NO_STDIO || _WIN32 || _WIN64 */ #endif @@ -5,7 +5,6 @@ */ #include <string.h> -#include <stdlib.h> #ifdef MRB_USE_MALLOC_TRIM #include <malloc.h> #endif @@ -24,6 +23,10 @@ #include <mruby/throw.h> #include <mruby/presym.h> +#ifdef MRB_GC_STRESS +#include <stdlib.h> +#endif + /* = Tri-color Incremental Garbage Collection @@ -131,12 +134,6 @@ typedef struct { struct RFiber fiber; struct RException exc; struct RBreak brk; -#ifdef MRB_WORD_BOXING -#ifndef MRB_NO_FLOAT - struct RFloat floatv; -#endif - struct RCptr cptr; -#endif } as; } RVALUE; @@ -295,7 +292,7 @@ MRB_API void* mrb_alloca(mrb_state *mrb, size_t size) { struct RString *s; - s = (struct RString*)mrb_obj_alloc(mrb, MRB_TT_STRING, mrb->string_class); + s = MRB_OBJ_ALLOC(mrb, MRB_TT_STRING, mrb->string_class); return s->as.heap.ptr = (char*)mrb_malloc(mrb, size); } @@ -745,6 +742,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) } break; + case MRB_TT_STRUCT: case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; @@ -860,6 +858,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) } break; + case MRB_TT_STRUCT: case MRB_TT_ARRAY: if (ARY_SHARED_P(obj)) mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared); @@ -1044,6 +1043,7 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) } break; + case MRB_TT_STRUCT: case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; @@ -1468,7 +1468,7 @@ gc_disable(mrb_state *mrb, mrb_value obj) /* * call-seq: - * GC.interval_ratio -> fixnum + * GC.interval_ratio -> int * * Returns ratio of GC interval. Default value is 200(%). * @@ -1477,12 +1477,12 @@ gc_disable(mrb_state *mrb, mrb_value obj) static mrb_value gc_interval_ratio_get(mrb_state *mrb, mrb_value obj) { - return mrb_fixnum_value(mrb->gc.interval_ratio); + return mrb_int_value(mrb, mrb->gc.interval_ratio); } /* * call-seq: - * GC.interval_ratio = fixnum -> nil + * GC.interval_ratio = int -> nil * * Updates ratio of GC interval. Default value is 200(%). * GC start as soon as after end all step of GC if you set 100(%). @@ -1501,7 +1501,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj) /* * call-seq: - * GC.step_ratio -> fixnum + * GC.step_ratio -> int * * Returns step span ratio of Incremental GC. Default value is 200(%). * @@ -1510,12 +1510,12 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj) static mrb_value gc_step_ratio_get(mrb_state *mrb, mrb_value obj) { - return mrb_fixnum_value(mrb->gc.step_ratio); + return mrb_int_value(mrb, mrb->gc.step_ratio); } /* * call-seq: - * GC.step_ratio = fixnum -> nil + * GC.step_ratio = int -> nil * * Updates step span ratio of Incremental GC. Default value is 200(%). * 1 step of incrementalGC becomes long if a rate is big. diff --git a/src/hash.c b/src/hash.c index 3b5d17761..918722a2b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -970,7 +970,7 @@ h_key_for(mrb_state *mrb, mrb_value key) static struct RHash* h_alloc(mrb_state *mrb) { - return (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + return MRB_OBJ_ALLOC(mrb, MRB_TT_HASH, mrb->hash_class); } static void @@ -1482,6 +1482,7 @@ static mrb_value mrb_hash_delete(mrb_state *mrb, mrb_value self) { mrb_value key = mrb_get_arg1(mrb); + mrb->c->ci->mid = 0; return mrb_hash_delete_key(mrb, self, key); } diff --git a/src/kernel.c b/src/kernel.c index 25aa41baf..f8ef1bfe1 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -84,8 +84,8 @@ mrb_equal_m(mrb_state *mrb, mrb_value self) * Document-method: object_id * * call-seq: - * obj.__id__ -> fixnum - * obj.object_id -> fixnum + * obj.__id__ -> int + * obj.object_id -> int * * Returns an integer identifier for <i>obj</i>. The same number will * be returned on all calls to <code>id</code> for a given object, and @@ -293,7 +293,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self) /* 15.3.1.3.15 */ /* * call-seq: - * obj.hash -> fixnum + * obj.hash -> int * * Generates a <code>Integer</code> hash value for this object. This * function must have the property that <code>a.eql?(b)</code> implies @@ -423,8 +423,8 @@ mrb_f_raise(mrb_state *mrb, mrb_value self) mrb_value a[2], exc; mrb_int argc; - argc = mrb_get_args(mrb, "|oo", &a[0], &a[1]); + mrb->c->ci->mid = 0; switch (argc) { case 0: mrb_raise(mrb, E_RUNTIME_ERROR, ""); @@ -510,7 +510,7 @@ mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) * # ... * end * def method_missing(methId) - * str = methId.id2name + * str = methId.to_s * romanToInt(str) * end * end @@ -527,6 +527,7 @@ mrb_obj_missing(mrb_state *mrb, mrb_value mod) const mrb_value *a; mrb_int alen; + mrb->c->ci->mid = 0; mrb_get_args(mrb, "n*!", &name, &a, &alen); mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); /* not reached */ @@ -584,6 +585,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) mrb_sym eqq = MRB_OPSYM(eqq); mrb_value ary; + mrb->c->ci->mid = 0; if (mrb_array_p(self)) { ary = self; } @@ -610,6 +612,17 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +static mrb_value +mrb_encoding(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); +#ifdef MRB_UTF8_STRING + return mrb_str_new_lit(mrb, "UTF-8"); +#else + return mrb_str_new_lit(mrb, "ASCII-8BIT"); +#endif +} + mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void @@ -649,8 +662,8 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ARG(1,1)); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ - mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ - mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ + mrb_define_method(mrb, krn, "__to_int", mrb_to_integer, MRB_ARGS_NONE()); /* internal */ + mrb_define_method(mrb, krn, "__ENCODING__", mrb_encoding, MRB_ARGS_NONE()); mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); } diff --git a/src/load.c b/src/load.c index f370dc67e..256dd58fd 100644 --- a/src/load.c +++ b/src/load.c @@ -4,10 +4,7 @@ ** See Copyright Notice in mruby.h */ -#include <limits.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +#include <mruby.h> #include <mruby/dump.h> #include <mruby/irep.h> #include <mruby/proc.h> @@ -16,6 +13,7 @@ #include <mruby/error.h> #include <mruby/data.h> #include <mruby/endian.h> +#include <string.h> #if SIZE_MAX < UINT32_MAX # error size_t must be at least 32 bits wide @@ -60,8 +58,6 @@ str_to_double(mrb_state *mrb, const char *p) } #endif -mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck); - static mrb_bool read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp) { @@ -146,7 +142,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } break; case IREP_TT_INT64: -#ifdef MRB_64BIT +#ifdef MRB_INT64 { uint64_t i64 = bin_to_uint32(src); src += sizeof(uint32_t); @@ -158,7 +154,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } break; #else - return FALSE; /* INT64 not supported on MRB_32BIT */ + return FALSE; #endif case IREP_TT_BIGINT: @@ -364,6 +360,12 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * } } break; + case mrb_debug_line_packed_map: { + file->lines.packed_map = (uint8_t*)mrb_calloc(mrb, 1, (size_t)file->line_entry_count); + memcpy(file->lines.packed_map, bin, file->line_entry_count); + bin += file->line_entry_count; + } break; + default: return MRB_DUMP_GENERAL_FAILURE; } } @@ -604,11 +606,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) static struct RProc* mrb_proc_read_irep(mrb_state *mrb, const uint8_t *bin) { -#if defined(MRB_USE_LINK_TIME_RO_DATA_P) || defined(MRB_USE_CUSTOM_RO_DATA_P) uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; -#else - uint8_t flags = FLAG_SRC_STATIC; -#endif return read_irep(mrb, bin, (size_t)-1, flags); } @@ -679,7 +677,7 @@ mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) MRB_API mrb_value mrb_load_proc(mrb_state *mrb, const struct RProc *proc) { - return mrb_vm_run(mrb, proc, mrb_top_self(mrb), 0); + return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0); } #ifndef MRB_NO_STDIO diff --git a/src/numeric.c b/src/numeric.c index fe1a18f04..fd9f5ce2c 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -4,36 +4,25 @@ ** See Copyright Notice in mruby.h */ -#ifndef MRB_NO_FLOAT -#include <float.h> -#include <math.h> -#endif -#include <limits.h> -#include <stdlib.h> -#include <string.h> - #include <mruby.h> #include <mruby/array.h> #include <mruby/numeric.h> #include <mruby/string.h> #include <mruby/class.h> #include <mruby/presym.h> +#include <string.h> #ifndef MRB_NO_FLOAT #ifdef MRB_USE_FLOAT32 #define trunc(f) truncf(f) -#define floor(f) floorf(f) -#define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define FLO_TO_STR_PREC 8 #else -#define FLO_TO_STR_PREC 16 #endif #endif #ifndef MRB_NO_FLOAT MRB_API mrb_float -mrb_to_flo(mrb_state *mrb, mrb_value val) +mrb_as_float(mrb_state *mrb, mrb_value val) { switch (mrb_type(val)) { case MRB_TT_INTEGER: @@ -137,10 +126,6 @@ mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y) return 0; } -#ifndef MRB_NO_FLOAT -mrb_float mrb_div_flo(mrb_float x, mrb_float y); -#endif - /* 15.2.8.3.4 */ /* 15.2.9.3.4 */ /* @@ -164,7 +149,7 @@ int_div(mrb_state *mrb, mrb_value x) #ifdef MRB_NO_FLOAT mrb_raise(mrb, E_TYPE_ERROR, "non integer division"); #else - return mrb_float_value(mrb, mrb_div_flo((mrb_float)a, mrb_to_flo(mrb, y))); + return mrb_float_value(mrb, mrb_div_float((mrb_float)a, mrb_as_float(mrb, y))); #endif } @@ -191,7 +176,7 @@ int_idiv(mrb_state *mrb, mrb_value x) if (y == 0) { int_zerodiv(mrb); } - return mrb_fixnum_value(mrb_integer(x) / y); + return mrb_int_value(mrb, mrb_integer(x) / y); } static mrb_value @@ -218,8 +203,9 @@ coerce_step_counter(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "oo", &num, &step); #ifndef MRB_NO_FLOAT - if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { - return mrb_Float(mrb, self); + mrb->c->ci->mid = 0; + if (mrb_float_p(num) || mrb_float_p(step)) { + return mrb_to_float(mrb, self); } #endif @@ -240,7 +226,7 @@ static mrb_value flo_pow(mrb_state *mrb, mrb_value x) { mrb_value y = mrb_get_arg1(mrb); - mrb_float d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y)); + mrb_float d = pow(mrb_as_float(mrb, x), mrb_as_float(mrb, y)); return mrb_float_value(mrb, d); } @@ -255,7 +241,7 @@ flo_idiv(mrb_state *mrb, mrb_value xv) } mrb_float -mrb_div_flo(mrb_float x, mrb_float y) +mrb_div_float(mrb_float x, mrb_float y) { if (y != 0.0) { return x / y; @@ -275,14 +261,39 @@ flo_div(mrb_state *mrb, mrb_value x) mrb_float a = mrb_float(x); if (mrb_float_p(y)) { - a = mrb_div_flo(a, mrb_float(y)); + a = mrb_div_float(a, mrb_float(y)); } else { - a = mrb_div_flo(a, mrb_to_flo(mrb, y)); + a = mrb_div_float(a, mrb_as_float(mrb, y)); } return mrb_float_value(mrb, a); } +/* the argument `fmt` is no longer used; you can pass `NULL` */ +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + char buf[25]; +#ifdef MRB_USE_FLOAT32 + const int prec = 7; +#else + const int prec = 15; +#endif + + mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', prec, '\0'); + for (char *p = buf; *p; p++) { + if (*p == '.') goto exit; + if (*p == 'e') { + memmove(p+2, p, strlen(p)+1); + memcpy(p, ".0", 2); + goto exit; + } + } + strcat(buf, ".0"); + exit: + return mrb_str_new_cstr(mrb, buf); +} + /* 15.2.9.3.16(x) */ /* * call-seq: @@ -307,49 +318,14 @@ flo_to_s(mrb_state *mrb, mrb_value flt) if (isinf(f)) { str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity") : mrb_str_new_lit(mrb, "Infinity"); - goto exit; } else if (isnan(f)) { str = mrb_str_new_lit(mrb, "NaN"); - goto exit; } else { - char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; - mrb_int len; - char *begp, *p, *endp; - - str = mrb_float_to_str(mrb, flt, fmt); - - insert_dot_zero: - begp = RSTRING_PTR(str); - len = RSTRING_LEN(str); - for (p = begp, endp = p + len; p < endp; ++p) { - if (*p == '.') { - goto exit; - } - else if (*p == 'e') { - ptrdiff_t e_pos = p - begp; - mrb_str_cat(mrb, str, ".0", 2); - p = RSTRING_PTR(str) + e_pos; - memmove(p + 2, p, len - e_pos); - memcpy(p, ".0", 2); - goto exit; - } - } - - if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) { - --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */ - str = mrb_float_to_str(mrb, flt, fmt); - goto insert_dot_zero; - } - else { - mrb_str_cat(mrb, str, ".0", 2); - } - - goto exit; + str = mrb_float_to_str(mrb, flt, NULL); } - exit: RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); return str; } @@ -376,7 +352,7 @@ flo_add(mrb_state *mrb, mrb_value x) return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x); #endif default: - return mrb_float_value(mrb, a + mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, a + mrb_as_float(mrb, y)); } } @@ -404,7 +380,7 @@ flo_sub(mrb_state *mrb, mrb_value x) return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0); #endif default: - return mrb_float_value(mrb, a - mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, a - mrb_as_float(mrb, y)); } } @@ -431,7 +407,7 @@ flo_mul(mrb_state *mrb, mrb_value x) return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x); #endif default: - return mrb_float_value(mrb, a * mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, a * mrb_as_float(mrb, y)); } } @@ -490,7 +466,7 @@ flo_mod(mrb_state *mrb, mrb_value x) mrb_value y = mrb_get_arg1(mrb); mrb_float mod; - flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod); + flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), 0, &mod); return mrb_float_value(mrb, mod); } #endif @@ -551,7 +527,7 @@ flo_eq(mrb_state *mrb, mrb_value x) return mrb_bool_value(mrb_float(x) == mrb_float(y)); #ifdef MRB_USE_RATIONAL case MRB_TT_RATIONAL: - return mrb_bool_value(mrb_float(x) == mrb_to_flo(mrb, y)); + return mrb_bool_value(mrb_float(x) == mrb_as_float(mrb, y)); #endif #ifdef MRB_USE_COMPLEX case MRB_TT_COMPLEX: @@ -761,49 +737,127 @@ mrb_check_num_exact(mrb_state *mrb, mrb_float num) } } +static mrb_value +flo_ceil_floor(mrb_state *mrb, mrb_value num, double (*func)(double)) +{ + mrb_float f = mrb_float(num); + mrb_int ndigits = 0; +#ifdef MRB_USE_FLOAT32 + const int fprec = 7; +#else + const int fprec = 15; +#endif + + mrb_get_args(mrb, "|i", &ndigits); + if (f == 0.0) { + return ndigits > 0 ? mrb_float_value(mrb, f) : mrb_fixnum_value(0); + } + if (ndigits > 0) { + if (ndigits > fprec) return num; + mrb_float d = pow(10, ndigits); + f = func(f * d) / d; + return mrb_float_value(mrb, f); + } + if (ndigits < 0) { + mrb_float d = pow(10, -ndigits); + f = func(f / d) * d; + } + else { /* ndigits == 0 */ + f = func(f); + } + mrb_check_num_exact(mrb, f); + return mrb_int_value(mrb, (mrb_int)f); +} + /* 15.2.9.3.10 */ /* * call-seq: - * flt.floor -> integer + * float.floor([ndigits]) -> integer or float * - * Returns the largest integer less than or equal to <i>flt</i>. + * Returns the largest number less than or equal to +float+ with + * a precision of +ndigits+ decimal digits (default: 0). + * + * When the precision is negative, the returned value is an integer + * with at least <code>ndigits.abs</code> trailing zeros. + * + * Returns a floating point number when +ndigits+ is positive, + * otherwise returns an integer. * * 1.2.floor #=> 1 * 2.0.floor #=> 2 * (-1.2).floor #=> -2 * (-2.0).floor #=> -2 + * + * 1.234567.floor(2) #=> 1.23 + * 1.234567.floor(3) #=> 1.234 + * 1.234567.floor(4) #=> 1.2345 + * 1.234567.floor(5) #=> 1.23456 + * + * 34567.89.floor(-5) #=> 0 + * 34567.89.floor(-4) #=> 30000 + * 34567.89.floor(-3) #=> 34000 + * 34567.89.floor(-2) #=> 34500 + * 34567.89.floor(-1) #=> 34560 + * 34567.89.floor(0) #=> 34567 + * 34567.89.floor(1) #=> 34567.8 + * 34567.89.floor(2) #=> 34567.89 + * 34567.89.floor(3) #=> 34567.89 + * + * Note that the limited precision of floating point arithmetic + * might lead to surprising results: + * + * (0.3 / 0.1).floor #=> 2 (!) */ - static mrb_value flo_floor(mrb_state *mrb, mrb_value num) { - mrb_float f = floor(mrb_float(num)); - - mrb_check_num_exact(mrb, f); - return mrb_int_value(mrb, (mrb_int)f); + return flo_ceil_floor(mrb, num, floor); } /* 15.2.9.3.8 */ /* * call-seq: - * flt.ceil -> integer + * float.ceil([ndigits]) -> integer or float + * + * Returns the smallest number greater than or equal to +float+ with + * a precision of +ndigits+ decimal digits (default: 0). + * + * When the precision is negative, the returned value is an integer + * with at least <code>ndigits.abs</code> trailing zeros. * - * Returns the smallest <code>Integer</code> greater than or equal to - * <i>flt</i>. + * Returns a floating point number when +ndigits+ is positive, + * otherwise returns an integer. * * 1.2.ceil #=> 2 * 2.0.ceil #=> 2 * (-1.2).ceil #=> -1 * (-2.0).ceil #=> -2 + * + * 1.234567.ceil(2) #=> 1.24 + * 1.234567.ceil(3) #=> 1.235 + * 1.234567.ceil(4) #=> 1.2346 + * 1.234567.ceil(5) #=> 1.23457 + * + * 34567.89.ceil(-5) #=> 100000 + * 34567.89.ceil(-4) #=> 40000 + * 34567.89.ceil(-3) #=> 35000 + * 34567.89.ceil(-2) #=> 34600 + * 34567.89.ceil(-1) #=> 34570 + * 34567.89.ceil(0) #=> 34568 + * 34567.89.ceil(1) #=> 34567.9 + * 34567.89.ceil(2) #=> 34567.89 + * 34567.89.ceil(3) #=> 34567.89 + * + * Note that the limited precision of floating point arithmetic + * might lead to surprising results: + * + * (2.1 / 0.7).ceil #=> 4 (!) */ static mrb_value flo_ceil(mrb_state *mrb, mrb_value num) { - mrb_float f = ceil(mrb_float(num)); - - mrb_check_num_exact(mrb, f); - return mrb_int_value(mrb, (mrb_int)f); + return flo_ceil_floor(mrb, num, ceil); } /* 15.2.9.3.12 */ @@ -853,6 +907,7 @@ flo_round(mrb_state *mrb, mrb_value num) mrb_check_num_exact(mrb, number); f = 1.0; + if (ndigits < -DBL_DIG-2) return mrb_fixnum_value(0); i = ndigits >= 0 ? ndigits : -ndigits; if (ndigits > DBL_DIG+2) return num; while (--i >= 0) @@ -891,6 +946,18 @@ flo_round(mrb_state *mrb, mrb_value num) } /* 15.2.9.3.14 */ +static mrb_value +flo_to_i(mrb_state *mrb, mrb_value num) +{ + mrb_float f = mrb_float(num); + + if (f > 0.0) f = floor(f); + if (f < 0.0) f = ceil(f); + + mrb_check_num_exact(mrb, f); + return mrb_int_value(mrb, (mrb_int)f); +} + /* 15.2.9.3.15 */ /* * call-seq: @@ -903,13 +970,8 @@ flo_round(mrb_state *mrb, mrb_value num) static mrb_value flo_truncate(mrb_state *mrb, mrb_value num) { - mrb_float f = mrb_float(num); - - if (f > 0.0) f = floor(f); - if (f < 0.0) f = ceil(f); - - mrb_check_num_exact(mrb, f); - return mrb_int_value(mrb, (mrb_int)f); + if (signbit(mrb_float(num))) return flo_ceil(mrb, num); + return flo_floor(mrb, num); } static mrb_value @@ -917,6 +979,15 @@ flo_nan_p(mrb_state *mrb, mrb_value num) { return mrb_bool_value(isnan(mrb_float(num))); } + +static mrb_value +flo_abs(mrb_state *mrb, mrb_value num) +{ + mrb_float f = mrb_float(num); + + if (signbit(f)) return mrb_float_value(mrb, -f); + return num; +} #endif /* @@ -967,7 +1038,7 @@ fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #ifdef MRB_NO_FLOAT mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication"); #else - return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a * mrb_as_float(mrb, y)); #endif } } @@ -980,7 +1051,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) } #ifndef MRB_NO_FLOAT if (mrb_float_p(x)) { - return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, mrb_float(x) * mrb_as_float(mrb, y)); } #endif #if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) @@ -999,7 +1070,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) /* 15.2.8.3.3 */ /* * call-seq: - * fix * numeric -> numeric_result + * int * numeric -> numeric_result * * Performs multiplication: the class of the resulting object depends on * the class of <code>numeric</code> and on the magnitude of the @@ -1015,7 +1086,7 @@ int_mul(mrb_state *mrb, mrb_value x) } static void -fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp) +intdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp) { if (y == 0) { int_zerodiv(mrb); @@ -1039,10 +1110,9 @@ fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp) /* 15.2.8.3.5 */ /* * call-seq: - * fix % other -> real - * fix.modulo(other) -> real + * int % other -> real * - * Returns <code>fix</code> modulo <code>other</code>. + * Returns <code>int</code> modulo <code>other</code>. * See <code>numeric.divmod</code> for more information. */ @@ -1053,27 +1123,29 @@ int_mod(mrb_state *mrb, mrb_value x) mrb_int a, b; a = mrb_integer(x); - if (mrb_integer_p(y) && a != MRB_INT_MIN && (b=mrb_integer(y)) != MRB_INT_MIN) { - mrb_int mod; - - fixdivmod(mrb, a, b, NULL, &mod); - return mrb_fixnum_value(mod); + if (mrb_integer_p(y)) { + b = mrb_integer(y); + if (b == 0) int_zerodiv(mrb); + if (a == MRB_INT_MIN && b == -1) return mrb_fixnum_value(0); + mrb_int mod = a % b; + if ((a < 0) != (b < 0) && mod != 0) { + mod += b; + } + return mrb_int_value(mrb, mod); } #ifdef MRB_NO_FLOAT mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo"); #else - else { - mrb_float mod; + mrb_float mod; - flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod); - return mrb_float_value(mrb, mod); - } + flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod); + return mrb_float_value(mrb, mod); #endif } /* * call-seq: - * fix.divmod(numeric) -> array + * int.divmod(numeric) -> array * * See <code>Numeric#divmod</code>. */ @@ -1085,7 +1157,7 @@ int_divmod(mrb_state *mrb, mrb_value x) if (mrb_integer_p(y)) { mrb_int div, mod; - fixdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod); + intdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod); return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod)); } #ifdef MRB_NO_FLOAT @@ -1095,7 +1167,7 @@ int_divmod(mrb_state *mrb, mrb_value x) mrb_float div, mod; mrb_value a, b; - flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_to_flo(mrb, y), &div, &mod); + flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_as_float(mrb, y), &div, &mod); a = mrb_int_value(mrb, (mrb_int)div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); @@ -1111,7 +1183,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_float div, mod; mrb_value a, b; - flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); + flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), &div, &mod); if (!FIXABLE_FLOAT(div)) a = mrb_float_value(mrb, div); else @@ -1124,9 +1196,9 @@ flo_divmod(mrb_state *mrb, mrb_value x) /* 15.2.8.3.7 */ /* * call-seq: - * fix == other -> true or false + * int == other -> true or false * - * Return <code>true</code> if <code>fix</code> equals <code>other</code> + * Return <code>true</code> if <code>int</code> equals <code>other</code> * numerically. * * 1 == 2 #=> false @@ -1161,7 +1233,7 @@ int_equal(mrb_state *mrb, mrb_value x) /* 15.2.8.3.8 */ /* * call-seq: - * ~fix -> integer + * ~int -> integer * * One's complement: returns a number where each bit is flipped. * ex.0---00001 (1)-> 1---11110 (-2) @@ -1194,7 +1266,7 @@ static mrb_value flo_xor(mrb_state *mrb, mrb_value x); /* 15.2.8.3.9 */ /* * call-seq: - * fix & integer -> integer_result + * int & integer -> integer_result * * Bitwise AND. */ @@ -1210,7 +1282,7 @@ int_and(mrb_state *mrb, mrb_value x) /* 15.2.8.3.10 */ /* * call-seq: - * fix | integer -> integer_result + * int | integer -> integer_result * * Bitwise OR. */ @@ -1226,7 +1298,7 @@ int_or(mrb_state *mrb, mrb_value x) /* 15.2.8.3.11 */ /* * call-seq: - * fix ^ integer -> integer_result + * int ^ integer -> integer_result * * Bitwise EXCLUSIVE OR. */ @@ -1241,45 +1313,48 @@ int_xor(mrb_state *mrb, mrb_value x) #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1) -static mrb_value -lshift(mrb_state *mrb, mrb_int val, mrb_int width) +mrb_bool +mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num) { - mrb_assert(width >= 0); - if (val > 0) { + if (width < 0) { /* rshift */ + if (width == MRB_INT_MIN || -width >= NUMERIC_SHIFT_WIDTH_MAX) { + if (val < 0) { + *num = -1; + } + else { + *num = 0; + } + } + else { + *num = val >> -width; + } + } + else if (val > 0) { if ((width > NUMERIC_SHIFT_WIDTH_MAX) || (val > (MRB_INT_MAX >> width))) { - int_overflow(mrb, "bit shift"); + return FALSE; } - return mrb_int_value(mrb, val << width); + *num = val << width; } else { if ((width > NUMERIC_SHIFT_WIDTH_MAX) || - (val <= (MRB_INT_MIN >> width))) { - int_overflow(mrb, "bit shift"); + (val < (MRB_INT_MIN >> width))) { + return FALSE; } - return mrb_int_value(mrb, (val * ((mrb_int)1 << width))); + if (width == NUMERIC_SHIFT_WIDTH_MAX) + *num = MRB_INT_MIN; + else + *num = val * ((mrb_int)1 << width); } -} - -static mrb_value -rshift(mrb_state *mrb, mrb_int val, mrb_int width) -{ - mrb_assert(width >= 0); - if (width >= NUMERIC_SHIFT_WIDTH_MAX) { - if (val < 0) { - return mrb_fixnum_value(-1); - } - return mrb_fixnum_value(0); - } - return mrb_int_value(mrb, val >> width); + return TRUE; } /* 15.2.8.3.12 */ /* * call-seq: - * fix << count -> integer or float + * int << count -> integer or float * - * Shifts _fix_ left _count_ positions (right if _count_ is negative). + * Shifts _int_ left _count_ positions (right if _count_ is negative). */ static mrb_value @@ -1293,19 +1368,18 @@ int_lshift(mrb_state *mrb, mrb_value x) } val = mrb_integer(x); if (val == 0) return x; - if (width < 0) { - if (width == MRB_INT_MIN) return rshift(mrb, val, MRB_INT_BIT); - return rshift(mrb, val, -width); + if (!mrb_num_shift(mrb, val, width, &val)) { + int_overflow(mrb, "bit shift"); } - return lshift(mrb, val, width); + return mrb_int_value(mrb, val); } /* 15.2.8.3.13 */ /* * call-seq: - * fix >> count -> integer or float + * int >> count -> integer or float * - * Shifts _fix_ right _count_ positions (left if _count_ is negative). + * Shifts _int_ right _count_ positions (left if _count_ is negative). */ static mrb_value @@ -1319,19 +1393,19 @@ int_rshift(mrb_state *mrb, mrb_value x) } val = mrb_integer(x); if (val == 0) return x; - if (width < 0) { - if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift"); - return lshift(mrb, val, -width); + if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift"); + if (!mrb_num_shift(mrb, val, -width, &val)) { + int_overflow(mrb, "bit shift"); } - return rshift(mrb, val, width); + return mrb_int_value(mrb, val); } /* 15.2.8.3.23 */ /* * call-seq: - * fix.to_f -> float + * int.to_f -> float * - * Converts <i>fix</i> to a <code>Float</code>. + * Converts <i>int</i> to a <code>Float</code>. * */ @@ -1357,13 +1431,12 @@ int_to_f(mrb_state *mrb, mrb_value num) */ /* ------------------------------------------------------------------------*/ MRB_API mrb_value -mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) +mrb_float_to_integer(mrb_state *mrb, mrb_value x) { mrb_int z = 0; if (!mrb_float_p(x)) { mrb_raise(mrb, E_TYPE_ERROR, "non float value"); - z = 0; /* not reached. just suppress warnings. */ } else { mrb_float d = mrb_float(x); @@ -1406,7 +1479,7 @@ int_plus(mrb_state *mrb, mrb_value x, mrb_value y) #ifdef MRB_NO_FLOAT mrb_raise(mrb, E_TYPE_ERROR, "non integer addition"); #else - return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a + mrb_as_float(mrb, y)); #endif } } @@ -1419,7 +1492,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) } #ifndef MRB_NO_FLOAT if (mrb_float_p(x)) { - return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, mrb_float(x) + mrb_as_float(mrb, y)); } #endif #if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) @@ -1438,7 +1511,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) /* 15.2.8.3.1 */ /* * call-seq: - * fix + numeric -> numeric_result + * int + numeric -> numeric_result * * Performs addition: the class of the resulting object depends on * the class of <code>numeric</code> and on the magnitude of the @@ -1478,7 +1551,7 @@ int_minus(mrb_state *mrb, mrb_value x, mrb_value y) #ifdef MRB_NO_FLOAT mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction"); #else - return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a - mrb_as_float(mrb, y)); #endif } } @@ -1491,7 +1564,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) } #ifndef MRB_NO_FLOAT if (mrb_float_p(x)) { - return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, mrb_float(x) - mrb_as_float(mrb, y)); } #endif #if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) @@ -1511,7 +1584,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) /* 15.2.8.3.16 */ /* * call-seq: - * fix - numeric -> numeric_result + * int - numeric -> numeric_result * * Performs subtraction: the class of the resulting object depends on * the class of <code>numeric</code> and on the magnitude of the @@ -1525,35 +1598,51 @@ int_sub(mrb_state *mrb, mrb_value self) return int_minus(mrb, self, other); } - -MRB_API mrb_value -mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base) +MRB_API char* +mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base) { - char buf[MRB_INT_BIT+1]; - char *b = buf + sizeof buf; - mrb_int val = mrb_integer(x); - mrb_value str; + char *bufend = buf + len; + char *b = bufend-1; - if (base < 2 || 36 < base) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base); - } + if (base < 2 || 36 < base) return NULL; + if (len < 2) return NULL; - if (val == 0) { - *--b = '0'; + if (n == 0) { + buf[0] = '0'; + buf[1] = '\0'; + return buf; } - else if (val < 0) { + + *b = '\0'; + if (n < 0) { do { - *--b = mrb_digitmap[-(val % base)]; - } while (val /= base); - *--b = '-'; + if (b-- == buf) return NULL; + *b = mrb_digitmap[-(n % base)]; + } while (n /= base); + if (b-- == buf) return NULL; + *b = '-'; } else { do { - *--b = mrb_digitmap[(int)(val % base)]; - } while (val /= base); + if (b-- == buf) return NULL; + *b = mrb_digitmap[(int)(n % base)]; + } while (n /= base); } + return b; +} - str = mrb_str_new(mrb, b, buf + sizeof(buf) - b); +MRB_API mrb_value +mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base) +{ + char buf[MRB_INT_BIT+1]; + mrb_int val = mrb_integer(x); + + if (base < 2 || 36 < base) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base); + } + const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base); + mrb_assert(p != NULL); + mrb_value str = mrb_str_new_cstr(mrb, p); RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); return str; } @@ -1561,9 +1650,9 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base) /* 15.2.8.3.25 */ /* * call-seq: - * fix.to_s(base=10) -> string + * int.to_s(base=10) -> string * - * Returns a string containing the representation of <i>fix</i> radix + * Returns a string containing the representation of <i>int</i> radix * <i>base</i> (between 2 and 36). * * 12345.to_s #=> "12345" @@ -1580,7 +1669,7 @@ int_to_s(mrb_state *mrb, mrb_value self) mrb_int base = 10; mrb_get_args(mrb, "|i", &base); - return mrb_fixnum_to_str(mrb, self, base); + return mrb_integer_to_str(mrb, self, base); } /* compare two numbers: (1:0:-1; -2 for error) */ @@ -1596,7 +1685,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) #ifdef MRB_NO_FLOAT x = mrb_integer(v1); #else - x = mrb_to_flo(mrb, v1); + x = mrb_as_float(mrb, v1); #endif switch (mrb_type(v2)) { case MRB_TT_INTEGER: @@ -1612,7 +1701,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) break; #ifdef MRB_USE_RATIONAL case MRB_TT_RATIONAL: - y = mrb_to_flo(mrb, v2); + y = mrb_as_float(mrb, v2); break; #endif #endif @@ -1635,7 +1724,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * < => -1 * = => 0 * > => +1 - * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is + * Comparison---Returns -1, 0, or +1 depending on whether <i>int</i> is * less than, equal to, or greater than <i>numeric</i>. This is the * basis for the tests in <code>Comparable</code>. When the operands are * not comparable, it returns nil instead of raising an exception. @@ -1817,21 +1906,21 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ + mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_OPT(1)); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ - mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ + mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */ mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */ mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ - mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ - mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); - mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ + mrb_define_method(mrb, fl, "to_i", flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */ mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "abs", flo_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */ #ifdef INFINITY mrb_define_const_id(mrb, fl, MRB_SYM(INFINITY), mrb_float_value(mrb, INFINITY)); diff --git a/src/object.c b/src/object.c index a44eab4bb..b3c9973bf 100644 --- a/src/object.c +++ b/src/object.c @@ -316,44 +316,15 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE()); } -static const struct types { - const enum mrb_vtype type; - const char *name; -} builtin_types[] = { -/* {MRB_TT_NIL, "nil"}, */ - {MRB_TT_FALSE, "false"}, - {MRB_TT_TRUE, "true"}, - {MRB_TT_INTEGER,"Integer"}, - {MRB_TT_SYMBOL, "Symbol"}, /* :symbol */ - {MRB_TT_MODULE, "Module"}, - {MRB_TT_OBJECT, "Object"}, - {MRB_TT_CLASS, "Class"}, - {MRB_TT_ICLASS, "iClass"}, /* internal use: mixed-in module holder */ - {MRB_TT_SCLASS, "SClass"}, - {MRB_TT_PROC, "Proc"}, -#ifndef MRB_NO_FLOAT - {MRB_TT_FLOAT, "Float"}, -#endif - {MRB_TT_ARRAY, "Array"}, - {MRB_TT_HASH, "Hash"}, - {MRB_TT_STRING, "String"}, - {MRB_TT_RANGE, "Range"}, -/* {MRB_TT_BIGNUM, "Bignum"}, */ - {MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */ -/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */ - {MRB_TT_MAXDEFINE, 0} -}; - static const char* type_name(enum mrb_vtype t) { - const struct types *type = builtin_types; - - while (type->type < MRB_TT_MAXDEFINE) { - if (type->type == t) return type->name; - type++; + switch (t) { +#define MRB_VTYPE_NAME(tt, type, name) case tt: return name; + MRB_VTYPE_FOREACH(MRB_VTYPE_NAME) +#undef MRB_VTYPE_NAME + default: return NULL; } - return NULL; } static mrb_value @@ -409,7 +380,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) ename = "nil"; } else if (mrb_integer_p(x)) { - ename = "Fixnum"; + ename = "Integer"; } else if (mrb_symbol_p(x)) { ename = "Symbol"; @@ -507,13 +478,13 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) } MRB_API mrb_value -mrb_to_int(mrb_state *mrb, mrb_value val) +mrb_to_integer(mrb_state *mrb, mrb_value val) { if (!mrb_integer_p(val)) { #ifndef MRB_NO_FLOAT if (mrb_float_p(val)) { - return mrb_flo_to_fixnum(mrb, val); + return mrb_float_to_integer(mrb, val); } #endif if (mrb_string_p(val)) { @@ -524,55 +495,9 @@ mrb_to_int(mrb_state *mrb, mrb_value val) return val; } -MRB_API mrb_value -mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) -{ - mrb_value tmp; - - if (mrb_nil_p(val)) { - if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); - } - switch (mrb_type(val)) { -#ifndef MRB_NO_FLOAT - case MRB_TT_FLOAT: - if (base != 0) goto arg_error; - return mrb_flo_to_fixnum(mrb, val); -#endif - - case MRB_TT_INTEGER: - if (base != 0) goto arg_error; - return val; - - case MRB_TT_STRING: - string_conv: - return mrb_str_to_inum(mrb, val, base, TRUE); - - default: - break; - } - if (base != 0) { - tmp = mrb_check_string_type(mrb, val); - if (!mrb_nil_p(tmp)) { - val = tmp; - goto string_conv; - } -arg_error: - mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); - } - /* to raise TypeError */ - return mrb_to_int(mrb, val); -} - -MRB_API mrb_value -mrb_Integer(mrb_state *mrb, mrb_value val) -{ - return mrb_convert_to_integer(mrb, val, 0); -} - #ifndef MRB_NO_FLOAT MRB_API mrb_value -mrb_Float(mrb_state *mrb, mrb_value val) +mrb_to_float(mrb_state *mrb, mrb_value val) { if (mrb_nil_p(val)) { mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Float"); @@ -594,19 +519,6 @@ mrb_Float(mrb_state *mrb, mrb_value val) #endif MRB_API mrb_value -mrb_to_str(mrb_state *mrb, mrb_value val) -{ - return mrb_ensure_string_type(mrb, val); -} - -/* obsolete: use mrb_ensure_string_type() instead */ -MRB_API mrb_value -mrb_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_ensure_string_type(mrb, str); -} - -MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str) { if (!mrb_string_p(str)) { diff --git a/src/proc.c b/src/proc.c index 78ce0e791..d48145f13 100644 --- a/src/proc.c +++ b/src/proc.c @@ -46,7 +46,7 @@ mrb_proc_new(mrb_state *mrb, const mrb_irep *irep) struct RProc *p; mrb_callinfo *ci = mrb->c->ci; - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class); if (ci) { struct RClass *tc = NULL; @@ -81,7 +81,8 @@ mrb_env_new(mrb_state *mrb, struct mrb_context *c, mrb_callinfo *ci, int nstacks struct REnv *e; mrb_int bidx; - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, tc); + e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL); + e->c = tc; MRB_ENV_SET_LEN(e, nstacks); bidx = ci->argc; if (bidx < 0) bidx = 2; @@ -105,7 +106,7 @@ closure_setup(mrb_state *mrb, struct RProc *p) /* do nothing, because e is assigned already */ } else if (up) { - struct RClass *tc = MRB_PROC_TARGET_CLASS(p); + struct RClass *tc = ci->u.target_class; e = mrb_env_new(mrb, mrb->c, ci, up->body.irep->nlocals, ci->stack, tc); ci->u.env = e; @@ -134,7 +135,7 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) { struct RProc *p; - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class); p->body.func = func; p->flags |= MRB_PROC_CFUNC_FL; p->upper = 0; @@ -224,7 +225,7 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) /* Calling Proc.new without a block is not implemented yet */ mrb_get_args(mrb, "&!", &blk); - p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); + p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); mrb_proc_copy(p, mrb_proc_ptr(blk)); proc = mrb_obj_value(p); mrb_funcall_with_block(mrb, proc, MRB_SYM(initialize), 0, NULL, proc); @@ -278,7 +279,7 @@ proc_lambda(mrb_state *mrb, mrb_value self) } p = mrb_proc_ptr(blk); if (!MRB_PROC_STRICT_P(p)) { - struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c); + struct RProc *p2 = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, p->c); mrb_proc_copy(p2, p); p2->flags |= MRB_PROC_STRICT; return mrb_obj_value(p2); @@ -417,7 +418,19 @@ mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, c mrb_sym *destlv = (mrb_sym*)irep->lv + irep->nlocals - 1 /* self */; mrb_value *destst = env->stack + irep->nlocals; memmove(destlv, lv, sizeof(mrb_sym) * num); - memmove(destst, stack, sizeof(mrb_value) * num); + if (stack) { + memmove(destst, stack, sizeof(mrb_value) * num); + for (int i = 0; i < num; i++) { + if (!mrb_immediate_p(stack[i])) { + mrb_field_write_barrier(mrb, (struct RBasic*)env, (struct RBasic*)mrb_obj_ptr(stack[i])); + } + } + } + else { + for (int i = num; i > 0; i--, destst++) { + *destst = mrb_nil_value(); + } + } irep->nlocals += num; irep->nregs = irep->nlocals; MRB_ENV_SET_LEN(env, irep->nlocals); diff --git a/src/range.c b/src/range.c index cb60bb63c..7507173b6 100644 --- a/src/range.c +++ b/src/range.c @@ -9,11 +9,12 @@ #include <mruby/range.h> #include <mruby/string.h> #include <mruby/array.h> +#include <mruby/numeric.h> #include <mruby/presym.h> -#define RANGE_INITIALIZED_MASK 1 -#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) -#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) +#define RANGE_INITIALIZED_FLAG 1 +#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_FLAG) +#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_FLAG) static void r_check(mrb_state *mrb, mrb_value a, mrb_value b) @@ -25,13 +26,13 @@ r_check(mrb_state *mrb, mrb_value a, mrb_value b) ta = mrb_type(a); tb = mrb_type(b); #ifdef MRB_NO_FLOAT - if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) { + if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) return; #else if ((ta == MRB_TT_INTEGER || ta == MRB_TT_FLOAT) && (tb == MRB_TT_INTEGER || tb == MRB_TT_FLOAT)) { -#endif return; } +#endif if (mrb_nil_p(a) || mrb_nil_p(b)) return; @@ -88,7 +89,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m } } else { - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + r = MRB_OBJ_ALLOC(mrb, MRB_TT_RANGE, mrb->range_class); range_ptr_alloc_edges(mrb, r); } @@ -342,6 +343,59 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) return copy; } +static mrb_value +range_num_to_a(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + mrb_value beg = RANGE_BEG(r); + mrb_value end = RANGE_END(r); + mrb_value ary; + + mrb->c->ci->mid = 0; + if (mrb_nil_p(end)) { + mrb_raise(mrb, E_RANGE_ERROR, "cannot convert endless range to an array"); + } + if (mrb_integer_p(beg)) { + if (mrb_integer_p(end)) { + mrb_int a = mrb_integer(beg); + mrb_int b = mrb_integer(end); + mrb_int len; + + if (mrb_int_sub_overflow(b, a, &len)) { + mrb_raise(mrb, E_RANGE_ERROR, "integer range too long"); + } + if (!RANGE_EXCL(r)) len++; + ary = mrb_ary_new_capa(mrb, len); + for (mrb_int i=0; i<len; i++) { + mrb_ary_push(mrb, ary, mrb_int_value(mrb, a+i)); + } + return ary; + } +#ifndef MRB_NO_FLOAT + if (mrb_float_p(end)) { + mrb_float a = (mrb_float)mrb_integer(beg); + mrb_float b = mrb_float(end); + + ary = mrb_ary_new_capa(mrb, (mrb_int)(b - a) + 1); + if (RANGE_EXCL(r)) { + while (a < b) { + mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a)); + a += 1.0; + } + } + else { + while (a <= b) { + mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a)); + a += 1.0; + } + } + return ary; + } +#endif + } + return mrb_nil_value(); +} + mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)) { @@ -409,8 +463,8 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (!mrb_range_p(range)) return MRB_RANGE_TYPE_MISMATCH; r = mrb_range_ptr(mrb, range); - beg = mrb_nil_p(RANGE_BEG(r)) ? 0 : mrb_int(mrb, RANGE_BEG(r)); - end = mrb_nil_p(RANGE_END(r)) ? -1 : mrb_int(mrb, RANGE_END(r)); + beg = mrb_nil_p(RANGE_BEG(r)) ? 0 : mrb_as_int(mrb, RANGE_BEG(r)); + end = mrb_nil_p(RANGE_END(r)) ? -1 : mrb_as_int(mrb, RANGE_END(r)); excl = mrb_nil_p(RANGE_END(r)) ? 0 : RANGE_EXCL(r); if (beg < 0) { @@ -456,4 +510,5 @@ mrb_init_range(mrb_state *mrb) mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */ + mrb_define_method(mrb, r, "__num_to_a", range_num_to_a, MRB_ARGS_NONE()); } diff --git a/src/readflt.c b/src/readflt.c new file mode 100644 index 000000000..b320a43c1 --- /dev/null +++ b/src/readflt.c @@ -0,0 +1,119 @@ +#include <mruby.h> + +#ifndef MRB_NO_FLOAT +/* + * strtod implementation. + * author: Yasuhiro Matsumoto (@mattn) + * license: public domain + */ + +/* +The original code can be found in https://github.com/mattn/strtod + +I modified the routine for mruby: + + * renamed the function `vim_strtod` -> `mrb_float_read` + * simplified the code + +My modifications in this file are also placed in the public domain. + +Matz (Yukihiro Matsumoto) +*/ + +#include <string.h> +#include <math.h> +#include <errno.h> + +MRB_API double +mrb_float_read(const char *str, char **end) +{ + double d = 0.0; + int sign; + int n = 0; + const char *p, *a; + + a = p = str; + while (ISSPACE(*p)) + ++p; + + /* decimal part */ + sign = 1; + if (*p == '-') { + sign = -1; + ++p; + } else if (*p == '+') + ++p; + if (ISDIGIT(*p)) { + d = (double)(*p++ - '0'); + while (*p && ISDIGIT(*p)) { + d = d * 10.0 + (double)(*p - '0'); + ++p; + ++n; + } + a = p; + } else if (*p != '.') + goto done; + d *= sign; + + /* fraction part */ + if (*p == '.') { + double f = 0.0; + double base = 0.1; + ++p; + + if (ISDIGIT(*p)) + { + while (*p && ISDIGIT(*p)) { + f += base * (*p - '0') ; + base /= 10.0; + ++p; + ++n; + } + } + d += f * sign; + a = p; + } + + /* exponential part */ + if ((*p == 'E') || (*p == 'e')) { + int e = 0; + ++p; + + sign = 1; + if (*p == '-') { + sign = -1; + ++p; + } else if (*p == '+') + ++p; + + if (ISDIGIT(*p)) { + while (*p == '0') + ++p; + if (*p == '\0') --p; + e = (int)(*p++ - '0'); + for (; *p && ISDIGIT(*p); p++) { + if (e < 10000) + e = e * 10 + (*p - '0'); + } + e *= sign; + } + else if (!ISDIGIT(*(a-1))) { + a = str; + goto done; + } + else if (*p == 0) + goto done; + d *= pow(10.0, (double) e); + a = p; + } + else if (p > str && !ISDIGIT(*(p-1))) { + a = str; + goto done; + } + +done: + if (end) + *end = (char*)a; + return d; +} +#endif diff --git a/src/readint.c b/src/readint.c new file mode 100644 index 000000000..5fae222c2 --- /dev/null +++ b/src/readint.c @@ -0,0 +1,30 @@ +#include <mruby.h> +#include <mruby/numeric.h> +#include <errno.h> + +/* mrb_int_read(): read mrb_int from a string (base 10 only) */ +/* const char *p - string to read */ +/* const char *e - end of string */ +/* char **endp - end of parsed integer */ + +/* if integer overflows, errno will be set to ERANGE */ +/* also endp will be set to NULL on overflow */ +MRB_API mrb_int +mrb_int_read(const char *p, const char *e, char **endp) +{ + mrb_int n = 0; + int ch; + + while ((e == NULL || p < e) && ISDIGIT(*p)) { + ch = *p - '0'; + if (mrb_int_mul_overflow(n, 10, &n) || + mrb_int_add_overflow(n, ch, &n)) { + if (endp) *endp = NULL; + errno = ERANGE; + return MRB_INT_MAX; + } + p++; + } + if (endp) *endp = (char*)p; + return n; +} diff --git a/src/string.c b/src/string.c index e440bff8c..ac0f4a920 100644 --- a/src/string.c +++ b/src/string.c @@ -8,14 +8,6 @@ # define _CRT_NONSTDC_NO_DEPRECATE #endif -#ifndef MRB_NO_FLOAT -#include <float.h> -#include <math.h> -#endif -#include <limits.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> #include <mruby.h> #include <mruby/array.h> #include <mruby/class.h> @@ -23,6 +15,7 @@ #include <mruby/string.h> #include <mruby/numeric.h> #include <mruby/presym.h> +#include <string.h> typedef struct mrb_shared_string { int refcnt; @@ -32,7 +25,7 @@ typedef struct mrb_shared_string { const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; -#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) +#define mrb_obj_alloc_string(mrb) MRB_OBJ_ALLOC((mrb), MRB_TT_STRING, (mrb)->string_class) static struct RString* str_init_normal_capa(mrb_state *mrb, struct RString *s, @@ -244,7 +237,7 @@ str_modify_keep_ascii(mrb_state *mrb, struct RString *s) static void check_null_byte(mrb_state *mrb, mrb_value str) { - mrb_to_str(mrb, str); + mrb_ensure_string_type(mrb, str); if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); } @@ -839,8 +832,15 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; + const char *p = RSTRING_PTR(str0); + size_t len = RSTRING_LEN(str0); check_null_byte(mrb, str0); - s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); + if (RSTR_EMBEDDABLE_P(len)) { + s = str_init_embed(mrb_obj_alloc_string(mrb), p, len); + } + else { + s = str_init_normal(mrb, mrb_obj_alloc_string(mrb), p, len); + } return RSTR_PTR(s); } @@ -897,14 +897,14 @@ static mrb_value mrb_str_size(mrb_state *mrb, mrb_value self) { mrb_int len = RSTRING_CHAR_LEN(self); - return mrb_fixnum_value(len); + return mrb_int_value(mrb, len); } static mrb_value mrb_str_bytesize(mrb_state *mrb, mrb_value self) { mrb_int len = RSTRING_LEN(self); - return mrb_fixnum_value(len); + return mrb_int_value(mrb, len); } /* 15.2.10.5.1 */ @@ -1018,7 +1018,7 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1) else { result = mrb_str_cmp(mrb, str1, str2); } - return mrb_fixnum_value(result); + return mrb_int_value(mrb, result); } static mrb_bool @@ -1071,7 +1071,7 @@ mrb_string_value_ptr(mrb_state *mrb, mrb_value str) MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { - mrb_to_str(mrb, ptr); + mrb_ensure_string_type(mrb, ptr); return RSTRING_LEN(ptr); } @@ -1102,8 +1102,8 @@ static enum str_convert_range str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len) { if (!mrb_undef_p(alen)) { - *beg = mrb_int(mrb, indx); - *len = mrb_int(mrb, alen); + *beg = mrb_as_int(mrb, indx); + *len = mrb_as_int(mrb, alen); return STR_CHAR_RANGE; } else { @@ -1123,7 +1123,7 @@ str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, goto range_arg; default: - indx = mrb_to_int(mrb, indx); + indx = mrb_to_integer(mrb, indx); if (mrb_integer_p(indx)) { *beg = mrb_integer(indx); *len = 1; @@ -1175,14 +1175,14 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) /* 15.2.10.5.34 */ /* * call-seq: - * str[fixnum] => fixnum or nil - * str[fixnum, fixnum] => new_str or nil - * str[range] => new_str or nil - * str[other_str] => new_str or nil - * str.slice(fixnum) => fixnum or nil - * str.slice(fixnum, fixnum) => new_str or nil - * str.slice(range) => new_str or nil - * str.slice(other_str) => new_str or nil + * str[int] => int or nil + * str[int, int] => new_str or nil + * str[range] => new_str or nil + * str[other_str] => new_str or nil + * str.slice(int) => int or nil + * str.slice(int, int) => new_str or nil + * str.slice(range) => new_str or nil + * str.slice(other_str) => new_str or nil * * Element Reference---If passed a single <code>Integer</code>, returns the code * of the character at that position. If passed two <code>Integer</code> @@ -1239,13 +1239,11 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb if (end > len) { end = len; } if (pos < 0 || pos > len) { - str_out_of_index(mrb, mrb_fixnum_value(pos)); + str_out_of_index(mrb, mrb_int_value(mrb, pos)); } replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); - newlen = replen + (len - (end - pos)); - - if (newlen >= MRB_SSIZE_MAX || newlen < replen /* overflowed */) { + if (mrb_int_add_overflow(replen, len - (end - pos), &newlen) || newlen >= MRB_SSIZE_MAX) { mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); } @@ -1358,8 +1356,7 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_ { mrb_int beg, len, charlen; - mrb_to_str(mrb, replace); - + mrb_ensure_string_type(mrb, replace); switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { case STR_OUT_OF_RANGE: default: @@ -1376,14 +1373,17 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_ str_range_to_bytes(str, &beg, &len); /* fall through */ case STR_BYTE_RANGE_CORRECTED: - str_replace_partial(mrb, str, beg, beg + len, replace); + if (mrb_int_add_overflow(beg, len, &len)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string index too big"); + } + str_replace_partial(mrb, str, beg, len, replace); } } /* * call-seq: - * str[fixnum] = replace - * str[fixnum, fixnum] = replace + * str[int] = replace + * str[int, int] = replace * str[range] = replace * str[other_str] = replace * @@ -1754,7 +1754,7 @@ mrb_str_hash(mrb_state *mrb, mrb_value str) /* 15.2.10.5.20 */ /* * call-seq: - * str.hash => fixnum + * str.hash => int * * Return a hash based on the string's length and content. */ @@ -1762,14 +1762,14 @@ static mrb_value mrb_str_hash_m(mrb_state *mrb, mrb_value self) { mrb_int key = mrb_str_hash(mrb, self); - return mrb_fixnum_value(key); + return mrb_int_value(mrb, key); } /* 15.2.10.5.21 */ /* * call-seq: * str.include? other_str => true or false - * str.include? fixnum => true or false + * str.include? int => true or false * * Returns <code>true</code> if <i>str</i> contains the given string or * character. @@ -1792,7 +1792,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self) /* 15.2.10.5.22 */ /* * call-seq: - * str.index(substring [, offset]) => fixnum or nil + * str.index(substring [, offset]) => int or nil * * Returns the index of the first occurrence of the given * <i>substring</i>. Returns <code>nil</code> if not found. @@ -1824,7 +1824,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) if (pos == -1) return mrb_nil_value(); BYTES_ALIGN_CHECK(pos); - return mrb_fixnum_value(pos); + return mrb_int_value(mrb, pos); } /* 15.2.10.5.24 */ @@ -1873,7 +1873,7 @@ mrb_str_init(mrb_state *mrb, mrb_value self) * str.to_sym => symbol * * Returns the <code>Symbol</code> corresponding to <i>str</i>, creating the - * symbol if it did not previously exist. See <code>Symbol#id2name</code>. + * symbol if it did not previously exist. * * "Koala".intern #=> :Koala * s = 'cat'.to_sym #=> :cat @@ -1901,7 +1901,7 @@ mrb_obj_as_string(mrb_state *mrb, mrb_value obj) case MRB_TT_SYMBOL: return mrb_sym_str(mrb, mrb_symbol(obj)); case MRB_TT_INTEGER: - return mrb_fixnum_to_str(mrb, obj, 10); + return mrb_integer_to_str(mrb, obj, 10); case MRB_TT_SCLASS: case MRB_TT_CLASS: case MRB_TT_MODULE: @@ -2018,7 +2018,7 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str) /* 15.2.10.5.31 */ /* * call-seq: - * str.rindex(substring [, offset]) => fixnum or nil + * str.rindex(substring [, offset]) => int or nil * * Returns the index of the last occurrence of the given <i>substring</i>. * Returns <code>nil</code> if not found. If the second parameter is @@ -2053,7 +2053,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) if (pos >= 0) { pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); BYTES_ALIGN_CHECK(pos); - return mrb_fixnum_value(pos); + return mrb_int_value(mrb, pos); } return mrb_nil_value(); } @@ -2199,8 +2199,8 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -mrb_value -mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck) +static mrb_value +mrb_str_len_to_integer(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck) { const char *p = str; const char *pend = str + len; @@ -2363,12 +2363,6 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, i return mrb_fixnum_value(0); } -MRB_API mrb_value -mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badcheck) -{ - return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); -} - /* obslete: use RSTRING_CSTR() or mrb_string_cstr() */ MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) @@ -2401,15 +2395,15 @@ mrb_string_cstr(mrb_state *mrb, mrb_value str) } MRB_API mrb_value -mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) +mrb_str_to_integer(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) { const char *s; mrb_int len; - mrb_to_str(mrb, str); + mrb_ensure_string_type(mrb, str); s = RSTRING_PTR(str); len = RSTRING_LEN(str); - return mrb_str_len_to_inum(mrb, s, len, base, badcheck); + return mrb_str_len_to_integer(mrb, s, len, base, badcheck); } /* 15.2.10.5.38 */ @@ -2439,14 +2433,14 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) mrb_int base = 10; mrb_get_args(mrb, "|i", &base); - if (base < 0) { + if (base < 0 || 36 < base) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base); } - return mrb_str_to_inum(mrb, self, base, FALSE); + return mrb_str_to_integer(mrb, self, base, FALSE); } #ifndef MRB_NO_FLOAT -double +static double mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) { char buf[DBL_DIG * 4 + 20]; @@ -2466,7 +2460,7 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) mrb_value x; if (!badcheck) return 0.0; - x = mrb_str_len_to_inum(mrb, p, pend-p, 0, badcheck); + x = mrb_str_len_to_integer(mrb, p, pend-p, 0, badcheck); if (mrb_integer_p(x)) d = (double)mrb_integer(x); else /* if (mrb_float_p(x)) */ @@ -2536,12 +2530,6 @@ bad: } MRB_API double -mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck) -{ - return mrb_str_len_to_dbl(mrb, s, strlen(s), badcheck); -} - -MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { return mrb_str_len_to_dbl(mrb, RSTRING_PTR(str), RSTRING_LEN(str), badcheck); @@ -2711,7 +2699,7 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { - mrb_to_str(mrb, str2); + mrb_ensure_string_type(mrb, str2); return mrb_str_cat_str(mrb, str1, str2); } @@ -2734,7 +2722,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) /* * call-seq: - * str.bytes -> array of fixnums + * str.bytes -> array of int * * Returns an array of bytes in _str_. * @@ -2843,7 +2831,7 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) } } else { - beg = mrb_integer(mrb_to_int(mrb, a1)); + beg = mrb_integer(mrb_to_integer(mrb, a1)); len = 1; empty = FALSE; } @@ -2860,6 +2848,51 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) } } +static mrb_value +sub_replace(mrb_state *mrb, mrb_value self) +{ + char *p, *match; + mrb_int plen, mlen; + mrb_int found, offset; + mrb_value result; + + mrb_get_args(mrb, "ssi", &p, &plen, &match, &mlen, &found); + result = mrb_str_new(mrb, 0, 0); + for (mrb_int i=0; i<plen; i++) { + if (p[i] != '\\' || i+1==plen) { + mrb_str_cat(mrb, result, p+i, 1); + continue; + } + i++; + switch (p[i]) { + case '\\': + mrb_str_cat(mrb, result, "\\", 1); + break; + case '`': + mrb_str_cat(mrb, result, RSTRING_PTR(self), chars2bytes(self, 0, found)); + break; + case '&': case '0': + mrb_str_cat(mrb, result, match, mlen); + break; + case '\'': + offset = chars2bytes(self, 0, found) + mlen; + if (RSTRING_LEN(self) > offset) { + mrb_str_cat(mrb, result, RSTRING_PTR(self)+offset, RSTRING_LEN(self)-offset); + } + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + /* ignore sub-group match (no Regexp supported) */ + break; + default: + mrb_str_cat(mrb, result, &p[i-1], 2); + break; + } + } + return result; +} + /* ---------------------------*/ void mrb_init_string(mrb_state *mrb) @@ -2921,251 +2954,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1)); -} - -#ifndef MRB_NO_FLOAT -/* - * Source code for the "strtod" library procedure. - * - * Copyright (c) 1988-1993 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $ - */ - -#include <ctype.h> -#include <errno.h> - -static const int maxExponent = 511; /* Largest possible base 10 exponent. Any - * exponent larger than this will already - * produce underflow or overflow, so there's - * no need to worry about additional digits. - */ -static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */ - 10., /* is 10^2^i. Used to convert decimal */ - 100., /* exponents into floating-point numbers. */ - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 -}; - -MRB_API double -mrb_float_read(const char *string, char **endPtr) -/* const char *string; A decimal ASCII floating-point number, - * optionally preceded by white space. - * Must have form "-I.FE-X", where I is the - * integer part of the mantissa, F is the - * fractional part of the mantissa, and X - * is the exponent. Either of the signs - * may be "+", "-", or omitted. Either I - * or F may be omitted, or both. The decimal - * point isn't necessary unless F is present. - * The "E" may actually be an "e". E and X - * may both be omitted (but not just one). - */ -/* char **endPtr; If non-NULL, store terminating character's - * address here. */ -{ - int sign, expSign = FALSE; - double fraction, dblExp; - const double *d; - const char *p; - int c; - int exp = 0; /* Exponent read from "EX" field. */ - int fracExp = 0; /* Exponent that derives from the fractional - * part. Under normal circumstances, it is - * the negative of the number of digits in F. - * However, if I is very long, the last digits - * of I get dropped (otherwise a long I with a - * large negative exponent could cause an - * unnecessary overflow on I alone). In this - * case, fracExp is incremented one for each - * dropped digit. */ - int mantSize; /* Number of digits in mantissa. */ - int decPt; /* Number of mantissa digits BEFORE decimal - * point. */ - const char *pExp; /* Temporarily holds location of exponent - * in string. */ - - /* - * Strip off leading blanks and check for a sign. - */ - - p = string; - while (ISSPACE(*p)) { - p += 1; - } - if (*p == '-') { - sign = TRUE; - p += 1; - } - else { - if (*p == '+') { - p += 1; - } - sign = FALSE; - } - - /* - * Count the number of digits in the mantissa (including the decimal - * point), and also locate the decimal point. - */ - - decPt = -1; - for (mantSize = 0; ; mantSize += 1) - { - c = *p; - if (!ISDIGIT(c)) { - if ((c != '.') || (decPt >= 0)) { - break; - } - decPt = mantSize; - } - p += 1; - } - - /* - * Now suck up the digits in the mantissa. Use two integers to - * collect 9 digits each (this is faster than using floating-point). - * If the mantissa has more than 18 digits, ignore the extras, since - * they can't affect the value anyway. - */ - - pExp = p; - p -= mantSize; - if (decPt < 0) { - decPt = mantSize; - } - else { - mantSize -= 1; /* One of the digits was the point. */ - } - if (mantSize > 18) { - if (decPt - 18 > 29999) { - fracExp = 29999; - } - else { - fracExp = decPt - 18; - } - mantSize = 18; - } - else { - fracExp = decPt - mantSize; - } - if (mantSize == 0) { - fraction = 0.0; - p = string; - goto done; - } - else { - int frac1, frac2; - frac1 = 0; - for ( ; mantSize > 9; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac1 = 10*frac1 + (c - '0'); - } - frac2 = 0; - for (; mantSize > 0; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac2 = 10*frac2 + (c - '0'); - } - fraction = (1.0e9 * frac1) + frac2; - } - - /* - * Skim off the exponent. - */ - p = pExp; - if ((*p == 'E') || (*p == 'e')) { - p += 1; - if (*p == '-') { - expSign = TRUE; - p += 1; - } - else { - if (*p == '+') { - p += 1; - } - expSign = FALSE; - } - while (ISDIGIT(*p)) { - exp = exp * 10 + (*p - '0'); - if (exp > 19999) { - exp = 19999; - } - p += 1; - } - } - if (expSign) { - exp = fracExp - exp; - } - else { - exp = fracExp + exp; - } - - /* - * Generate a floating-point number that represents the exponent. - * Do this by processing the exponent one bit at a time to combine - * many powers of 2 of 10. Then combine the exponent with the - * fraction. - */ - - if (exp < 0) { - expSign = TRUE; - exp = -exp; - } - else { - expSign = FALSE; - } - if (exp > maxExponent) { - exp = maxExponent; - errno = ERANGE; - } - dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; - } - } - if (expSign) { - fraction /= dblExp; - } - else { - fraction *= dblExp; - } - -done: - if (endPtr != NULL) { - *endPtr = (char *) p; - } - - if (sign) { - return -fraction; - } - return fraction; + mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */ } -#endif diff --git a/src/symbol.c b/src/symbol.c index 3cd925d99..cc8986eaa 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <limits.h> #include <string.h> #include <mruby.h> #include <mruby/khash.h> @@ -54,13 +53,6 @@ presym_sym2name(mrb_sym sym, mrb_int *lenp) #endif /* MRB_NO_PRESYM */ /* ------------------------------------------------------ */ -typedef struct symbol_name { - mrb_bool lit : 1; - uint8_t prev; - uint16_t len; - const char *name; -} symbol_name; - static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -81,7 +73,11 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS static mrb_sym sym_inline_pack(const char *name, size_t len) { +#if defined(MRB_WORD_BOXING) && defined(MRB_32BIT) && !defined(MRB_WORDBOX_NO_FLOAT_TRUNCATE) + const size_t pack_length_max = 4; +#else const size_t pack_length_max = 5; +#endif char c; const char *p; @@ -138,11 +134,38 @@ symhash(const char *key, size_t len) return hash & 0xff; } +size_t mrb_packed_int_len(uint32_t num); +size_t mrb_packed_int_encode(uint32_t num, uint8_t *p, uint8_t *pend); +uint32_t mrb_packed_int_decode(uint8_t *p, uint8_t **newpos); + +#define sym_lit_p(mrb, i) (mrb->symflags[i>>3]&(1<<(i&7))) +#define sym_lit_set(mrb, i) mrb->symflags[i>>3]|=(1<<(i&7)) +#define sym_flags_clear(mrb, i) mrb->symflags[i>>3]&=~(1<<(i&7)) +#define sym_len(mrb, i) (size_t)(sym_lit_p(mrb, i)?strlen(mrb->symtbl[i]):mrb_packed_int_decode(mrb->symtbl[i],NULL)) + +static mrb_bool +sym_check(mrb_state *mrb, const char *name, size_t len, mrb_sym i) +{ + const char *symname = mrb->symtbl[i]; + size_t symlen; + + if (sym_lit_p(mrb, i)) { + symlen = strlen(symname); + } + else { + /* length in BER */ + symlen = mrb_packed_int_decode((uint8_t*)symname, (uint8_t**)&symname); + } + if (len == symlen && memcmp(symname, name, len) == 0) { + return TRUE; + } + return FALSE; +} + static mrb_sym find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp) { mrb_sym i; - symbol_name *sname; uint8_t hash; #ifndef MRB_NO_PRESYM @@ -160,24 +183,24 @@ find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp) i = mrb->symhash[hash]; if (i == 0) return 0; - do { - sname = &mrb->symtbl[i]; - if (sname->len == len && memcmp(sname->name, name, len) == 0) { + for (;;) { + if (sym_check(mrb, name, len, i)) { return (i+MRB_PRESYM_MAX); } - if (sname->prev == 0xff) { + uint8_t diff = mrb->symlink[i]; + if (diff == 0xff) { i -= 0xff; - sname = &mrb->symtbl[i]; - while (mrb->symtbl < sname) { - if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)((sname - mrb->symtbl)+MRB_PRESYM_MAX); + while (i > 0) { + if (sym_check(mrb, name, len, i)) { + return (i+MRB_PRESYM_MAX); } - sname--; + i--; } return 0; } - i -= sname->prev; - } while (sname->prev > 0); + if (diff == 0) return 0; + i -= diff; + } return 0; } @@ -185,7 +208,6 @@ static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { mrb_sym sym; - symbol_name *sname; uint8_t hash; sym_validate_len(mrb, len); @@ -194,35 +216,38 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) /* registering a new symbol */ sym = mrb->symidx + 1; - if (mrb->symcapa < sym) { + if (mrb->symcapa <= sym) { size_t symcapa = mrb->symcapa; if (symcapa == 0) symcapa = 100; else symcapa = (size_t)(symcapa * 6 / 5); - mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(symcapa+1)); + mrb->symtbl = (const char**)mrb_realloc(mrb, mrb->symtbl, sizeof(char*)*symcapa); + mrb->symflags = (uint8_t*)mrb_realloc(mrb, mrb->symflags, symcapa/8+1); + memset(mrb->symflags+mrb->symcapa/8+1, 0, (symcapa-mrb->symcapa)/8); + mrb->symlink = (uint8_t*)mrb_realloc(mrb, mrb->symlink, symcapa); mrb->symcapa = symcapa; } - sname = &mrb->symtbl[sym]; - sname->len = (uint16_t)len; - if (lit || mrb_ro_data_p(name)) { - sname->name = name; - sname->lit = TRUE; + sym_flags_clear(mrb, sym); + if ((lit || mrb_ro_data_p(name)) && strlen(name) == len) { + sym_lit_set(mrb, sym); + mrb->symtbl[sym] = name; } else { - char *p = (char *)mrb_malloc(mrb, len+1); - memcpy(p, name, len); - p[len] = 0; - sname->name = (const char*)p; - sname->lit = FALSE; + int ilen = mrb_packed_int_len(len); + char *p = (char *)mrb_malloc(mrb, len+ilen+1); + mrb_packed_int_encode(len, (uint8_t*)p, (uint8_t*)p+ilen); + memcpy(p+ilen, name, len); + p[ilen+len] = 0; + mrb->symtbl[sym] = p; } if (mrb->symhash[hash]) { mrb_sym i = sym - mrb->symhash[hash]; if (i > 0xff) - sname->prev = 0xff; + mrb->symlink[sym] = 0xff; else - sname->prev = i; + mrb->symlink[sym] = i; } else { - sname->prev = 0; + mrb->symlink[sym] = 0; } mrb->symhash[hash] = mrb->symidx = sym; @@ -320,8 +345,15 @@ sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) return NULL; } - if (lenp) *lenp = mrb->symtbl[sym].len; - return mrb->symtbl[sym].name; + const char *symname = mrb->symtbl[sym]; + if (!sym_lit_p(mrb, sym)) { + size_t len = mrb_packed_int_decode((uint8_t*)symname, (uint8_t**)&symname); + if (lenp) *lenp = (mrb_int)len; + } + else if (lenp) { + *lenp = (mrb_int)strlen(symname); + } + return symname; } MRB_API const char* @@ -334,25 +366,19 @@ mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) #endif } -mrb_bool -mrb_sym_static_p(mrb_state *mrb, mrb_sym sym) -{ - if (SYMBOL_INLINE_P(sym)) return TRUE; - if (sym > MRB_PRESYM_MAX) return FALSE; - return TRUE; -} - void mrb_free_symtbl(mrb_state *mrb) { mrb_sym i, lim; for (i=1, lim=mrb->symidx+1; i<lim; i++) { - if (!mrb->symtbl[i].lit) { - mrb_free(mrb, (char*)mrb->symtbl[i].name); + if (!sym_lit_p(mrb, i)) { + mrb_free(mrb, (char*)mrb->symtbl[i]); } } mrb_free(mrb, mrb->symtbl); + mrb_free(mrb, mrb->symlink); + mrb_free(mrb, mrb->symflags); } void @@ -397,12 +423,11 @@ mrb_init_symtbl(mrb_state *mrb) /* 15.2.11.3.3 */ /* * call-seq: - * sym.id2name -> string * sym.to_s -> string * * Returns the name or string corresponding to <i>sym</i>. * - * :fred.id2name #=> "fred" + * :fred.to_s #=> "fred" */ static mrb_value sym_to_s(mrb_state *mrb, mrb_value sym) @@ -410,6 +435,30 @@ sym_to_s(mrb_state *mrb, mrb_value sym) return mrb_sym_str(mrb, mrb_symbol(sym)); } +/* + * call-seq: + * sym.name -> string + * + * Returns the name or string corresponding to <i>sym</i>. Unlike #to_s, the + * returned string is frozen. + * + * :fred.name #=> "fred" + * :fred.name.frozen? #=> true + */ +static mrb_value +sym_name(mrb_state *mrb, mrb_value vsym) +{ + mrb_sym sym = mrb_symbol(vsym); + mrb_int len; + const char *name = mrb_sym_name_len(mrb, sym, &len); + + mrb_assert(name != NULL); + if (SYMBOL_INLINE_P(sym)) { + return mrb_str_new_frozen(mrb, name, len); + } + return mrb_str_new_static_frozen(mrb, name, len); +} + /* 15.2.11.3.4 */ /* * call-seq: @@ -596,7 +645,7 @@ mrb_sym_str(mrb_state *mrb, mrb_sym sym) } static const char* -sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump) +sym_cstr(mrb_state *mrb, mrb_sym sym, mrb_bool dump) { mrb_int len; const char *name = mrb_sym_name_len(mrb, sym, &len); @@ -615,13 +664,13 @@ sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump) MRB_API const char* mrb_sym_name(mrb_state *mrb, mrb_sym sym) { - return sym_name(mrb, sym, FALSE); + return sym_cstr(mrb, sym, FALSE); } MRB_API const char* mrb_sym_dump(mrb_state *mrb, mrb_sym sym) { - return sym_name(mrb, sym, TRUE); + return sym_cstr(mrb, sym, TRUE); } #define lesser(a,b) (((a)>(b))?(b):(a)) @@ -665,8 +714,8 @@ mrb_init_symbol(mrb_state *mrb) MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ + mrb_define_method(mrb, sym, "name", sym_name, MRB_ARGS_NONE()); mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); diff --git a/src/variable.c b/src/variable.c index 646353bfd..d89295229 100644 --- a/src/variable.c +++ b/src/variable.c @@ -766,16 +766,17 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip) { struct RClass *c = base; mrb_value v; mrb_bool retry = FALSE; mrb_value name; + if (skip) c = c->super; L_RETRY: while (c) { - if (c->iv) { + if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && c->iv) { if (iv_get(mrb, c->iv, sym, &v)) return v; } @@ -794,7 +795,7 @@ MRB_API mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); - return const_get(mrb, mrb_class_ptr(mod), sym); + return const_get(mrb, mrb_class_ptr(mod), sym, FALSE); } mrb_value @@ -803,9 +804,9 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) struct RClass *c; struct RClass *c2; mrb_value v; - const struct RProc *proc; + const struct RProc *proc = mrb->c->ci->proc; - c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); + c = MRB_PROC_TARGET_CLASS(proc); if (!c) c = mrb->object_class; if (iv_get(mrb, c->iv, sym, &v)) { return v; @@ -821,8 +822,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) c2 = mrb_class_ptr(klass); } if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2; - mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc)); - proc = mrb->c->ci->proc; + proc = proc->upper; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); if (c2 && iv_get(mrb, c2->iv, sym, &v)) { @@ -830,7 +830,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) } proc = proc->upper; } - return const_get(mrb, c, sym); + return const_get(mrb, c, sym, TRUE); } MRB_API void @@ -4,11 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stddef.h> -#include <stdarg.h> -#ifndef MRB_NO_FLOAT -#include <math.h> -#endif #include <mruby.h> #include <mruby/array.h> #include <mruby/class.h> @@ -91,14 +86,10 @@ void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value static inline void stack_clear(mrb_value *from, size_t count) { -#ifdef MRB_NAN_BOXING while (count-- > 0) { SET_NIL_VALUE(*from); from++; } -#else - memset(from, 0, sizeof(mrb_value)*count); -#endif } static inline void @@ -245,12 +236,13 @@ top_proc(mrb_state *mrb, const struct RProc *proc) return proc; } -#define CI_ACC_SKIP -1 -#define CI_ACC_DIRECT -2 -#define CI_ACC_RESUMED -3 +#define CINFO_NONE 0 +#define CINFO_SKIP 1 +#define CINFO_DIRECT 2 +#define CINFO_RESUMED 3 static inline mrb_callinfo* -cipush(mrb_state *mrb, mrb_int push_stacks, mrb_int acc, +cipush(mrb_state *mrb, mrb_int push_stacks, uint8_t cci, struct RClass *target_class, const struct RProc *proc, mrb_sym mid, mrb_int argc) { struct mrb_context *c = mrb->c; @@ -268,7 +260,7 @@ cipush(mrb_state *mrb, mrb_int push_stacks, mrb_int acc, mrb_vm_ci_proc_set(ci, proc); ci->stack = ci[-1].stack + push_stacks; ci->argc = (int16_t)argc; - ci->acc = (int16_t)acc; + ci->cci = cci; ci->u.target_class = target_class; return ci; @@ -314,7 +306,7 @@ mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, mrb_value result = mrb_nil_value(); int ai = mrb_gc_arena_save(mrb); const struct mrb_context *c = mrb->c; - int ci_index = c->ci - c->cibase; + ptrdiff_t ci_index = c->ci - c->cibase; if (error) { *error = FALSE; } @@ -335,9 +327,9 @@ mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, } else { // It was probably switched by mrb_fiber_resume(). - // Simply destroy all successive CI_ACC_DIRECTs once the fiber has been switched. + // Simply destroy all successive CINFO_DIRECTs once the fiber has been switched. c = mrb->c; - while (c->ci > c->cibase && c->ci->acc == CI_ACC_DIRECT) { + while (c->ci > c->cibase && c->ci->cci == CINFO_DIRECT) { cipop(mrb); } } @@ -506,12 +498,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb->c->ci->stack[argc+1] = blk; if (MRB_METHOD_CFUNC_P(m)) { - ci->acc = CI_ACC_DIRECT; + ci->cci = CINFO_DIRECT; val = MRB_METHOD_CFUNC(m)(mrb, self); cipop(mrb); } else { - ci->acc = CI_ACC_SKIP; + ci->cci = CINFO_SKIP; val = mrb_run(mrb, MRB_METHOD_PROC(m), self); } } @@ -526,68 +518,8 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); } -#define DECOMPOSE32(n) (((n) >> 24) & 0xff), (((n) >> 16) & 0xff), (((n) >> 8) & 0xff), (((n) >> 0) & 0xff) -#define CATCH_HANDLER_MAKE_BYTECODE(t, b, e, j) t, DECOMPOSE32(b), DECOMPOSE32(e), DECOMPOSE32(j) -#define CATCH_HANDLER_NUM_TO_BYTE(n) ((n) * sizeof(struct mrb_irep_catch_handler)) - -static void -exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_func_t posthook) -{ - /* - * stack: [proc, errinfo, return value by called proc] - * - * begin - * OP_NOP # A dummy instruction built in to make the catch handler react. - * ensure - * OP_EXCEPT R1 # Save the exception object. - * OP_CALL # Call a C function for the hook. - * # The stack is kept as it is in the called proc. - * # The exception will be rethrown within the hook function. - * end - */ - static const mrb_code hook_iseq[] = { - OP_NOP, - OP_EXCEPT, 1, - OP_CALL, - CATCH_HANDLER_MAKE_BYTECODE(MRB_CATCH_ENSURE, 0, 1, 1), - }; - static const mrb_irep hook_irep = { - 1, 3, 1, MRB_IREP_STATIC, hook_iseq, - NULL, NULL, NULL, NULL, NULL, - sizeof(hook_iseq) / sizeof(hook_iseq[0]) - CATCH_HANDLER_NUM_TO_BYTE(1), - 0, 0, 0, 0 - }; - static const struct RProc hook_caller = { - NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_FL_OBJ_IS_FROZEN, { &hook_irep }, NULL, { NULL } - }; - - struct RProc *hook = mrb_proc_new_cfunc(mrb, posthook); - int acc = 2; - memmove(ci->stack + acc, ci->stack, sizeof(mrb_value) * nregs); - ci->stack[0] = mrb_obj_value(hook); - ci->stack[1] = mrb_nil_value(); - mrb_callinfo hook_ci = { 0, 0, ci->acc, &hook_caller, ci->stack, &hook_iseq[1], { NULL } }; - ci = cipush(mrb, acc, acc, NULL, ci[0].proc, ci[0].mid, ci[0].argc); - ci->u.env = ci[-1].u.env; - ci[-1] = hook_ci; -} - -/* - * If `posthook` is given, `posthook` will be called even if an - * exception or global jump occurs in `p`. Exception or global jump objects - * are stored in `mrb->c->stack[1]` and should be rethrown in `posthook`. - * - * if (!mrb_nil_p(mrb->c->stack[1])) { - * mrb_exc_raise(mrb, mrb->c->stack[1]); - * } - * - * If you want to return the return value by `proc` as it is, please do - * `return mrb->c->stack[2]`. - * - * However, if `proc` is a C function, it will be ignored. - */ static mrb_value -exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; int keep, nregs; @@ -600,17 +532,12 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) nregs = p->body.irep->nregs; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; - int extra = posthook ? (2 /* hook proc + errinfo */) : 0; if (nregs < keep) { - mrb_stack_extend(mrb, keep + extra); + mrb_stack_extend(mrb, keep); } else { - mrb_stack_extend(mrb, nregs + extra); - stack_clear(ci->stack+keep, nregs-keep + extra); - } - - if (posthook) { - exec_irep_prepare_posthook(mrb, ci, (nregs < keep ? keep : nregs), posthook); + mrb_stack_extend(mrb, nregs); + stack_clear(ci->stack+keep, nregs-keep); } cipush(mrb, 0, 0, NULL, NULL, 0, 0); @@ -619,16 +546,16 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) } mrb_value -mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; - if (ci->acc >= 0) { - return exec_irep(mrb, self, p, posthook); + if (ci->cci == CINFO_NONE) { + return exec_irep(mrb, self, p); } else { mrb_value ret; if (MRB_PROC_CFUNC_P(p)) { - cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc); + cipush(mrb, 0, CINFO_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc); ret = MRB_PROC_CFUNC(p)(mrb, self); cipop(mrb); } @@ -675,7 +602,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block); ci = mrb->c->ci; - if (ci->acc < 0) { + if (ci->cci > CINFO_NONE) { funcall: return mrb_funcall_with_block(mrb, self, name, argc, argv, block); } @@ -706,7 +633,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) } return MRB_METHOD_CFUNC(m)(mrb, self); } - return exec_irep(mrb, self, MRB_METHOD_PROC(m), NULL); + return exec_irep(mrb, self, MRB_METHOD_PROC(m)); } static mrb_value @@ -720,7 +647,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } ci = mrb->c->ci; - if (ci->acc == CI_ACC_DIRECT) { + if (ci->cci == CINFO_DIRECT) { return mrb_yield_with_class(mrb, blk, 1, &self, self, c); } ci->u.target_class = c; @@ -792,21 +719,11 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) { mrb_value a, b; - struct RClass *c; if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented"); } - switch (mrb_type(self)) { - case MRB_TT_MODULE: - case MRB_TT_CLASS: - case MRB_TT_ICLASS: - c = mrb_class_ptr(self); - break; - default: - c = mrb_singleton_class_ptr(mrb, self); - } - return eval_under(mrb, self, b, c); + return eval_under(mrb, self, b, mrb_singleton_class_ptr(mrb, self)); } MRB_API mrb_value @@ -827,7 +744,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); - ci = cipush(mrb, n, CI_ACC_SKIP, c, p, mid, 0 /* dummy */); + ci = cipush(mrb, n, CINFO_SKIP, c, p, mid, 0 /* dummy */); if (argc >= CALL_MAXARGS) { ci->argc = -1; n = 3; @@ -848,7 +765,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value mrb->c->ci->stack[argc+1] = mrb_nil_value(); if (MRB_PROC_CFUNC_P(p)) { - ci->acc = CI_ACC_DIRECT; + ci->cci = CINFO_DIRECT; val = MRB_PROC_CFUNC(p)(mrb, self); cipop(mrb); } @@ -894,7 +811,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->ci->stack[2] = mrb_nil_value(); ci->argc = -1; - return exec_irep(mrb, self, p, NULL); + return exec_irep(mrb, self, p); } static struct RBreak* @@ -902,7 +819,7 @@ break_new(mrb_state *mrb, uint32_t tag, const struct RProc *p, mrb_value val) { struct RBreak *brk; - brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL); + brk = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL); mrb_break_proc_set(brk, p); mrb_break_value_set(brk, val); mrb_break_tag_set(brk, tag); @@ -1079,7 +996,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb #ifndef DIRECT_THREADED #define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { -#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; +#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY: #define NEXT goto L_END_DISPATCH #define JUMP NEXT #define END_DISPATCH L_END_DISPATCH:;}} @@ -1087,7 +1004,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; +#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY: #define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] #define JUMP NEXT @@ -1125,19 +1042,27 @@ mrb_vm_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int sta return result; } -static mrb_bool +static struct RClass* check_target_class(mrb_state *mrb) { - if (!mrb_vm_ci_target_class(mrb->c->ci)) { + struct RClass *target = mrb_vm_ci_target_class(mrb->c->ci); + if (!target) { mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR, "no target class or module"); mrb_exc_set(mrb, exc); - return FALSE; } - return TRUE; + return target; +} + +mrb_value +get_send_args(mrb_state *mrb, mrb_int argc, mrb_value *regs) +{ + if (argc < 0) return regs[0]; + return mrb_ary_new_from_values(mrb, argc, regs); } mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod); void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); +void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid); MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *pc) @@ -1191,11 +1116,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LOADL16, BS) { - goto op_loadl; - } CASE(OP_LOADL, BB) { - op_loadl: switch (pool[b].tt) { /* number */ case IREP_TT_INT32: regs[a] = mrb_int_value(mrb, (mrb_int)pool[b].u.i32); @@ -1267,11 +1188,6 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LOADSYM16, BS) { - SET_SYM_VALUE(regs[a], syms[b]); - NEXT; - } - CASE(OP_LOADNIL, B) { SET_NIL_VALUE(regs[a]); NEXT; @@ -1552,11 +1468,18 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = MRB_SYM(method_missing); - m = mrb_method_search_vm(mrb, &cls, missing); - if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); + mrb_value args; + + if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) { + method_missing: + args = get_send_args(mrb, argc, regs+a+1); mrb_method_missing(mrb, mid, recv, args); } + if (mid != missing) { + cls = mrb_class(mrb, recv); + } + m = mrb_method_search_vm(mrb, &cls, missing); + if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */ if (argc >= 0) { if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); @@ -1570,7 +1493,7 @@ RETRY_TRY_BLOCK: } /* push callinfo */ - ci = cipush(mrb, a, a, cls, NULL, mid, argc); + ci = cipush(mrb, a, 0, cls, NULL, mid, argc); if (MRB_METHOD_CFUNC_P(m)) { if (MRB_METHOD_PROC_P(m)) { @@ -1598,7 +1521,7 @@ RETRY_TRY_BLOCK: } } if (!ci->u.target_class) { /* return from context modifying method (resume/yield) */ - if (ci->acc == CI_ACC_RESUMED) { + if (ci->cci == CINFO_RESUMED) { mrb->jmp = prev_jmp; return recv; } @@ -1614,7 +1537,6 @@ RETRY_TRY_BLOCK: /* pop stackpos */ ci = cipop(mrb); pc = ci->pc; - JUMP; } else { /* setup environment for calling method */ @@ -1624,9 +1546,9 @@ RETRY_TRY_BLOCK: syms = irep->syms; mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; - JUMP; } } + JUMP; CASE(OP_CALL, Z) { mrb_callinfo *ci; @@ -1650,7 +1572,7 @@ RETRY_TRY_BLOCK: /* pop stackpos */ ci = cipop(mrb); pc = ci->pc; - regs[ci[1].acc] = recv; + ci[1].stack[0] = recv; irep = mrb->c->ci->proc->body.irep; pool = irep->pool; syms = irep->syms; @@ -1664,7 +1586,7 @@ RETRY_TRY_BLOCK: mrb->c->ci->stack[0] = mrb_nil_value(); a = 0; c = OP_R_NORMAL; - goto L_RETURN; + goto L_OP_RETURN_BODY; } pool = irep->pool; syms = irep->syms; @@ -1712,13 +1634,12 @@ RETRY_TRY_BLOCK: else if (target_class->tt == MRB_TT_MODULE) { target_class = mrb_vm_ci_target_class(ci); if (target_class->tt != MRB_TT_ICLASS) { - mrb_value exc = mrb_exc_new_lit(mrb, E_RUNTIME_ERROR, "superclass info lost [mruby limitations]"); - mrb_exc_set(mrb, exc); - goto L_RAISE; + goto super_typeerror; } } recv = regs[0]; if (!mrb_obj_is_kind_of(mrb, recv, target_class)) { + super_typeerror: ; mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR, "self has wrong type to call super in this context"); mrb_exc_set(mrb, exc); @@ -1736,20 +1657,18 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = MRB_SYM(method_missing); + mrb_value args; if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); + super_missing: + args = get_send_args(mrb, argc, regs+a+1); mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid); } if (mid != missing) { cls = mrb_class(mrb, recv); } m = mrb_method_search_vm(mrb, &cls, missing); - if (MRB_METHOD_UNDEF_P(m)) { /* just in case */ - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); - mrb_method_missing(mrb, missing, recv, args); - } - mid = missing; + if (MRB_METHOD_UNDEF_P(m)) goto super_missing; /* just in case */ if (argc >= 0) { if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); @@ -1758,7 +1677,8 @@ RETRY_TRY_BLOCK: regs[a+2] = blk; argc = -1; } - mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); + mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid)); + mid = missing; } /* push callinfo */ @@ -1779,7 +1699,7 @@ RETRY_TRY_BLOCK: ci = mrb->c->ci; mrb_assert(!mrb_break_p(v)); if (!mrb_vm_ci_target_class(ci)) { /* return from context modifying method (resume/yield) */ - if (ci->acc == CI_ACC_RESUMED) { + if (ci->cci == CINFO_RESUMED) { mrb->jmp = prev_jmp; return v; } @@ -1797,9 +1717,6 @@ RETRY_TRY_BLOCK: JUMP; } else { - /* fill callinfo */ - ci->acc = a; - /* setup environment for calling method */ mrb_vm_ci_proc_set(ci, (proc = MRB_METHOD_PROC(m))); irep = proc->body.irep; @@ -2086,7 +2003,7 @@ RETRY_TRY_BLOCK: } while ((ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL)) == NULL) { ci = cipop(mrb); - if (ci[1].acc == CI_ACC_SKIP && prev_jmp) { + if (ci[1].cci == CINFO_SKIP && prev_jmp) { mrb->jmp = prev_jmp; MRB_THROW(prev_jmp); } @@ -2134,7 +2051,7 @@ RETRY_TRY_BLOCK: switch (c) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ - if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { + if (ci->cci == CINFO_NONE && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { const struct RProc *dst; mrb_callinfo *cibase; cibase = mrb->c->cibase; @@ -2150,7 +2067,7 @@ RETRY_TRY_BLOCK: } /* check jump destination */ while (cibase <= ci && ci->proc != dst) { - if (ci->acc < 0) { /* jump cross C boudary */ + if (ci->cci > CINFO_NONE) { /* jump cross C boundary */ localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } @@ -2258,7 +2175,7 @@ RETRY_TRY_BLOCK: c->prev = NULL; ci = mrb->c->ci; } - if (ci->acc < 0) { + if (ci->cci > CINFO_NONE) { ci = cipop(mrb); mrb_gc_arena_restore(mrb, ai); mrb->c->vmexec = FALSE; @@ -2284,7 +2201,7 @@ RETRY_TRY_BLOCK: } } while (mrb->c->cibase < ci && ci[-1].proc != proc->upper) { - if (ci[-1].acc == CI_ACC_SKIP) { + if (ci[-1].cci == CINFO_SKIP) { goto L_BREAK_ERROR; } CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_UPPER) { @@ -2322,21 +2239,21 @@ RETRY_TRY_BLOCK: mrb->jmp = prev_jmp; return v; } - acc = ci->acc; + acc = ci->cci; ci = cipop(mrb); - if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) { + if (acc == CINFO_SKIP || acc == CINFO_DIRECT) { mrb_gc_arena_restore(mrb, ai); mrb->jmp = prev_jmp; return v; } - pc = ci[0].pc; + pc = ci->pc; DEBUG(fprintf(stderr, "from :%s\n", mrb_sym_name(mrb, ci->mid))); - proc = mrb->c->ci->proc; + proc = ci->proc; irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - regs[acc] = v; + ci[1].stack[0] = v; mrb_gc_arena_restore(mrb, ai); } JUMP; @@ -2440,9 +2357,7 @@ RETRY_TRY_BLOCK: CASE(OP_DIV, B) { #ifndef MRB_NO_FLOAT mrb_float x, y, f; - mrb_float mrb_div_flo(mrb_float x, mrb_float y); #endif - mrb_int mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { @@ -2475,7 +2390,7 @@ RETRY_TRY_BLOCK: } #ifndef MRB_NO_FLOAT - f = mrb_div_flo(x, y); + f = mrb_div_float(x, y); SET_FLOAT_VALUE(mrb, regs[a], f); #endif NEXT; @@ -2625,14 +2540,18 @@ RETRY_TRY_BLOCK: regs[a] = splat; } else { + mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY); mrb_ary_concat(mrb, regs[a], splat); } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYPUSH, B) { - mrb_ary_push(mrb, regs[a], regs[a+1]); + CASE(OP_ARYPUSH, BB) { + mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY); + for (mrb_int i=0; i<b; i++) { + mrb_ary_push(mrb, regs[a], regs[a+i+1]); + } NEXT; } @@ -2667,6 +2586,7 @@ RETRY_TRY_BLOCK: } CASE(OP_ASET, BBB) { + mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY); mrb_ary_set(mrb, regs[b], c, regs[a]); NEXT; } @@ -2709,16 +2629,29 @@ RETRY_TRY_BLOCK: mrb_sym sym = mrb_intern_str(mrb, regs[a]); regs[a] = mrb_symbol_value(sym); - mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_STRING16, BS) { - goto op_string; + CASE(OP_SYMBOL, BB) { + size_t len; + mrb_sym sym; + + mrb_assert((pool[b].tt&IREP_TT_NFLAG)==0); + len = pool[b].tt >> 2; + if (pool[b].tt & IREP_TT_SFLAG) { + sym = mrb_intern_static(mrb, pool[b].u.str, len); + } + else { + sym = mrb_intern(mrb, pool[b].u.str, len); + } + regs[a] = mrb_symbol_value(sym); + NEXT; } + CASE(OP_STRING, BB) { size_t len; - op_string: + + mrb_assert((pool[b].tt&IREP_TT_NFLAG)==0); len = pool[b].tt >> 2; if (pool[b].tt & IREP_TT_SFLAG) { regs[a] = mrb_str_new_static(mrb, pool[b].u.str, len); @@ -2753,7 +2686,8 @@ RETRY_TRY_BLOCK: int i; int lim = a+b*2+1; - hash = mrb_ensure_hash_type(mrb, regs[a]); + hash = regs[a]; + mrb_ensure_hash_type(mrb, hash); for (i=a+1; i<lim; i+=2) { mrb_hash_set(mrb, hash, regs[i], regs[i+1]); } @@ -2761,8 +2695,9 @@ RETRY_TRY_BLOCK: NEXT; } CASE(OP_HASHCAT, B) { - mrb_value hash = mrb_ensure_hash_type(mrb, regs[a]); + mrb_value hash = regs[a]; + mrb_ensure_hash_type(mrb, hash); mrb_hash_merge(mrb, hash, regs[a+1]); mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2795,18 +2730,6 @@ RETRY_TRY_BLOCK: c = OP_L_METHOD; goto L_MAKE_LAMBDA; } - CASE(OP_LAMBDA16, BS) { - c = OP_L_LAMBDA; - goto L_MAKE_LAMBDA; - } - CASE(OP_BLOCK16, BS) { - c = OP_L_BLOCK; - goto L_MAKE_LAMBDA; - } - CASE(OP_METHOD16, BS) { - c = OP_L_METHOD; - goto L_MAKE_LAMBDA; - } CASE(OP_RANGE_INC, B) { mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); @@ -2862,10 +2785,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_EXEC16, BS) - goto L_EXEC; CASE(OP_EXEC, BB) - L_EXEC: { mrb_value recv = regs[a]; struct RProc *p; @@ -2879,7 +2799,7 @@ RETRY_TRY_BLOCK: p->flags |= MRB_PROC_SCOPE; /* prepare call stack */ - cipush(mrb, a, a, mrb_class_ptr(recv), p, 0, 0); + cipush(mrb, a, 0, mrb_class_ptr(recv), p, 0, 0); irep = p->body.irep; pool = irep->pool; @@ -2894,10 +2814,13 @@ RETRY_TRY_BLOCK: struct RClass *target = mrb_class_ptr(regs[a]); struct RProc *p = mrb_proc_ptr(regs[a+1]); mrb_method_t m; + mrb_sym mid = syms[b]; MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, target, syms[b], m); + mrb_define_method_raw(mrb, target, mid, m); + mrb_method_added(mrb, target, mid); mrb_gc_arena_restore(mrb, ai); + regs[a] = mrb_symbol_value(mid); NEXT; } @@ -2908,24 +2831,24 @@ RETRY_TRY_BLOCK: } CASE(OP_TCLASS, B) { - if (!check_target_class(mrb)) goto L_RAISE; - regs[a] = mrb_obj_value(mrb_vm_ci_target_class(mrb->c->ci)); + struct RClass *target = check_target_class(mrb); + if (!target) goto L_RAISE; + regs[a] = mrb_obj_value(target); NEXT; } CASE(OP_ALIAS, BB) { - struct RClass *target; + struct RClass *target = check_target_class(mrb); - if (!check_target_class(mrb)) goto L_RAISE; - target = mrb_vm_ci_target_class(mrb->c->ci); + if (!target) goto L_RAISE; mrb_alias_method(mrb, target, syms[a], syms[b]); + mrb_method_added(mrb, target, syms[a]); NEXT; } CASE(OP_UNDEF, B) { - struct RClass *target; + struct RClass *target = check_target_class(mrb); - if (!check_target_class(mrb)) goto L_RAISE; - target = mrb_vm_ci_target_class(mrb->c->ci); + if (!target) goto L_RAISE; mrb_undef_method_id(mrb, target, syms[a]); NEXT; } @@ -2958,6 +2881,37 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_EXT1, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT2, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT3, Z) { + uint8_t insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_STOP, Z) { /* stop VM */ CHECKPOINT_RESTORE(RBREAK_TAG_STOP) { @@ -2981,7 +2935,7 @@ RETRY_TRY_BLOCK: } MRB_CATCH(&c_jmp) { mrb_callinfo *ci = mrb->c->ci; - while (ci > mrb->c->cibase && ci->acc == CI_ACC_DIRECT) { + while (ci > mrb->c->cibase && ci->cci == CINFO_DIRECT) { ci = cipop(mrb); } exc_catched = TRUE; @@ -3014,7 +2968,7 @@ mrb_top_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int st mrb_vm_ci_env_set(mrb->c->ci, NULL); return mrb_vm_run(mrb, proc, self, stack_keep); } - cipush(mrb, 0, CI_ACC_SKIP, mrb->object_class, NULL, 0, 0); + cipush(mrb, 0, CINFO_SKIP, mrb->object_class, NULL, 0, 0); v = mrb_vm_run(mrb, proc, self, stack_keep); return v; |
