diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 14 | ||||
| -rw-r--r-- | src/backtrace.c | 87 | ||||
| -rw-r--r-- | src/class.c | 155 | ||||
| -rw-r--r-- | src/codedump.c | 4 | ||||
| -rw-r--r-- | src/dump.c | 68 | ||||
| -rw-r--r-- | src/error.c | 88 | ||||
| -rw-r--r-- | src/etc.c | 17 | ||||
| -rw-r--r-- | src/fmt_fp.c | 120 | ||||
| -rw-r--r-- | src/gc.c | 10 | ||||
| -rw-r--r-- | src/hash.c | 13 | ||||
| -rw-r--r-- | src/kernel.c | 12 | ||||
| -rw-r--r-- | src/load.c | 48 | ||||
| -rw-r--r-- | src/numeric.c | 13 | ||||
| -rw-r--r-- | src/print.c | 1 | ||||
| -rw-r--r-- | src/string.c | 325 | ||||
| -rw-r--r-- | src/symbol.c | 32 | ||||
| -rw-r--r-- | src/variable.c | 2 | ||||
| -rw-r--r-- | src/vm.c | 51 |
18 files changed, 518 insertions, 542 deletions
diff --git a/src/array.c b/src/array.c index 85481fe9e..ad0d5b8db 100644 --- a/src/array.c +++ b/src/array.c @@ -631,11 +631,13 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) ptr = a->as.heap.ptr; } else { + mrb_bool same = vals == ARY_PTR(a); ary_modify(mrb, a); if (ARY_CAPA(a) < len + alen) ary_expand_capa(mrb, a, len + alen); ptr = ARY_PTR(a); value_move(ptr + alen, ptr, len); + if (same) vals = ptr; } array_copy(ptr, vals, alen); ARY_SET_LEN(a, len+alen); @@ -730,6 +732,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val argv = ARY_PTR(r); } } + else if (mrb_undef_p(rpl)) { + argc = 0; + argv = NULL; + } else { argc = 1; argv = &rpl; @@ -802,6 +808,13 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) return mrb_obj_value(b); } +mrb_value +mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len) +{ + struct RArray *a = mrb_ary_ptr(ary); + return ary_subseq(mrb, a, beg, len); +} + static mrb_int aget_index(mrb_state *mrb, mrb_value index) { @@ -1302,6 +1315,7 @@ init_ary_each(mrb_state *mrb, struct RClass *ary) each_irep->nregs = 7; each_irep->nlocals = 3; p = mrb_proc_new(mrb, each_irep); + p->flags |= MRB_PROC_SCOPE | MRB_PROC_STRICT; MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, ary, mrb_intern_lit(mrb, "each"), m); } diff --git a/src/backtrace.c b/src/backtrace.c index 803c5e285..591f4ea4b 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -25,6 +25,9 @@ typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location* static const mrb_data_type bt_type = { "Backtrace", mrb_free }; +mrb_value mrb_exc_inspect(mrb_state *mrb, mrb_value exc); +mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace); + static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtrace_func func, void *data) { @@ -74,66 +77,27 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtr #ifndef MRB_DISABLE_STDIO static void -print_backtrace(mrb_state *mrb, mrb_value backtrace) +print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace) { - int i; - mrb_int n; + mrb_int i; + mrb_int n = RARRAY_LEN(backtrace); + mrb_value *loc, mesg; FILE *stream = stderr; - n = RARRAY_LEN(backtrace) - 1; - if (n == 0) return; - - fprintf(stream, "trace (most recent call last):\n"); - for (i=0; i<n; i++) { - mrb_value entry = RARRAY_PTR(backtrace)[n-i-1]; - - if (mrb_string_p(entry)) { - fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + if (n != 0) { + fprintf(stream, "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", + (int)i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); + } } - } -} - -static int -packed_bt_len(const struct backtrace_location *bt, int n) -{ - int len = 0; - int i; - - for (i=0; i<n; i++) { - if (!bt[i].filename && !bt[i].lineno && !bt[i].method_id) - continue; - len++; - } - return len; -} - -static void -print_packed_backtrace(mrb_state *mrb, mrb_value packed) -{ - FILE *stream = stderr; - const struct backtrace_location *bt; - int n, i; - int ai = mrb_gc_arena_save(mrb); - - bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type); - if (bt == NULL) return; - n = (mrb_int)RDATA(packed)->flags; - - if (packed_bt_len(bt, n) == 0) return; - fprintf(stream, "trace (most recent call last):\n"); - for (i = 0; i<n; i++) { - const struct backtrace_location *entry = &bt[n-i-1]; - if (entry->filename == NULL) continue; - fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno); - if (entry->method_id != 0) { - const char *method_name; - - method_name = mrb_sym_name(mrb, entry->method_id); - fprintf(stream, ":in %s", method_name); - mrb_gc_arena_restore(mrb, ai); + if (mrb_string_p(*loc)) { + fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); } - fprintf(stream, "\n"); } + mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc)); + fprintf(stream, "%.*s\n", (int)RSTRING_LEN(mesg), RSTRING_PTR(mesg)); } /* mrb_print_backtrace @@ -152,12 +116,8 @@ mrb_print_backtrace(mrb_state *mrb) backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace")); if (mrb_nil_p(backtrace)) return; - if (mrb_array_p(backtrace)) { - print_backtrace(mrb, backtrace); - } - else { - print_packed_backtrace(mrb, backtrace); - } + if (!mrb_array_p(backtrace)) backtrace = mrb_unpack_backtrace(mrb, backtrace); + print_backtrace(mrb, mrb->exc, backtrace); } #else @@ -175,7 +135,6 @@ count_backtrace_i(mrb_state *mrb, { int *lenp = (int*)data; - if (loc->filename == NULL) return; (*lenp)++; } @@ -187,7 +146,6 @@ pack_backtrace_i(mrb_state *mrb, struct backtrace_location **pptr = (struct backtrace_location**)data; struct backtrace_location *ptr = *pptr; - if (loc->filename == NULL) return; *ptr = *loc; *pptr = ptr+1; } @@ -205,7 +163,7 @@ packed_backtrace(mrb_state *mrb) size = len * sizeof(struct backtrace_location); ptr = mrb_malloc(mrb, size); backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); - backtrace->flags = (unsigned int)len; + backtrace->flags = (uint32_t)len; each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); return mrb_obj_value(backtrace); } @@ -245,8 +203,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) const struct backtrace_location *entry = &bt[i]; mrb_value btline; - if (entry->filename == NULL) continue; - btline = mrb_format(mrb, "%s:%d", entry->filename, entry->lineno); + btline = mrb_format(mrb, "%s:%d", entry->filename, (int)entry->lineno); if (entry->method_id != 0) { mrb_str_cat_lit(mrb, btline, ":in "); mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id)); diff --git a/src/class.c b/src/class.c index 2656806d2..d30edd41e 100644 --- a/src/class.c +++ b/src/class.c @@ -65,23 +65,21 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_symbol_value(id); } else { - const char *n; - mrb_int len; - mrb_value outer_name = mrb_class_path(mrb, outer); - - if (mrb_nil_p(outer_name)) { /* unnamed outer class */ + name = mrb_class_path(mrb, outer); + if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), mrb_obj_value(outer)); } return; } - n = mrb_sym_name_len(mrb, id, &len); - name = mrb_str_new_capa(mrb, RSTRING_LEN(outer_name) + 2 + len); - mrb_str_cat_str(mrb, name, outer_name); - mrb_str_cat_lit(mrb, name, "::"); - mrb_str_cat(mrb, name, n, len); - MRB_SET_FROZEN_FLAG(mrb_obj_ptr(name)); + else { + mrb_int len; + const char *n = mrb_sym_name_len(mrb, id, &len); + + mrb_str_cat_lit(mrb, name, "::"); + mrb_str_cat(mrb, name, n, len); + } } mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } @@ -287,11 +285,9 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super) static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value); #ifdef MRB_METHOD_CACHE static void mc_clear_all(mrb_state *mrb); -static void mc_clear_by_class(mrb_state *mrb, struct RClass*); static void mc_clear_by_id(mrb_state *mrb, struct RClass*, mrb_sym); #else #define mc_clear_all(mrb) -#define mc_clear_by_class(mrb,c) #define mc_clear_by_id(mrb,c,s) #endif @@ -305,7 +301,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) super = mrb->object_class; super->flags |= MRB_FL_CLASS_IS_INHERITED; s = mrb_obj_value(super); - mc_clear_by_class(mrb, klass); + mrb_mc_clear_by_class(mrb, klass); mid = mrb_intern_lit(mrb, "inherited"); if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) { mrb_value c = mrb_obj_value(klass); @@ -544,15 +540,12 @@ MRB_API mrb_value* mrb_get_argv(mrb_state *mrb) { mrb_int argc = mrb->c->ci->argc; - mrb_value *array_argv; + mrb_value *array_argv = mrb->c->stack + 1; if (argc < 0) { - struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]); + struct RArray *a = mrb_ary_ptr(*array_argv); array_argv = ARY_PTR(a); } - else { - array_argv = NULL; - } return array_argv; } @@ -596,9 +589,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) char c; mrb_int i = 0; va_list ap; - mrb_int argc = mrb_get_argc(mrb); - mrb_int arg_i = 0; - mrb_value *array_argv = mrb_get_argv(mrb); + mrb_int argc = mrb->c->ci->argc; + mrb_value *array_argv = mrb->c->stack+1; + mrb_bool argv_on_stack = argc >= 0; mrb_bool opt = FALSE; mrb_bool opt_skip = TRUE; mrb_bool given = TRUE; @@ -606,10 +599,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool reqkarg = FALSE; mrb_int needargc = 0; + if (!argv_on_stack) { + struct RArray *a = mrb_ary_ptr(*array_argv); + array_argv = ARY_PTR(a); + argc = ARY_LEN(a); + } va_start(ap, format); -#define ARGV \ - (array_argv ? array_argv : (mrb->c->stack + 1)) +#define ARGV array_argv while ((c = *fmt++)) { switch (c) { @@ -622,11 +619,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) goto check_exit; case '!': break; - case '&': case '?': - if (opt) opt_skip = FALSE; - break; case ':': reqkarg = TRUE; + /* fall through */ + case '&': case '?': + if (opt) opt_skip = FALSE; break; default: if (!opt) needargc ++; @@ -679,8 +676,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = argv[arg_i++]; - i++; + *p = argv[i++]; } } break; @@ -692,12 +688,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = argv[arg_i++]; + ss = argv[i++]; if (!class_ptr_p(ss)) { mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); } *p = ss; - i++; } } break; @@ -707,8 +702,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = argv[arg_i++]; - i++; + *p = argv[i++]; if (!(altmode && mrb_nil_p(*p))) { mrb_to_str(mrb, *p); } @@ -721,8 +715,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = argv[arg_i++]; - i++; + *p = argv[i++]; if (!(altmode && mrb_nil_p(*p))) { *p = to_ary(mrb, *p); } @@ -735,8 +728,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = argv[arg_i++]; - i++; + *p = argv[i++]; if (!(altmode && mrb_nil_p(*p))) { *p = to_hash(mrb, *p); } @@ -752,8 +744,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, char**); pl = va_arg(ap, mrb_int*); if (i < argc) { - ss = argv[arg_i++]; - i++; + ss = argv[i++]; if (altmode && mrb_nil_p(ss)) { *ps = NULL; *pl = 0; @@ -773,8 +764,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, const char**); if (i < argc) { - ss = argv[arg_i++]; - i++; + ss = argv[i++]; if (altmode && mrb_nil_p(ss)) { *ps = NULL; } @@ -795,8 +785,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); if (i < argc) { - aa = argv[arg_i++]; - i++; + aa = argv[i++]; if (altmode && mrb_nil_p(aa)) { *pb = 0; *pl = 0; @@ -817,14 +806,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, void**); if (i < argc) { - ss = argv[arg_i]; + ss = argv[i++]; if (!mrb_istruct_p(ss)) { mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss); } *p = mrb_istruct_ptr(ss); - arg_i++; - i++; } } break; @@ -835,9 +822,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_float*); if (i < argc) { - *p = mrb_to_flo(mrb, argv[arg_i]); - arg_i++; - i++; + *p = mrb_to_flo(mrb, argv[i++]); } } break; @@ -848,9 +833,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - *p = mrb_fixnum(mrb_to_int(mrb, argv[arg_i])); - arg_i++; - i++; + *p = mrb_fixnum(mrb_to_int(mrb, argv[i++])); } } break; @@ -859,9 +842,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[arg_i++]; + mrb_value b = argv[i++]; *boolp = mrb_test(b); - i++; } } break; @@ -873,9 +855,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = argv[arg_i++]; + ss = argv[i++]; *symp = to_sym(mrb, ss); - i++; } } break; @@ -887,8 +868,7 @@ 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[arg_i++]; - i++; + mrb_value dd = argv[i++]; if (altmode && mrb_nil_p(dd)) { *datap = 0; } @@ -917,7 +897,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } break; case '|': - if (opt_skip && i == argc) return argc; + if (opt_skip && i == argc) goto finish; opt = TRUE; break; case '?': @@ -933,7 +913,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value **var; mrb_int *pl; - mrb_bool nocopy = altmode || array_argv ? TRUE : FALSE; + mrb_bool nocopy = (altmode || !argv_on_stack) ? TRUE : FALSE; var = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); @@ -941,16 +921,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) *pl = argc-i; if (*pl > 0) { if (nocopy) { - *var = argv+arg_i; + *var = argv+i; } else { - mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+arg_i); + mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+i); RARRAY(args)->c = NULL; *var = RARRAY_PTR(args); } } i = argc; - arg_i += *pl; } else { *pl = 0; @@ -1025,6 +1004,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (!c && argc > i) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } + +finish: va_end(ap); return i; } @@ -1109,7 +1090,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru m->flags |= MRB_FL_CLASS_IS_INHERITED; ins_pos->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); - mc_clear_by_class(mrb, ins_pos); + mrb_mc_clear_by_class(mrb, ins_pos); ins_pos = ic; skip: m = m->super; @@ -1261,33 +1242,45 @@ mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod) return mod; } -MRB_API mrb_value -mrb_singleton_class(mrb_state *mrb, mrb_value v) +/* returns mrb_class_ptr(mrb_singleton_class()) */ +/* except that it return NULL for immediate values */ +MRB_API struct RClass* +mrb_singleton_class_ptr(mrb_state *mrb, mrb_value v) { struct RBasic *obj; switch (mrb_type(v)) { case MRB_TT_FALSE: if (mrb_nil_p(v)) - return mrb_obj_value(mrb->nil_class); - return mrb_obj_value(mrb->false_class); + return mrb->nil_class; + return mrb->false_class; case MRB_TT_TRUE: - return mrb_obj_value(mrb->true_class); + return mrb->true_class; case MRB_TT_CPTR: - return mrb_obj_value(mrb->object_class); + return mrb->object_class; case MRB_TT_SYMBOL: case MRB_TT_FIXNUM: #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: #endif - mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton"); - return mrb_nil_value(); /* not reached */ + return NULL; default: break; } obj = mrb_basic_ptr(v); prepare_singleton_class(mrb, obj); - return mrb_obj_value(obj->c); + return obj->c; +} + +MRB_API mrb_value +mrb_singleton_class(mrb_state *mrb, mrb_value v) +{ + struct RClass *c = mrb_singleton_class_ptr(mrb, v); + + if (c == NULL) { + mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton"); + } + return mrb_obj_value(c); } MRB_API void @@ -1322,8 +1315,8 @@ mc_clear_all(mrb_state *mrb) } } -static void -mc_clear_by_class(mrb_state *mrb, struct RClass *c) +void +mrb_mc_clear_by_class(mrb_state *mrb, struct RClass *c) { struct mrb_cache_entry *mc = mrb->cache; int i; @@ -1718,7 +1711,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) /* toplevel class/module */ return mrb_sym_str(mrb, mrb_symbol(path)); } - return path; + return mrb_str_dup(mrb, path); } MRB_API struct RClass* @@ -1735,7 +1728,10 @@ mrb_class_real(struct RClass* cl) MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { - mrb_value name = class_name_str(mrb, c); + mrb_value name; + + if (c == NULL) return NULL; + name = class_name_str(mrb, c); return RSTRING_PTR(name); } @@ -1885,8 +1881,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) return mrb_str_cat_lit(mrb, str, ">"); } else { - mrb_value str = class_name_str(mrb, mrb_class_ptr(klass)); - return mrb_frozen_p(mrb_basic_ptr(str)) ? mrb_str_dup(mrb, str) : str; + return class_name_str(mrb, mrb_class_ptr(klass)); } } @@ -2324,7 +2319,9 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); 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_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE()); diff --git a/src/codedump.c b/src/codedump.c index 7faa39360..649be176b 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -130,6 +130,10 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_LOADI\tR%d\t-%d\t", a, b); print_lv_a(mrb, irep, a); break; + 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_LOADI__1, B): printf("OP_LOADI__1\tR%d\t\t", a); print_lv_a(mrb, irep, a); diff --git a/src/dump.c b/src/dump.c index 183f3b67d..a6bbe68f3 100644 --- a/src/dump.c +++ b/src/dump.c @@ -13,9 +13,6 @@ #include <mruby/numeric.h> #include <mruby/debug.h> -#define FLAG_BYTEORDER_NATIVE 2 -#define FLAG_BYTEORDER_NONATIVE 0 - #ifndef MRB_WITHOUT_FLOAT #ifdef MRB_USE_FLOAT #define MRB_FLOAT_FMT "%.9g" @@ -709,22 +706,7 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 uint16_t crc; uint32_t offset; - switch (flags & DUMP_ENDIAN_NAT) { - endian_big: - case DUMP_ENDIAN_BIG: - memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); - break; - endian_little: - case DUMP_ENDIAN_LIL: - memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)); - break; - - case DUMP_ENDIAN_NAT: - if (bigendian_p()) goto endian_big; - goto endian_little; - break; - } - + memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)); memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name)); memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version)); @@ -764,21 +746,6 @@ lv_defined_p(mrb_irep *irep) return FALSE; } -static uint8_t -dump_flags(uint8_t flags, uint8_t native) -{ - if (native == FLAG_BYTEORDER_NATIVE) { - if ((flags & DUMP_ENDIAN_NAT) == 0) { - return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT; - } - return flags; - } - if ((flags & DUMP_ENDIAN_NAT) == 0) { - return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG; - } - return flags; -} - static int dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) { @@ -870,7 +837,7 @@ error_exit: int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) { - return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size); + return dump_irep(mrb, irep, flags, bin, bin_size); } #ifndef MRB_DISABLE_STDIO @@ -886,7 +853,7 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp) return MRB_DUMP_INVALID_ARGUMENT; } - result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size); + result = dump_irep(mrb, irep, flags, &bin, &bin_size); if (result == MRB_DUMP_OK) { if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) { result = MRB_DUMP_WRITE_FAULT; @@ -897,20 +864,6 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp) return result; } -static mrb_bool -dump_bigendian_p(uint8_t flags) -{ - switch (flags & DUMP_ENDIAN_NAT) { - case DUMP_ENDIAN_BIG: - return TRUE; - case DUMP_ENDIAN_LIL: - return FALSE; - default: - case DUMP_ENDIAN_NAT: - return bigendian_p(); - } -} - int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname) { @@ -921,23 +874,8 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con if (fp == NULL || initname == NULL || initname[0] == '\0') { return MRB_DUMP_INVALID_ARGUMENT; } - flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE); result = dump_irep(mrb, irep, flags, &bin, &bin_size); if (result == MRB_DUMP_OK) { - if (!dump_bigendian_p(flags)) { - if (fprintf(fp, "/* dumped in little endian order.\n" - " use `mrbc -E` option for big endian CPU. */\n") < 0) { - mrb_free(mrb, bin); - return MRB_DUMP_WRITE_FAULT; - } - } - else { - if (fprintf(fp, "/* dumped in big endian order.\n" - " use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) { - mrb_free(mrb, bin); - return MRB_DUMP_WRITE_FAULT; - } - } if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */ mrb_free(mrb, bin); return MRB_DUMP_WRITE_FAULT; diff --git a/src/error.c b/src/error.c index 43b09ec66..260ca7a3d 100644 --- a/src/error.c +++ b/src/error.c @@ -13,7 +13,6 @@ #include <mruby/proc.h> #include <mruby/string.h> #include <mruby/variable.h> -#include <mruby/debug.h> #include <mruby/error.h> #include <mruby/class.h> #include <mruby/throw.h> @@ -88,7 +87,7 @@ exc_exception(mrb_state *mrb, mrb_value self) * no message is set). */ -static mrb_value +mrb_value exc_to_s(mrb_state *mrb, mrb_value exc) { mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); @@ -128,37 +127,13 @@ exc_message(mrb_state *mrb, mrb_value exc) * returns message and class name. */ -static mrb_value -exc_inspect(mrb_state *mrb, mrb_value exc) +mrb_value +mrb_exc_inspect(mrb_state *mrb, mrb_value exc) { - mrb_value str, mesg, file, line; - mrb_bool append_mesg; - const char *cname; - - mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); - file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file")); - line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line")); - - append_mesg = !mrb_nil_p(mesg); - if (append_mesg) { - mesg = mrb_obj_as_string(mrb, mesg); - append_mesg = RSTRING_LEN(mesg) > 0; - } - - cname = mrb_obj_classname(mrb, exc); - str = mrb_str_new_cstr(mrb, cname); - if (mrb_string_p(file) && mrb_fixnum_p(line)) { - if (append_mesg) { - str = mrb_format(mrb, "%v:%v: %v (%v)", file, line, mesg, str); - } - else { - str = mrb_format(mrb, "%v:%v: %v", file, line, str); - } - } - else if (append_mesg) { - str = mrb_format(mrb, "%v: %v", str, mesg); - } - return str; + mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); + mrb_value cname = mrb_mod_to_s(mrb, mrb_obj_value(mrb_obj_class(mrb, exc))); + mesg = mrb_obj_as_string(mrb, mesg); + return RSTRING_LEN(mesg) == 0 ? cname : mrb_format(mrb, "%v (%v)", mesg, cname); } void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc); @@ -192,33 +167,6 @@ exc_set_backtrace(mrb_state *mrb, mrb_value exc) return backtrace; } -static void -exc_debug_info(mrb_state *mrb, struct RObject *exc) -{ - mrb_callinfo *ci = mrb->c->ci; - const mrb_code *pc = ci->pc; - - if (mrb_obj_iv_defined(mrb, exc, mrb_intern_lit(mrb, "file"))) return; - while (ci >= mrb->c->cibase) { - const mrb_code *err = ci->err; - - if (!err && pc) err = pc - 1; - if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { - mrb_irep *irep = ci->proc->body.irep; - - int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq); - char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq); - if (line != -1 && file) { - mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); - mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); - return; - } - } - pc = ci->pc; - ci--; - } -} - void mrb_exc_set(mrb_state *mrb, mrb_value exc) { @@ -232,7 +180,6 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) mrb->gc.arena_idx--; } if (!mrb->gc.out_of_memory && !mrb_frozen_p(mrb->exc)) { - exc_debug_info(mrb, mrb->exc); mrb_keep_backtrace(mrb, exc); } } @@ -355,7 +302,11 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) mrb_gc_arena_restore(mrb, ai); break; case 'n': +#if UINT32_MAX < INT_MAX + obj = mrb_symbol_value((mrb_sym)va_arg(ap, int)); +#else obj = mrb_symbol_value(va_arg(ap, mrb_sym)); +#endif goto L_cat_obj; case 's': chars = va_arg(ap, char*); @@ -530,7 +481,7 @@ exception_call: break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 0..3)", argc); + mrb_argnum_error(mrb, argc, 0, 3); break; } if (argc > 0) { @@ -586,6 +537,19 @@ mrb_frozen_error(mrb_state *mrb, void *frozen_obj) mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", mrb_obj_value(frozen_obj)); } +MRB_API mrb_noreturn void +mrb_argnum_error(mrb_state *mrb, mrb_int argc, int min, int max) +{ +#define FMT(exp) "wrong number of arguments (given %i, expected " exp ")" + if (min == max) + mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d"), argc, min); + else if (max < 0) + mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d+"), argc, min); + else + mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d..%d"), argc, min, max); +#undef FMT +} + void mrb_init_exception(mrb_state *mrb) { @@ -598,7 +562,7 @@ mrb_init_exception(mrb_state *mrb) mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_OPT(1)); mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); - mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "inspect", mrb_exc_inspect, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1)); @@ -140,7 +140,13 @@ mrb_obj_id(mrb_value obj) } } +#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT) +#define mrb_xxx_boxing_cptr_value mrb_nan_boxing_cptr_value +#endif + #ifdef MRB_WORD_BOXING +#define mrb_xxx_boxing_cptr_value mrb_word_boxing_cptr_value + #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) @@ -164,17 +170,20 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ +#endif /* MRB_WORD_BOXING */ +#if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_64BIT)) MRB_API mrb_value -mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) +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); - v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class); - v.value.vp->p = p; + SET_OBJ_VALUE(v, cptr); + cptr->p = p; return v; } -#endif /* MRB_WORD_BOXING */ +#endif #if defined _MSC_VER && _MSC_VER < 1900 diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 1f1af6764..9ae5dd177 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -30,7 +30,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <limits.h> #include <string.h> -#include <stdint.h> #include <math.h> #include <float.h> #include <ctype.h> @@ -38,9 +37,19 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <mruby.h> #include <mruby/string.h> +struct fmt_args; + +typedef void output_func(struct fmt_args *f, const char *s, size_t l); + struct fmt_args { mrb_state *mrb; - mrb_value str; + output_func *output; + void *opaque; +}; + +struct mrb_cstr { + char *buf; + size_t len; }; #define MAX(a,b) ((a)>(b) ? (a) : (b)) @@ -55,15 +64,44 @@ struct fmt_args { #define PAD_POS (1U<<(' '-' ')) #define MARK_POS (1U<<('+'-' ')) +#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS) + +static output_func strcat_value; +static output_func strcat_cstr; + +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; + + if (l > cstr->len) { + mrb_state *mrb = f->mrb; + + mrb_raise(mrb, E_ARGUMENT_ERROR, "string buffer too small"); + } + + memcpy(cstr->buf, s, l); + + cstr->buf += l; + cstr->len -= l; +} + static void out(struct fmt_args *f, const char *s, size_t l) { - mrb_str_cat(f->mrb, f->str, s, l); + f->output(f, s, l); } #define PAD_SIZE 256 static void -pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint8_t fl) +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; @@ -93,7 +131,7 @@ typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double) #endif static int -fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) +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 @@ -118,11 +156,11 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) if (!isfinite(y)) { const char *ss = (t&32)?"inf":"INF"; if (y!=y) ss=(t&32)?"nan":"NAN"; - pad(f, ' ', 0, 3+pl, fl&~ZERO_PAD); + pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); out(f, prefix, pl); out(f, ss, 3); - pad(f, ' ', 0, 3+pl, fl^LEFT_ADJ); - return 3+(int)pl; + pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); + return MAX(w, 3+(int)pl); } y = frexp((double)y, &e2) * 2; @@ -170,14 +208,14 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) else l = (s-buf) + (ebuf-estr); - pad(f, ' ', 0, pl+l, fl); + pad(f, ' ', w, pl+l, fl); out(f, prefix, pl); - pad(f, '0', 0, pl+l, fl^ZERO_PAD); + 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, ' ', 0, pl+l, fl^LEFT_ADJ); - return (int)pl+(int)l; + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + return MAX(w, (int)pl+(int)l); } if (p<0) p=6; @@ -289,9 +327,9 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) l += ebuf-estr; } - pad(f, ' ', 0, pl+l, fl); + pad(f, ' ', w, pl+l, fl); out(f, prefix, pl); - pad(f, '0', 0, pl+l, fl^ZERO_PAD); + pad(f, '0', w, pl+l, fl^ZERO_PAD); if ((t|32)=='f') { if (a>r) a=r; @@ -326,21 +364,33 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) out(f, estr, ebuf-estr); } - pad(f, ' ', 0, pl+l, fl^LEFT_ADJ); + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); - return (int)pl+(int)l; + return MAX(w, (int)pl+(int)l); } static int fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) { - ptrdiff_t p; + 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'); + } + if (*fmt == '.') { ++fmt; for (p = 0; ISDIGIT(*fmt); ++fmt) { @@ -354,29 +404,49 @@ fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) switch (*fmt) { case 'e': case 'f': case 'g': case 'a': case 'E': case 'F': case 'G': case 'A': - return fmt_fp(f, flo, p, 0, *fmt); + return fmt_fp(f, flo, w, p, fl, *fmt); default: return -1; } } -mrb_value +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.str = mrb_str_new_capa(mrb, 24); + 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"); } - return f.str; + 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"); + } + *cstr.buf = '\0'; + return cstr.buf - buf; } #else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include <mruby.h> #include <stdio.h> -mrb_value +MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { char buf[25]; @@ -384,5 +454,11 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } + +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); +} #endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif @@ -280,8 +280,9 @@ mrb_free(mrb_state *mrb, void *p) MRB_API void* mrb_alloca(mrb_state *mrb, size_t size) { - mrb_value str = mrb_str_new(mrb, NULL, size); - return RSTRING_PTR(str); + struct RString *s; + s = (struct RString*)mrb_obj_alloc(mrb, MRB_TT_STRING, mrb->string_class); + return s->as.heap.ptr = (char*)mrb_malloc(mrb, size); } static mrb_bool @@ -806,10 +807,12 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) case MRB_TT_SCLASS: mrb_gc_free_mt(mrb, (struct RClass*)obj); mrb_gc_free_iv(mrb, (struct RObject*)obj); + mrb_mc_clear_by_class(mrb, (struct RClass*)obj); break; case MRB_TT_ICLASS: if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_free_mt(mrb, (struct RClass*)obj); + mrb_mc_clear_by_class(mrb, (struct RClass*)obj); break; case MRB_TT_ENV: { @@ -1609,6 +1612,9 @@ mrb_init_gc(mrb_state *mrb) { struct RClass *gc; + mrb_static_assert(sizeof(RVALUE) <= sizeof(void*) * 6, + "RVALUE size must be within 6 words"); + gc = mrb_define_module(mrb, "GC"); mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE()); diff --git a/src/hash.c b/src/hash.c index 21e34a5ea..ec79a3def 100644 --- a/src/hash.c +++ b/src/hash.c @@ -222,9 +222,8 @@ static void ht_compact(mrb_state *mrb, htable *t) { segment *seg; - mrb_int i; + uint16_t i, i2; segment *seg2 = NULL; - mrb_int i2; mrb_int size = 0; if (t == NULL) return; @@ -374,7 +373,7 @@ ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) deleted++; continue; } - if (ht_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, key, k)) { seg->e[i].val = val; return; } @@ -455,7 +454,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } if (mrb_undef_p(k)) continue; - if (ht_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, key, k)) { if (vp) *vp = seg->e[i].val; return TRUE; } @@ -800,7 +799,7 @@ mrb_hash_init(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (!mrb_nil_p(block)) { if (ifnone_p) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + mrb_argnum_error(mrb, 1, 0, 0); } RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; ifnone = block; @@ -1414,7 +1413,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */ mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */ mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */ - mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_ANY()); /* 15.2.13.4.5 */ + mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_OPT(1)); /* 15.2.13.4.5 */ mrb_define_method(mrb, h, "default=", mrb_hash_set_default, MRB_ARGS_REQ(1)); /* 15.2.13.4.6 */ mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */ @@ -1423,7 +1422,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */ mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */ mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */ - mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)); /* 15.2.13.4.16 */ + mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.2.13.4.16 */ mrb_define_method(mrb, h, "key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.18 */ mrb_define_method(mrb, h, "keys", mrb_hash_keys, MRB_ARGS_NONE()); /* 15.2.13.4.19 */ mrb_define_method(mrb, h, "length", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.20 */ diff --git a/src/kernel.c b/src/kernel.c index c88a457f0..ae9617686 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -325,7 +325,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_value clone; if (mrb_immediate_p(self)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %v", self); + return self; } if (mrb_sclass_p(self)) { mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); @@ -366,7 +366,7 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) mrb_value dup; if (mrb_immediate_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %v", obj); + return obj; } if (mrb_sclass_p(obj)) { mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); @@ -384,7 +384,7 @@ mrb_obj_extend(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value obj) mrb_int i; if (argc == 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (at least 1)"); + mrb_argnum_error(mrb, argc, 1, -1); } for (i = 0; i < argc; i++) { mrb_check_type(mrb, argv[i], MRB_TT_MODULE); @@ -685,7 +685,6 @@ mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) * r.xxiii #=> 23 * r.mm #=> 2000 */ -#ifdef MRB_DEFAULT_METHOD_MISSING static mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod) { @@ -698,7 +697,6 @@ mrb_obj_missing(mrb_state *mrb, mrb_value mod) /* not reached */ return mrb_nil_value(); } -#endif static inline mrb_bool basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) @@ -791,14 +789,12 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ -#ifdef MRB_DEFAULT_METHOD_MISSING mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ -#endif mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ - mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ + 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 */ diff --git a/src/load.c b/src/load.c index 471ff3841..2a118c922 100644 --- a/src/load.c +++ b/src/load.c @@ -19,9 +19,6 @@ # error size_t must be at least 32 bits wide #endif -#define FLAG_BYTEORDER_BIG 2 -#define FLAG_BYTEORDER_LIL 4 -#define FLAG_BYTEORDER_NATIVE 8 #define FLAG_SRC_MALLOC 1 #define FLAG_SRC_STATIC 0 @@ -42,22 +39,22 @@ offset_crc_body(void) } #ifndef MRB_WITHOUT_FLOAT +double mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck); + static double -str_to_double(mrb_state *mrb, mrb_value str) +str_to_double(mrb_state *mrb, const char *p, size_t len) { - const char *p = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - /* `i`, `inf`, `infinity` */ if (len > 0 && p[0] == 'i') return INFINITY; /* `I`, `-inf`, `-infinity` */ if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY; - - return mrb_str_to_dbl(mrb, str, TRUE); + return mrb_str_len_to_dbl(mrb, p, len, TRUE); } #endif +mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck); + static mrb_irep* read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { @@ -94,8 +91,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) { return NULL; } - if ((flags & FLAG_SRC_MALLOC) == 0 && - (flags & FLAG_BYTEORDER_NATIVE)) { + if ((flags & FLAG_SRC_MALLOC) == 0) { irep->iseq = (mrb_code*)src; src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; @@ -119,21 +115,17 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen); for (i = 0; i < plen; i++) { - mrb_value s; + const char *s; + mrb_bool st = (flags & FLAG_SRC_MALLOC)==0; tt = *src++; /* pool TT */ pool_data_len = bin_to_uint16(src); /* pool data length */ src += sizeof(uint16_t); - if (flags & FLAG_SRC_MALLOC) { - s = mrb_str_new(mrb, (char *)src, pool_data_len); - } - else { - s = mrb_str_new_static(mrb, (char *)src, pool_data_len); - } + s = (const char*)src; src += pool_data_len; switch (tt) { /* pool data */ case IREP_TT_FIXNUM: { - mrb_value num = mrb_str_to_inum(mrb, s, 10, FALSE); + mrb_value num = mrb_str_len_to_inum(mrb, s, pool_data_len, 10, FALSE); #ifdef MRB_WITHOUT_FLOAT irep->pool[i] = num; #else @@ -144,12 +136,12 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag #ifndef MRB_WITHOUT_FLOAT case IREP_TT_FLOAT: - irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s)); + irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s, pool_data_len)); break; #endif case IREP_TT_STRING: - irep->pool[i] = mrb_str_pool(mrb, s); + irep->pool[i] = mrb_str_pool(mrb, s, pool_data_len, st); break; default: @@ -468,19 +460,7 @@ read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_ return MRB_DUMP_READ_FAULT; } - if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { - if (bigendian_p()) - *flags |= FLAG_BYTEORDER_NATIVE; - else - *flags |= FLAG_BYTEORDER_BIG; - } - else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { - if (bigendian_p()) - *flags |= FLAG_BYTEORDER_LIL; - else - *flags |= FLAG_BYTEORDER_NATIVE; - } - else { + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) != 0) { return MRB_DUMP_INVALID_FILE_HEADER; } diff --git a/src/numeric.c b/src/numeric.c index 306b6ef4d..07a2d20a8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1485,13 +1485,14 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) /* 15.2.9.3.6 */ /* * call-seq: - * self.f <=> other.f => -1, 0, +1 + * self.f <=> other.f => -1, 0, +1, or nil * < => -1 * = => 0 * > => +1 * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is * less than, equal to, or greater than <i>numeric</i>. This is the - * basis for the tests in <code>Comparable</code>. + * basis for the tests in <code>Comparable</code>. When the operands are + * not comparable, it returns nil instead of raising an exception. */ static mrb_value integral_cmp(mrb_state *mrb, mrb_value self) @@ -1648,10 +1649,10 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT - mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ - mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ - mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 (x) */ - mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.15 (x) */ + mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.8 (x) */ + mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.10 (x) */ + mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.12 (x) */ + mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.15 (x) */ #endif /* Fixnum Class */ diff --git a/src/print.c b/src/print.c index 03b5eadfa..7d2d16086 100644 --- a/src/print.c +++ b/src/print.c @@ -31,7 +31,6 @@ MRB_API void mrb_print_error(mrb_state *mrb) { mrb_print_backtrace(mrb); - printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr); } MRB_API void diff --git a/src/string.c b/src/string.c index b7eef5888..44e3c9069 100644 --- a/src/string.c +++ b/src/string.c @@ -10,6 +10,7 @@ #ifndef MRB_WITHOUT_FLOAT #include <float.h> +#include <math.h> #endif #include <limits.h> #include <stddef.h> @@ -24,7 +25,7 @@ typedef struct mrb_shared_string { int refcnt; - mrb_int capa; + mrb_ssize capa; char *ptr; } mrb_shared_string; @@ -40,8 +41,8 @@ str_init_normal_capa(mrb_state *mrb, struct RString *s, if (p) memcpy(dst, p, len); dst[len] = '\0'; s->as.heap.ptr = dst; - s->as.heap.len = (mrb_int)len; - s->as.heap.aux.capa = (mrb_int)capa; + s->as.heap.len = (mrb_ssize)len; + s->as.heap.aux.capa = (mrb_ssize)capa; RSTR_UNSET_TYPE_FLAG(s); return s; } @@ -66,7 +67,7 @@ static struct RString* str_init_nofree(struct RString *s, const char *p, size_t len) { s->as.heap.ptr = (char *)p; - s->as.heap.len = (mrb_int)len; + s->as.heap.len = (mrb_ssize)len; s->as.heap.aux.capa = 0; /* nofree */ RSTR_SET_TYPE_FLAG(s, NOFREE); return s; @@ -118,7 +119,7 @@ str_new_static(mrb_state *mrb, const char *p, size_t len) if (RSTR_EMBEDDABLE_P(len)) { return str_init_embed(mrb_obj_alloc_string(mrb), p, len); } - if (len >= MRB_INT_MAX) { + if (len >= MRB_SSIZE_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } return str_init_nofree(mrb_obj_alloc_string(mrb), p, len); @@ -130,7 +131,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) if (RSTR_EMBEDDABLE_P(len)) { return str_init_embed(mrb_obj_alloc_string(mrb), p, len); } - if (len >= MRB_INT_MAX) { + if (len >= MRB_SSIZE_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } if (p && mrb_ro_data_p(p)) { @@ -162,7 +163,7 @@ mrb_str_new_capa(mrb_state *mrb, size_t capa) if (RSTR_EMBEDDABLE_P(capa)) { s = str_init_embed(mrb_obj_alloc_string(mrb), NULL, 0); } - else if (capa >= MRB_INT_MAX) { + else if (capa >= MRB_SSIZE_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big"); /* not reached */ s = NULL; @@ -190,8 +191,8 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa) static void resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) { -#if SIZE_MAX > MRB_INT_MAX - mrb_assert(capacity < MRB_INT_MAX); +#if SIZE_MAX > MRB_SSIZE_MAX + mrb_assert(capacity < MRB_SSIZE_MAX); #endif if (RSTR_EMBED_P(s)) { if (!RSTR_EMBEDDABLE_P(capacity)) { @@ -200,7 +201,7 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) } else { s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); - s->as.heap.aux.capa = (mrb_int)capacity; + s->as.heap.aux.capa = (mrb_ssize)capacity; } } @@ -246,6 +247,28 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } static void +str_modify_keep_ascii(mrb_state *mrb, struct RString *s) +{ + if (RSTR_SHARED_P(s)) { + mrb_shared_string *shared = s->as.heap.aux.shared; + + if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + s->as.heap.aux.capa = shared->capa; + s->as.heap.ptr[s->as.heap.len] = '\0'; + RSTR_UNSET_SHARED_FLAG(s); + mrb_free(mrb, shared); + } + else { + str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); + str_decref(mrb, shared); + } + } + else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { + str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); + } +} + +static void check_null_byte(mrb_state *mrb, mrb_value str) { mrb_to_str(mrb, str); @@ -278,8 +301,8 @@ static const char utf8len_codepage[256] = 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1, }; -static mrb_int -utf8len(const char* p, const char* e) +mrb_int +mrb_utf8len(const char* p, const char* e) { mrb_int len; mrb_int i; @@ -295,14 +318,14 @@ utf8len(const char* p, const char* e) } mrb_int -mrb_utf8_len(const char *str, mrb_int byte_len) +mrb_utf8_strlen(const char *str, mrb_int byte_len) { mrb_int total = 0; const char *p = str; const char *e = p + byte_len; while (p < e) { - p += utf8len(p, e); + p += mrb_utf8len(p, e); total++; } return total; @@ -318,7 +341,7 @@ utf8_strlen(mrb_value str) return byte_len; } else { - mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + mrb_int utf8_len = mrb_utf8_strlen(RSTR_PTR(s), byte_len); if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); return utf8_len; } @@ -339,7 +362,7 @@ chars2bytes(mrb_value s, mrb_int off, mrb_int idx) const char *e = RSTRING_END(s); for (b=i=0; p<e && i<idx; i++) { - n = utf8len(p, e); + n = mrb_utf8len(p, e); b += n; p += n; } @@ -356,7 +379,7 @@ bytes2chars(char *p, mrb_int len, mrb_int bi) mrb_int i; for (i = 0; p < pivot; i ++) { - p += utf8len(p, e); + p += mrb_utf8len(p, e); } if (p != pivot) return -1; return i; @@ -377,7 +400,7 @@ char_adjust(const char *beg, const char *end, const char *ptr) while (p > beg) { p --; if ((*p & 0xc0) != 0x80) { - int clen = utf8len(p, end); + int clen = mrb_utf8len(p, end); if (clen > ptr - p) return p; break; } @@ -440,10 +463,10 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co } pivot = p + qstable[(unsigned char)p[slen - 1]]; - if (pivot > pend || pivot < p /* overflowed */) { return -1; } + if (pivot >= pend || pivot < p /* overflowed */) { return -1; } do { - p += utf8len(p, pend); + p += mrb_utf8len(p, pend); off ++; } while (p < pivot); } @@ -462,7 +485,7 @@ str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) for (; pos > 0; pos --) { if (pend - p < 1) { return -1; } - p += utf8len(p, pend); + p += mrb_utf8len(p, pend); } if (slen < 1) { return off; } @@ -481,25 +504,45 @@ str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) #define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif +#ifndef MRB_QS_SHORT_STRING_LENGTH +#define MRB_QS_SHORT_STRING_LENGTH 2048 +#endif + static inline mrb_int mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) { - const unsigned char *x = xs, *xe = xs + m; - const unsigned char *y = ys; - int i; - ptrdiff_t qstable[256]; + if (n + m < MRB_QS_SHORT_STRING_LENGTH) { + const unsigned char *y = ys; + const unsigned char *ye = ys+n-m+1; - /* Preprocessing */ - for (i = 0; i < 256; ++i) - qstable[i] = m + 1; - for (; x < xe; ++x) - qstable[*x] = xe - x; - /* Searching */ - for (; y + m <= ys + n; y += *(qstable + y[m])) { - if (*xs == *y && memcmp(xs, y, m) == 0) - return (mrb_int)(y - ys); + for (;;) { + y = (const unsigned char*)memchr(y, xs[0], (size_t)(ye-y)); + if (y == NULL) return -1; + if (memcmp(xs, y, m) == 0) { + return (mrb_int)(y - ys); + } + y++; + } + return -1; + } + else { + const unsigned char *x = xs, *xe = xs + m; + const unsigned char *y = ys; + int i; + ptrdiff_t qstable[256]; + + /* Preprocessing */ + for (i = 0; i < 256; ++i) + qstable[i] = m + 1; + for (; x < xe; ++x) + qstable[*x] = xe - x; + /* Searching */ + for (; y + m <= ys + n; y += *(qstable + y[m])) { + if (*xs == *y && memcmp(xs, y, m) == 0) + return (mrb_int)(y - ys); + } + return -1; } - return -1; } static mrb_int @@ -531,7 +574,7 @@ str_share(mrb_state *mrb, struct RString *orig, struct RString *s) size_t len = (size_t)orig->as.heap.len; mrb_assert(!RSTR_EMBED_P(orig)); - if (RSTR_NOFREE_P(orig) || RSTR_POOL_P(orig)) { + if (RSTR_NOFREE_P(orig)) { str_init_nofree(s, orig->as.heap.ptr, len); } else if (RSTR_SHARED_P(orig)) { @@ -540,13 +583,13 @@ str_share(mrb_state *mrb, struct RString *orig, struct RString *s) else if (RSTR_FSHARED_P(orig)) { str_init_fshared(orig, s, orig->as.heap.aux.fshared); } - else if (mrb_frozen_p(orig)) { + else if (mrb_frozen_p(orig) && !RSTR_POOL_P(orig)) { str_init_fshared(orig, s, orig); } else { if (orig->as.heap.aux.capa > orig->as.heap.len) { orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); - orig->as.heap.aux.capa = len; + orig->as.heap.aux.capa = (mrb_ssize)len; } str_init_shared(mrb, orig, s, NULL); str_init_shared(mrb, orig, orig, s->as.heap.aux.shared); @@ -554,12 +597,9 @@ str_share(mrb_state *mrb, struct RString *orig, struct RString *s) } mrb_value -mrb_str_pool(mrb_state *mrb, mrb_value str) +mrb_str_pool(mrb_state *mrb, const char *p, mrb_int len, mrb_bool nofree) { struct RString *s = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); - struct RString *orig = mrb_str_ptr(str); - const char *p = RSTR_PTR(orig); - size_t len = (size_t)RSTR_LEN(orig); s->tt = MRB_TT_STRING; s->c = mrb->string_class; @@ -568,7 +608,7 @@ mrb_str_pool(mrb_state *mrb, mrb_value str) if (RSTR_EMBEDDABLE_P(len)) { str_init_embed(s, p, len); } - else if (RSTR_NOFREE_P(orig)) { + else if (nofree) { str_init_nofree(s, p, len); } else { @@ -591,8 +631,8 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) } else { str_share(mrb, orig, s); - s->as.heap.ptr += beg; - s->as.heap.len = len; + s->as.heap.ptr += (mrb_ssize)beg; + s->as.heap.len = (mrb_ssize)len; } RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); @@ -814,22 +854,7 @@ MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - if (RSTR_SHARED_P(s)) { - mrb_shared_string *shared = s->as.heap.aux.shared; - - if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { - s->as.heap.aux.capa = shared->capa; - s->as.heap.ptr[s->as.heap.len] = '\0'; - mrb_free(mrb, shared); - } - else { - str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); - str_decref(mrb, shared); - } - } - else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { - str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); - } + str_modify_keep_ascii(mrb, s); } MRB_API void @@ -954,7 +979,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) if (times < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); } - if (times && MRB_INT_MAX / times < RSTRING_LEN(self)) { + if (times && MRB_SSIZE_MAX / times < RSTRING_LEN(self)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "argument too big"); } @@ -1088,7 +1113,6 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ -mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass); MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) @@ -1295,7 +1319,7 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); newlen = replen + len - (end - pos); - if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + if (newlen >= MRB_SSIZE_MAX || newlen < replen /* overflowed */) { mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); } @@ -1338,7 +1362,7 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) unsigned char c, cc; #ifdef MRB_UTF8_STRING if (inspect) { - mrb_int clen = utf8len(p, pend); + mrb_int clen = mrb_utf8len(p, pend); if (clen > 1) { mrb_int i; @@ -1641,7 +1665,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) const char* t = RSTR_PTR(s), *p = t; const char* e = p + RSTR_LEN(s); while (p<e) { - mrb_int clen = utf8len(p, e); + mrb_int clen = mrb_utf8len(p, e); if (p + clen>=e) break; p += clen; } @@ -1942,15 +1966,10 @@ mrb_str_intern(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj) { - mrb_value str; - if (mrb_string_p(obj)) { return obj; } - str = mrb_funcall(mrb, obj, "to_s", 0); - if (!mrb_string_p(str)) - return mrb_any_to_s(mrb, obj); - return str; + return mrb_str_to_str(mrb, obj); } MRB_API mrb_value @@ -2018,7 +2037,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) p = RSTR_PTR(s); e = p + RSTR_LEN(s); while (p<e) { - mrb_int clen = utf8len(p, e); + mrb_int clen = mrb_utf8len(p, e); str_reverse(p, p + clen - 1); p += clen; } @@ -2241,7 +2260,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -static mrb_value +mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck) { const char *p = str; @@ -2352,7 +2371,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, if (*(p - 1) == '0') p--; } - if (p == pend) { + if (p == pend || *p == '_') { if (badcheck) goto bad; return mrb_fixnum_value(0); } @@ -2391,9 +2410,10 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, } val = (mrb_int)n; if (badcheck) { - if (p == str) goto bad; /* no number */ + if (p == str) goto bad; /* no number */ + if (*(p - 1) == '_') goto bad; /* trailing '_' */ while (p<pend && ISSPACE(*p)) p++; - if (p<pend) goto bad; /* trailing garbage */ + if (p<pend) goto bad; /* trailing garbage */ } return mrb_fixnum_value(sign ? val : -val); @@ -2427,15 +2447,12 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) if (p[len] == '\0') { return p; } - if (mrb_frozen_p(ps) || RSTR_CAPA(ps) == len) { - ps = str_new(mrb, NULL, len+1); - memcpy(RSTR_PTR(ps), p, len); - RSTR_SET_LEN(ps, len); - *ptr = mrb_obj_value(ps); - } - else { - mrb_str_modify(mrb, ps); - } + + /* + * Even after str_modify_keep_ascii(), NULL termination is not ensured if + * RSTR_SET_LEN() is used explicitly (e.g. String#delete_suffix!). + */ + str_modify_keep_ascii(mrb, ps); RSTR_PTR(ps)[len] = '\0'; return RSTR_PTR(ps); } @@ -2492,73 +2509,105 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) } #ifndef MRB_WITHOUT_FLOAT -MRB_API double -mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) +double +mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) { + char buf[DBL_DIG * 4 + 20]; + const char *p = s, *p2; + const char *pend = p + len; char *end; - char buf[DBL_DIG * 4 + 10]; + char *n; + char prev = 0; double d; - - enum {max_width = 20}; + mrb_bool dot = FALSE; if (!p) return 0.0; - while (ISSPACE(*p)) p++; - - if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { - return 0.0; + while (p<pend && ISSPACE(*p)) p++; + p2 = p; + + if (pend - p > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + mrb_value x; + + if (!badcheck) return 0.0; + x = mrb_str_len_to_inum(mrb, p, pend-p, 0, badcheck); + if (mrb_fixnum_p(x)) + d = (double)mrb_fixnum(x); + else /* if (mrb_float_p(x)) */ + d = mrb_float(x); + return d; + } + while (p < pend) { + if (!*p) { + if (badcheck) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); + /* not reached */ + } + pend = p; + p = p2; + goto nocopy; + } + if (!badcheck && *p == ' ') { + pend = p; + p = p2; + goto nocopy; + } + if (*p == '_') break; + p++; } + p = p2; + n = buf; + while (p < pend) { + char c = *p++; + if (c == '.') dot = TRUE; + if (c == '_') { + /* remove an underscore between digits */ + if (n == buf || !ISDIGIT(prev) || p == pend) { + if (badcheck) goto bad; + break; + } + } + else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad; + else { + const char *bend = buf+sizeof(buf)-1; + if (n==bend) { /* buffer overflow */ + if (dot) break; /* cut off remaining fractions */ + return INFINITY; + } + *n++ = c; + } + prev = c; + } + *n = '\0'; + p = buf; + pend = n; +nocopy: d = mrb_float_read(p, &end); if (p == end) { if (badcheck) { bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%s)", p); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%!s)", s); /* not reached */ } return d; } - if (*end) { - char *n = buf; - char *e = buf + sizeof(buf) - 1; - char prev = 0; - - while (p < end && n < e) prev = *n++ = *p++; - while (*p) { - if (*p == '_') { - /* remove underscores between digits */ - if (badcheck) { - if (n == buf || !ISDIGIT(prev)) goto bad; - ++p; - if (!ISDIGIT(*p)) goto bad; - } - else { - while (*++p == '_'); - continue; - } - } - prev = *p++; - if (n < e) *n++ = prev; - } - *n = '\0'; - p = buf; - - if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { - return 0.0; - } - - d = mrb_float_read(p, &end); - if (badcheck) { - if (!end || p == end) goto bad; - while (*end && ISSPACE(*end)) end++; - if (*end) goto bad; - } + if (badcheck) { + if (!end || p == end) goto bad; + while (end<pend && ISSPACE(*end)) end++; + if (end<pend) goto bad; } return d; } 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_cstr_to_dbl(mrb, RSTRING_CSTR(mrb, str), badcheck); + return mrb_str_len_to_dbl(mrb, RSTRING_PTR(str), RSTRING_LEN(str), badcheck); } /* 15.2.10.5.39 */ @@ -2678,21 +2727,21 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) capa = RSTR_CAPA(s); total = RSTR_LEN(s)+len; - if (total >= MRB_INT_MAX) { + if (total >= MRB_SSIZE_MAX) { size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } if (capa <= total) { if (capa == 0) capa = 1; while (capa <= total) { - if (capa <= MRB_INT_MAX / 2) { + if (capa <= MRB_SSIZE_MAX / 2) { capa *= 2; } else { capa = total+1; } } - if (capa <= total || capa > MRB_INT_MAX) { + if (capa <= total || capa > MRB_SSIZE_MAX) { goto size_error; } resize_capa(mrb, s, capa); @@ -2701,7 +2750,7 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) ptr = RSTR_PTR(s) + off; } memcpy(RSTR_PTR(s) + RSTR_LEN(s), ptr, len); - mrb_assert_int_fit(size_t, total, mrb_int, MRB_INT_MAX); + mrb_assert_int_fit(size_t, total, mrb_ssize, MRB_SSIZE_MAX); RSTR_SET_LEN(s, total); RSTR_PTR(s)[total] = '\0'; /* sentinel */ return str; @@ -2710,7 +2759,7 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr) { - return mrb_str_cat(mrb, str, ptr, strlen(ptr)); + return mrb_str_cat(mrb, str, ptr, ptr ? strlen(ptr) : 0); } MRB_API mrb_value @@ -2873,7 +2922,7 @@ mrb_init_string(mrb_state *mrb) { struct RClass *s; - mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << MRB_STR_EMBED_LEN_BITSIZE), + mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << MRB_STR_EMBED_LEN_BIT), "pointer size too big for embedded string"); mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */ diff --git a/src/symbol.c b/src/symbol.c index 2696b5210..ad186dce3 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -20,12 +20,12 @@ typedef struct symbol_name { const char *name; } symbol_name; -#define SYMBOL_INLINE_BIT 1 -#define SYMBOL_INLINE_LOWER_BIT 2 -#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1)) -#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1)) -#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT -#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT +#define SYMBOL_INLINE_BIT_POS 1 +#define SYMBOL_INLINE_LOWER_BIT_POS 2 +#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT_POS - 1)) +#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT_POS - 1)) +#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT_POS +#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT_POS #ifdef MRB_ENABLE_ALL_SYMBOLS # define SYMBOL_INLINE_P(sym) FALSE # define SYMBOL_INLINE_LOWER_P(sym) FALSE @@ -48,14 +48,14 @@ sym_validate_len(mrb_state *mrb, size_t len) static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static mrb_sym -sym_inline_pack(const char *name, uint16_t len) +sym_inline_pack(const char *name, size_t len) { - const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5; - const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6; + const size_t lower_length_max = (MRB_SYMBOL_BIT - 2) / 5; + const size_t mix_length_max = (MRB_SYMBOL_BIT - 2) / 6; char c; const char *p; - int i; + size_t i; mrb_sym sym = 0; mrb_bool lower = TRUE; @@ -124,7 +124,7 @@ symhash(const char *key, size_t len) } static mrb_sym -find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t *hashp) +find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp) { mrb_sym i; symbol_name *sname; @@ -517,18 +517,14 @@ mrb_sym_str(mrb_state *mrb, mrb_sym sym) { mrb_int len; const char *name = mrb_sym_name_len(mrb, sym, &len); - mrb_value str; if (!name) return mrb_undef_value(); /* can't happen */ if (SYMBOL_INLINE_P(sym)) { - str = mrb_str_new(mrb, name, len); + mrb_value str = mrb_str_new(mrb, name, len); RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; } - else { - str = mrb_str_new_static(mrb, name, len); - } - MRB_SET_FROZEN_FLAG(mrb_str_ptr(str)); - return str; + return mrb_str_new_static(mrb, name, len); } static const char* diff --git a/src/variable.c b/src/variable.c index 8fc01fe2d..030aa7b00 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1123,7 +1123,7 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); - MRB_SET_FROZEN_FLAG(mrb_obj_ptr(path)); + path = mrb_str_dup(mrb, path); } return path; } @@ -6,7 +6,9 @@ #include <stddef.h> #include <stdarg.h> +#ifndef MRB_WITHOUT_FLOAT #include <math.h> +#endif #include <mruby.h> #include <mruby/array.h> #include <mruby/class.h> @@ -322,6 +324,7 @@ cipop(mrb_state *mrb) } void mrb_exc_set(mrb_state *mrb, mrb_value exc); +static mrb_value mrb_run(mrb_state *mrb, struct RProc* proc, mrb_value self); static void ecall(mrb_state *mrb) @@ -333,10 +336,12 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - uint16_t i = --c->eidx; + uint16_t i; int nregs; - if (i<0) return; + if (c->eidx == 0) return; + i = --c->eidx; + /* restrict total call depth of ecall() */ if (++mrb->ecall_nest > MRB_ECALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); @@ -428,6 +433,7 @@ MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) { mrb_value val; + int ai = mrb_gc_arena_save(mrb); if (!mrb->jmp) { struct mrb_jmpbuf c_jmp; @@ -516,19 +522,17 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb->c->stack[argc+1] = blk; if (MRB_METHOD_CFUNC_P(m)) { - int ai = mrb_gc_arena_save(mrb); - ci->acc = CI_ACC_DIRECT; val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); - mrb_gc_arena_restore(mrb, ai); } else { ci->acc = CI_ACC_SKIP; val = mrb_run(mrb, MRB_METHOD_PROC(m), self); } } + mrb_gc_arena_restore(mrb, ai); mrb_gc_protect(mrb, val); return val; } @@ -623,7 +627,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) ci->argc--; } else { /* variable length arguments */ - mrb_ary_shift(mrb, regs[0]); + regs[0] = mrb_ary_subseq(mrb, regs[0], 1, RARRAY_LEN(regs[0]) - 1); } if (MRB_METHOD_CFUNC_P(m)) { @@ -647,8 +651,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) } ci = mrb->c->ci; if (ci->acc == CI_ACC_DIRECT) { - ci->target_class = c; - return mrb_yield_cont(mrb, blk, self, 1, &self); + return mrb_yield_with_class(mrb, blk, 1, &self, self, c); } ci->target_class = c; p = mrb_proc_ptr(blk); @@ -723,26 +726,11 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) { mrb_value a, b; - mrb_value cv; - 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_SYMBOL: - case MRB_TT_FIXNUM: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - c = 0; - break; - default: - cv = mrb_singleton_class(mrb, self); - c = mrb_class_ptr(cv); - break; - } - return eval_under(mrb, self, b, c); + return eval_under(mrb, self, b, mrb_singleton_class_ptr(mrb, self)); } MRB_API mrb_value @@ -1061,6 +1049,11 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_LOADI16, BS) { + SET_INT_VALUE(regs[a], (mrb_int)(int16_t)b); + NEXT; + } + CASE(OP_LOADSYM, BB) { SET_SYM_VALUE(regs[a], syms[b]); NEXT; @@ -1098,13 +1091,13 @@ RETRY_TRY_BLOCK: } CASE(OP_GETSV, BB) { - mrb_value val = mrb_vm_special_get(mrb, b); + mrb_value val = mrb_vm_special_get(mrb, syms[b]); regs[a] = val; NEXT; } CASE(OP_SETSV, BB) { - mrb_vm_special_set(mrb, b, regs[a]); + mrb_vm_special_set(mrb, syms[b], regs[a]); NEXT; } @@ -1495,11 +1488,9 @@ RETRY_TRY_BLOCK: ci->target_class = MRB_PROC_TARGET_CLASS(m); ci->proc = m; if (MRB_PROC_ENV_P(m)) { - mrb_sym mid; struct REnv *e = MRB_PROC_ENV(m); - mid = e->mid; - if (mid) ci->mid = mid; + ci->mid = e->mid; if (!e->stack) { e->stack = mrb->c->stack; } @@ -2825,7 +2816,7 @@ RETRY_TRY_BLOCK: MRB_END_EXC(&c_jmp); } -MRB_API mrb_value +static mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { if (mrb->c->ci->argc < 0) { |
