diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 128 | ||||
| -rw-r--r-- | src/backtrace.c | 31 | ||||
| -rw-r--r-- | src/class.c | 695 | ||||
| -rw-r--r-- | src/codedump.c | 800 | ||||
| -rw-r--r-- | src/debug.c | 87 | ||||
| -rw-r--r-- | src/dump.c | 179 | ||||
| -rw-r--r-- | src/enum.c | 16 | ||||
| -rw-r--r-- | src/error.c | 14 | ||||
| -rw-r--r-- | src/etc.c | 44 | ||||
| -rw-r--r-- | src/ext/.gitkeep | 0 | ||||
| -rw-r--r-- | src/fmt_fp.c | 16 | ||||
| -rw-r--r-- | src/gc.c | 114 | ||||
| -rw-r--r-- | src/hash.c | 982 | ||||
| -rw-r--r-- | src/kernel.c | 511 | ||||
| -rw-r--r-- | src/load.c | 169 | ||||
| -rw-r--r-- | src/mruby_core.rake | 5 | ||||
| -rw-r--r-- | src/numeric.c | 306 | ||||
| -rw-r--r-- | src/object.c | 127 | ||||
| -rw-r--r-- | src/proc.c | 97 | ||||
| -rw-r--r-- | src/range.c | 364 | ||||
| -rw-r--r-- | src/state.c | 39 | ||||
| -rw-r--r-- | src/string.c | 699 | ||||
| -rw-r--r-- | src/symbol.c | 270 | ||||
| -rw-r--r-- | src/variable.c | 483 | ||||
| -rw-r--r-- | src/vm.c | 1699 |
25 files changed, 3902 insertions, 3973 deletions
diff --git a/src/array.c b/src/array.c index 2152e292d..8cf813743 100644 --- a/src/array.c +++ b/src/array.c @@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify_check(mrb_state *mrb, struct RArray *a) { - if (MRB_FROZEN_P(a)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array"); - } + mrb_check_frozen(mrb, a); } static void @@ -231,7 +229,7 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) static void ary_shrink_capa(mrb_state *mrb, struct RArray *a) { - + mrb_int capa; if (ARY_EMBED_P(a)) return; @@ -853,14 +851,14 @@ static mrb_value mrb_ary_aget(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int i, len, alen = ARY_LEN(a); + mrb_int i, len, alen; mrb_value index; if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { return ary_subseq(mrb, a, i, len); } else { @@ -874,6 +872,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) } i = aget_index(mrb, index); + alen = ARY_LEN(a); if (i < 0) i += alen; if (i < 0 || alen < i) return mrb_nil_value(); if (len < 0) return mrb_nil_value(); @@ -928,13 +927,13 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { /* a[n..m] = v */ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - case 1: /* range */ + case MRB_RANGE_OK: mrb_ary_splice(mrb, self, i, len, v2); break; - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } @@ -953,9 +952,10 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self) mrb_int index; mrb_value val; mrb_value *ptr; - mrb_int len, alen = ARY_LEN(a); + mrb_int len, alen; mrb_get_args(mrb, "i", &index); + alen = ARY_LEN(a); if (index < 0) index += alen; if (index < 0 || alen <= index) return mrb_nil_value(); @@ -980,16 +980,17 @@ static mrb_value mrb_ary_first(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int size, alen; if (mrb_get_argc(mrb) == 0) { - return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value(); + return (ARY_LEN(a) > 0)? ARY_PTR(a)[0]: mrb_nil_value(); } mrb_get_args(mrb, "|i", &size); if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); } + alen = ARY_LEN(a); if (size > alen) size = alen; if (ARY_SHARED_P(a)) { return ary_subseq(mrb, a, 0, size); @@ -1001,10 +1002,13 @@ static mrb_value mrb_ary_last(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int n, size, alen; - if (mrb_get_args(mrb, "|i", &size) == 0) - return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + n = mrb_get_args(mrb, "|i", &size); + alen = ARY_LEN(a); + if (n == 0) { + return (alen > 0) ? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + } if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); @@ -1052,7 +1056,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value v) { - mrb_value a, recv_class; + mrb_value a; if (mrb_array_p(v)) { return v; @@ -1063,22 +1067,11 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) } a = mrb_funcall(mrb, v, "to_a", 0); - if (mrb_array_p(a)) { - return a; - } - else if (mrb_nil_p(a)) { + if (mrb_nil_p(a)) { return mrb_ary_new_from_values(mrb, 1, &v); } - else { - recv_class = mrb_obj_value(mrb_obj_class(mrb, v)); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)", - recv_class, - recv_class, - mrb_obj_value(mrb_obj_class(mrb, a)) - ); - /* not reached */ - return mrb_undef_value(); - } + mrb_ensure_array_type(mrb, a); + return a; } static mrb_value @@ -1108,6 +1101,13 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) } static mrb_value +mrb_ary_clear_m(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_ary_clear(mrb, self); +} + +static mrb_value mrb_ary_empty_p(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); @@ -1116,12 +1116,6 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) } MRB_API mrb_value -mrb_check_array_type(mrb_state *mrb, mrb_value ary) -{ - return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); -} - -MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset) { if (offset < 0) { @@ -1174,7 +1168,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) val = tmp; goto str_join; } - tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + tmp = mrb_check_array_type(mrb, val); if (!mrb_nil_p(tmp)) { val = tmp; goto ary_join; @@ -1268,41 +1262,39 @@ mrb_init_array(mrb_state *mrb) { struct RClass *a; - mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); - mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ - - mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ - mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ - mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ - mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ - mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ - mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ - mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ - mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ - mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ - mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ - mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ - mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ - mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ - mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ - mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ - mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); - mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ - mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ - mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ - mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ - mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ - mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ - mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ - mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ - mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); } diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..991a67d00 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,24 +16,24 @@ #include <mruby/data.h> struct backtrace_location { - int lineno; - const char *filename; + int32_t lineno; mrb_sym method_id; + const char *filename; }; -typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); +typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*); static const mrb_data_type bt_type = { "Backtrace", mrb_free }; static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data) { - ptrdiff_t i, j; + ptrdiff_t i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ - for (i=ciidx, j=0; i >= 0; i--,j++) { + for (i=ciidx; i >= 0; i--) { struct backtrace_location loc; mrb_callinfo *ci; mrb_irep *irep; @@ -57,11 +57,11 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu else { pc = pc0; } - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, pc - irep->iseq); if (loc.lineno == -1) continue; + loc.filename = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } @@ -80,8 +80,6 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) mrb_int n; FILE *stream = stderr; - if (!mrb_array_p(backtrace)) return; - n = RARRAY_LEN(backtrace) - 1; if (n == 0) return; @@ -96,7 +94,7 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) } static int -packed_bt_len(struct backtrace_location *bt, int n) +packed_bt_len(const struct backtrace_location *bt, int n) { int len = 0; int i; @@ -113,7 +111,7 @@ static void print_packed_backtrace(mrb_state *mrb, mrb_value packed) { FILE *stream = stderr; - struct backtrace_location *bt; + const struct backtrace_location *bt; int n, i; int ai = mrb_gc_arena_save(mrb); @@ -124,7 +122,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed) if (packed_bt_len(bt, n) == 0) return; fprintf(stream, "trace (most recent call last):\n"); for (i = 0; i<n; i++) { - struct backtrace_location *entry = &bt[n-i-1]; + 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) { @@ -172,7 +170,7 @@ mrb_print_backtrace(mrb_state *mrb) static void count_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { int *lenp = (int*)data; @@ -183,7 +181,7 @@ count_backtrace_i(mrb_state *mrb, static void pack_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { struct backtrace_location **pptr = (struct backtrace_location**)data; @@ -206,7 +204,6 @@ packed_backtrace(mrb_state *mrb) each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len); size = len * sizeof(struct backtrace_location); ptr = mrb_malloc(mrb, size); - if (ptr) memset(ptr, 0, size); backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); backtrace->flags = (unsigned int)len; each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); @@ -230,7 +227,7 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) { - struct backtrace_location *bt; + const struct backtrace_location *bt; mrb_int n, i; int ai; @@ -245,7 +242,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) backtrace = mrb_ary_new_capa(mrb, n); ai = mrb_gc_arena_save(mrb); for (i = 0; i < n; i++) { - struct backtrace_location *entry = &bt[i]; + const struct backtrace_location *entry = &bt[i]; mrb_value btline; if (entry->filename == NULL) continue; diff --git a/src/class.c b/src/class.c index c761f46af..edee95678 100644 --- a/src/class.c +++ b/src/class.c @@ -65,16 +65,22 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb else { name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ - if (outer != mrb->object_class) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + 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; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); +} + +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); } static void @@ -93,7 +99,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->flags |= MRB_FLAG_IS_INHERITED; + sc->flags |= MRB_FL_CLASS_IS_INHERITED; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -120,6 +126,20 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc); mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o); mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); + sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; +} + +static mrb_value +class_name_str(mrb_state *mrb, struct RClass* c) +{ + mrb_value path = mrb_class_path(mrb, c); + if (mrb_nil_p(path)) { + path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") : + mrb_str_new_lit(mrb, "#<Class:"); + mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); + mrb_str_cat_lit(mrb, path, ">"); + } + return path; } static struct RClass* @@ -275,7 +295,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) if (!super) super = mrb->object_class; - super->flags |= MRB_FLAG_IS_INHERITED; + super->flags |= MRB_FL_CLASS_IS_INHERITED; s = mrb_obj_value(super); mc_clear_by_class(mrb, klass); mid = mrb_intern_lit(mrb, "inherited"); @@ -428,12 +448,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; @@ -471,15 +486,11 @@ mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t MRB_API void mrb_notimplement(mrb_state *mrb) { - const char *str; - mrb_int len; mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - str = mrb_sym2name_len(mrb, ci->mid, &len); - mrb_raisef(mrb, E_NOTIMP_ERROR, - "%S() function is unimplemented on this machine", - mrb_str_new_static(mrb, str, (size_t)len)); + mrb_value str = mrb_sym2str(mrb, ci->mid); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); } } @@ -492,52 +503,34 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -static mrb_value -check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) -{ - mrb_value tmp; - - tmp = mrb_check_convert_type(mrb, val, t, c, m); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c)); - } - return tmp; -} +#define CHECK_TYPE(mrb, val, t, c) do { \ + if (mrb_type(val) != (t)) {\ + mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ + }\ +} while (0) static mrb_value to_str(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); + CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); + return val; } static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + return val; } static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); + CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + return val; } -static mrb_sym -to_sym(mrb_state *mrb, mrb_value ss) -{ - if (mrb_type(ss) == MRB_TT_SYMBOL) { - return mrb_symbol(ss); - } - else if (mrb_string_p(ss)) { - return mrb_intern_str(mrb, to_str(mrb, ss)); - } - else { - mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj); - /* not reached */ - return 0; - } -} +#define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss) MRB_API mrb_int mrb_get_argc(mrb_state *mrb) @@ -580,20 +573,20 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] 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 [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - b: Boolean [mrb_bool] - n: 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 - I: Inline struct [void*] - &: Block [mrb_value] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/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*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [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 @@ -851,29 +844,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } @@ -1061,7 +1032,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru while (m) { int superclass_seen = 0; - if (m->flags & MRB_FLAG_IS_PREPENDED) + if (m->flags & MRB_FL_CLASS_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -1084,7 +1055,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru } ic = include_class_new(mrb, m, ins_pos->super); - m->flags |= MRB_FLAG_IS_INHERITED; + 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); @@ -1099,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1111,15 +1082,16 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + mrb_check_frozen(mrb, c); + if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); - origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED; + origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->super = c->super; c->super = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); - c->flags |= MRB_FLAG_IS_PREPENDED; + c->flags |= MRB_FL_CLASS_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1196,7 +1168,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + else if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1217,27 +1189,6 @@ mrb_mod_extend_object(mrb_state *mrb, mrb_value mod) } static mrb_value -mrb_mod_included_modules(mrb_state *mrb, mrb_value self) -{ - mrb_value result; - struct RClass *c = mrb_class_ptr(self); - struct RClass *origin = c; - - MRB_CLASS_ORIGIN(origin); - result = mrb_ary_new(mrb); - while (c) { - if (c != origin && c->tt == MRB_TT_ICLASS) { - if (c->c->tt == MRB_TT_MODULE) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); - } - } - c = c->super; - } - - return result; -} - -static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; @@ -1250,45 +1201,6 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) return mod; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - -/* 15.2.2.4.33 */ -/* - * call-seq: - * mod.instance_methods(include_super=true) -> array - * - * Returns an array containing the names of the public and protected instance - * methods in the receiver. For a module, these are the public and protected methods; - * for a class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is <code>false</code>, the - * instance methods in <i>mod</i> are returned, otherwise the methods - * in <i>mod</i> and <i>mod</i>'s superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> [:method1] - * B.instance_methods(false) #=> [:method2] - * C.instance_methods(false) #=> [:method3] - * C.instance_methods(true).length #=> 43 - */ - -static mrb_value -mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) -{ - struct RClass *c = mrb_class_ptr(mod); - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_class_instance_method_list(mrb, recur, c, 0); -} - /* implementation of module_eval/class_eval */ mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); @@ -1365,9 +1277,9 @@ mc_clear_by_class(mrb_state *mrb, struct RClass *c) struct mrb_cache_entry *mc = mrb->cache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) { @@ -1381,9 +1293,9 @@ mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid) struct mrb_cache_entry *mc = mrb->cache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) { @@ -1480,7 +1392,7 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); name = mrb_symbol_value(sym); p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); MRB_METHOD_FROM_PROC(m, p); @@ -1525,7 +1437,7 @@ mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); attr = mrb_symbol_value(sym); /* prepare method name (name=) */ @@ -1572,29 +1484,20 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; mrb_get_args(mrb, "*&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } @@ -1751,11 +1654,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - const char *str; - mrb_int len; - - str = mrb_sym2name_len(mrb, mrb_symbol(path), &len); - return mrb_str_new(mrb, str, len); + return mrb_sym2str(mrb, mrb_symbol(path)); } return mrb_str_dup(mrb, path); } @@ -1763,10 +1662,10 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) MRB_API struct RClass* mrb_class_real(struct RClass* cl) { - if (cl == 0) - return NULL; + if (cl == 0) return NULL; while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) { cl = cl->super; + if (cl == 0) return NULL; } return cl; } @@ -1774,13 +1673,8 @@ mrb_class_real(struct RClass* cl) MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { - mrb_value path = mrb_class_path(mrb, c); - if (mrb_nil_p(path)) { - path = mrb_str_new_lit(mrb, "#<Class:"); - mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); - mrb_str_cat_lit(mrb, path, ">"); - } - return RSTRING_PTR(path); + mrb_value name = class_name_str(mrb, c); + return RSTRING_PTR(name); } MRB_API const char* @@ -1892,15 +1786,13 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const * show information on the thing we're attached to as well. */ -static mrb_value +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - mrb_value str; if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); - - str = mrb_str_new_lit(mrb, "#<Class:"); + mrb_value str = mrb_str_new_lit(mrb, "#<Class:"); if (class_ptr_p(v)) { mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); @@ -1911,34 +1803,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) return mrb_str_cat_lit(mrb, str, ">"); } else { - struct RClass *c; - mrb_value path; - - str = mrb_str_new_capa(mrb, 32); - c = mrb_class_ptr(klass); - path = mrb_class_path(mrb, c); - - if (mrb_nil_p(path)) { - switch (mrb_type(klass)) { - case MRB_TT_CLASS: - mrb_str_cat_lit(mrb, str, "#<Class:"); - break; - - case MRB_TT_MODULE: - mrb_str_cat_lit(mrb, str, "#<Module:"); - break; - - default: - /* Shouldn't be happened? */ - mrb_str_cat_lit(mrb, str, "#<??????:"); - break; - } - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); - return mrb_str_cat_lit(mrb, str, ">"); - } - else { - return path; - } + return class_name_str(mrb, mrb_class_ptr(klass)); } } @@ -1950,11 +1815,11 @@ 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); - return mrb_nil_value(); + return mod; } -static void -undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +void +mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); @@ -1970,7 +1835,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - undef_method(mrb, c, mrb_intern_cstr(mrb, name)); + mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1988,297 +1853,20 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, to_sym(mrb, *argv)); + mrb_undef_method_id(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); } -static mrb_value -mod_define_method(mrb_state *mrb, mrb_value self) -{ - struct RClass *c = mrb_class_ptr(self); - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value proc = mrb_undef_value(); - mrb_value blk; - - mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); - switch (mrb_type(proc)) { - case MRB_TT_PROC: - blk = proc; - break; - case MRB_TT_UNDEF: - /* ignored */ - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); - break; - } - 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); - 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); - return mrb_symbol_value(mid); -} - -static mrb_value -top_define_method(mrb_state *mrb, mrb_value self) -{ - return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); -} - -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) -{ - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } -} - -static void -check_cv_name_sym(mrb_state *mrb, mrb_sym id) -{ - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); -} - -/* 15.2.2.4.16 */ -/* - * call-seq: - * obj.class_variable_defined?(symbol) -> true or false - * - * Returns <code>true</code> if the given class variable is defined - * in <i>obj</i>. - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_defined?(:@@foo) #=> true - * Fred.class_variable_defined?(:@@bar) #=> false - */ - -static mrb_value -mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); -} - -/* 15.2.2.4.17 */ -/* - * call-seq: - * mod.class_variable_get(symbol) -> obj - * - * Returns the value of the given class variable (or throws a - * <code>NameError</code> exception). The <code>@@</code> part of the - * variable name should be included for regular class variables - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_get(:@@foo) #=> 99 - */ - -static mrb_value -mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_cv_get(mrb, mod, id); -} - -/* 15.2.2.4.18 */ -/* - * call-seq: - * obj.class_variable_set(symbol, obj) -> obj - * - * Sets the class variable names by <i>symbol</i> to - * <i>object</i>. - * - * class Fred - * @@foo = 99 - * def foo - * @@foo - * end - * end - * Fred.class_variable_set(:@@foo, 101) #=> 101 - * Fred.new.foo #=> 101 - */ - -static mrb_value -mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) -{ - mrb_value value; - mrb_sym id; - - mrb_get_args(mrb, "no", &id, &value); - check_cv_name_sym(mrb, id); - mrb_cv_set(mrb, mod, id, value); - return value; -} - -/* 15.2.2.4.39 */ -/* - * call-seq: - * remove_class_variable(sym) -> obj - * - * Removes the definition of the <i>sym</i>, returning that - * constant's value. - * - * class Dummy - * @@var = 99 - * puts @@var - * p class_variables - * remove_class_variable(:@@var) - * p class_variables - * end - * - * <em>produces:</em> - * - * 99 - * [:@@var] - * [] - */ - -static mrb_value -mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) -{ - mrb_value val; - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - - val = mrb_iv_remove(mrb, mod, id); - if (!mrb_undef_p(val)) return val; - - if (mrb_cv_defined(mrb, mod, id)) { - mrb_name_error(mrb, id, "cannot remove %S for %S", - mrb_sym2str(mrb, id), mod); - } - - mrb_name_error(mrb, id, "class variable %S not defined for %S", - mrb_sym2str(mrb, id), mod); - - /* not reached */ - return mrb_nil_value(); -} - -/* 15.2.2.4.34 */ -/* - * call-seq: - * mod.method_defined?(symbol) -> true or false - * - * Returns +true+ if the named method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). Public and protected methods are matched. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.method_defined? "method1" #=> true - * C.method_defined? "method2" #=> true - * C.method_defined? "method3" #=> true - * C.method_defined? "method4" #=> false - */ - -static mrb_value -mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); -} - -static void -remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) -{ - struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = find_origin(c)->mt; - khiter_t k; - - if (h) { - k = kh_get(mt, mrb, h, mid); - if (k != kh_end(h)) { - kh_del(mt, mrb, h, k); - mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); - return; - } - } - - mrb_name_error(mrb, mid, "method '%S' not defined in %S", - mrb_sym2str(mrb, mid), mod); -} - -/* 15.2.2.4.41 */ -/* - * call-seq: - * remove_method(symbol) -> self - * - * Removes the method identified by _symbol_ from the current - * class. For an example, see <code>Module.undef_method</code>. - */ - -static mrb_value -mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) -{ - mrb_int argc; - mrb_value *argv; - - mrb_get_args(mrb, "*", &argv, &argc); - while (argc--) { - remove_method(mrb, mod, to_sym(mrb, *argv)); - argv++; - } - return mod; -} - - - -static void -check_const_name_str(mrb_state *mrb, mrb_value str) -{ - if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str); - } -} - static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { - check_const_name_str(mrb, mrb_sym2str(mrb, id)); -} - -static mrb_value -const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) -{ - if (inherit) { - return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!mrb_const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); } - return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); } static mrb_value @@ -2289,7 +1877,10 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n|b", &id, &inherit); check_const_name_sym(mrb, id); - return const_defined(mrb, mod, id, inherit); + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); } static mrb_value @@ -2316,7 +1907,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) } /* const get with class path string */ - path = mrb_string_type(mrb, path); + path = mrb_ensure_string_type(mrb, path); ptr = RSTRING_PTR(path); len = RSTRING_LEN(path); off = 0; @@ -2326,7 +1917,14 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) end = (end == -1) ? len : end; id = mrb_intern(mrb, ptr+off, end-off); mod = mrb_const_get_sym(mrb, mod, id); - off = (end == len) ? end : end+2; + if (end == len) + off = end; + else { + off = end + 2; + if (off == len) { /* trailing "::" */ + mrb_name_error(mrb, id, "wrong constant name '%S'", path); + } + } } return mod; @@ -2379,11 +1977,79 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + +static mrb_value +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); +} + +static mrb_value +mod_define_method(mrb_state *mrb, mrb_value self) +{ + struct RClass *c = mrb_class_ptr(self); + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value proc = mrb_undef_value(); + mrb_value blk; + + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } + 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); + 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); + return mrb_symbol_value(mid); +} + static mrb_value -mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +top_define_method(mrb_state *mrb, mrb_value self) { - mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); - return mrb_nil_value(); /* not reached */ + return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); } static mrb_value @@ -2398,7 +2064,7 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } -MRB_API mrb_value +static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { mrb_value *argv; @@ -2439,8 +2105,6 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); static mrb_value inspect_main(mrb_state *mrb, mrb_value mod) @@ -2489,8 +2153,9 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ - mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 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_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); @@ -2500,9 +2165,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); - mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ - mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ - mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); @@ -2511,18 +2173,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ - mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ - mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ - mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ - mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); @@ -2533,14 +2189,11 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ - mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ - mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/codedump.c b/src/codedump.c index d79a65a70..12d609075 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -6,457 +6,526 @@ #include <mruby/proc.h> #ifndef MRB_DISABLE_STDIO -static int -print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +static void +print_r(mrb_state *mrb, mrb_irep *irep, size_t n) { size_t i; - if (n == 0) return 0; + if (n == 0) return; for (i=0; i+1<irep->nlocals; i++) { if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; - if (pre) printf(" "); - printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); - return 1; + printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + break; } } - return 0; } -#define RA 1 -#define RB 2 -#define RAB 3 - static void -print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a) { - int pre = 0; + if (!irep->lv || a >= irep->nlocals || a == 0) { + printf("\n"); + return; + } + printf("\t;"); + print_r(mrb, irep, a); + printf("\n"); +} - if (!irep->lv - || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) - && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { +static void +print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) +{ + if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) { printf("\n"); return; } - printf("\t; "); - if (r & RA) { - pre = print_r(mrb, irep, GETARG_A(c), 0); + printf("\t;"); + if (a > 0) print_r(mrb, irep, a); + if (b > 0) print_r(mrb, irep, b); + printf("\n"); +} + +static void +print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i) +{ + int32_t line; + + line = mrb_debug_get_line(mrb, irep, i); + if (line < 0) { + printf(" "); } - if (r & RB) { - print_r(mrb, irep, GETARG_B(c), pre); + else { + printf("%5d ", line); } - printf("\n"); + + printf("%03d ", (int)i); } -#endif + +#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn static void codedump(mrb_state *mrb, mrb_irep *irep) { -#ifndef MRB_DISABLE_STDIO - int i; int ai; - mrb_code c; + mrb_code *pc, *pcend; + mrb_code ins; const char *file = NULL, *next_file; - int32_t line; if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, - irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); + + if (irep->lv) { + int i; + + printf("local variable names:\n"); + for (i = 1; i < irep->nlocals; ++i) { + char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name); + int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i; + printf(" R%d:%s\n", n, s ? s : ""); + } + } + + pc = irep->iseq; + pcend = pc + irep->ilen; + while (pc < pcend) { + ptrdiff_t i; + uint32_t a; + uint16_t b; + uint8_t c; - for (i = 0; i < (int)irep->ilen; i++) { ai = mrb_gc_arena_save(mrb); - next_file = mrb_debug_get_filename(irep, i); + i = pc - irep->iseq; + next_file = mrb_debug_get_filename(mrb, irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - line = mrb_debug_get_line(irep, i); - if (line < 0) { - printf(" "); - } - else { - printf("%5d ", line); - } - - printf("%03d ", i); - c = irep->iseq[i]; - switch (GET_OPCODE(c)) { - case OP_NOP: + print_header(mrb, irep, i); + ins = READ_B(); + switch (ins) { + CASE(OP_NOP, Z): printf("OP_NOP\n"); break; - case OP_MOVE: - printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_MOVE, BB): + printf("OP_MOVE\tR%d\tR%d\t", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_LOADL: + CASE(OP_LOADL, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); - break; - case OP_LOADI: - printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSYM: - printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADNIL: - printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSELF: - printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADT: - printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADF: - printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETGLOBAL: - printf("OP_SETGLOBAL\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCONST: - printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCONST: - printf("OP_SETCONST\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETMCNST: - printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RAB); - break; - case OP_SETMCNST: - printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETIV: - printf("OP_GETIV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETIV: - printf("OP_SETIV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETUPVAR: - printf("OP_GETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_SETUPVAR: - printf("OP_SETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCV: - printf("OP_GETCV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCV: - printf("OP_SETCV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_JMP: - printf("OP_JMP\t%03d (%d)\n", i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPIF: - printf("OP_JMPIF\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPNOT: - printf("OP_JMPNOT\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_SEND: - printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SENDB: - printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_CALL: - printf("OP_CALL\tR%d\n", GETARG_A(c)); - break; - case OP_TAILCALL: - printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUPER: - printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), - GETARG_C(c)); - break; - case OP_ARGARY: - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + 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): + printf("OP_LOADI\tR%d\t-%d\t", a, 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); + 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): + 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_ENTER: + CASE(OP_LOADSYM, BB): + printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADNIL, B): + printf("OP_LOADNIL\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADSELF, B): + printf("OP_LOADSELF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADT, B): + printf("OP_LOADT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + 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_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETGV, BB): + printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(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_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETSV, BB): + printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(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_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCONST, BB): + printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(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_sym2name(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_sym2name(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_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETIV, BB): + printf("OP_SETIV\t%s\tR%d", mrb_sym2name(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); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETUPVAR, BBB): + printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCV, BB): + printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCV, BB): + printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMP, S): + printf("OP_JMP\t\t%03d\n", a); + break; + CASE(OP_JMPIF, BS): + printf("OP_JMPIF\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNOT, BS): + printf("OP_JMPNOT\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNIL, BS): + printf("OP_JMPNIL\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SENDV, BB): + printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SENDVB, BB): + printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SEND, BBB): + printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SENDB, BBB): + printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_CALL, Z): + printf("OP_CALL\n"); + break; + 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, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (GETARG_Ax(c)>>18)&0x1f, - (GETARG_Ax(c)>>13)&0x1f, - (GETARG_Ax(c)>>12)&0x1, - (GETARG_Ax(c)>>7)&0x1f, - (GETARG_Ax(c)>>2)&0x1f, - (GETARG_Ax(c)>>1)&0x1, - GETARG_Ax(c) & 0x1); - break; - case OP_RETURN: - printf("OP_RETURN\tR%d", GETARG_A(c)); - switch (GETARG_B(c)) { - case OP_R_NORMAL: - printf("\tnormal\t"); break; - case OP_R_RETURN: - printf("\treturn\t"); break; - case OP_R_BREAK: - printf("\tbreak\t"); break; - default: - printf("\tbroken\t"); break; - } - print_lv(mrb, irep, c, RA); + MRB_ASPEC_REQ(a), + MRB_ASPEC_OPT(a), + MRB_ASPEC_REST(a), + MRB_ASPEC_POST(a), + MRB_ASPEC_KEY(a), + MRB_ASPEC_KDICT(a), + MRB_ASPEC_BLOCK(a)); break; - case OP_BLKPUSH: - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + CASE(OP_KEY_P, BB): + printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - - case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1); - switch (GETARG_c(c)) { - case OP_L_METHOD: - printf("method"); break; - case OP_L_BLOCK: - printf("block"); break; - case OP_L_LAMBDA: - printf("lambda"); break; - } - print_lv(mrb, irep, c, RA); + CASE(OP_KEYEND, Z): + printf("OP_KEYEND\n"); break; - case OP_RANGE: - printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_KARG, BB): + printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_METHOD: - printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_RETURN, B): + printf("OP_RETURN\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_ADD: - printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_ADDI: - printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUB: - printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUBI: - printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_MUL: - printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_DIV: - printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LT: - printf("OP_LT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LE: - printf("OP_LE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GT: - printf("OP_GT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GE: - printf("OP_GE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_EQ: - printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); + CASE(OP_RETURN_BLK, B): + printf("OP_RETURN_BLK\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_STOP: - printf("OP_STOP\n"); + CASE(OP_BREAK, B): + printf("OP_BREAK\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_ARRAY: - printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_BLKPUSH, BS): + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, + (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, irep->reps[b]); + break; + CASE(OP_BLOCK, BB): + printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_METHOD, BB): + printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_RANGE_INC, B): + printf("OP_RANGE_INC\tR%d\n", a); + break; + CASE(OP_RANGE_EXC, B): + printf("OP_RANGE_EXC\tR%d\n", a); + break; + CASE(OP_DEF, BB): + printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_UNDEF, B): + printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); + break; + CASE(OP_ALIAS, BB): + printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADD, B): + printf("OP_ADD\tR%d\t\n", a); + break; + CASE(OP_ADDI, BB): + printf("OP_ADDI\tR%d\t%d\n", a, b); + break; + CASE(OP_SUB, B): + printf("OP_SUB\tR%d\t\n", a); + break; + CASE(OP_SUBI, BB): + printf("OP_SUBI\tR%d\t%d\n", a, b); + break; + CASE(OP_MUL, B): + printf("OP_MUL\tR%d\t\n", a); + break; + CASE(OP_DIV, B): + printf("OP_DIV\tR%d\t\n", a); + break; + CASE(OP_LT, B): + printf("OP_LT\t\tR%d\t\n", a); + break; + CASE(OP_LE, B): + printf("OP_LE\t\tR%d\t\n", a); + break; + CASE(OP_GT, B): + printf("OP_GT\t\tR%d\t\n", a); + break; + CASE(OP_GE, B): + printf("OP_GE\t\tR%d\t\n", a); + break; + CASE(OP_EQ, B): + printf("OP_EQ\t\tR%d\t\n", a); + break; + 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): + printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); + print_lv_ab(mrb, irep, a, b); break; - case OP_ARYCAT: - printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYCAT, B): + printf("OP_ARYCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_ARYPUSH: - printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYPUSH, B): + printf("OP_ARYPUSH\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_AREF: - printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYDUP, B): + printf("OP_ARYDUP\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_APOST: - printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); + 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_STRING: + 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): + 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); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRING, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); break; - case OP_STRCAT: - printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_STRCAT, B): + printf("OP_STRCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_HASH: - printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + 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): + printf("OP_HASHADD\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_HASHCAT, B): + printf("OP_HASHCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_OCLASS: - printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_OCLASS, B): + printf("OP_OCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_CLASS: - printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_CLASS, BB): + printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_MODULE: - printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_MODULE, BB): + printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); - print_lv(mrb, irep, c, RA); + CASE(OP_EXEC, BB): + printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]); + print_lv_a(mrb, irep, a); break; - case OP_SCLASS: - printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_SCLASS, B): + printf("OP_SCLASS\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_TCLASS: - printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_TCLASS, B): + printf("OP_TCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_ERR: + CASE(OP_ERR, B): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[a]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; - case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + CASE(OP_EPUSH, B): + printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]); break; - case OP_ONERR: - printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + CASE(OP_ONERR, S): + printf("OP_ONERR\t%03d\n", a); + break; + CASE(OP_EXCEPT, B): + printf("OP_EXCEPT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_RESCUE, BB): + printf("OP_RESCUE\tR%d\tR%d", a, b); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_RAISE, B): + printf("OP_RAISE\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_POPERR, B): + printf("OP_POPERR\t%d\t\t\n", a); + break; + CASE(OP_EPOP, B): + printf("OP_EPOP\t%d\n", a); break; - case OP_RESCUE: - { - int a = GETARG_A(c); - int b = GETARG_B(c); - int cnt = GETARG_C(c); - if (b == 0) { - printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RA); - break; - } - else { - printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RAB); - break; - } - } + CASE(OP_DEBUG, BBB): + printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); break; - case OP_RAISE: - printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + + CASE(OP_STOP, Z): + printf("OP_STOP\n"); break; - case OP_POPERR: - printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); + + CASE(OP_EXT1, Z): + ins = READ_B(); + printf("OP_EXT1\n"); + print_header(mrb, irep, pc-irep->iseq-2); + 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_EPOP: - printf("OP_EPOP\t%d\n", GETARG_A(c)); + CASE(OP_EXT2, Z): + ins = READ_B(); + printf("OP_EXT2\n"); + print_header(mrb, irep, pc-irep->iseq-2); + 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(); + printf("OP_EXT3\n"); + print_header(mrb, irep, pc-irep->iseq-2); + 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 %d\t%d\t%d\t%d\n", GET_OPCODE(c), - GETARG_A(c), GETARG_B(c), GETARG_C(c)); + printf("OP_unknown (0x%x)\n", ins); break; } mrb_gc_arena_restore(mrb, ai); } printf("\n"); -#endif } static void @@ -469,9 +538,12 @@ codedump_recur(mrb_state *mrb, mrb_irep *irep) codedump_recur(mrb, irep->reps[i]); } } +#endif void mrb_codedump_all(mrb_state *mrb, struct RProc *proc) { +#ifndef MRB_DISABLE_STDIO codedump_recur(mrb, proc->body.irep); +#endif } diff --git a/src/debug.c b/src/debug.c index e55f11d4f..0dc02a1e3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -51,25 +51,25 @@ select_line_type(const uint16_t *lines, size_t lines_len) } MRB_API char const* -mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; - if (!irep->debug_info) { return irep->filename; } + if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { - return f->filename; + return mrb_sym2name_len(mrb, f->filename_sym, NULL); } } return NULL; } MRB_API int32_t -mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) { - return irep->lines? irep->lines[pc] : -1; + return -1; } else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { switch (f->line_type) { @@ -122,82 +122,79 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) } MRB_API mrb_irep_debug_info_file* -mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, + const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos) { - mrb_irep_debug_info *info; - mrb_irep_debug_info_file *ret; + mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; - mrb_int len; uint32_t i; - if (!irep->debug_info) { return NULL; } + if (!d) return NULL; + if (start_pos == end_pos) return NULL; - mrb_assert(irep->filename); - mrb_assert(irep->lines); + mrb_assert(filename); + mrb_assert(lines); - info = irep->debug_info; - - if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) { - return NULL; + if (d->flen > 0) { + const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); + if (strcmp(filename, fn) == 0) + return NULL; } - ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret)); - info->files = - (mrb_irep_debug_info_file**)( - info->files - ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1)) + 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*))); - info->files[info->flen++] = ret; + d->files[d->flen++] = f; file_pc_count = end_pos - start_pos; - ret->start_pos = start_pos; - info->pc_count = end_pos; + f->start_pos = start_pos; + d->pc_count = end_pos; - fn_len = strlen(irep->filename); - ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len); - len = 0; - ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); + fn_len = strlen(filename); + f->filename_sym = mrb_intern(mrb, filename, fn_len); - ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos); - ret->lines.ptr = NULL; + f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); + f->lines.ptr = NULL; - switch (ret->line_type) { + switch (f->line_type) { case mrb_debug_line_ary: - ret->line_entry_count = file_pc_count; - ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); + 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) { - ret->lines.ary[i] = irep->lines[start_pos + 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; - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); - ret->line_entry_count = 0; + 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 (irep->lines[start_pos + i] == prev_line) { continue; } + if (lines[start_pos + i] == prev_line) { continue; } - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( - mrb, ret->lines.flat_map, - sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); + 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 = irep->lines[start_pos + i]; - ret->lines.flat_map[ret->line_entry_count] = m; + m.line = lines[start_pos + i]; + f->lines.flat_map[f->line_entry_count] = m; /* update */ - ++ret->line_entry_count; - prev_line = irep->lines[start_pos + i]; + ++f->line_entry_count; + prev_line = lines[start_pos + i]; } } break; default: mrb_assert(0); break; } - return ret; + return f; } MRB_API void diff --git a/src/dump.c b/src/dump.c index df1e171e4..f1e167e35 100644 --- a/src/dump.c +++ b/src/dump.c @@ -6,6 +6,7 @@ #include <string.h> #include <limits.h> +#include <math.h> #include <mruby/dump.h> #include <mruby/string.h> #include <mruby/irep.h> @@ -17,9 +18,9 @@ #ifndef MRB_WITHOUT_FLOAT #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.8e" +#define MRB_FLOAT_FMT "%.9g" #else -#define MRB_FLOAT_FMT "%.16e" +#define MRB_FLOAT_FMT "%.17g" #endif #endif @@ -81,34 +82,27 @@ static ptrdiff_t write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) { uint8_t *cur = buf; - int iseq_no; cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += write_padding(cur); - switch (flags & DUMP_ENDIAN_NAT) { - case DUMP_ENDIAN_BIG: - if (bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - case DUMP_ENDIAN_LIL: - if (!bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - - native: - case DUMP_ENDIAN_NAT: - memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); - cur += irep->ilen * sizeof(mrb_code); - break; - } + memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); + cur += irep->ilen * sizeof(mrb_code); return cur - buf; } +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +float_to_str(mrb_state *mrb, mrb_value flt) +{ + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i"); + } + return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT); +} +#endif static size_t get_pool_block_size(mrb_state *mrb, mrb_irep *irep) @@ -135,7 +129,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); { mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); @@ -184,7 +178,7 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); break; #endif @@ -372,118 +366,6 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, return MRB_DUMP_OK; } -static int -write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin) -{ - struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; - - memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident)); - uint32_to_bin((uint32_t)section_size, header->section_size); - - return MRB_DUMP_OK; -} - -static size_t -get_lineno_record_size(mrb_state *mrb, mrb_irep *irep) -{ - size_t size = 0; - - size += sizeof(uint32_t); /* record size */ - size += sizeof(uint16_t); /* filename size */ - if (irep->filename) { - size += strlen(irep->filename); /* filename */ - } - size += sizeof(uint32_t); /* niseq */ - if (irep->lines) { - size += sizeof(uint16_t) * irep->ilen; /* lineno */ - } - - return size; -} - -static size_t -write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - uint8_t *cur = bin; - int iseq_no; - size_t filename_len; - ptrdiff_t diff; - - cur += sizeof(uint32_t); /* record size */ - - if (irep->filename) { - filename_len = strlen(irep->filename); - } - else { - filename_len = 0; - } - mrb_assert_int_fit(size_t, filename_len, uint16_t, UINT16_MAX); - cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */ - - if (filename_len) { - memcpy(cur, irep->filename, filename_len); - cur += filename_len; /* filename */ - } - - if (irep->lines) { - mrb_assert_int_fit(size_t, irep->ilen, uint32_t, UINT32_MAX); - cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */ - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */ - } - } - else { - cur += uint32_to_bin(0, cur); /* niseq */ - } - - diff = cur - bin; - mrb_assert_int_fit(ptrdiff_t, diff, uint32_t, UINT32_MAX); - - uint32_to_bin((uint32_t)diff, bin); /* record size */ - - mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); - return (size_t)diff; -} - -static size_t -write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - size_t rlen, size = 0; - int i; - - rlen = write_lineno_record_1(mrb, irep, bin); - bin += rlen; - size += rlen; - for (i=0; i<irep->rlen; i++) { - rlen = write_lineno_record(mrb, irep, bin); - bin += rlen; - size += rlen; - } - return size; -} - -static int -write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) -{ - size_t section_size = 0; - size_t rlen = 0; /* size of irep record */ - uint8_t *cur = bin; - - if (mrb == NULL || bin == NULL) { - return MRB_DUMP_INVALID_ARGUMENT; - } - - cur += sizeof(struct rite_section_lineno_header); - section_size += sizeof(struct rite_section_lineno_header); - - rlen = write_lineno_record(mrb, irep, cur); - section_size += rlen; - - write_section_lineno_header(mrb, section_size, bin); - - return MRB_DUMP_OK; -} - static size_t get_debug_record_size(mrb_state *mrb, mrb_irep *irep) { @@ -857,26 +739,26 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 } static mrb_bool -is_debug_info_defined(mrb_irep *irep) +debug_info_defined_p(mrb_irep *irep) { int i; if (!irep->debug_info) return FALSE; for (i=0; i<irep->rlen; i++) { - if (!is_debug_info_defined(irep->reps[i])) return FALSE; + if (!debug_info_defined_p(irep->reps[i])) return FALSE; } return TRUE; } static mrb_bool -is_lv_defined(mrb_irep *irep) +lv_defined_p(mrb_irep *irep) { int i; if (irep->lv) { return TRUE; } for (i = 0; i < irep->rlen; ++i) { - if (is_lv_defined(irep->reps[i])) { return TRUE; } + if (lv_defined_p(irep->reps[i])) { return TRUE; } } return FALSE; @@ -905,7 +787,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * size_t section_irep_size; size_t section_lineno_size = 0, section_lv_size = 0; uint8_t *cur = NULL; - mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep); + mrb_bool const debug_info_defined = debug_info_defined_p(irep), lv_defined = lv_defined_p(irep); mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0; mrb_sym *filenames = NULL; uint16_t filenames_len = 0; @@ -930,10 +812,6 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * section_lineno_size += get_debug_record_size(mrb, irep); } - else { - section_lineno_size += sizeof(struct rite_section_lineno_header); - section_lineno_size += get_lineno_record_size(mrb, irep); - } } if (lv_defined) { @@ -961,12 +839,9 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); - } - else { - result = write_section_lineno(mrb, irep, cur); - } - if (result != MRB_DUMP_OK) { - goto error_exit; + if (result != MRB_DUMP_OK) { + goto error_exit; + } } cur += section_lineno_size; } diff --git a/src/enum.c b/src/enum.c index ea05777b3..1e9445176 100644 --- a/src/enum.c +++ b/src/enum.c @@ -14,21 +14,9 @@ enum_update_hash(mrb_state *mrb, mrb_value self) mrb_int hash; mrb_int index; mrb_int hv; - mrb_value item_hash; - mrb_get_args(mrb, "iio", &hash, &index, &item_hash); - if (mrb_fixnum_p(item_hash)) { - hv = mrb_fixnum(item_hash); - } -#ifndef MRB_WITHOUT_FLOAT - else if (mrb_float_p(item_hash)) { - hv = (mrb_int)mrb_float(item_hash); - } -#endif - else { - mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash"); - } - hash ^= (hv << (index % 16)); + mrb_get_args(mrb, "iii", &hash, &index, &hv); + hash ^= ((uint32_t)hv << (index % 16)); return mrb_fixnum_value(hash); } diff --git a/src/error.c b/src/error.c index 599612b97..4c1b67c99 100644 --- a/src/error.c +++ b/src/error.c @@ -28,7 +28,7 @@ mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { - str = mrb_str_to_str(mrb, str); + mrb_to_str(mrb, str); return mrb_obj_new(mrb, c, 1, &str); } @@ -208,8 +208,8 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) 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(irep, err - irep->iseq); - char const* file = mrb_debug_get_filename(irep, err - irep->iseq); + 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)); @@ -376,6 +376,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...) str = mrb_vformat(mrb, fmt, ap); fputs("warning: ", stderr); fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + putc('\n', stderr); va_end(ap); #endif } @@ -483,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, mrb_exc_raise(mrb, exc); } +MRB_API mrb_noreturn void +mrb_frozen_error(mrb_state *mrb, void *frozen_obj) +{ + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", + mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj)))); +} + void mrb_init_exception(mrb_state *mrb) { @@ -1,5 +1,5 @@ /* -** etc.c - +** etc.c ** ** See Copyright Notice in mruby.h */ @@ -8,8 +8,6 @@ #include <mruby/string.h> #include <mruby/data.h> #include <mruby/class.h> -#include <mruby/re.h> -#include <mruby/irep.h> MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) @@ -67,23 +65,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_sym id; - - switch (mrb_type(name)) { - default: - name = mrb_check_string_type(mrb, name); - if (mrb_nil_p(name)) { - name = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); - } - /* fall through */ - case MRB_TT_STRING: - name = mrb_str_intern(mrb, name); - /* fall through */ - case MRB_TT_SYMBOL: - id = mrb_symbol(name); - } - return id; + if (mrb_symbol_p(name)) return mrb_symbol(name); + if (mrb_string_p(name)) return mrb_intern_str(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol nor a string", mrb_inspect(mrb, name)); + return 0; /* not reached */ } MRB_API mrb_int @@ -166,6 +151,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -176,6 +162,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ @@ -191,23 +178,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -MRB_API mrb_bool -mrb_regexp_p(mrb_state *mrb, mrb_value v) -{ - if (mrb->flags & MRB_STATE_NO_REGEXP) { - return FALSE; - } - if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { - mrb->flags |= MRB_STATE_REGEXP; - return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); - } - else { - mrb->flags |= MRB_STATE_REGEXP; - mrb->flags |= MRB_STATE_NO_REGEXP; - } - return FALSE; -} - #if defined _MSC_VER && _MSC_VER < 1900 #ifndef va_copy diff --git a/src/ext/.gitkeep b/src/ext/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/src/ext/.gitkeep +++ /dev/null diff --git a/src/fmt_fp.c b/src/fmt_fp.c index f8a8f7904..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,3 +1,5 @@ +#ifndef MRB_WITHOUT_FLOAT +#if defined(MRB_DISABLE_STDIO) || defined(_WIN32) || defined(_WIN64) /* Most code in this file originates from musl (src/stdio/vfprintf.c) @@ -36,7 +38,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <mruby.h> #include <mruby/string.h> -#ifndef MRB_WITHOUT_FLOAT struct fmt_args { mrb_state *mrb; mrb_value str; @@ -371,4 +372,17 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } +#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ +#include <mruby.h> +#include <stdio.h> + +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); +} +#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif @@ -10,6 +10,7 @@ #include <mruby/array.h> #include <mruby/class.h> #include <mruby/data.h> +#include <mruby/istruct.h> #include <mruby/hash.h> #include <mruby/proc.h> #include <mruby/range.h> @@ -109,8 +110,10 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; + struct RIStruct istruct; struct RProc proc; struct REnv env; + struct RFiber fiber; struct RException exc; struct RBreak brk; #ifdef MRB_WORD_BOXING @@ -274,9 +277,36 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + mrb_value str = mrb_str_new(mrb, NULL, size); + return RSTRING_PTR(str); +} + +static mrb_bool +heap_p(mrb_gc *gc, struct RBasic *object) +{ + mrb_heap_page* page; + + page = gc->heaps; + while (page) { + RVALUE *p; + + p = objects(page); + if (&p[0].as.basic <= object && object <= &p[MRB_HEAP_PAGE_SIZE].as.basic) { + return TRUE; + } + page = page->next; + } + return FALSE; +} + MRB_API mrb_bool mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) { - return is_dead(&mrb->gc, object); + mrb_gc *gc = &mrb->gc; + if (!heap_p(gc, object)) return TRUE; + return is_dead(gc, object); } static void @@ -376,7 +406,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); -void +static void free_heap(mrb_state *mrb, mrb_gc *gc) { mrb_heap_page *page = gc->heaps; @@ -443,9 +473,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); @@ -457,11 +490,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; struct RArray *a; mrb_int i; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { mrb_gv_set(mrb, root, mrb_nil_value()); @@ -470,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); for (i = 0; i < ARY_LEN(a); i++) { - if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) { mrb_int len = ARY_LEN(a)-1; mrb_value *ptr = ARY_PTR(a); @@ -548,21 +584,39 @@ add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) gc->gray_list = obj; } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p = ci->proc; + int n = 0; + + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + static void mark_context_stack(mrb_state *mrb, struct mrb_context *c) { size_t i; size_t e; mrb_value nil; - mrb_int nregs; if (c->stack == NULL) return; e = c->stack - c->stbase; if (c->ci) { - nregs = c->ci->argc + 2; - if (c->ci->nregs > nregs) - nregs = c->ci->nregs; - e += nregs; + e += ci_nregs(c->ci); } if (c->stbase + e > c->stend) e = c->stend - c->stbase; for (i=0; i<e; i++) { @@ -622,7 +676,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) case MRB_TT_ICLASS: { struct RClass *c = (struct RClass*)obj; - if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN)) + if (MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_mark_mt(mrb, c); mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); } @@ -701,14 +755,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_RANGE: - { - struct RRange *r = (struct RRange*)obj; - - if (r->edges) { - mrb_gc_mark_value(mrb, r->edges->beg); - mrb_gc_mark_value(mrb, r->edges->end); - } - } + mrb_gc_mark_range(mrb, (struct RRange*)obj); break; default: @@ -761,7 +808,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) mrb_gc_free_iv(mrb, (struct RObject*)obj); break; case MRB_TT_ICLASS: - if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_free_mt(mrb, (struct RClass*)obj); break; case MRB_TT_ENV: @@ -770,7 +817,8 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) if (MRB_ENV_STACK_SHARED_P(e)) { /* cannot be freed */ - return; + e->stack = NULL; + break; } mrb_free(mrb, e->stack); e->stack = NULL; @@ -782,13 +830,13 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) struct mrb_context *c = ((struct RFiber*)obj)->cxt; if (c && c != mrb->root_c) { - mrb_callinfo *ci = c->ci; - mrb_callinfo *ce = c->cibase; + if (!end && c->status != MRB_FIBER_TERMINATED) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; - if (!end) { while (ce <= ci) { struct REnv *e = ci->env; - if (e && !is_dead(&mrb->gc, e) && + if (e && !mrb_object_dead_p(mrb, (struct RBasic*)e) && e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) { mrb_env_unshare(mrb, e); } @@ -831,7 +879,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; case MRB_TT_RANGE: - mrb_free(mrb, ((struct RRange*)obj)->edges); + mrb_gc_free_range(mrb, ((struct RRange*)obj)); break; case MRB_TT_DATA: @@ -947,10 +995,14 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) size_t i; mrb_callinfo *ci; - if (!c) break; + if (!c || c->status == MRB_FIBER_TERMINATED) break; + /* mark stack */ i = c->stack - c->stbase; - if (c->ci) i += c->ci->nregs; + + if (c->ci) { + i += ci_nregs(c->ci); + } if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; @@ -1537,7 +1589,7 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo mrb->jmp = &c_jmp; gc_each_objects(mrb, &mrb->gc, callback, data); mrb->jmp = prev_jmp; - mrb->gc.iterating = iterating; + mrb->gc.iterating = iterating; } MRB_CATCH(&c_jmp) { mrb->gc.iterating = iterating; mrb->jmp = prev_jmp; diff --git a/src/hash.c b/src/hash.c index db9d1d9c8..2a0a19363 100644 --- a/src/hash.c +++ b/src/hash.c @@ -8,7 +8,6 @@ #include <mruby/array.h> #include <mruby/class.h> #include <mruby/hash.h> -#include <mruby/khash.h> #include <mruby/string.h> #include <mruby/variable.h> @@ -17,14 +16,47 @@ mrb_int mrb_float_id(mrb_float f); #endif -static inline khint_t -mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) +#ifndef MRB_HT_INIT_SIZE +#define MRB_HT_INIT_SIZE 4 +#endif +#define HT_SEG_INCREASE_RATIO 6 / 5 + +struct segkv { + mrb_value key; + mrb_value val; +}; + +typedef struct segment { + uint16_t size; + struct segment *next; + struct segkv e[]; +} segment; + +typedef struct segindex { + size_t size; + size_t capa; + struct segkv *table[]; +} segindex; + +/* hash table structure */ +typedef struct htable { + segment *rootseg; + segment *lastseg; + mrb_int size; + uint16_t last_len; + segindex *index; +} htable; + +static /* inline */ size_t +ht_hash_func(mrb_state *mrb, htable *t, mrb_value key) { - enum mrb_vtype t = mrb_type(key); + enum mrb_vtype tt = mrb_type(key); mrb_value hv; - khint_t h; + size_t h; + segindex *index = t->index; + size_t capa = index ? index->capa : 0; - switch (t) { + switch (tt) { case MRB_TT_STRING: h = mrb_str_hash(mrb, key); break; @@ -36,23 +68,26 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: #endif - h = (khint_t)mrb_obj_id(key); + h = (size_t)mrb_obj_id(key); break; default: hv = mrb_funcall(mrb, key, "hash", 0); - h = (khint_t)t ^ (khint_t)mrb_fixnum(hv); + h = (size_t)t ^ (size_t)mrb_fixnum(hv); break; } - return kh_int_hash_func(mrb, h); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return ((h)^((h)<<2)^((h)>>2)); } -static inline khint_t -mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) +static inline mrb_bool +ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) { - enum mrb_vtype t = mrb_type(a); + enum mrb_vtype tt = mrb_type(a); - switch (t) { + switch (tt) { case MRB_TT_STRING: return mrb_str_equal(mrb, a, b); @@ -85,16 +120,461 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) #endif default: - return mrb_eql(mrb, a, b); + { + segindex *index = t->index; + size_t capa = index ? index->capa : 0; + mrb_bool eql = mrb_eql(mrb, a, b); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return eql; + } + } +} + +/* Creates the hash table. */ +static htable* +ht_new(mrb_state *mrb) +{ + htable *t; + + t = (htable*)mrb_malloc(mrb, sizeof(htable)); + t->size = 0; + t->rootseg = NULL; + t->lastseg = NULL; + t->last_len = 0; + t->index = NULL; + + return t; +} + +#define power2(v) do { \ + v--;\ + v |= v >> 1;\ + v |= v >> 2;\ + v |= v >> 4;\ + v |= v >> 8;\ + v |= v >> 16;\ + v++;\ +} while (0) + +#ifndef UPPER_BOUND +#define UPPER_BOUND(x) ((x)>>2|(x)>>1) +#endif + +#define HT_MASK(index) ((index->capa)-1) + +/* Build index for the hash table */ +static void +ht_index(mrb_state *mrb, htable *t) +{ + size_t size = (size_t)t->size; + size_t mask; + segindex *index = t->index; + segment *seg; + size_t i; + + /* allocate index table */ + if (index && index->size >= UPPER_BOUND(index->capa)) { + size = index->capa+1; + } + power2(size); + if (!index || index->capa < size) { + index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); + if (index == NULL) { + mrb_free(mrb, t->index); + t->index = NULL; + return; + } + t->index = index; + } + index->size = t->size; + index->capa = size; + for (i=0; i<size; i++) { + index->table[i] = NULL; + } + + /* rebuld index */ + mask = HT_MASK(index); + seg = t->rootseg; + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value key; + size_t k, step = 0; + + if (!seg->next && i >= (size_t)t->last_len) { + return; + } + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + k = ht_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + k = (k+(++step)) & mask; + } + index->table[k] = &seg->e[i]; + } + seg = seg->next; + } +} + +/* Compacts the hash table removing deleted entries. */ +static void +ht_compact(mrb_state *mrb, htable *t) +{ + segment *seg; + mrb_int i; + segment *seg2 = NULL; + mrb_int i2; + mrb_int size = 0; + + if (t == NULL) return; + seg = t->rootseg; + if (t->index && (size_t)t->size == t->index->size) { + ht_index(mrb, t); + return; + } + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value k = seg->e[i].key; + + if (!seg->next && i >= t->last_len) { + goto exit; + } + if (mrb_undef_p(k)) { /* found deleted key */ + if (seg2 == NULL) { + seg2 = seg; + i2 = i; + } + } + else { + size++; + if (seg2 != NULL) { + seg2->e[i2++] = seg->e[i]; + if (i2 >= seg2->size) { + seg2 = seg2->next; + i2 = 0; + } + } + } + } + seg = seg->next; + } + exit: + /* reached at end */ + t->size = size; + if (seg2) { + seg = seg2->next; + seg2->next = NULL; + t->last_len = i2; + t->lastseg = seg2; + while (seg) { + seg2 = seg->next; + mrb_free(mrb, seg); + seg = seg2; + } + } + if (t->index) { + ht_index(mrb, t); + } +} + +static segment* +segment_alloc(mrb_state *mrb, segment *seg) +{ + uint32_t size; + + if (!seg) size = MRB_HT_INIT_SIZE; + else { + size = seg->size*HT_SEG_INCREASE_RATIO + 1; + if (size > UINT16_MAX) size = UINT16_MAX; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)+sizeof(struct segkv)*size); + seg->size = size; + seg->next = NULL; + + return seg; +} + +/* Set the value for the key in the indexed table. */ +static void +ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) +{ + segindex *index = t->index; + size_t k, sp, step = 0, mask; + segment *seg; + + if (index->size >= UPPER_BOUND(index->capa)) { + /* need to expand table */ + ht_compact(mrb, t); + index = t->index; + } + mask = HT_MASK(index); + sp = index->capa; + k = ht_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + mrb_value key2 = index->table[k]->key; + if (mrb_undef_p(key2)) { + if (sp == index->capa) sp = k; + } + else if (ht_hash_equal(mrb, t, key, key2)) { + index->table[k]->val = val; + return; + } + k = (k+(++step)) & mask; + } + if (sp < index->capa) { + k = sp; + } + + /* put the value at the last */ + seg = t->lastseg; + if (t->last_len < seg->size) { + index->table[k] = &seg->e[t->last_len++]; + } + else { /* append a new segment */ + seg->next = segment_alloc(mrb, seg); + seg = seg->next; + seg->next = NULL; + t->lastseg = seg; + t->last_len = 1; + index->table[k] = &seg->e[0]; + } + index->table[k]->key = key; + index->table[k]->val = val; + index->size++; + t->size++; +} + +/* Set the value for the key in the hash table. */ +static void +ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) +{ + segment *seg; + mrb_int i, deleted = 0; + + if (t == NULL) return; + if (t->index) { + ht_index_put(mrb, t, key, val); + return; + } + seg = t->rootseg; + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value k = seg->e[i].key; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + t->size++; + return; + } + if (mrb_undef_p(k)) { + deleted++; + continue; + } + if (ht_hash_equal(mrb, t, k, key)) { + seg->e[i].val = val; + return; + } + } + seg = seg->next; + } + /* Not found */ + + /* Compact if last segment has room */ + if (deleted > 0 && deleted > MRB_HT_INIT_SIZE) { + ht_compact(mrb, t); + } + t->size++; + + /* check if thre's room after compaction */ + if (t->lastseg && t->last_len < t->lastseg->size) { + seg = t->lastseg; + i = t->last_len; + } + else { + /* append new segment */ + seg = segment_alloc(mrb, t->lastseg); + i = 0; + if (t->rootseg == NULL) { + t->rootseg = seg; + } + else { + t->lastseg->next = seg; + } + t->lastseg = seg; + } + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + if (t->index == NULL && t->size > MRB_HT_INIT_SIZE*4) { + ht_index(mrb, t); } } -KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal) +/* Get a value for a key from the indexed table. */ +static mrb_bool +ht_index_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) +{ + segindex *index = t->index; + size_t mask = HT_MASK(index); + size_t k = ht_hash_func(mrb, t, key) & mask; + size_t step = 0; + + while (index->table[k]) { + mrb_value key2 = index->table[k]->key; + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { + if (vp) *vp = index->table[k]->val; + return TRUE; + } + k = (k+(++step)) & mask; + } + return FALSE; +} + +/* Get a value for a key from the hash table. */ +static mrb_bool +ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + mrb_int i; + + if (t == NULL) return FALSE; + if (t->index) { + return ht_index_get(mrb, t, key, vp); + } + + seg = t->rootseg; + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value k = seg->e[i].key; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (mrb_undef_p(k)) continue; + if (ht_hash_equal(mrb, t, k, key)) { + if (vp) *vp = seg->e[i].val; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Deletes the value for the symbol from the hash table. */ +/* Deletion is done by overwriting keys by `undef`. */ +static mrb_bool +ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + mrb_int i; + + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value key2; + + if (!seg->next && i >= t->last_len) { + /* not found */ + return FALSE; + } + key2 = seg->e[i].key; + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { + if (vp) *vp = seg->e[i].val; + seg->e[i].key = mrb_undef_value(); + t->size--; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Iterates over the hash table. */ +static void +ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) +{ + segment *seg; + mrb_int i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; i<seg->size; i++) { + /* no value in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + return; + } + if (mrb_undef_p(seg->e[i].key)) continue; + if ((*func)(mrb, seg->e[i].key, seg->e[i].val, p) != 0) + return; + } + seg = seg->next; + } +} + +/* Iterates over the hash table. */ +MRB_API void +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) +{ + ht_foreach(mrb, hash->ht, func, p); +} + +/* Copy the hash table. */ +static htable* +ht_copy(mrb_state *mrb, htable *t) +{ + segment *seg; + htable *t2; + mrb_int i; + + seg = t->rootseg; + t2 = ht_new(mrb); + if (t->size == 0) return t2; + + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value key = seg->e[i].key; + mrb_value val = seg->e[i].val; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + if (mrb_undef_p(key)) continue; /* skip deleted key */ + ht_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; +} + +/* Free memory of the hash table. */ +static void +ht_free(mrb_state *mrb, htable *t) +{ + segment *seg; + + if (!t) return; + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + if (t->index) mrb_free(mrb, t->index); + mrb_free(mrb, t); +} static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value -mrb_hash_ht_key(mrb_state *mrb, mrb_value key) +ht_key(mrb_state *mrb, mrb_value key) { if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); @@ -103,59 +583,57 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) return key; } -#define KEY(key) mrb_hash_ht_key(mrb, key) +#define KEY(key) ht_key(mrb, key) + +static int +hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_gc_mark_value(mrb, key); + mrb_gc_mark_value(mrb, val); + return 0; +} void mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) { - khiter_t k; - khash_t(ht) *h = hash->ht; - - if (!h) return; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value key = kh_key(h, k); - mrb_value val = kh_value(h, k).v; - - mrb_gc_mark_value(mrb, key); - mrb_gc_mark_value(mrb, val); - } - } + ht_foreach(mrb, hash->ht, hash_mark_i, NULL); } size_t mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) { if (!hash->ht) return 0; - return kh_size(hash->ht)*2; + return hash->ht->size*2; } void mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) { - if (hash->ht) kh_destroy(ht, mrb, hash->ht); + ht_free(mrb, hash->ht); } - MRB_API mrb_value -mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) +mrb_hash_new(mrb_state *mrb) { struct RHash *h; h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - /* khash needs 1/4 empty space so it is not resized immediately */ - if (capa == 0) - h->ht = 0; - else - h->ht = kh_init_size(ht, mrb, (khint_t)(capa*4/3)); + h->ht = 0; h->iv = 0; return mrb_obj_value(h); } MRB_API mrb_value -mrb_hash_new(mrb_state *mrb) +mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) { - return mrb_hash_new_capa(mrb, 0); + struct RHash *h; + + h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + /* preallocate hash table */ + h->ht = ht_new(mrb); + /* capacity ignored */ + h->iv = 0; + return mrb_obj_value(h); } static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); @@ -166,7 +644,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) { mrb_value orig; struct RHash* copy; - khash_t(ht) *orig_h; + htable *orig_h; mrb_value ifnone, vret; mrb_get_args(mrb, "o", &orig); @@ -177,22 +655,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = kh_init(ht, mrb); - - if (orig_h && kh_size(orig_h) > 0) { - khash_t(ht) *copy_h = copy->ht; - khiter_t k, copy_k; - - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - int ai = mrb_gc_arena_save(mrb); - copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); - mrb_gc_arena_restore(mrb, ai); - kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; - kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; - } - } - } + copy->ht = ht_copy(mrb, orig_h); if (MRB_RHASH_DEFAULT_P(self)) { copy->flags |= MRB_HASH_DEFAULT; @@ -208,17 +671,45 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +static int +check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + if (!mrb_symbol_p(key)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } + return 0; +} + +void +mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) +{ + htable *t; + + t = RHASH_TBL(self); + if (!t || t->size == 0) return; + ht_foreach(mrb, t, check_kdict_i, NULL); +} + +MRB_API mrb_value +mrb_hash_dup(mrb_state *mrb, mrb_value self) +{ + struct RHash* copy; + htable *orig_h; + + orig_h = RHASH_TBL(self); + copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + copy->ht = orig_h ? ht_copy(mrb, orig_h) : NULL; + return mrb_obj_value(copy); +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; mrb_sym mid; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } mid = mrb_intern_lit(mrb, "default"); @@ -232,15 +723,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } - /* not found */ return def; } @@ -248,54 +735,22 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { - khash_t(ht) *h; - khiter_t k; - int r; - mrb_hash_modify(mrb, hash); - h = RHASH_TBL(hash); - - if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb); - k = kh_put2(ht, mrb, h, key, &r); - kh_value(h, k).v = val; - - if (r != 0) { - /* expand */ - int ai = mrb_gc_arena_save(mrb); - key = kh_key(h, k) = KEY(key); - mrb_gc_arena_restore(mrb, ai); - kh_value(h, k).n = kh_size(h)-1; - } + key = KEY(key); + ht_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); return; } -MRB_API mrb_value -mrb_check_hash_type(mrb_state *mrb, mrb_value hash) -{ - return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); -} - -MRB_API khash_t(ht)* -mrb_hash_tbl(mrb_state *mrb, mrb_value hash) -{ - khash_t(ht) *h = RHASH_TBL(hash); - - if (!h) { - return RHASH_TBL(hash) = kh_init(ht, mrb); - } - return h; -} - static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); + mrb_check_frozen(mrb, mrb_hash_ptr(hash)); + if (!RHASH_TBL(hash)) { + RHASH_TBL(hash) = ht_new(mrb); } - mrb_hash_tbl(mrb, hash); } /* 15.2.13.4.16 */ @@ -535,47 +990,17 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delVal; - mrb_int n; - - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) { - delVal = kh_value(h, k).v; - n = kh_value(h, k).n; - kh_del(ht, mrb, h, k); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - if (kh_value(h, k).n > n) kh_value(h, k).n--; - } - return delVal; - } + htable *t = RHASH_TBL(hash); + mrb_value del_val; + + if (ht_del(mrb, t, key, &del_val)) { + return del_val; } /* not found */ return mrb_nil_value(); } -/* 15.2.13.4.8 */ -/* - * call-seq: - * hsh.delete(key) -> value - * hsh.delete(key) {| key | block } -> value - * - * Deletes and returns a key-value pair from <i>hsh</i> whose key is - * equal to <i>key</i>. If the key is not found, returns the - * <em>default value</em>. If the optional code block is given and the - * key is not found, pass in the key and return the result of - * <i>block</i>. - * - * h = { "a" => 100, "b" => 200 } - * h.delete("a") #=> 100 - * h.delete("z") #=> nil - * h.delete("z") { |el| "#{el} not found" } #=> "z not found" - * - */ static mrb_value mrb_hash_delete(mrb_state *mrb, mrb_value self) { @@ -586,6 +1011,33 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } +/* find first element in the hash table, and remove it. */ +static void +ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) +{ + segment *seg = t->rootseg; + mrb_int i; + + while (seg) { + for (i=0; i<seg->size; i++) { + mrb_value key; + + if (!seg->next && i >= t->last_len) { + return; + } + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + *kp = key; + *vp = seg->e[i].val; + /* delete element */ + seg->e[i].key = mrb_undef_value(); + t->size--; + return; + } + seg = seg->next; + } +} + /* 15.2.13.4.24 */ /* * call-seq: @@ -603,22 +1055,16 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delKey, delVal; + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h && kh_size(h) > 0) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - - delKey = kh_key(h, k); - mrb_gc_protect(mrb, delKey); - delVal = mrb_hash_delete_key(mrb, hash, delKey); - mrb_gc_protect(mrb, delVal); + if (t && t->size > 0) { + mrb_value del_key, del_val; - return mrb_assoc_new(mrb, delKey, delVal); - } + ht_shift(mrb, t, &del_key, &del_val); + mrb_gc_protect(mrb, del_key); + mrb_gc_protect(mrb, del_val); + return mrb_assoc_new(mrb, del_key, del_val); } if (MRB_RHASH_DEFAULT_P(hash)) { @@ -647,10 +1093,13 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h) kh_clear(ht, mrb, h); + if (t) { + ht_free(mrb, t); + RHASH_TBL(hash) = NULL; + } return hash; } @@ -683,6 +1132,15 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) return val; } +MRB_API mrb_int +mrb_hash_size(mrb_state *mrb, mrb_value hash) +{ + htable *t = RHASH_TBL(hash); + + if (!t) return 0; + return t->size; +} + /* 15.2.13.4.20 */ /* 15.2.13.4.25 */ /* @@ -700,10 +1158,17 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_TBL(self); + mrb_int size = mrb_hash_size(mrb, self); + return mrb_fixnum_value(size); +} + +MRB_API mrb_bool +mrb_hash_empty_p(mrb_state *mrb, mrb_value self) +{ + htable *t = RHASH_TBL(self); - if (!h) return mrb_fixnum_value(0); - return mrb_fixnum_value(kh_size(h)); + if (!t) return TRUE; + return t->size == 0; } /* 15.2.13.4.12 */ @@ -716,27 +1181,17 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_value -mrb_hash_empty_p(mrb_state *mrb, mrb_value self) +static mrb_value +mrb_hash_empty_m(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_TBL(self); - - if (h) return mrb_bool_value(kh_size(h) == 0); - return mrb_true_value(); + return mrb_bool_value(mrb_hash_empty_p(mrb, self)); } -/* 15.2.13.4.29 (x)*/ -/* - * call-seq: - * hsh.to_hash => hsh - * - * Returns +self+. - */ - -static mrb_value -mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) +static int +hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) { - return hash; + mrb_ary_push(mrb, *(mrb_value*)p, key); + return 0; } /* 15.2.13.4.19 */ @@ -755,33 +1210,24 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_int end; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - mrb_value *p; - - if (!h || kh_size(h) == 0) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - end = kh_size(h)-1; - mrb_ary_set(mrb, ary, end, mrb_nil_value()); - p = RARRAY_PTR(ary); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value kv = kh_key(h, k); - mrb_hash_value hv = kh_value(h, k); - - if (hv.n <= end) { - p[hv.n] = kv; - } - else { - p[end] = kv; - } - } - } + + if (!t || (size = t->size) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + ht_foreach(mrb, t, hash_keys_i, (void*)&ary); return ary; } +static int +hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_ary_push(mrb, *(mrb_value*)p, val); + return 0; +} + /* 15.2.13.4.28 */ /* * call-seq: @@ -798,19 +1244,14 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - if (!h) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_hash_value hv = kh_value(h, k); - - mrb_ary_set(mrb, ary, hv.n, hv.v); - } - } + if (!t || (size = t->size) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + ht_foreach(mrb, t, hash_vals_i, (void*)&ary); return ary; } @@ -833,21 +1274,44 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) * */ +MRB_API mrb_bool +mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + htable *t; + + t = RHASH_TBL(hash); + if (ht_get(mrb, t, key, NULL)) { + return TRUE; + } + return FALSE; +} + static mrb_value mrb_hash_has_key(mrb_state *mrb, mrb_value hash) { mrb_value key; - khash_t(ht) *h; - khiter_t k; + mrb_bool key_p; mrb_get_args(mrb, "o", &key); + key_p = mrb_hash_key_p(mrb, hash, key); + return mrb_bool_value(key_p); +} - h = RHASH_TBL(hash); - if (h) { - k = kh_get(ht, mrb, h, key); - return mrb_bool_value(k != kh_end(h)); +struct has_v_arg { + mrb_bool found; + mrb_value val; +}; + +static int +hash_has_value_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + struct has_v_arg *arg = (struct has_v_arg*)p; + + if (mrb_equal(mrb, arg->val, val)) { + arg->found = TRUE; + return 1; } - return mrb_false_value(); + return 0; } /* 15.2.13.4.14 */ @@ -869,22 +1333,73 @@ static mrb_value mrb_hash_has_value(mrb_state *mrb, mrb_value hash) { mrb_value val; - khash_t(ht) *h; - khiter_t k; - + struct has_v_arg arg; + mrb_get_args(mrb, "o", &val); - h = RHASH_TBL(hash); + arg.found = FALSE; + arg.val = val; + ht_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); + return mrb_bool_value(arg.found); +} - if (h) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; +static int +merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + htable *h1 = (htable*)data; - if (mrb_equal(mrb, kh_value(h, k).v, val)) { - return mrb_true_value(); - } - } + ht_put(mrb, h1, key, val); + return 0; +} + +MRB_API void +mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) +{ + htable *h1, *h2; + + mrb_hash_modify(mrb, hash1); + hash2 = mrb_ensure_hash_type(mrb, hash2); + h1 = RHASH_TBL(hash1); + h2 = RHASH_TBL(hash2); + + if (!h2) return; + if (!h1) { + RHASH_TBL(hash1) = ht_copy(mrb, h2); + return; } - return mrb_false_value(); + ht_foreach(mrb, h2, merge_i, h1); + mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); + return; +} + +/* + * call-seq: + * hsh.rehash -> hsh + * + * Rebuilds the hash based on the current hash values for each key. If + * values of key objects have changed since they were inserted, this + * method will reindex <i>hsh</i>. + * + * keys = (1..17).map{|n| [n]} + * k = keys[0] + * h = {} + * keys.each{|key| h[key] = key[0]} + * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> 1 + * k[0] = keys.size + 1 + * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> nil + * h.rehash + * h[k] #=> 1 + */ +static mrb_value +mrb_hash_rehash(mrb_state *mrb, mrb_value self) +{ + ht_compact(mrb, RHASH_TBL(self)); + return self; } void @@ -904,7 +1419,7 @@ mrb_init_hash(mrb_state *mrb) 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 */ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */ - mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ + mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ 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 */ @@ -918,6 +1433,5 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */ mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ - - mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ + mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE()); } diff --git a/src/kernel.c b/src/kernel.c index f378004cb..a3c2d2ec6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,24 +14,11 @@ #include <mruby/error.h> #include <mruby/istruct.h> -typedef enum { - NOEX_PUBLIC = 0x00, - NOEX_NOSUPER = 0x01, - NOEX_PRIVATE = 0x02, - NOEX_PROTECTED = 0x04, - NOEX_MASK = 0x06, - NOEX_BASIC = 0x08, - NOEX_UNDEF = NOEX_NOSUPER, - NOEX_MODFUNC = 0x12, - NOEX_SUPER = 0x20, - NOEX_VCALL = 0x40, - NOEX_RESPONDS = 0x80 -} mrb_method_flag_t; - MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { - mrb_method_t m = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + struct RClass *c = mrb_class(mrb, obj); + mrb_method_t m = mrb_method_search_vm(mrb, &c, mid); struct RProc *p; if (MRB_METHOD_UNDEF_P(m)) return FALSE; @@ -252,18 +239,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->flags & MRB_FLAG_IS_PREPENDED) { + if (sc->flags & MRB_FL_CLASS_IS_PREPENDED) { struct RClass *c0 = sc->super; struct RClass *c1 = dc; /* copy prepended iclasses */ - while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + while (!(c0->flags & MRB_FL_CLASS_IS_ORIGIN)) { c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); c1 = c1->super; c0 = c0->super; } c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); - c1->super->flags |= MRB_FLAG_IS_ORIGIN; + c1->super->flags |= MRB_FL_CLASS_IS_ORIGIN; } if (sc->mt) { dc->mt = kh_copy(mt, mrb, sc->mt); @@ -348,7 +335,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags = mrb_obj_ptr(self)->flags; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FL_OBJ_IS_FROZEN; return clone; } @@ -447,24 +434,12 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); + } } return self; } @@ -472,26 +447,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_frozen(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ @@ -505,7 +461,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self) * <code>Hash</code>. Any hash value that exceeds the capacity of a * <code>Fixnum</code> will be truncated before being used. */ -MRB_API mrb_value +static mrb_value mrb_obj_hash(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); @@ -551,96 +507,6 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); } -/* 15.3.1.3.20 */ -/* - * call-seq: - * obj.instance_variable_defined?(symbol) -> true or false - * - * Returns <code>true</code> if the given instance variable is - * defined in <i>obj</i>. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_defined?(:@a) #=> true - * fred.instance_variable_defined?("@b") #=> true - * fred.instance_variable_defined?("@c") #=> false - */ -static mrb_value -mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) -{ - mrb_sym sym; - - mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); - return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); -} - -/* 15.3.1.3.21 */ -/* - * call-seq: - * obj.instance_variable_get(symbol) -> obj - * - * Returns the value of the given instance variable, or nil if the - * instance variable is not set. The <code>@</code> part of the - * variable name should be included for regular instance - * variables. Throws a <code>NameError</code> exception if the - * supplied symbol is not valid as an instance variable name. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_get(:@a) #=> "cat" - * fred.instance_variable_get("@b") #=> 99 - */ -static mrb_value -mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - - mrb_get_args(mrb, "n", &iv_name); - mrb_iv_check(mrb, iv_name); - return mrb_iv_get(mrb, self, iv_name); -} - -/* 15.3.1.3.22 */ -/* - * call-seq: - * obj.instance_variable_set(symbol, obj) -> obj - * - * Sets the instance variable names by <i>symbol</i> to - * <i>object</i>, thereby frustrating the efforts of the class's - * author to attempt to provide proper encapsulation. The variable - * did not have to exist prior to this call. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_set(:@a, 'dog') #=> "dog" - * fred.instance_variable_set(:@c, 'cat') #=> "cat" - * fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">" - */ -static mrb_value -mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - mrb_value val; - - mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_check(mrb, iv_name); - mrb_iv_set(mrb, self, iv_name, val); - return val; -} - /* 15.3.1.3.24 */ /* 15.3.1.3.26 */ /* @@ -681,124 +547,6 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) KHASH_DECLARE(st, mrb_sym, char, FALSE) KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal) -static void -method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) -{ - khint_t i; - - khash_t(mt) *h = klass->mt; - if (!h || kh_size(h) == 0) return; - for (i=0;i<kh_end(h);i++) { - if (kh_exist(h, i)) { - mrb_method_t m = kh_value(h, i); - if (MRB_METHOD_UNDEF_P(m)) continue; - kh_put(st, mrb, set, kh_key(h, i)); - } - } -} - -mrb_value -mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) -{ - khint_t i; - mrb_value ary; - mrb_bool prepended = FALSE; - struct RClass* oldklass; - khash_t(st)* set = kh_init(st, mrb); - - if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { - MRB_CLASS_ORIGIN(klass); - prepended = TRUE; - } - - oldklass = 0; - while (klass && (klass != oldklass)) { - method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS && !prepended) || - (klass->tt == MRB_TT_SCLASS)) { - } - else { - if (!recur) break; - } - oldklass = klass; - klass = klass->super; - } - - ary = mrb_ary_new_capa(mrb, kh_size(set)); - for (i=0;i<kh_end(set);i++) { - if (kh_exist(set, i)) { - mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); - } - } - kh_destroy(st, mrb, set); - - return ary; -} - -static mrb_value -mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) -{ - khint_t i; - mrb_value ary; - struct RClass* klass; - khash_t(st)* set = kh_init(st, mrb); - - klass = mrb_class(mrb, obj); - - if (klass && (klass->tt == MRB_TT_SCLASS)) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - if (recur) { - while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - } - - ary = mrb_ary_new(mrb); - for (i=0;i<kh_end(set);i++) { - if (kh_exist(set, i)) { - mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); - } - } - kh_destroy(st, mrb, set); - - return ary; -} - -static mrb_value -mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag) -{ - return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); -} -/* 15.3.1.3.31 */ -/* - * call-seq: - * obj.methods -> array - * - * Returns a list of the names of methods publicly accessible in - * <i>obj</i>. This will include all the methods accessible in - * <i>obj</i>'s ancestors. - * - * class Klass - * def kMethod() - * end - * end - * k = Klass.new - * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, - * # :class, :instance_variable_set, - * # :methods, :extend, :__send__, :instance_eval] - * k.methods.length #=> 42 - */ -static mrb_value -mrb_obj_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ -} - /* 15.3.1.3.32 */ /* * call_seq: @@ -813,57 +561,6 @@ mrb_false(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.3.36 */ -/* - * call-seq: - * obj.private_methods(all=true) -> array - * - * Returns the list of private methods accessible to <i>obj</i>. If - * the <i>all</i> parameter is set to <code>false</code>, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_private_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ -} - -/* 15.3.1.3.37 */ -/* - * call-seq: - * obj.protected_methods(all=true) -> array - * - * Returns the list of protected methods accessible to <i>obj</i>. If - * the <i>all</i> parameter is set to <code>false</code>, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ -} - -/* 15.3.1.3.38 */ -/* - * call-seq: - * obj.public_methods(all=true) -> array - * - * Returns the list of public methods accessible to <i>obj</i>. If - * the <i>all</i> parameter is set to <code>false</code>, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_public_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ -} - /* 15.3.1.2.12 */ /* 15.3.1.3.40 */ /* @@ -912,16 +609,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self) return mrb_nil_value(); /* not reached */ } -static mrb_value -mrb_krn_class_defined(mrb_state *mrb, mrb_value self) -{ - mrb_value str; - - mrb_get_args(mrb, "S", &str); - return mrb_bool_value(mrb_class_defined(mrb, RSTRING_PTR(str))); -} - - /* 15.3.1.3.41 */ /* * call-seq: @@ -951,7 +638,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); @@ -1018,6 +705,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { return mrb_respond_to(mrb, obj, id); } + /* 15.3.1.3.43 */ /* * call-seq: @@ -1037,45 +725,16 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { - mrb_value mid; mrb_sym id, rtm_id; - mrb_bool priv = FALSE, respond_to_p = TRUE; - - mrb_get_args(mrb, "o|b", &mid, &priv); - - if (mrb_symbol_p(mid)) { - id = mrb_symbol(mid); - } - else { - mrb_value tmp; - if (mrb_string_p(mid)) { - tmp = mrb_check_intern_str(mrb, mid); - } - else { - tmp = mrb_check_string_type(mrb, mid); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, mid); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); - } - tmp = mrb_check_intern_str(mrb, tmp); - } - if (mrb_nil_p(tmp)) { - respond_to_p = FALSE; - } - else { - id = mrb_symbol(tmp); - } - } - - if (respond_to_p) { - respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); - } + mrb_bool priv = FALSE, respond_to_p; + mrb_get_args(mrb, "n|b", &id, &priv); + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); if (!respond_to_p) { rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { mrb_value args[2], v; - args[0] = mid; + args[0] = mrb_symbol_value(id); args[1] = mrb_bool_value(priv); v = mrb_funcall_argv(mrb, self, rtm_id, 2, args); return mrb_bool_value(mrb_bool(v)); @@ -1084,67 +743,6 @@ obj_respond_to(mrb_state *mrb, mrb_value self) return mrb_bool_value(respond_to_p); } -/* 15.3.1.3.45 */ -/* - * call-seq: - * obj.singleton_methods(all=true) -> array - * - * Returns an array of the names of singleton methods for <i>obj</i>. - * If the optional <i>all</i> parameter is true, the list will include - * methods in modules included in <i>obj</i>. - * Only public and protected singleton methods are returned. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> [:four] - * a.singleton_methods(false) #=> [:two, :one] - * a.singleton_methods #=> [:two, :one, :three] - */ -static mrb_value -mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_singleton_methods(mrb, recur, self); -} - -static mrb_value -mod_define_singleton_method(mrb_state *mrb, mrb_value self) -{ - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value blk = mrb_nil_value(); - - mrb_get_args(mrb, "n&", &mid, &blk); - 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); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); - return mrb_symbol_value(mid); -} - static mrb_value mrb_obj_ceqq(mrb_state *mrb, mrb_value self) { @@ -1162,51 +760,8 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.2.7 */ -/* - * call-seq: - * local_variables -> array - * - * Returns the names of local variables in the current scope. - * - * [mruby limitation] - * If variable symbol information was stripped out from - * compiled binary files using `mruby-strip -l`, this - * method always returns an empty array. - */ -static mrb_value -mrb_local_variables(mrb_state *mrb, mrb_value self) -{ - struct RProc *proc; - mrb_irep *irep; - mrb_value vars; - size_t i; - - proc = mrb->c->ci[-1].proc; - - if (MRB_PROC_CFUNC_P(proc)) { - return mrb_ary_new(mrb); - } - vars = mrb_hash_new(mrb); - while (proc) { - if (MRB_PROC_CFUNC_P(proc)) break; - irep = proc->body.irep; - if (!irep->lv) break; - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); - } - } - if (!MRB_PROC_ENV_P(proc)) break; - proc = proc->upper; - //if (MRB_PROC_SCOPE_P(proc)) break; - if (!proc->c) break; - } - - return mrb_hash_keys(mrb, vars); -} - mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); + void mrb_init_kernel(mrb_state *mrb) { @@ -1214,13 +769,10 @@ mrb_init_kernel(mrb_state *mrb) mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */ mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ - mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ - mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ ; /* 15.3.1.2.11 */ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */ - mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ @@ -1228,43 +780,30 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ - mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ - mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ - mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ - mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ - mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + 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 */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ #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, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ 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, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ - mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ - mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ 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, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ - mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ - mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); 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, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); + 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_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); + mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/src/load.c b/src/load.c index ddf3cdfbf..97eafdbb5 100644 --- a/src/load.c +++ b/src/load.c @@ -7,6 +7,7 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <math.h> #include <mruby/dump.h> #include <mruby/irep.h> #include <mruby/proc.h> @@ -40,6 +41,23 @@ offset_crc_body(void) return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc); } +#ifndef MRB_WITHOUT_FLOAT +static double +str_to_double(mrb_state *mrb, mrb_value str) +{ + 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); +} +#endif + static mrb_irep* read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { @@ -68,7 +86,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag /* Binary Data Section */ /* ISEQ BLOCK */ - irep->ilen = (size_t)bin_to_uint32(src); + irep->ilen = (uint16_t)bin_to_uint32(src); src += sizeof(uint32_t); src += skip_padding(src); @@ -79,27 +97,14 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag if ((flags & FLAG_SRC_MALLOC) == 0 && (flags & FLAG_BYTEORDER_NATIVE)) { irep->iseq = (mrb_code*)src; - src += sizeof(uint32_t) * irep->ilen; + src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; } else { - irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); - if (flags & FLAG_BYTEORDER_NATIVE) { - memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); - src += sizeof(uint32_t) * irep->ilen; - } - else if (flags & FLAG_BYTEORDER_BIG) { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ - src += sizeof(uint32_t); - } - } - else { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ - src += sizeof(uint32_t); - } - } + size_t data_len = sizeof(mrb_code) * irep->ilen; + irep->iseq = (mrb_code *)mrb_malloc(mrb, data_len); + memcpy(irep->iseq, src, data_len); + src += data_len; } } @@ -138,7 +143,7 @@ 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, mrb_str_to_dbl(mrb, s, FALSE)); + irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s)); break; #endif @@ -157,7 +162,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } /* SYMS BLOCK */ - irep->slen = (size_t)bin_to_uint32(src); /* syms length */ + irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */ src += sizeof(uint32_t); if (irep->slen > 0) { if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { @@ -229,74 +234,6 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) } static int -read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) -{ - size_t i, fname_len, niseq; - char *fname; - uint16_t *lines; - - *len = 0; - bin += sizeof(uint32_t); /* record size */ - *len += sizeof(uint32_t); - fname_len = bin_to_uint16(bin); - bin += sizeof(uint16_t); - *len += sizeof(uint16_t); - fname = (char *)mrb_malloc(mrb, fname_len + 1); - memcpy(fname, bin, fname_len); - fname[fname_len] = '\0'; - bin += fname_len; - *len += fname_len; - - niseq = (size_t)bin_to_uint32(bin); - bin += sizeof(uint32_t); /* niseq */ - *len += sizeof(uint32_t); - - if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { - return MRB_DUMP_GENERAL_FAILURE; - } - lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t)); - for (i = 0; i < niseq; i++) { - lines[i] = bin_to_uint16(bin); - bin += sizeof(uint16_t); /* niseq */ - *len += sizeof(uint16_t); - } - - irep->filename = fname; - irep->lines = lines; - return MRB_DUMP_OK; -} - -static int -read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) -{ - int result = read_lineno_record_1(mrb, bin, irep, lenp); - int i; - - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - size_t len; - - result = read_lineno_record(mrb, bin, irep->reps[i], &len); - if (result != MRB_DUMP_OK) break; - bin += len; - *lenp += len; - } - return result; -} - -static int -read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) -{ - size_t len; - - len = 0; - bin += sizeof(struct rite_section_lineno_header); - - /* Read Binary Data Section */ - return read_lineno_record(mrb, bin, irep, &len); -} - -static int read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) { const uint8_t *bin = start; @@ -320,7 +257,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { mrb_irep_debug_info_file *file; uint16_t filename_idx; - mrb_int len; file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file)); irep->debug_info->files[f_idx] = file; @@ -333,8 +269,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * bin += sizeof(uint16_t); mrb_assert(filename_idx < filenames_len); file->filename_sym = filenames[filename_idx]; - len = 0; - file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len); file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t); @@ -525,10 +459,14 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + if (bufsize < sizeof(struct rite_binary_header)) { + 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; @@ -545,16 +483,24 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t return MRB_DUMP_INVALID_FILE_HEADER; } + if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + return MRB_DUMP_INVALID_FILE_HEADER; + } + if (crc) { *crc = bin_to_uint16(header->binary_crc); } *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (bufsize < *bin_size) { + return MRB_DUMP_READ_FAULT; + } + return MRB_DUMP_OK; } static mrb_irep* -read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -567,7 +513,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return NULL; } - result = read_binary_header(bin, &bin_size, &crc, &flags); + result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -584,13 +530,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { - if (!irep) return NULL; /* corrupted data */ - result = read_section_lineno(mrb, bin, irep); - if (result < MRB_DUMP_OK) { - return NULL; - } - } else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); @@ -614,13 +553,19 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) mrb_irep* mrb_read_irep(mrb_state *mrb, const uint8_t *bin) { -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_ETEXT_EDATA) || 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, flags); + return read_irep(mrb, bin, (size_t)-1, flags); +} + +MRB_API mrb_irep* +mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC); } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -657,11 +602,23 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) } MRB_API mrb_value +mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c); +} + +MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); } +MRB_API mrb_value +mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL); +} + #ifndef MRB_DISABLE_STDIO mrb_irep* @@ -682,7 +639,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf, header_size, 1, fp) == 0) { goto irep_exit; } - result = read_binary_header(buf, &buf_size, NULL, &flags); + result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags); if (result != MRB_DUMP_OK || buf_size <= header_size) { goto irep_exit; } @@ -691,7 +648,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { goto irep_exit; } - irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC); irep_exit: mrb_free(mrb, buf); diff --git a/src/mruby_core.rake b/src/mruby_core.rake index bb3d7b633..73fddb220 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -5,16 +5,15 @@ MRuby.each_target do objs = Dir.glob("#{current_dir}/*.c").map { |f| next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/ - next nil if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") and f =~ /fmt_fp.c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact if cxx_exception_enabled? objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end - self.libmruby << objs + self.libmruby_objs << objs - file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| + file libmruby_core_static => objs do |t| archiver.run t.name, t.prerequisites end end diff --git a/src/numeric.c b/src/numeric.c index 4e5fc394e..4288df44a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -10,6 +10,7 @@ #endif #include <limits.h> #include <stdlib.h> +#include <string.h> #include <mruby.h> #include <mruby/array.h> @@ -23,9 +24,9 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define MRB_FLO_TO_STR_FMT "%.8g" +#define FLO_TO_STR_PREC 8 #else -#define MRB_FLO_TO_STR_FMT "%.16g" +#define FLO_TO_STR_PREC 16 #endif #endif @@ -43,6 +44,15 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) } return mrb_float(val); } + +MRB_API mrb_value +mrb_int_value(mrb_state *mrb, mrb_float f) +{ + if (FIXABLE_FLOAT(f)) { + return mrb_fixnum_value((mrb_int)f); + } + return mrb_float_value(mrb, f); +} #endif /* @@ -55,7 +65,7 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -102,6 +112,25 @@ num_pow(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +integral_idiv(mrb_state *mrb, mrb_value x) +{ +#ifdef MRB_WITHOUT_FLOAT + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) { + mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + } + return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); +#else + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y); +#endif +} + /* 15.2.8.3.4 */ /* 15.2.9.3.4 */ /* @@ -113,19 +142,6 @@ num_pow(mrb_state *mrb, mrb_value x) * result. */ -mrb_value -mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) -{ -#ifdef MRB_WITHOUT_FLOAT - if (!mrb_fixnum_p(y)) { - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); - } - return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); -#else - return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); -#endif -} - /* 15.2.9.3.19(x) */ /* * call-seq: @@ -135,7 +151,7 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -153,6 +169,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + return mrb_Float(mrb, self); + } +#endif + + return self; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -177,10 +209,49 @@ num_div(mrb_state *mrb, mrb_value x) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - if (isnan(mrb_float(flt))) { + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "-Infinity") + : mrb_str_new_lit(mrb, "Infinity"); + } + else if (isnan(f)) { return mrb_str_new_lit(mrb, "NaN"); } - return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); + else { + char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; + mrb_value str = mrb_float_to_str(mrb, flt, fmt); + mrb_int len; + char *begp, *p, *endp; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (p = begp, endp = p + len; p < endp; ++p) { + if (*p == '.') { + return str; + } + 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); + return str; + } + } + + 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); + } + + return str; + } } /* 15.2.9.3.2 */ @@ -220,29 +291,40 @@ flo_mul(mrb_state *mrb, mrb_value x) } static void -flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) +flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) { - mrb_float div; - mrb_float mod; + double div, mod; + if (isnan(y)) { + /* y is NaN so all results are NaN */ + div = mod = y; + goto exit; + } if (y == 0.0) { - if (x > 0.0) div = INFINITY; - else if (x < 0.0) div = -INFINITY; - else div = NAN; /* x == 0.0 */ + if (x == 0) div = NAN; + else if (x > 0.0) div = INFINITY; + else div = -INFINITY; /* x < 0.0 */ mod = NAN; + goto exit; + } + if ((x == 0.0) || (isinf(y) && !isinf(x))) { + mod = x; } else { mod = fmod(x, y); - if (isinf(x) && isfinite(y)) - div = x; - else - div = (x - mod) / y; - if (y*mod < 0) { - mod += y; - div -= 1.0; - } } - + if (isinf(x) && !isinf(y)) { + div = x; + } + else { + div = (x - mod) / y; + if (modp && divp) div = round(div); + } + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + exit: if (modp) *modp = mod; if (divp) *divp = div; } @@ -302,7 +384,7 @@ flo_eql(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); if (!mrb_float_p(y)) return mrb_false_value(); - return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + return mrb_bool_value(mrb_float(x) == mrb_float(y)); } /* 15.2.9.3.7 */ @@ -354,7 +436,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (FIXABLE(v)) { + if (TYPED_FIXABLE(v,int64_t)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); @@ -417,12 +499,16 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) if (width < 0) { while (width++) { val /= 2; + if (val < 1.0) { + val = 0; + break; + } } #if defined(_ISOC99_SOURCE) val = trunc(val); #else if (val > 0){ - val = floor(val); + val = floor(val); } else { val = ceil(val); } @@ -436,14 +522,11 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val *= 2; } } - if (FIXABLE_FLOAT(val)) { - return mrb_fixnum_value((mrb_int)val); - } - return mrb_float_value(mrb, val); + return mrb_int_value(mrb, val); } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -452,7 +535,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -545,10 +628,7 @@ flo_floor(mrb_state *mrb, mrb_value num) mrb_float f = floor(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.8 */ @@ -571,10 +651,7 @@ flo_ceil(mrb_state *mrb, mrb_value num) mrb_float f = ceil(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.12 */ @@ -655,7 +732,7 @@ flo_round(mrb_state *mrb, mrb_value num) if (!isfinite(number)) return num; return mrb_float_value(mrb, number); } - return mrb_fixnum_value((mrb_int)number); + return mrb_int_value(mrb, number); } /* 15.2.9.3.14 */ @@ -663,7 +740,6 @@ flo_round(mrb_state *mrb, mrb_value num) /* * call-seq: * flt.to_i -> integer - * flt.to_int -> integer * flt.truncate -> integer * * Returns <i>flt</i> truncated to an <code>Integer</code>. @@ -678,10 +754,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) if (f < 0.0) f = ceil(f); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } static mrb_value @@ -703,7 +776,6 @@ flo_nan_p(mrb_state *mrb, mrb_value num) /* * call-seq: * int.to_i -> integer - * int.to_int -> integer * * As <i>int</i> is already an <code>Integer</code>, all these * methods simply return the receiver. @@ -715,8 +787,8 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } -mrb_value -mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -740,6 +812,21 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_mul(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.3 */ /* * call-seq: @@ -756,7 +843,7 @@ fix_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - return mrb_fixnum_mul(mrb, x, y); + return fixnum_mul(mrb, x, y); } static void @@ -868,7 +955,7 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value a, b; flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -886,7 +973,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -1141,7 +1228,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) * (in particular infinite or NaN) * to numerical classes which don't support them. * - * Float::INFINITY.to_r + * Float::INFINITY.to_i * * <em>raises the exception:</em> * @@ -1160,25 +1247,20 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) else { mrb_float d = mrb_float(x); - if (isinf(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); - } - if (isnan(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); - } + mrb_check_num_exact(mrb, d); if (FIXABLE_FLOAT(d)) { z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); } } return mrb_fixnum_value(z); } #endif -mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1202,6 +1284,21 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_plus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.1 */ /* * call-seq: @@ -1217,11 +1314,11 @@ fix_plus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_plus(mrb, self, other); + return fixnum_plus(mrb, self, other); } -mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1244,6 +1341,21 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_minus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.2 */ /* 15.2.8.3.16 */ /* @@ -1260,7 +1372,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_minus(mrb, self, other); + return fixnum_minus(mrb, self, other); } @@ -1370,7 +1482,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in <code>Comparable</code>. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1390,7 +1502,7 @@ cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1403,7 +1515,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1416,7 +1528,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1429,7 +1541,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1478,22 +1590,25 @@ flo_plus(mrb_state *mrb, mrb_value x) void mrb_init_numeric(mrb_state *mrb) { - struct RClass *numeric, *integer, *fixnum; + struct RClass *numeric, *integer, *fixnum, *integral; #ifndef MRB_WITHOUT_FLOAT struct RClass *fl; #endif + integral = mrb_define_module(mrb, "Integral"); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); @@ -1545,8 +1660,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "<<", flo_rshift, 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, "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 */ @@ -1569,6 +1684,7 @@ mrb_init_numeric(mrb_state *mrb) #ifdef NAN mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); #endif + + mrb_include_module(mrb, fl, integral); #endif - mrb_define_module(mrb, "Integral"); } diff --git a/src/object.c b/src/object.c index 8724c5416..7c1879019 100644 --- a/src/object.c +++ b/src/object.c @@ -323,19 +323,6 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho } MRB_API mrb_value -mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, FALSE); - if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { - return mrb_nil_value(); - } - return v; -} - -MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { mrb_value v; @@ -447,8 +434,10 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); - mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + if (!mrb_immediate_p(obj)) { + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + } mrb_str_cat_lit(mrb, str, ">"); return str; @@ -505,25 +494,22 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) return FALSE; } -static mrb_value -mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, TRUE); - if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", - type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); - } - return v; -} - MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { - return mrb_to_integer(mrb, val, "to_int"); + + if (!mrb_fixnum_p(val)) { + mrb_value type; + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(val)) { + return mrb_flo_to_fixnum(mrb, val); + } +#endif + type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + } + return val; } MRB_API mrb_value @@ -533,18 +519,12 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) if (mrb_nil_p(val)) { if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: if (base != 0) goto arg_error; - else { - mrb_float f = mrb_float(val); - if (FIXABLE_FLOAT(f)) { - break; - } - } return mrb_flo_to_fixnum(mrb, val); #endif @@ -568,11 +548,8 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } - tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); - if (mrb_nil_p(tmp) || !mrb_fixnum_p(tmp)) { - tmp = mrb_to_integer(mrb, val, "to_i"); - } - return tmp; + /* to raise TypeError */ + return mrb_to_int(mrb, val); } MRB_API mrb_value @@ -605,6 +582,70 @@ 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)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", + inspect_type(mrb, str)); + } + return str; +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) return mrb_nil_value(); + return str; +} + +MRB_API mrb_value +mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", + inspect_type(mrb, ary)); + } + return ary; +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) return mrb_nil_value(); + return ary; +} + +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash", + inspect_type(mrb, hash)); + } + return hash; +} + +MRB_API mrb_value +mrb_check_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) return mrb_nil_value(); + return hash; +} + +MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0)); diff --git a/src/proc.c b/src/proc.c index c6e9be433..094fff816 100644 --- a/src/proc.c +++ b/src/proc.c @@ -10,7 +10,7 @@ #include <mruby/opcode.h> static mrb_code call_iseq[] = { - MKOP_A(OP_CALL, 0), + OP_CALL, }; struct RProc* @@ -63,12 +63,12 @@ closure_setup(mrb_state *mrb, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; struct RProc *up = p->upper; - struct REnv *e; + struct REnv *e = NULL; - if (ci->env) { + if (ci && ci->env) { e = ci->env; } - else { + else if (up) { struct RClass *tc = MRB_PROC_TARGET_CLASS(p); e = env_new(mrb, up->body.irep->nlocals); @@ -78,9 +78,11 @@ closure_setup(mrb_state *mrb, struct RProc *p) mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); } } - p->e.env = e; - p->flags |= MRB_PROC_ENVSET; - mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + if (e) { + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + } } struct RProc* @@ -211,46 +213,11 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) return self; } -int -mrb_proc_cfunc_p(struct RProc *p) -{ - return MRB_PROC_CFUNC_P(p); -} - /* 15.2.17.4.2 */ static mrb_value -mrb_proc_arity(mrb_state *mrb, mrb_value self) +proc_arity(mrb_state *mrb, mrb_value self) { - struct RProc *p = mrb_proc_ptr(self); - struct mrb_irep *irep; - mrb_code *iseq; - mrb_aspec aspec; - int ma, op, ra, pa, arity; - - if (MRB_PROC_CFUNC_P(p)) { - /* TODO cfunc aspec not implemented yet */ - return mrb_fixnum_value(-1); - } - - irep = p->body.irep; - if (!irep) { - return mrb_fixnum_value(0); - } - - iseq = irep->iseq; - /* arity is depend on OP_ENTER */ - if (GET_OPCODE(*iseq) != OP_ENTER) { - return mrb_fixnum_value(0); - } - - aspec = GETARG_Ax(*iseq); - ma = MRB_ASPEC_REQ(aspec); - op = MRB_ASPEC_OPT(aspec); - ra = MRB_ASPEC_REST(aspec); - pa = MRB_ASPEC_POST(aspec); - arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; - - return mrb_fixnum_value(arity); + return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self))); } /* 15.3.1.2.6 */ @@ -285,6 +252,40 @@ proc_lambda(mrb_state *mrb, mrb_value self) return blk; } +mrb_int +mrb_proc_arity(const struct RProc *p) +{ + struct mrb_irep *irep; + mrb_code *pc; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return -1; + } + + irep = p->body.irep; + if (!irep) { + return 0; + } + + pc = irep->iseq; + /* arity is depend on OP_ENTER */ + if (*pc != OP_ENTER) { + return 0; + } + + aspec = PEEK_W(pc+1); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return arity; +} + void mrb_init_proc(mrb_state *mrb) { @@ -299,15 +300,15 @@ mrb_init_proc(mrb_state *mrb) call_irep->ilen = 1; call_irep->nregs = 2; /* receiver and block */ - mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); p = mrb_proc_new(mrb, call_irep); MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); - mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ - mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ + mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */ + mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */ } diff --git a/src/range.c b/src/range.c index 0360b48ae..c9dfb2b3c 100644 --- a/src/range.c +++ b/src/range.c @@ -10,19 +10,12 @@ #include <mruby/string.h> #include <mruby/array.h> -MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value v) -{ - struct RRange *r = (struct RRange*)mrb_ptr(v); - - if (r->edges == NULL) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); - } - return r; -} +#define RANGE_INITIALIZED_MASK 1 +#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) +#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) static void -range_check(mrb_state *mrb, mrb_value a, mrb_value b) +r_check(mrb_state *mrb, mrb_value a, mrb_value b) { mrb_value ans; enum mrb_vtype ta; @@ -46,18 +39,83 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) { - struct RRange *r; + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ - range_check(mrb, beg, end); - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_gt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; +} + +static mrb_bool +r_ge(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == 1) return TRUE; + } + + return FALSE; +} + +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) +{ +#ifndef MRB_RANGE_EMBED r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - r->edges->beg = beg; - r->edges->end = end; - r->excl = excl; - return mrb_range_value(r); +#endif +} + +static struct RRange * +range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + r_check(mrb, beg, end); + + if (r) { + if (RANGE_INITIALIZED_P(r)) { + /* Ranges are immutable, so that they should be initialized only once. */ + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); + } + else { + range_ptr_alloc_edges(mrb, r); + } + } + else { + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + range_ptr_alloc_edges(mrb, r); + } + + RANGE_BEG(r) = beg; + RANGE_END(r) = end; + RANGE_EXCL(r) = excl; + RANGE_INITIALIZED(r); + + return r; +} + +static void +range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + range_ptr_init(mrb, r, beg, end, excl); + mrb_write_barrier(mrb, (struct RBasic*)r); } /* @@ -67,12 +125,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) * * Returns the first object in <i>rng</i>. */ -mrb_value -mrb_range_beg(mrb_state *mrb, mrb_value range) +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->beg; + return mrb_range_beg(mrb, range); } /* @@ -85,13 +141,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) * (1..10).end #=> 10 * (1...10).end #=> 10 */ - -mrb_value -mrb_range_end(mrb_state *mrb, mrb_value range) +static mrb_value +range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->end; + return mrb_range_end(mrb, range); } /* @@ -100,27 +153,12 @@ mrb_range_end(mrb_state *mrb, mrb_value range) * * Returns <code>true</code> if <i>range</i> excludes its end value. */ -mrb_value -mrb_range_excl(mrb_state *mrb, mrb_value range) +static mrb_value +range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return mrb_bool_value(r->excl); + return mrb_bool_value(mrb_range_excl_p(mrb, range)); } -static void -range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - range_check(mrb, beg, end); - r->excl = exclude_end; - if (!r->edges) { - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - } - r->edges->beg = beg; - r->edges->end = end; -} /* * call-seq: * Range.new(start, end, exclusive=false) => range @@ -129,25 +167,17 @@ range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bo * parameter is omitted or is <code>false</code>, the <i>range</i> will include * the end object; otherwise, it will be excluded. */ - -mrb_value -mrb_range_initialize(mrb_state *mrb, mrb_value range) +static mrb_value +range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; - mrb_bool exclusive; - mrb_int n; + mrb_bool exclusive = FALSE; - n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); - if (n != 3) { - exclusive = FALSE; - } - /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_raw_ptr(range)->edges) { - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); - } - range_init(mrb, range, beg, end, exclusive); + mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } + /* * call-seq: * range == obj => true or false @@ -160,11 +190,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false - * */ - -mrb_value -mrb_range_eq(mrb_state *mrb, mrb_value range) +static mrb_value +range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; @@ -179,60 +207,22 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) rr = mrb_range_ptr(mrb, range); ro = mrb_range_ptr(mrb, obj); - v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); - v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); - if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { + v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); + v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); + if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { return mrb_false_value(); } return mrb_true_value(); } -static mrb_bool -r_le(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == -1) return TRUE; - } - - return FALSE; -} - -static mrb_bool -r_gt(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; -} - -static mrb_bool -r_ge(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == 1) return TRUE; - } - - return FALSE; -} - /* * call-seq: * range === obj => true or false * range.member?(val) => true or false * range.include?(val) => true or false - * */ -mrb_value -mrb_range_include(mrb_state *mrb, mrb_value range) +static mrb_value +range_include(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -241,48 +231,15 @@ mrb_range_include(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - (r->excl ? r_gt(mrb, end, val) /* end > val */ - : r_ge(mrb, end, val)); /* end >= val */ + beg = RANGE_BEG(r); + end = RANGE_END(r); + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } -MRB_API mrb_int -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) -{ - mrb_int beg, end; - struct RRange *r; - - if (mrb_type(range) != MRB_TT_RANGE) return 0; - r = mrb_range_ptr(mrb, range); - - beg = mrb_int(mrb, r->edges->beg); - end = mrb_int(mrb, r->edges->end); - - if (beg < 0) { - beg += len; - if (beg < 0) return 2; - } - - if (trunc) { - if (beg > len) return 2; - if (end > len) end = len; - } - - if (end < 0) end += len; - if (!r->excl && (!trunc || end < len)) - end++; /* include end point */ - len = end - beg; - if (len < 0) len = 0; - - *begp = beg; - *lenp = len; - return 1; -} - /* 15.2.14.4.12(x) */ /* * call-seq: @@ -290,17 +247,16 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, * * Convert this range object to a printable form. */ - static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_obj_as_string(mrb, r->edges->beg); - str2 = mrb_obj_as_string(mrb, r->edges->end); + str = mrb_obj_as_string(mrb, RANGE_BEG(r)); + str2 = mrb_obj_as_string(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -315,17 +271,16 @@ range_to_s(mrb_state *mrb, mrb_value range) * <code>inspect</code> to convert the start and end * objects). */ - static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_inspect(mrb, r->edges->beg); - str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_inspect(mrb, RANGE_BEG(r)); + str2 = mrb_inspect(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -343,9 +298,7 @@ range_inspect(mrb_state *mrb, mrb_value range) * (0..2).eql?(0..2) #=> true * (0..2).eql?(Range.new(0,2)) #=> true * (0..2).eql?(0...2) #=> false - * */ - static mrb_value range_eql(mrb_state *mrb, mrb_value range) { @@ -355,16 +308,14 @@ range_eql(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { - return mrb_false_value(); - } + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value(); if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); r = mrb_range_ptr(mrb, range); o = mrb_range_ptr(mrb, obj); - if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || - !mrb_eql(mrb, r->edges->end, o->edges->end) || - (r->excl != o->excl)) { + if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) || + !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) || + (RANGE_EXCL(r) != RANGE_EXCL(o))) { return mrb_false_value(); } return mrb_true_value(); @@ -385,7 +336,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) } r = mrb_range_ptr(mrb, src); - range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r)); return copy; } @@ -401,7 +352,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == MRB_RANGE_OK) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); @@ -420,6 +371,66 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con } void +mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) +{ + if (RANGE_INITIALIZED_P(r)) { + mrb_gc_mark_value(mrb, RANGE_BEG(r)); + mrb_gc_mark_value(mrb, RANGE_END(r)); + } +} + +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); + return mrb_range_value(r); +} + +MRB_API enum mrb_range_beg_len +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +{ + mrb_int beg, end; + struct RRange *r; + + if (mrb_type(range) != MRB_TT_RANGE) return MRB_RANGE_TYPE_MISMATCH; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); + + if (beg < 0) { + beg += len; + if (beg < 0) return MRB_RANGE_OUT; + } + + if (trunc) { + if (beg > len) return MRB_RANGE_OUT; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return MRB_RANGE_OK; +} + +void mrb_init_range(mrb_state *mrb) { struct RClass *r; @@ -428,17 +439,16 @@ mrb_init_range(mrb_state *mrb) mrb->range_class = r; MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); - mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ - mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ - mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ - mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ - mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ - mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ - mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ - mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ - mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ - mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ - + mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ + mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ 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) */ diff --git a/src/state.c b/src/state.c index 18d104555..c42df71ba 100644 --- a/src/state.c +++ b/src/state.c @@ -26,6 +26,7 @@ mrb_open_core(mrb_allocf f, void *ud) static const struct mrb_context mrb_context_zero = { 0 }; mrb_state *mrb; + if (f == NULL) f = mrb_default_allocf; mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud); if (mrb == NULL) return NULL; @@ -56,38 +57,6 @@ mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) } } -struct alloca_header { - struct alloca_header *next; - char buf[1]; -}; - -MRB_API void* -mrb_alloca(mrb_state *mrb, size_t size) -{ - struct alloca_header *p; - - p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); - p->next = mrb->mems; - mrb->mems = p; - return (void*)p->buf; -} - -static void -mrb_alloca_free(mrb_state *mrb) -{ - struct alloca_header *p; - struct alloca_header *tmp; - - if (mrb == NULL) return; - p = mrb->mems; - - while (p) { - tmp = p; - p = p->next; - mrb_free(mrb, tmp); - } -} - MRB_API mrb_state* mrb_open(void) { @@ -168,10 +137,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, irep->reps); mrb_free(mrb, irep->lv); - if (irep->own_filename) { - mrb_free(mrb, (void *)irep->filename); - } - mrb_free(mrb, irep->lines); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); } @@ -259,7 +224,6 @@ mrb_close(mrb_state *mrb) mrb_gc_free_gv(mrb); mrb_free_context(mrb, mrb->root_c); mrb_free_symtbl(mrb); - mrb_alloca_free(mrb); mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } @@ -273,7 +237,6 @@ mrb_add_irep(mrb_state *mrb) irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); *irep = mrb_irep_zero; irep->refcnt = 1; - irep->own_filename = FALSE; return irep; } diff --git a/src/string.c b/src/string.c index 5cca6d460..6b7cced13 100644 --- a/src/string.c +++ b/src/string.c @@ -20,6 +20,7 @@ #include <mruby/class.h> #include <mruby/range.h> #include <mruby/string.h> +#include <mruby/numeric.h> #include <mruby/re.h> typedef struct mrb_shared_string { @@ -82,7 +83,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) } static inline void -str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +str_with_class(struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; } @@ -92,7 +93,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) { struct RString *s = str_new(mrb, 0, 0); - str_with_class(mrb, s, str); + str_with_class(s, str); return mrb_obj_value(s); } @@ -156,13 +157,6 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len) return mrb_obj_value(str_new(mrb, p, len)); } -/* - * call-seq: (Caution! NULL string) - * String.new(str="") => new_str - * - * Returns a new string object containing a copy of <i>str</i>. - */ - MRB_API mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) { @@ -200,6 +194,15 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -230,35 +233,47 @@ utf8len(const char* p, const char* e) mrb_int len; mrb_int i; + if ((unsigned char)*p < 0x80) return 1; len = utf8len_codepage[(unsigned char)*p]; - if (p + len > e) return 1; + if (len == 1) return 1; + if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) return 1; return len; } -static mrb_int -utf8_strlen(mrb_value str, mrb_int len) +mrb_int +mrb_utf8_len(const char *str, mrb_int byte_len) { mrb_int total = 0; - char* p = RSTRING_PTR(str); - char* e = p; - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { - return RSTRING_LEN(str); - } - e += len < 0 ? RSTRING_LEN(str) : len; - while (p<e) { + const char *p = str; + const char *e = p + byte_len; + + while (p < e) { p += utf8len(p, e); total++; } - if (RSTRING_LEN(str) == total) { - RSTRING(str)->flags |= MRB_STR_NO_UTF; - } return total; } -#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1) +static mrb_int +utf8_strlen(mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); + + if (RSTR_ASCII_P(s)) { + return byte_len; + } + else { + mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); + return utf8_len; + } +} + +#define RSTRING_CHAR_LEN(s) utf8_strlen(s) /* map character index to byte offset index */ static mrb_int @@ -291,12 +306,71 @@ bytes2chars(char *p, mrb_int bi) return i; } +static mrb_int +str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) +{ + /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */ + + ptrdiff_t qstable[1 << CHAR_BIT]; + + /* Preprocessing */ + { + mrb_int i; + + for (i = 0; i < 1 << CHAR_BIT; i ++) { + qstable[i] = slen; + } + for (i = 0; i < slen; i ++) { + qstable[(unsigned char)s[i]] = slen - (i + 1); + } + } + + /* Searching */ + while (p < pend && pend - p >= slen) { + const char *pivot; + + if (memcmp(p, s, slen) == 0) { + return off; + } + + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } + + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); + } + + return -1; +} + +static mrb_int +str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +{ + const char *p = RSTRING_PTR(str); + const char *pend = p + RSTRING_LEN(str); + const char *s = RSTRING_PTR(sub); + const mrb_int slen = RSTRING_LEN(sub); + mrb_int off = pos; + + for (; pos > 0; pos --) { + if (pend - p < 1) { return -1; } + p += utf8len(p, pend); + } + + if (slen < 1) { return off; } + + return str_index_str_by_char_search(mrb, p, pend, s, slen, off); +} + #define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); #else #define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) #define chars2bytes(p, off, ci) (ci) #define bytes2chars(p, bi) (bi) #define BYTES_ALIGN_CHECK(pos) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif static inline mrb_int @@ -398,8 +472,8 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) } } -static mrb_value -byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_value +mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { struct RString *orig, *s; @@ -413,44 +487,48 @@ byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) s->as.heap.ptr += beg; s->as.heap.len = len; } + RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); } + +static void +str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len) +{ + *pos = chars2bytes(str, 0, *pos); + *len = chars2bytes(str, *pos, *len); +} #ifdef MRB_UTF8_STRING static inline mrb_value str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { - beg = chars2bytes(str, 0, beg); - len = chars2bytes(str, beg, len); - - return byte_subseq(mrb, str, beg, len); + str_range_to_bytes(str, &beg, &len); + return mrb_str_byte_subseq(mrb, str, beg, len); } #else -#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len) #endif -static mrb_value -str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_bool +mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp) { - mrb_int clen = RSTRING_CHAR_LEN(str); - - if (len < 0) return mrb_nil_value(); - if (clen == 0) { - len = 0; - } - else if (beg < 0) { - beg = clen + beg; - } - if (beg > clen) return mrb_nil_value(); - if (beg < 0) { - beg += clen; - if (beg < 0) return mrb_nil_value(); + if (str_len < *begp || *lenp < 0) return FALSE; + if (*begp < 0) { + *begp += str_len; + if (*begp < 0) return FALSE; } - if (len > clen - beg) - len = clen - beg; - if (len <= 0) { - len = 0; + if (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - return str_subseq(mrb, str, beg, len); + return TRUE; +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ? + str_subseq(mrb, str, beg, len) : mrb_nil_value(); } MRB_API mrb_int @@ -490,23 +568,14 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) return mrb_str_index(mrb, str, ptr, len, offset); } -static void -check_frozen(mrb_state *mrb, struct RString *s) -{ - if (MRB_FROZEN_P(s)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string"); - } -} - static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { mrb_int len; - check_frozen(mrb, s1); + mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_NO_UTF; - s1->flags |= s2->flags&MRB_STR_NO_UTF; + RSTR_COPY_ASCII_FLAG(s1, s2); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -641,10 +710,9 @@ mrb_locale_from_utf8(const char *utf8, int len) #endif MRB_API void -mrb_str_modify(mrb_state *mrb, struct RString *s) +mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { - check_frozen(mrb, s); - s->flags &= ~MRB_STR_NO_UTF; + mrb_check_frozen(mrb, s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -708,6 +776,9 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) mrb_int slen; struct RString *s = mrb_str_ptr(str); + if (len < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); + } mrb_str_modify(mrb, s); slen = RSTR_LEN(s); if (len != slen) { @@ -725,38 +796,18 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } -/* - * call-seq: (Caution! String("abcd") change) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of <i>str</i>. - */ MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { - if (!mrb_string_p(other)) { - other = mrb_str_to_str(mrb, other); - } + other = mrb_str_to_str(mrb, other); mrb_str_cat_str(mrb, self, other); } -/* - * call-seq: (Caution! String("abcd") remain) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of <i>str</i>. - */ MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -774,10 +825,13 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) /* 15.2.10.5.2 */ /* - * call-seq: (Caution! String("abcd") remain) for stack_argument - * String("abcdefg") = String("abcd") + String("efg") + * call-seq: + * str + other_str -> new_str * - * Returns a new string object containing a copy of <i>str</i>. + * Concatenation---Returns a new <code>String</code> containing + * <i>other_str</i> concatenated to <i>str</i>. + * + * "Hello from " + self.to_s #=> "Hello from main" */ static mrb_value mrb_str_plus_m(mrb_state *mrb, mrb_value self) @@ -837,7 +891,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) len = RSTRING_LEN(self)*times; str2 = str_new(mrb, 0, len); - str_with_class(mrb, str2, self); + str_with_class(str2, self); p = RSTR_PTR(str2); if (len > 0) { n = RSTRING_LEN(self); @@ -849,6 +903,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) memcpy(p + n, p, len-n); } p[RSTR_LEN(str2)] = '\0'; + RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self)); return mrb_obj_value(str2); } @@ -953,15 +1008,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) { - if (mrb_immediate_p(str2)) return FALSE; - if (!mrb_string_p(str2)) { - if (mrb_nil_p(str2)) return FALSE; - if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { - return FALSE; - } - str2 = mrb_funcall(mrb, str2, "to_str", 0); - return mrb_equal(mrb, str2, str1); - } + if (!mrb_string_p(str2)) return FALSE; return str_eql(mrb, str1, str2); } @@ -986,47 +1033,38 @@ 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) { - mrb_value s; - - if (!mrb_string_p(str)) { - s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(s)) { - s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); - } - return s; + switch (mrb_type(str)) { + case MRB_TT_STRING: + return str; + case MRB_TT_SYMBOL: + return mrb_sym2str(mrb, mrb_symbol(str)); + case MRB_TT_FIXNUM: + return mrb_fixnum_to_str(mrb, str, 10); + case MRB_TT_CLASS: + case MRB_TT_MODULE: + return mrb_mod_to_s(mrb, str); + default: + return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } - return str; } MRB_API const char* -mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) +mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { - mrb_value str = mrb_str_to_str(mrb, ptr); + str = mrb_str_to_str(mrb, str); return RSTRING_PTR(str); } MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_LEN(str); -} - -void -mrb_noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); -} - -void -mrb_regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - mrb_noregexp(mrb, obj); - } + mrb_to_str(mrb, ptr); + return RSTRING_LEN(ptr); } MRB_API mrb_value @@ -1035,56 +1073,95 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); struct RString *dup = str_new(mrb, 0, 0); - str_with_class(mrb, dup, str); + str_with_class(dup, str); return str_replace(mrb, dup, s); } -static mrb_value -mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) -{ - mrb_int idx; +enum str_convert_range { + /* `beg` and `len` are byte unit in `0 ... str.bytesize` */ + STR_BYTE_RANGE_CORRECTED = 1, - mrb_regexp_check(mrb, indx); - switch (mrb_type(indx)) { - case MRB_TT_FIXNUM: - idx = mrb_fixnum(indx); + /* `beg` and `len` are char unit in any range */ + STR_CHAR_RANGE = 2, -num_index: - str = str_substr(mrb, str, idx, 1); - if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); - return str; + /* `beg` and `len` are char unit in `0 ... str.size` */ + STR_CHAR_RANGE_CORRECTED = 3, - case MRB_TT_STRING: - if (str_index_str(mrb, str, indx, 0) != -1) - return mrb_str_dup(mrb, indx); - return mrb_nil_value(); + /* `beg` is out of range */ + STR_OUT_OF_RANGE = -1 +}; - case MRB_TT_RANGE: - goto range_arg; +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); + return STR_CHAR_RANGE; + } + else { + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; - default: - indx = mrb_Integer(mrb, indx); - if (mrb_nil_p(indx)) { - range_arg: - { - mrb_int beg, len; - - len = RSTRING_CHAR_LEN(str); - switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case 1: - return str_subseq(mrb, str, beg, len); - case 2: - return mrb_nil_value(); + case MRB_TT_STRING: + *beg = str_index_str(mrb, str, indx, 0); + if (*beg < 0) { break; } + *len = RSTRING_LEN(indx); + return STR_BYTE_RANGE_CORRECTED; + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_to_int(mrb, indx); + if (mrb_fixnum_p(indx)) { + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + } +range_arg: + *len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) { + case MRB_RANGE_OK: + return STR_CHAR_RANGE_CORRECTED; + case MRB_RANGE_OUT: + return STR_OUT_OF_RANGE; default: break; - } } + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + } + return STR_OUT_OF_RANGE; +} + +static mrb_value +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) +{ + mrb_int beg, len; + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_CHAR_RANGE_CORRECTED: + return str_subseq(mrb, str, beg, len); + case STR_CHAR_RANGE: + str = str_substr(mrb, str, beg, len); + if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + return str; + case STR_BYTE_RANGE_CORRECTED: + if (mrb_string_p(indx)) { + return mrb_str_dup(mrb, indx); + } + else { + return mrb_str_byte_subseq(mrb, str, beg, len); } - idx = mrb_fixnum(indx); - goto num_index; + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1131,20 +1208,118 @@ static mrb_value mrb_str_aref_m(mrb_state *mrb, mrb_value str) { mrb_value a1, a2; - mrb_int argc; - argc = mrb_get_args(mrb, "o|o", &a1, &a2); - if (argc == 2) { - mrb_int n1, n2; + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) { + a2 = mrb_undef_value(); + } + + return mrb_str_aref(mrb, str, a1, a2); +} + +static mrb_noreturn void +str_out_of_index(mrb_state *mrb, mrb_value index) +{ + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", index); +} + +static mrb_value +str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep) +{ + const mrb_int shrink_threshold = 256; + struct RString *str = mrb_str_ptr(src); + mrb_int len = RSTR_LEN(str); + mrb_int replen, newlen; + char *strp; + + if (end > len) { end = len; } + + if (pos < 0 || pos > len) { + str_out_of_index(mrb, mrb_fixnum_value(pos)); + } + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); - mrb_regexp_check(mrb, a1); - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); + + mrb_str_modify(mrb, str); + + if (len < newlen) { + resize_capa(mrb, str, newlen); + } + + strp = RSTR_PTR(str); + + memmove(strp + newlen - (len - end), strp + end, len - end); + if (!mrb_nil_p(rep)) { + memcpy(strp + pos, RSTRING_PTR(rep), replen); + } + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + return src; +} + +static void +mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) +{ + mrb_int beg, len, charlen; + + replace = mrb_to_str(mrb, replace); + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_OUT_OF_RANGE: + default: + mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); + case STR_CHAR_RANGE: + if (len < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %S", alen); + } + charlen = RSTRING_CHAR_LEN(str); + if (beg < 0) { beg += charlen; } + if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); } + /* fall through */ + case STR_CHAR_RANGE_CORRECTED: + str_range_to_bytes(str, &beg, &len); + /* fall through */ + case STR_BYTE_RANGE_CORRECTED: + str_replace_partial(mrb, str, beg, beg + len, replace); + } +} + +/* + * call-seq: + * str[fixnum] = replace + * str[fixnum, fixnum] = replace + * str[range] = replace + * str[regexp] = replace + * str[regexp, fixnum] = replace + * str[other_str] = replace + * + * Modify +self+ by replacing the content of +self+. + * The portion of the string affected is determined using the same criteria as +String#[]+. + */ +static mrb_value +mrb_str_aset_m(mrb_state *mrb, mrb_value str) +{ + mrb_value indx, alen, replace; + + switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) { + case 2: + replace = alen; + alen = mrb_undef_value(); + break; + case 3: + break; } - return mrb_str_aref(mrb, str, a1); + mrb_str_aset(mrb, str, indx, alen, replace); + return str; } /* 15.2.10.5.8 */ @@ -1167,7 +1342,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); if (ISLOWER(*p)) { @@ -1226,7 +1401,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); argc = mrb_get_args(mrb, "|S", &rs); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); len = RSTR_LEN(s); if (argc == 0) { if (len == 0) return mrb_nil_value(); @@ -1325,7 +1500,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) > 0) { mrb_int len; #ifdef MRB_UTF8_STRING @@ -1394,7 +1569,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); while (p < pend) { @@ -1567,16 +1742,13 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - mrb_regexp_check(mrb, sub); - clen = RSTRING_CHAR_LEN(str); if (pos < 0) { + clen = RSTRING_CHAR_LEN(str); pos += clen; if (pos < 0) { return mrb_nil_value(); } } - if (pos > clen) return mrb_nil_value(); - pos = chars2bytes(str, 0, pos); switch (mrb_type(sub)) { default: { @@ -1590,18 +1762,15 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) } /* fall through */ case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); + pos = str_index_str_by_char(mrb, str, sub, pos); break; } if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -#define STR_REPLACE_SHARED_MIN 10 - /* 15.2.10.5.24 */ /* 15.2.10.5.28 */ /* @@ -1711,16 +1880,16 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } -MRB_API mrb_value -mrb_string_type(mrb_state *mrb, mrb_value str) +static inline void +str_reverse(char *p, char *e) { - return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} + char c; -MRB_API mrb_value -mrb_check_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } } /* 15.2.10.5.30 */ @@ -1733,53 +1902,38 @@ mrb_check_string_type(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + #ifdef MRB_UTF8_STRING mrb_int utf8_len = RSTRING_CHAR_LEN(str); - mrb_int len = RSTRING_LEN(str); - - if (utf8_len == len) goto bytes; - if (utf8_len > 1) { - char *buf; - char *p, *e, *r; - - mrb_str_modify(mrb, mrb_str_ptr(str)); - len = RSTRING_LEN(str); - buf = (char*)mrb_malloc(mrb, (size_t)len); - p = buf; - e = buf + len; - - memcpy(buf, RSTRING_PTR(str), len); - r = RSTRING_PTR(str) + len; + mrb_int len = RSTR_LEN(s); + if (utf8_len < 2) return str; + if (utf8_len < len) { + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + e = p + RSTR_LEN(s); while (p<e) { mrb_int clen = utf8len(p, e); - r -= clen; - memcpy(r, p, clen); + str_reverse(p, p + clen - 1); p += clen; } - mrb_free(mrb, buf); + goto bytes; } - return str; - - bytes: #endif - { - struct RString *s = mrb_str_ptr(str); - char *p, *e; - char c; + if (RSTR_LEN(s) > 1) { mrb_str_modify(mrb, s); - if (RSTR_LEN(s) > 1) { - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - while (p < e) { - c = *p; - *p++ = *e; - *e-- = c; - } - } - return str; + goto bytes; } + return str; + + bytes: + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); + return str; } /* ---------------------------------- */ @@ -1833,7 +1987,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -1847,7 +2000,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) sub = mrb_nil_value(); } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { default: { @@ -1941,16 +2093,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) if (argc == 0 || mrb_nil_p(spat)) { split_type = awk; } - else { - if (mrb_string_p(spat)) { - split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { - split_type = awk; - } - } - else { - mrb_noregexp(mrb, str); - } + else if (!mrb_string_p(spat)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; } result = mrb_ary_new(mrb); @@ -1976,7 +2123,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else if (ISSPACE(c)) { - mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; beg = idx; @@ -1987,7 +2134,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } } - else if (split_type == string) { + else { /* split_type == string */ mrb_int str_len = RSTRING_LEN(str); mrb_int pat_len = RSTRING_LEN(spat); mrb_int idx = 0; @@ -2001,22 +2148,19 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { end = chars2bytes(str, idx, 1); } - mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end)); mrb_gc_arena_restore(mrb, ai); idx += end + pat_len; if (lim_p && lim <= ++i) break; } beg = idx; } - else { - mrb_noregexp(mrb, str); - } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { tmp = mrb_str_new_empty(mrb, str); } else { - tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); } mrb_ary_push(mrb, result, tmp); } @@ -2030,7 +2174,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -MRB_API mrb_value +static 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; @@ -2174,7 +2318,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", + mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer", mrb_str_new(mrb, str, pend-str)); } } @@ -2198,7 +2342,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, } MRB_API mrb_value -mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) +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); } @@ -2206,20 +2350,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_str_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + else { if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); + ps = str_new(mrb, p, len); + *ptr = mrb_obj_value(ps); + } + else { + mrb_str_modify(mrb, ps); } - mrb_str_modify(mrb, ps); return RSTR_PTR(ps); } - return p; } MRB_API mrb_value @@ -2333,22 +2484,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - char *s; - mrb_int len; - - str = mrb_str_to_str(mrb, str); - s = RSTRING_PTR(str); - len = RSTRING_LEN(str); - if (s) { - if (badcheck && memchr(s, '\0', len)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); - } - if (s[len]) { /* no sentinel somehow */ - struct RString *temp_str = str_new(mrb, s, len); - s = RSTR_PTR(temp_str); - } - } - return mrb_cstr_to_dbl(mrb, s, badcheck); + return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck); } /* 15.2.10.5.39 */ @@ -2376,7 +2512,6 @@ mrb_str_to_f(mrb_state *mrb, mrb_value self) /* * call-seq: * str.to_s => str - * str.to_str => str * * Returns the receiver. */ @@ -2404,7 +2539,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) char *p, *pend; mrb_bool modify = FALSE; - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { @@ -2485,7 +2620,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); + str_with_class(result, str); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); q = RSTR_PTR(result); *q++ = '"'; @@ -2624,7 +2759,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) { - str2 = mrb_str_to_str(mrb, str2); + mrb_to_str(mrb, str2); return mrb_str_cat_str(mrb, str1, str2); } @@ -2704,6 +2839,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); + RSTR_COPY_ASCII_FLAG(mrb_str_ptr(result), mrb_str_ptr(str)); return result; } @@ -2749,6 +2885,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ @@ -2869,7 +3006,7 @@ mrb_float_read(const char *string, char **endPtr) */ p = string; - while (isspace(*p)) { + while (ISSPACE(*p)) { p += 1; } if (*p == '-') { @@ -2892,7 +3029,7 @@ mrb_float_read(const char *string, char **endPtr) for (mantSize = 0; ; mantSize += 1) { c = *p; - if (!isdigit(c)) { + if (!ISDIGIT(c)) { if ((c != '.') || (decPt >= 0)) { break; } @@ -2977,7 +3114,7 @@ mrb_float_read(const char *string, char **endPtr) } expSign = FALSE; } - while (isdigit(*p)) { + while (ISDIGIT(*p)) { exp = exp * 10 + (*p - '0'); if (exp > 19999) { exp = 19999; diff --git a/src/symbol.c b/src/symbol.c index 5e1f9f561..53f4f6e1d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -15,54 +15,158 @@ /* ------------------------------------------------------ */ typedef struct symbol_name { mrb_bool lit : 1; + uint8_t prev; uint16_t len; const char *name; } symbol_name; -static inline khint_t -sym_hash_func(mrb_state *mrb, mrb_sym s) +#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 +#ifdef MRB_ENABLE_ALL_SYMBOLS +# define SYMBOL_INLINE_P(sym) FALSE +# define SYMBOL_INLINE_LOWER_P(sym) FALSE +# define sym_inline_pack(name, len) 0 +# define sym_inline_unpack(sym, buf, lenp) NULL +#else +# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE) +# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER) +#endif + +static void +sym_validate_len(mrb_state *mrb, size_t len) { - khint_t h = 0; - size_t i, len = mrb->symtbl[s].len; - const char *p = mrb->symtbl[s].name; + if (len >= RITE_LV_NULL_MARK) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + } +} +#ifndef MRB_ENABLE_ALL_SYMBOLS +static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static mrb_sym +sym_inline_pack(const char *name, uint16_t len) +{ + const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5; + const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6; + + char c; + const char *p; + int i; + mrb_sym sym = 0; + mrb_bool lower = TRUE; + + if (len > lower_length_max) return 0; /* too long */ for (i=0; i<len; i++) { - h = (h << 5) - h + *p++; + uint32_t bits; + + c = name[i]; + if (c == 0) return 0; /* NUL in name */ + p = strchr(pack_table, (int)c); + if (p == 0) return 0; /* non alnum char */ + bits = (uint32_t)(p - pack_table)+1; + if (bits > 27) lower = FALSE; + if (i >= mix_length_max) break; + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } - return h; + if (lower) { + sym = 0; + for (i=0; i<len; i++) { + uint32_t bits; + + c = name[i]; + p = strchr(pack_table, (int)c); + bits = (uint32_t)(p - pack_table)+1; + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); + } + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; + } + if (len > mix_length_max) return 0; + return sym | SYMBOL_INLINE; } -#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) - -KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) -KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) -/* ------------------------------------------------------ */ -static void -sym_validate_len(mrb_state *mrb, size_t len) +static const char* +sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - if (len >= RITE_LV_NULL_MARK) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; + int i; + + mrb_assert(SYMBOL_INLINE_P(sym)); + + for (i=0; i<30/bit_per_char; i++) { + uint32_t bits = sym>>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1<<bit_per_char)-1); + if (bits == 0) break; + buf[i] = pack_table[bits-1];; } + buf[i] = '\0'; + if (lenp) *lenp = i; + return buf; +} +#endif + +static uint8_t +symhash(const char *key, size_t len) +{ + uint32_t hash, i; + + for(hash = i = 0; i < len; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash & 0xff; +} + +static mrb_sym +find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) +{ + mrb_sym i; + symbol_name *sname; + + /* inline symbol */ + i = sym_inline_pack(name, len); + if (i > 0) return i; + + i = mrb->symhash[hash]; + if (i == 0) return 0; + do { + sname = &mrb->symtbl[i]; + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return i<<SYMBOL_NORMAL_SHIFT; + } + if (sname->prev == 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)<<SYMBOL_NORMAL_SHIFT; + } + sname--; + } + return 0; + } + i -= sname->prev; + } while (sname->prev > 0); + return 0; } static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ - khiter_t k; mrb_sym sym; - char *p; + symbol_name *sname; + uint8_t hash; sym_validate_len(mrb, len); - if (sname) { - sname->lit = lit; - sname->len = (uint16_t)len; - sname->name = name; - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) - return kh_key(h, k); - } + hash = symhash(name, len); + sym = find_symbol(mrb, name, len, hash); + if (sym > 0) return sym; /* registering a new symbol */ sym = ++mrb->symidx; @@ -78,15 +182,25 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->lit = TRUE; } else { - p = (char *)mrb_malloc(mrb, len+1); + char *p = (char *)mrb_malloc(mrb, len+1); memcpy(p, name, len); p[len] = 0; sname->name = (const char*)p; sname->lit = FALSE; } - kh_put(n2s, mrb, h, sym); + if (mrb->symhash[hash]) { + mrb_sym i = sym - mrb->symhash[hash]; + if (i > 0xff) + sname->prev = 0xff; + else + sname->prev = i; + } + else { + sname->prev = 0; + } + mrb->symhash[hash] = sym; - return sym; + return sym<<SYMBOL_NORMAL_SHIFT; } MRB_API mrb_sym @@ -116,25 +230,18 @@ mrb_intern_str(mrb_state *mrb, mrb_value str) MRB_API mrb_value mrb_check_intern(mrb_state *mrb, const char *name, size_t len) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; - khiter_t k; + mrb_sym sym; sym_validate_len(mrb, len); - sname->len = (uint16_t)len; - sname->name = name; - - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) { - return mrb_symbol_value(kh_key(h, k)); - } + sym = find_symbol(mrb, name, len, symhash(name, len)); + if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } MRB_API mrb_value mrb_check_intern_cstr(mrb_state *mrb, const char *name) { - return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); + return mrb_check_intern(mrb, name, strlen(name)); } MRB_API mrb_value @@ -143,10 +250,12 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -/* lenp must be a pointer to a size_t variable */ -MRB_API const char* -mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +static const char* +sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { + if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp); + + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -156,6 +265,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) return mrb->symtbl[sym].name; } +MRB_API const char* +mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +{ + return sym2name_len(mrb, sym, mrb->symbuf, lenp); +} + void mrb_free_symtbl(mrb_state *mrb) { @@ -167,13 +282,11 @@ mrb_free_symtbl(mrb_state *mrb) } } mrb_free(mrb, mrb->symtbl); - kh_destroy(n2s, mrb, mrb->name2sym); } void mrb_init_symtbl(mrb_state *mrb) { - mrb->name2sym = kh_init(n2s, mrb); } /********************************************************************** @@ -209,26 +322,6 @@ mrb_init_symtbl(mrb_state *mrb) * */ - -/* 15.2.11.3.1 */ -/* - * call-seq: - * sym == obj -> true or false - * - * Equality---If <i>sym</i> and <i>obj</i> are exactly the same - * symbol, returns <code>true</code>. - */ - -static mrb_value -sym_equal(mrb_state *mrb, mrb_value sym1) -{ - mrb_value sym2; - - mrb_get_args(mrb, "o", &sym2); - - return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); -} - /* 15.2.11.3.2 */ /* 15.2.11.3.3 */ /* @@ -241,14 +334,9 @@ sym_equal(mrb_state *mrb, mrb_value sym1) * :fred.id2name #=> "fred" */ static mrb_value -mrb_sym_to_s(mrb_state *mrb, mrb_value sym) +sym_to_s(mrb_state *mrb, mrb_value sym) { - mrb_sym id = mrb_symbol(sym); - const char *p; - mrb_int len; - - p = mrb_sym2name_len(mrb, id, &len); - return mrb_str_new_static(mrb, p, len); + return mrb_sym2str(mrb, mrb_symbol(sym)); } /* 15.2.11.3.4 */ @@ -387,8 +475,8 @@ id: switch (*m) { case '!': case '?': case '=': ++m; default: break; - } } + } break; } return *m ? FALSE : TRUE; @@ -406,7 +494,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) name = mrb_sym2name_len(mrb, id, &len); str = mrb_str_new(mrb, 0, len+1); sp = RSTRING_PTR(str); - RSTRING_PTR(str)[0] = ':'; + sp[0] = ':'; memcpy(sp+1, name, len); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); if (!symname_p(name) || strlen(name) != (size_t)len) { @@ -415,6 +503,9 @@ sym_inspect(mrb_state *mrb, mrb_value sym) sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } @@ -425,6 +516,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ + if (SYMBOL_INLINE_P(sym)) { + mrb_value str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; + } return mrb_str_new_static(mrb, name, len); } @@ -439,7 +535,9 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); + mrb_value str = SYMBOL_INLINE_P(sym) ? + mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len); + str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } } @@ -461,9 +559,10 @@ sym_cmp(mrb_state *mrb, mrb_value s1) const char *p1, *p2; int retval; mrb_int len, len1, len2; + char buf1[8], buf2[8]; - p1 = mrb_sym2name_len(mrb, sym1, &len1); - p2 = mrb_sym2name_len(mrb, sym2, &len2); + p1 = sym2name_len(mrb, sym1, buf1, &len1); + p2 = sym2name_len(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { @@ -481,14 +580,13 @@ mrb_init_symbol(mrb_state *mrb) { struct RClass *sym; - mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ - mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ - mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ - 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)); + 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, "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 de36efac6..e6f2f397e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -9,155 +9,241 @@ #include <mruby/class.h> #include <mruby/proc.h> #include <mruby/string.h> +#include <mruby/variable.h> -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); - -#include <mruby/khash.h> - -#ifndef MRB_IVHASH_INIT_SIZE -#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE +#ifndef MRB_IV_SEGMENT_SIZE +#define MRB_IV_SEGMENT_SIZE 4 #endif -KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) -KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) +typedef struct segment { + mrb_sym key[MRB_IV_SEGMENT_SIZE]; + mrb_value val[MRB_IV_SEGMENT_SIZE]; + struct segment *next; +} segment; /* Instance variable table structure */ typedef struct iv_tbl { - khash_t(iv) h; + segment *rootseg; + size_t size; + size_t last_len; } iv_tbl; -/* - * Creates the instance variable table. - * - * Parameters - * mrb - * Returns - * the instance variable table. - */ +/* Creates the instance variable table. */ static iv_tbl* iv_new(mrb_state *mrb) { - return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); + iv_tbl *t; + + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; } -/* - * Set the value for the symbol in the instance variable table. - * - * Parameters - * mrb - * t the instance variable table to be set in. - * sym the symbol to be used as the key. - * val the value to be set. - */ +/* Set the value for the symbol in the instance variable table. */ static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + segment *prev = NULL; + segment *matched_seg = NULL; + size_t matched_idx = 0; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { + mrb_sym key = seg->key[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = sym; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (!matched_seg && key == 0) { + matched_seg = seg; + matched_idx = i; + } + else if (key == sym) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } - k = kh_put(iv, mrb, h, sym); - kh_value(h, k) = val; + /* Not found */ + if (matched_seg) { + matched_seg->key[matched_idx] = sym; + matched_seg->val[matched_idx] = val; + t->size++; + return; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg->next = NULL; + seg->key[0] = sym; + seg->val[0] = val; + t->last_len = 1; + t->size++; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } } -/* - * Get a value for a symbol from the instance variable table. - * - * Parameters - * mrb - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receives the value if the specified symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Get a value for a symbol from the instance variable table. */ static mrb_bool iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + size_t i; - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - if (vp) *vp = kh_value(h, k); - return TRUE; + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { + mrb_sym key = seg->key[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; } return FALSE; } -/* - * Deletes the value for the symbol from the instance variable table. - * - * Parameters - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receive the deleted value if the symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Deletes the value for the symbol from the instance variable table. */ static mrb_bool iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { + segment *seg; + size_t i; + if (t == NULL) return FALSE; - else { - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k); - kh_del(iv, mrb, h, k); - if (vp) *vp = val; - return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { + mrb_sym key = seg->key[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + t->size--; + seg->key[i] = 0; + if (vp) *vp = seg->val[i]; + return TRUE; + } } + seg = seg->next; } return FALSE; } -static mrb_bool -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +/* Iterates over the instance variable table. */ +static void +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { - if (t == NULL) { - return TRUE; - } - else { - khash_t(iv) *h = &t->h; - khiter_t k; - int n; - - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); - if (n > 0) return FALSE; - if (n < 0) { - kh_del(iv, mrb, h, k); + segment *seg; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { + mrb_sym key = seg->key[i]; + + /* no value in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + return; + } + if (key != 0) { + if ((*func)(mrb, key, seg->val[i], p) != 0) { + return; } } } + seg = seg->next; } - return TRUE; + return; } +/* Get the size of the instance variable table. */ static size_t iv_size(mrb_state *mrb, iv_tbl *t) { - if (t) { - return kh_size(&t->h); + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_IV_SEGMENT_SIZE; } + /* empty iv_tbl */ return 0; } +/* Copy the instance variable table. */ static iv_tbl* iv_copy(mrb_state *mrb, iv_tbl *t) { - return (iv_tbl*)kh_copy(iv, mrb, &t->h); + segment *seg; + iv_tbl *t2; + + size_t i; + + seg = t->rootseg; + t2 = iv_new(mrb); + + while (seg != NULL) { + for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { + mrb_sym key = seg->key[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + iv_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; } +/* Free memory of the instance variable table. */ static void iv_free(mrb_state *mrb, iv_tbl *t) { - kh_destroy(iv, mrb, &t->h); + segment *seg; + + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); } static int @@ -170,9 +256,7 @@ iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) static void mark_tbl(mrb_state *mrb, iv_tbl *t) { - if (t) { - iv_foreach(mrb, t, iv_mark_i, 0); - } + iv_foreach(mrb, t, iv_mark_i, 0); } void @@ -255,19 +339,64 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); + +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + assign_class_name(mrb, obj, sym, v); + if (!obj->iv) { + obj->iv = iv_new(mrb); + } + iv_put(mrb, obj->iv, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)obj); +} + MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t = obj->iv; + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} - if (MRB_FROZEN_P(obj)) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); - } - if (!t) { - t = obj->iv = iv_new(mrb); +/* Iterates over the instance variable table. */ +MRB_API void +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) +{ + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} + +static inline mrb_bool +namespace_p(enum mrb_vtype tt) +{ + return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; +} + +static inline void +assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + if (namespace_p(obj->tt) && namespace_p(mrb_type(v))) { + struct RObject *c = mrb_obj_ptr(v); + if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); + + if (mrb_nil_p(o)) { + mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); + } + } + } + } } - mrb_write_barrier(mrb, (struct RBasic*)obj); - iv_put(mrb, t, sym, v); } MRB_API void @@ -300,28 +429,23 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - MRB_API mrb_bool -mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; - mrb_int i, len; + mrb_int len; s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; - if (s[1] == '@') return FALSE; - for (i=1; i<len; i++) { - if (!identchar(s[i])) return FALSE; - } - return TRUE; + if (ISDIGIT(s[1])) return FALSE; + return mrb_ident_p(s+1, len-1); } MRB_API void -mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { - if (!mrb_iv_p(mrb, iv_name)) { + if (!mrb_iv_name_sym_p(mrb, iv_name)) { mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } @@ -401,27 +525,14 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; - if (t && iv_del(mrb, t, sym, &val)) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); + if (iv_del(mrb, t, sym, &val)) { return val; } } return mrb_undef_value(); } -mrb_value -mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) -{ - /* get self */ - return mrb_iv_get(mrb, mrb->c->stack[0], sym); -} - -void -mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) -{ - /* get self */ - mrb_iv_set(mrb, mrb->c->stack[0], sym, v); -} - static int iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { @@ -460,7 +571,7 @@ mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) mrb_value ary; ary = mrb_ary_new(mrb); - if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + if (obj_iv_p(self)) { iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); } return ary; @@ -506,15 +617,13 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, cv_i, &ary); - } + iv_foreach(mrb, c->iv, cv_i, &ary); c = c->super; } return ary; } -MRB_API mrb_value +mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; @@ -563,14 +672,13 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; + iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } + if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); + iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); + return; } c = c->super; } @@ -595,12 +703,13 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); } MRB_API void @@ -609,14 +718,12 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -MRB_API mrb_bool +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) return TRUE; - } + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -662,24 +769,23 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) { struct RClass *c = base; mrb_value v; mrb_bool retry = FALSE; mrb_value name; - struct RClass *oclass = mrb->object_class; L_RETRY: while (c) { - if (c->iv && (top || c != oclass || base == oclass)) { + if (c->iv) { if (iv_get(mrb, c->iv, sym, &v)) return v; } c = c->super; } if (!retry && base->tt == MRB_TT_MODULE) { - c = oclass; + c = mrb->object_class; retry = TRUE; goto L_RETRY; } @@ -691,7 +797,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, FALSE); + return const_get(mrb, mrb_class_ptr(mod), sym); } mrb_value @@ -703,27 +809,30 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) struct RProc *proc; c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, c->iv, sym, &v)) { return v; } c2 = c; while (c2 && c2->tt == MRB_TT_SCLASS) { mrb_value klass; - klass = mrb_obj_iv_get(mrb, (struct RObject *)c2, - mrb_intern_lit(mrb, "__attached__")); + + if (!iv_get(mrb, c2->iv, mrb_intern_lit(mrb, "__attached__"), &klass)) { + c2 = NULL; + break; + } c2 = mrb_class_ptr(klass); } - if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2; + 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; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && c2->iv && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; } - return const_get(mrb, c, sym, TRUE); + return const_get(mrb, c, sym); } MRB_API void @@ -796,9 +905,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, const_i, &ary); - } + iv_foreach(mrb, c->iv, const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -811,9 +918,6 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; - if (!mrb->globals) { - return mrb_nil_value(); - } if (iv_get(mrb, mrb->globals, sym, &v)) return v; return mrb_nil_value(); @@ -825,20 +929,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_tbl *t; if (!mrb->globals) { - t = mrb->globals = iv_new(mrb); - } - else { - t = mrb->globals; + mrb->globals = iv_new(mrb); } + t = mrb->globals; iv_put(mrb, t, sym, v); } MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { - if (!mrb->globals) { - return; - } iv_del(mrb, mrb->globals, sym, NULL); } @@ -867,18 +966,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; - if (t) { - iv_foreach(mrb, t, gv_i, &ary); - } - buf[0] = '$'; - buf[2] = 0; - for (i = 1; i <= 9; ++i) { - buf[1] = (char)(i + '0'); - mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); - } + iv_foreach(mrb, t, gv_i, &ary); return ary; } @@ -892,7 +981,7 @@ mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, tmp = klass; retry: while (tmp) { - if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, tmp->iv, id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; @@ -928,25 +1017,25 @@ struct csym_arg { struct RClass *c; mrb_sym sym; }; - + static int csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { struct csym_arg *a = (struct csym_arg*)p; struct RClass *c = a->c; - + if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { a->sym = sym; return 1; /* stop iteration */ } return 0; } - + static mrb_sym find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) { struct csym_arg arg; - + if (!outer) return 0; if (outer == c) return 0; arg.c = c; @@ -1009,8 +1098,24 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); - 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); + if (RSTRING_PTR(path)[0] != '#') { + 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); + path = mrb_str_dup(mrb, path); + } return path; } + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +mrb_bool +mrb_ident_p(const char *s, mrb_int len) +{ + mrb_int i; + + for (i = 0; i < len; i++) { + if (!identchar(s[i])) return FALSE; + } + return TRUE; +} @@ -55,7 +55,7 @@ void abort(void); /* Maximum depth of ecall() recursion. */ #ifndef MRB_ECALL_DEPTH_MAX -#define MRB_ECALL_DEPTH_MAX 32 +#define MRB_ECALL_DEPTH_MAX 512 #endif /* Maximum stack depth. Should be set lower on memory constrained systems. @@ -101,7 +101,7 @@ static inline void stack_clear(mrb_value *from, size_t count) { #ifndef MRB_NAN_BOXING - const mrb_value mrb_value_zero = { 0 }; + const mrb_value mrb_value_zero = { { 0 } }; while (count-- > 0) { *from++ = mrb_value_zero; @@ -141,7 +141,7 @@ stack_init(mrb_state *mrb) } static inline void -envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) +envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize) { mrb_callinfo *ci = mrb->c->cibase; @@ -151,7 +151,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) mrb_value *st; if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -161,7 +161,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) e = MRB_PROC_ENV(ci->proc); if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -176,7 +176,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) /** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */ static void -stack_extend_alloc(mrb_state *mrb, int room) +stack_extend_alloc(mrb_state *mrb, mrb_int room) { mrb_value *oldbase = mrb->c->stbase; mrb_value *newstack; @@ -186,7 +186,7 @@ stack_extend_alloc(mrb_state *mrb, int room) if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING - if (room <= size) + if ((size_t)room <= size) size *= 2; else size += room; @@ -205,7 +205,7 @@ stack_extend_alloc(mrb_state *mrb, int room) mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } stack_clear(&(newstack[oldsize]), size - oldsize); - envadjust(mrb, oldbase, newstack, size); + envadjust(mrb, oldbase, newstack, oldsize); mrb->c->stbase = newstack; mrb->c->stack = mrb->c->stbase + off; mrb->c->stend = mrb->c->stbase + size; @@ -217,8 +217,8 @@ stack_extend_alloc(mrb_state *mrb, int room) } } -static inline void -stack_extend(mrb_state *mrb, int room) +MRB_API void +mrb_stack_extend(mrb_state *mrb, mrb_int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); @@ -333,11 +333,12 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - int i = --c->eidx; + uint16_t i = --c->eidx; int nregs; if (i<0) return; - if (ci - c->cibase > MRB_ECALL_DEPTH_MAX) { + /* restrict total call depth of ecall() */ + if (++mrb->ecall_nest > MRB_ECALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = c->ensure[i]; @@ -356,7 +357,6 @@ ecall(mrb_state *mrb) ci->acc = CI_ACC_SKIP; ci->argc = 0; ci->proc = p; - ci->nregs = p->body.irep->nregs; ci->target_class = MRB_PROC_TARGET_CLASS(p); env = MRB_PROC_ENV(p); mrb_assert(env); @@ -365,11 +365,15 @@ ecall(mrb_state *mrb) if (exc) { mrb_gc_protect(mrb, mrb_obj_value(exc)); } + if (mrb->c->fib) { + mrb_gc_protect(mrb, mrb_obj_value(mrb->c->fib)); + } mrb_run(mrb, p, env->stack[0]); mrb->c = c; c->ci = c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; mrb_gc_arena_restore(mrb, ai); + mrb->ecall_nest--; } #ifndef MRB_FUNCALL_ARGC_MAX @@ -396,6 +400,30 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) return mrb_funcall_argv(mrb, self, mid, argc, argv); } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p; + int n = 0; + + if (!ci) return 3; + p = ci->proc; + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + 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) { @@ -426,13 +454,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_t m; struct RClass *c; mrb_callinfo *ci; - int n; + int n = ci_nregs(mrb->c->ci); ptrdiff_t voff = -1; if (!mrb->c->stack) { stack_init(mrb); } - n = mrb->c->ci->nregs; if (argc < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); } @@ -446,7 +473,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_missing(mrb, mid, self, args); } mrb_ary_unshift(mrb, args, mrb_symbol_value(mid)); - stack_extend(mrb, n+2); + mrb_stack_extend(mrb, n+2); mrb->c->stack[n+1] = args; argc = -1; } @@ -459,26 +486,25 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = (int)argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } - if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (int)(argc + 2); - stack_extend(mrb, ci->nregs); - } - else if (argc >= CALL_MAXARGS) { + if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - stack_extend(mrb, ci->nregs+2); + mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } - else { + mrb_stack_extend(mrb, argc + 2); + if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); + ci->proc = p; - if (argc < 0) argc = 1; - ci->nregs = (int)(p->body.irep->nregs + argc); - stack_extend(mrb, ci->nregs); + if (!MRB_PROC_CFUNC_P(p)) { + mrb_stack_extend(mrb, p->body.irep->nregs + argc); + } } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -493,9 +519,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc int ai = mrb_gc_arena_save(mrb); ci->acc = CI_ACC_DIRECT; - if (MRB_METHOD_PROC_P(m)) { - ci->proc = MRB_METHOD_PROC(m); - } val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); @@ -520,28 +543,25 @@ mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; - int keep; + int keep, nregs; mrb->c->stack[0] = self; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; - ci->env = MRB_PROC_ENV(p); - if (ci->env) ci->env->stack[0] = self; + nregs = p->body.irep->nregs; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; - if (ci->nregs < keep) { - stack_extend(mrb, keep); + if (nregs < keep) { + mrb_stack_extend(mrb, keep); } else { - stack_extend(mrb, ci->nregs); - stack_clear(mrb->c->stack+keep, ci->nregs-keep); + mrb_stack_extend(mrb, nregs); + stack_clear(mrb->c->stack+keep, nregs-keep); } ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -569,7 +589,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) * k = Klass.new * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" */ -MRB_API mrb_value +mrb_value mrb_f_send(mrb_state *mrb, mrb_value self) { mrb_sym name; @@ -620,6 +640,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) { struct RProc *p; mrb_callinfo *ci; + int nregs; if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); @@ -635,19 +656,19 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) ci->argc = 1; ci->mid = ci[-1].mid; if (MRB_PROC_CFUNC_P(p)) { - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; - stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + nregs = p->body.irep->nregs; + if (nregs < 3) nregs = 3; + mrb_stack_extend(mrb, nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; - mrb->c->stack[2] = mrb_nil_value(); + stack_clear(mrb->c->stack+2, nregs-2); ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -730,13 +751,15 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value struct RProc *p; mrb_sym mid = mrb->c->ci->mid; mrb_callinfo *ci; - int n = mrb->c->ci->nregs; mrb_value val; + int n; if (mrb_nil_p(b)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + ci = mrb->c->ci; + n = ci_nregs(ci); + if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); @@ -747,9 +770,9 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->argc = (int)argc; ci->target_class = c; ci->acc = CI_ACC_SKIP; + n = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; mrb->c->stack = mrb->c->stack + n; - ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, n); mrb->c->stack[0] = self; if (argc > 0) { @@ -800,38 +823,13 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const p = mrb_proc_ptr(b); ci = mrb->c->ci; - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->stack[2] = mrb_nil_value(); ci->argc = -1; return mrb_exec_irep(mrb, self, p); } -mrb_value -mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) -{ - struct RProc *proc; - mrb_value ary; - struct RClass *c = NULL; - - mrb_get_args(mrb, ""); - ary = mrb_ary_new(mrb); - proc = mrb->c->ci[-1].proc; /* callee proc */ - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - while (proc) { - if (MRB_PROC_SCOPE_P(proc)) { - struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); - - if (c2 != c) { - c = c2; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); - } - } - proc = proc->upper; - } - return ary; -} - static struct RBreak* break_new(mrb_state *mrb, struct RProc *p, mrb_value val) { @@ -892,8 +890,8 @@ argnum_error(mrb_state *mrb, mrb_int num) mrb_exc_set(mrb, exc); } -#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc; -#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; +#define ERR_PC_SET(mrb) mrb->c->ci->err = pc0; +#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; #ifdef MRB_ENABLE_DEBUG_HOOK #define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)); #else @@ -906,25 +904,26 @@ argnum_error(mrb_state *mrb, mrb_int num) #define BYTECODE_DECODER(x) (x) #endif - +#ifndef MRB_DISABLE_DIRECT_THREADING #if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER #define DIRECT_THREADED #endif +#endif /* ifndef MRB_DISABLE_DIRECT_THREADING */ #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) { -#define CASE(op) case op: -#define NEXT pc++; break -#define JUMP break +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define CASE(insn,ops) case insn: pc0=pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define NEXT break +#define JUMP NEXT #define END_DISPATCH }} #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(op) L_ ## op: -#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] -#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] +#define CASE(insn,ops) L_ ## insn: pc0=pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] +#define JUMP NEXT #define END_DISPATCH @@ -944,51 +943,57 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac } if (stack_keep > nregs) nregs = stack_keep; - stack_extend(mrb, nregs); + mrb_stack_extend(mrb, nregs); stack_clear(c->stack + stack_keep, nregs - stack_keep); c->stack[0] = self; result = mrb_vm_exec(mrb, proc, irep->iseq); - if (c->ci - c->cibase > cioff) { + if (mrb->c != c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } + mrb->c = c; + } + else if (c->ci - c->cibase > cioff) { c->ci = c->cibase + cioff; } - mrb->c = c; return result; } +static mrb_bool +check_target_class(mrb_state *mrb) +{ + if (!mrb->c->ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); + mrb_exc_set(mrb, exc); + return FALSE; + } + return TRUE; +} + +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { - /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ + mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; - mrb_code i; + mrb_code insn; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; + uint32_t a; + uint16_t b; + uint8_t c; + mrb_sym mid; #ifdef DIRECT_THREADED static void *optable[] = { - &&L_OP_NOP, &&L_OP_MOVE, - &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, - &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, - &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, - &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, - &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, - &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, - &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, - &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, - &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, - &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, - &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, - &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, - &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, - &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, - &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, - &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, - &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, - &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, - &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, +#define OPCODE(x,_) &&L_OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #endif @@ -999,35 +1004,29 @@ RETRY_TRY_BLOCK: if (exc_catched) { exc_catched = FALSE; + mrb_gc_arena_restore(mrb, ai); if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK) goto L_BREAK; goto L_RAISE; } mrb->jmp = &c_jmp; mrb->c->ci->proc = proc; - mrb->c->ci->nregs = irep->nregs; #define regs (mrb->c->stack) INIT_DISPATCH { - CASE(OP_NOP) { + CASE(OP_NOP, Z) { /* do nothing */ NEXT; } - CASE(OP_MOVE) { - /* A B R(A) := R(B) */ - int a = GETARG_A(i); - int b = GETARG_B(i); + CASE(OP_MOVE, BB) { regs[a] = regs[b]; NEXT; } - CASE(OP_LOADL) { - /* A Bx R(A) := Pool(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_LOADL, BB) { #ifdef MRB_WORD_BOXING - mrb_value val = pool[bx]; + mrb_value val = pool[b]; #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { val = mrb_float_value(mrb, mrb_float(val)); @@ -1035,167 +1034,138 @@ RETRY_TRY_BLOCK: #endif regs[a] = val; #else - regs[a] = pool[bx]; + regs[a] = pool[b]; #endif NEXT; } - CASE(OP_LOADI) { - /* A sBx R(A) := sBx */ - int a = GETARG_A(i); - mrb_int bx = GETARG_sBx(i); - SET_INT_VALUE(regs[a], bx); + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + + CASE(OP_LOADI__1,B) goto L_LOADI; + 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: + SET_INT_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0); NEXT; } - CASE(OP_LOADSYM) { - /* A Bx R(A) := Syms(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - SET_SYM_VALUE(regs[a], syms[bx]); + CASE(OP_LOADSYM, BB) { + SET_SYM_VALUE(regs[a], syms[b]); NEXT; } - CASE(OP_LOADSELF) { - /* A R(A) := self */ - int a = GETARG_A(i); + CASE(OP_LOADNIL, B) { + SET_NIL_VALUE(regs[a]); + NEXT; + } + + CASE(OP_LOADSELF, B) { regs[a] = regs[0]; NEXT; } - CASE(OP_LOADT) { - /* A R(A) := true */ - int a = GETARG_A(i); + CASE(OP_LOADT, B) { SET_TRUE_VALUE(regs[a]); NEXT; } - CASE(OP_LOADF) { - /* A R(A) := false */ - int a = GETARG_A(i); + CASE(OP_LOADF, B) { SET_FALSE_VALUE(regs[a]); NEXT; } - CASE(OP_GETGLOBAL) { - /* A Bx R(A) := getglobal(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_gv_get(mrb, syms[bx]); + CASE(OP_GETGV, BB) { + mrb_value val = mrb_gv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETGLOBAL) { - /* A Bx setglobal(Syms(Bx), R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_gv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETGV, BB) { + mrb_gv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETSPECIAL) { - /* A Bx R(A) := Special[Bx] */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_special_get(mrb, bx); + CASE(OP_GETSV, BB) { + mrb_value val = mrb_vm_special_get(mrb, b); regs[a] = val; NEXT; } - CASE(OP_SETSPECIAL) { - /* A Bx Special[Bx] := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_special_set(mrb, bx, regs[a]); + CASE(OP_SETSV, BB) { + mrb_vm_special_set(mrb, b, regs[a]); NEXT; } - CASE(OP_GETIV) { - /* A Bx R(A) := ivget(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_iv_get(mrb, syms[bx]); - regs[a] = val; + CASE(OP_GETIV, BB) { + regs[a] = mrb_iv_get(mrb, regs[0], syms[b]); NEXT; } - CASE(OP_SETIV) { - /* A Bx ivset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_iv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETIV, BB) { + mrb_iv_set(mrb, regs[0], syms[b], regs[a]); NEXT; } - CASE(OP_GETCV) { - /* A Bx R(A) := cvget(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_GETCV, BB) { mrb_value val; - ERR_PC_SET(mrb, pc); - val = mrb_vm_cv_get(mrb, syms[bx]); + ERR_PC_SET(mrb); + val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETCV) { - /* A Bx cvset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_cv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCV, BB) { + mrb_vm_cv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCONST) { - /* A Bx R(A) := constget(Syms(Bx)) */ + CASE(OP_GETCONST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_sym sym = syms[bx]; + mrb_sym sym = syms[b]; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_vm_const_get(mrb, sym); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETCONST) { - /* A Bx constset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_const_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCONST, BB) { + mrb_vm_const_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETMCNST) { - /* A Bx R(A) := R(A)::Syms(Bx) */ + CASE(OP_GETMCNST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - ERR_PC_SET(mrb, pc); - val = mrb_const_get(mrb, regs[a], syms[bx]); + ERR_PC_SET(mrb); + val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETMCNST) { - /* A Bx R(A+1)::Syms(Bx) := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]); + CASE(OP_SETMCNST, BB) { + mrb_const_set(mrb, regs[a+1], syms[b], regs[a]); NEXT; } - CASE(OP_GETUPVAR) { - /* A B C R(A) := uvget(B,C) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_GETUPVAR, BBB) { mrb_value *regs_a = regs + a; struct REnv *e = uvenv(mrb, c); @@ -1208,12 +1178,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETUPVAR) { - /* A B C uvset(B,C,R(A)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - + CASE(OP_SETUPVAR, BBB) { struct REnv *e = uvenv(mrb, c); if (e) { @@ -1227,127 +1192,126 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_JMP) { - /* sBx pc+=sBx */ - int sbx = GETARG_sBx(i); - pc += sbx; + CASE(OP_JMP, S) { + pc = irep->iseq+a; JUMP; } - - CASE(OP_JMPIF) { - /* A sBx if R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPIF, BS) { if (mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; JUMP; } NEXT; } - - CASE(OP_JMPNOT) { - /* A sBx if !R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPNOT, BS) { if (!mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; + JUMP; + } + NEXT; + } + CASE(OP_JMPNIL, BS) { + if (mrb_nil_p(regs[a])) { + pc = irep->iseq+b; JUMP; } NEXT; } - CASE(OP_ONERR) { - /* sBx pc+=sBx on exception */ - int sbx = GETARG_sBx(i); + CASE(OP_ONERR, S) { + /* check rescue stack */ + if (mrb->c->ci->ridx == UINT16_MAX-1) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested rescues"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand rescue stack */ if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; - else mrb->c->rsize *= 2; - mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize); + else { + mrb->c->rsize *= 2; + if (mrb->c->rsize <= mrb->c->ci->ridx) { + mrb->c->rsize = UINT16_MAX; + } + } + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t)*mrb->c->rsize); } - mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx; + /* push rescue stack */ + mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } - CASE(OP_RESCUE) { - /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - mrb_value exc; - - if (c == 0) { - exc = mrb_obj_value(mrb->exc); - mrb->exc = 0; - } - else { /* continued; exc taken from R(A) */ - exc = regs[a]; - } - if (b != 0) { - mrb_value e = regs[b]; - struct RClass *ec; + CASE(OP_EXCEPT, B) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = 0; + regs[a] = exc; + NEXT; + } + CASE(OP_RESCUE, BB) { + mrb_value exc = regs[a]; /* exc on stack */ + mrb_value e = regs[b]; + struct RClass *ec; - switch (mrb_type(e)) { - case MRB_TT_CLASS: - case MRB_TT_MODULE: - break; - default: - { - mrb_value exc; + switch (mrb_type(e)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + break; + default: + { + mrb_value exc; - exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, - "class or module required for rescue clause"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } + exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, + "class or module required for rescue clause"); + mrb_exc_set(mrb, exc); + goto L_RAISE; } - ec = mrb_class_ptr(e); - regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); - } - if (a != 0 && c == 0) { - regs[a] = exc; } + ec = mrb_class_ptr(e); + regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); NEXT; } - CASE(OP_POPERR) { - /* A A.times{rescue_pop()} */ - int a = GETARG_A(i); - + CASE(OP_POPERR, B) { mrb->c->ci->ridx -= a; NEXT; } - CASE(OP_RAISE) { - /* A raise(R(A)) */ - int a = GETARG_A(i); - + CASE(OP_RAISE, B) { mrb_exc_set(mrb, regs[a]); goto L_RAISE; } - CASE(OP_EPUSH) { - /* Bx ensure_push(SEQ[Bx]) */ - int bx = GETARG_Bx(i); + CASE(OP_EPUSH, B) { struct RProc *p; - p = mrb_closure_new(mrb, irep->reps[bx]); - /* push ensure_stack */ + p = mrb_closure_new(mrb, irep->reps[a]); + /* check ensure stack */ + if (mrb->c->eidx == UINT16_MAX-1) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested ensures"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand ensure stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; - else mrb->c->esize *= 2; - mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize); + else { + mrb->c->esize *= 2; + if (mrb->c->esize <= mrb->c->eidx) { + mrb->c->esize = UINT16_MAX; + } + } + mrb->c->ensure = (struct RProc**)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*)*mrb->c->esize); } + /* push ensure stack */ mrb->c->ensure[mrb->c->eidx++] = p; mrb->c->ensure[mrb->c->eidx] = NULL; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_EPOP) { - /* A A.times{ensure_pop().call} */ - int a = GETARG_A(i); + CASE(OP_EPOP, B) { mrb_callinfo *ci = mrb->c->ci; - int n, epos = ci->epos; + unsigned int n, epos = ci->epos; mrb_value self = regs[0]; struct RClass *target_class = ci->target_class; @@ -1355,10 +1319,11 @@ RETRY_TRY_BLOCK: NEXT; } - if (a > mrb->c->eidx - epos) + if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; - pc = pc + 1; for (n=0; n<a; n++) { + int nregs = irep->nregs; + proc = mrb->c->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; if (proc == NULL) continue; @@ -1368,12 +1333,11 @@ RETRY_TRY_BLOCK: ci->argc = 0; ci->proc = proc; ci->stackent = mrb->c->stack; - ci->nregs = irep->nregs; ci->target_class = target_class; ci->pc = pc; - ci->acc = ci[-1].nregs; + ci->acc = nregs; mrb->c->stack += ci->acc; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); regs[0] = self; pc = irep->iseq; } @@ -1383,63 +1347,69 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_LOADNIL) { - /* A R(A) := nil */ - int a = GETARG_A(i); + CASE(OP_SENDV, BB) { + c = CALL_MAXARGS; + goto L_SEND; + }; - SET_NIL_VALUE(regs[a]); - NEXT; - } + CASE(OP_SENDVB, BB) { + c = CALL_MAXARGS; + goto L_SENDB; + }; - CASE(OP_SENDB) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - /* fall through */ + CASE(OP_SEND, BBB) + L_SEND: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB; + }; + L_SEND_SYM: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB_SYM; }; - L_SEND: - CASE(OP_SEND) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ - int a = GETARG_A(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SENDB, BBB) + L_SENDB: + mid = syms[b]; + L_SENDB_SYM: + { + int argc = (c == CALL_MAXARGS) ? -1 : c; + int bidx = (argc < 0) ? a+2 : a+c+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; - mrb_sym mid = syms[GETARG_B(i)]; - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); recv = regs[a]; - if (GET_OPCODE(i) != OP_SENDB) { - SET_NIL_VALUE(regs[bidx]); - blk = regs[bidx]; - } - else { - blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { - blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); - /* The stack might have been reallocated during mrb_convert_type(), - see #3622 */ - regs[bidx] = blk; - } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack might have been reallocated during mrb_convert_type(), + see #3622 */ + regs[bidx] = blk; } - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); + cls = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, 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, n, regs+a+1); - ERR_PC_SET(mrb, pc); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } if (argc >= 0) { if (a+2 >= irep->nregs) { - stack_extend(mrb, a+3); + mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, c, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1451,17 +1421,16 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; + ci->target_class = cls; ci->argc = argc; - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; /* prepare stack */ mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : n+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1475,12 +1444,10 @@ RETRY_TRY_BLOCK: mrb_gc_arena_shrink(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; - if (GET_OPCODE(i) == OP_SENDB) { - if (mrb_type(blk) == MRB_TT_PROC) { - struct RProc *p = mrb_proc_ptr(blk); - if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { - p->flags |= MRB_PROC_ORPHAN; - } + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; } } if (!ci->target_class) { /* return from context modifying method (resume/yield) */ @@ -1509,21 +1476,13 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } } - CASE(OP_FSEND) { - /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */ - /* not implemented yet */ - NEXT; - } - - CASE(OP_CALL) { - /* A R(A) := self.call(frame.argc, frame.argv) */ + CASE(OP_CALL, Z) { mrb_callinfo *ci; mrb_value recv = mrb->c->stack[0]; struct RProc *m = mrb_proc_ptr(recv); @@ -1566,12 +1525,13 @@ RETRY_TRY_BLOCK: irep = m->body.irep; if (!irep) { mrb->c->stack[0] = mrb_nil_value(); - goto L_RETURN; + a = 0; + c = OP_R_NORMAL; + goto L_OP_RETURN_BODY; } pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1588,20 +1548,17 @@ RETRY_TRY_BLOCK: } } - CASE(OP_SUPER) { - /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SUPER, BB) { + int argc = (b == CALL_MAXARGS) ? -1 : b; + int bidx = (argc < 0) ? a+2 : a+b+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = ci->mid; struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -1631,26 +1588,26 @@ RETRY_TRY_BLOCK: regs[bidx] = blk; ci = mrb->c->ci; } - c = target_class->super; - m = mrb_method_search_vm(mrb, &c, mid); + cls = target_class->super; + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); if (mid != missing) { - c = mrb_class(mrb, recv); + cls = mrb_class(mrb, recv); } - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); - ERR_PC_SET(mrb, pc); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } mid = missing; if (argc >= 0) { - if (a+2 >= ci->nregs) { - stack_extend(mrb, a+3); + if (a+2 >= irep->nregs) { + mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1661,8 +1618,8 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; - ci->pc = pc + 1; + ci->target_class = cls; + ci->pc = pc; ci->argc = argc; /* prepare stack */ @@ -1671,7 +1628,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : n+2; + if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1708,21 +1665,18 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } } - CASE(OP_ARGARY) { - /* A Bx R(A) := argument array (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_ARGARY, BS) { + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; + int lv = (b>>0)&0xf; mrb_value *stack; if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) { @@ -1737,12 +1691,12 @@ RETRY_TRY_BLOCK: else { struct REnv *e = uvenv(mrb, lv-1); if (!e) goto L_NOSUPER; - if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) + if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+kd+1) goto L_NOSUPER; stack = e->stack + 1; } if (r == 0) { - regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack); + regs[a] = mrb_ary_new_from_values(mrb, m1+m2+kd, stack); } else { mrb_value *pp = NULL; @@ -1755,7 +1709,7 @@ RETRY_TRY_BLOCK: pp = ARY_PTR(ary); len = (int)ARY_LEN(ary); } - regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); + regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd); rest = mrb_ary_ptr(regs[a]); if (m1 > 0) { stack_copy(ARY_PTR(rest), stack, m1); @@ -1766,89 +1720,126 @@ RETRY_TRY_BLOCK: if (m2 > 0) { stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); } - ARY_SET_LEN(rest, m1+len+m2); + if (kd) { + stack_copy(ARY_PTR(rest)+m1+len+m2, stack+m1+m2+1, kd); + } + ARY_SET_LEN(rest, m1+len+m2+kd); } regs[a+1] = stack[m1+r+m2]; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ENTER) { - /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - /* number of optional arguments times OP_JMP should follow */ - mrb_aspec ax = GETARG_Ax(i); - int m1 = MRB_ASPEC_REQ(ax); - int o = MRB_ASPEC_OPT(ax); - int r = MRB_ASPEC_REST(ax); - int m2 = MRB_ASPEC_POST(ax); + CASE(OP_ENTER, W) { + int m1 = MRB_ASPEC_REQ(a); + int o = MRB_ASPEC_OPT(a); + int r = MRB_ASPEC_REST(a); + int m2 = MRB_ASPEC_POST(a); + int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0; /* unused - int k = MRB_ASPEC_KEY(ax); - int kd = MRB_ASPEC_KDICT(ax); - int b = MRB_ASPEC_BLOCK(ax); + int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; - mrb_value *argv0 = argv; - int len = m1 + o + r + m2; + mrb_value * const argv0 = argv; + int const len = m1 + o + r + m2; + int const blk_pos = len + kd + 1; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + mrb_value kdict; + int kargs = kd; + /* arguments is passed with Array */ if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ARY_PTR(ary); argc = (int)ARY_LEN(ary); mrb_gc_protect(mrb, regs[1]); } + + /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0) { - if (argc < m1 + m2 || (r == 0 && argc > len)) { - argnum_error(mrb, m1+m2); - goto L_RAISE; - } + if (argc < m1 + m2 || (r == 0 && argc > len + kd)) { + argnum_error(mrb, m1+m2); + goto L_RAISE; } } + /* extract first argument array to arguments */ else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { mrb_gc_protect(mrb, argv[0]); argc = (int)RARRAY_LEN(argv[0]); argv = RARRAY_PTR(argv[0]); } - if (argc < len) { + + if (kd) { + /* check last arguments is hash if method takes keyword arguments */ + if (argc == m1+m2) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + if (argv && argc > 0 && mrb_hash_p(argv[argc-1])) { + kdict = argv[argc-1]; + mrb_hash_check_kdict(mrb, kdict); + } + else if (r || argc <= m1+m2+o + || !(mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc))) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + argnum_error(mrb, m1+m2); + goto L_RAISE; + } + if (MRB_ASPEC_KEY(a) > 0) { + kdict = mrb_hash_dup(mrb, kdict); + } + } + } + + /* no rest arguments */ + if (argc-kargs < len) { int mlen = m2; if (argc < m1+m2) { - if (m1 < argc) - mlen = argc - m1; - else - mlen = 0; + mlen = m1 < argc ? argc - m1 : 0; } - regs[len+1] = *blk; /* move block */ - SET_NIL_VALUE(regs[argc+1]); + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; + + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ } if (argc < m1) { stack_clear(®s[argc+1], m1-argc); } + /* copy post mandatory arguments */ if (mlen) { value_move(®s[len-m2+1], &argv[argc-mlen], mlen); } if (mlen < m2) { stack_clear(®s[len-m2+mlen+1], m2-mlen); } + /* initalize rest arguments with empty Array */ if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o == 0 || argc < m1+m2) pc++; - else - pc += argc - m1 - m2 + 1; + /* skip initailizer of passed arguments */ + if (o > 0 && argc-kargs > m1+m2) + pc += (argc - kargs - m1 - m2)*3; } else { int rnum = 0; if (argv0 != argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; value_move(®s[1], argv, m1+o); } if (r) { - rnum = argc-m1-o-m2; - regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + mrb_value ary; + + rnum = argc-m1-o-m2-kargs; + ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + regs[m1+o+1] = ary; } if (m2) { if (argc-m2 > m1) { @@ -1856,36 +1847,74 @@ RETRY_TRY_BLOCK: } } if (argv0 == argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; } - pc += o + 1; + pc += o*3; } - mrb->c->ci->argc = len; + + /* format arguments for generated code */ + mrb->c->ci->argc = len + kd; + /* clear local (but non-argument) variables */ - if (irep->nlocals-len-2 > 0) { - stack_clear(®s[len+2], irep->nlocals-len-2); + if (irep->nlocals-blk_pos-1 > 0) { + stack_clear(®s[blk_pos+1], irep->nlocals-blk_pos-1); } JUMP; } - CASE(OP_KARG) { - /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ - /* if C == 2; raise unless kdict.empty? */ - /* OP_JMP should follow to skip init code */ + CASE(OP_KARG, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) { + mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + regs[a] = mrb_hash_get(mrb, kdict, k); + mrb_hash_delete_key(mrb, kdict, k); NEXT; } - CASE(OP_KDICT) { - /* A C R(A) := kdict */ + CASE(OP_KEY_P, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + mrb_bool key_p = FALSE; + + if (mrb_hash_p(kdict)) { + key_p = mrb_hash_key_p(mrb, kdict, k); + } + regs[a] = mrb_bool_value(key_p); NEXT; } + CASE(OP_KEYEND, Z) { + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { + mrb_value keys = mrb_hash_keys(mrb, kdict); + mrb_value key1 = RARRAY_PTR(keys)[0]; + mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + NEXT; + } + + CASE(OP_BREAK, B) { + c = OP_R_BREAK; + goto L_RETURN; + } + CASE(OP_RETURN_BLK, B) { + c = OP_R_RETURN; + goto L_RETURN; + } + CASE(OP_RETURN, B) + c = OP_R_NORMAL; L_RETURN: - i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); - /* fall through */ - CASE(OP_RETURN) { - /* A B return R(A) (B=normal,in-block return/break) */ - mrb_callinfo *ci; + { + mrb_callinfo *ci; #define ecall_adjust() do {\ ptrdiff_t cioff = ci - mrb->c->cibase;\ @@ -1943,7 +1972,7 @@ RETRY_TRY_BLOCK: while (c->eidx > ci->epos) { ecall_adjust(); } - mrb->c->status = MRB_FIBER_TERMINATED; + c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; goto L_RAISE; @@ -1967,8 +1996,8 @@ RETRY_TRY_BLOCK: if (ci < ci0) { mrb->c->stack = ci[1].stackent; } - stack_extend(mrb, irep->nregs); - pc = mrb->c->rescue[--ci->ridx]; + mrb_stack_extend(mrb, irep->nregs); + pc = irep->iseq+mrb->c->rescue[--ci->ridx]; } else { int acc; @@ -1976,9 +2005,9 @@ RETRY_TRY_BLOCK: struct RProc *dst; ci = mrb->c->ci; - v = regs[GETARG_A(i)]; + v = regs[a]; mrb_gc_protect(mrb, v); - switch (GETARG_B(i)) { + 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)) { @@ -2010,22 +2039,21 @@ RETRY_TRY_BLOCK: case OP_R_NORMAL: NORMAL_RETURN: if (ci == mrb->c->cibase) { - struct mrb_context *c; + struct mrb_context *c = mrb->c; - if (!mrb->c->prev) { /* toplevel return */ - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; + if (!c->prev) { /* toplevel return */ + regs[irep->nlocals] = v; + goto L_STOP; } - if (mrb->c->prev->ci == mrb->c->prev->cibase) { + if (c->prev->ci == c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); mrb_exc_set(mrb, exc); goto L_RAISE; } - while (mrb->c->eidx > 0) { + while (c->eidx > 0) { ecall(mrb); } /* automatic yield at the end */ - c = mrb->c; c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; @@ -2035,7 +2063,7 @@ RETRY_TRY_BLOCK: break; case OP_R_BREAK: if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; - if (MRB_PROC_ORPHAN_P(proc)) { + if (MRB_PROC_ORPHAN_P(proc)) { mrb_value exc; L_BREAK_ERROR: @@ -2133,91 +2161,12 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_TAILCALL) { - /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - mrb_method_t m; - struct RClass *c; - mrb_callinfo *ci; - mrb_value recv; - mrb_sym mid = syms[b]; - - recv = regs[a]; - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value sym = mrb_symbol_value(mid); - mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args; - - if (n == CALL_MAXARGS) { - args = regs[a+1]; - } - else { - args = mrb_ary_new_from_values(mrb, n, regs+a+1); - } - ERR_PC_SET(mrb, pc); - mrb_method_missing(mrb, mid, recv, args); - } - mid = missing; - if (n == CALL_MAXARGS) { - mrb_ary_unshift(mrb, regs[a+1], sym); - } - else { - value_move(regs+a+2, regs+a+1, ++n); - regs[a+1] = sym; - } - } - - /* replace callinfo */ - ci = mrb->c->ci; - ci->mid = mid; - ci->target_class = c; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; - } - - /* move stack */ - value_move(mrb->c->stack, ®s[a], ci->argc+1); - - if (MRB_METHOD_CFUNC_P(m)) { - mrb_value v = MRB_METHOD_CFUNC(m)(mrb, recv); - mrb->c->stack[0] = v; - mrb_gc_arena_restore(mrb, ai); - goto L_RETURN; - } - else { - /* setup environment for calling method */ - struct RProc *p = MRB_METHOD_PROC(m); - irep = p->body.irep; - pool = irep->pool; - syms = irep->syms; - if (ci->argc < 0) { - stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); - } - else { - stack_extend(mrb, irep->nregs); - } - pc = irep->iseq; - } - JUMP; - } - - CASE(OP_BLKPUSH) { - /* A Bx R(A) := block (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_BLKPUSH, BS) { + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; + int lv = (b>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; @@ -2234,197 +2183,75 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_YIELD); goto L_RAISE; } - regs[a] = stack[m1+r+m2]; + regs[a] = stack[m1+r+m2+kd]; NEXT; } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_BODY(op,v1,v2) do {\ - v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ -} while(0) - - CASE(OP_ADD) { - /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ - int a = GETARG_A(i); - - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - mrb_value *regs_a = regs + a; - - x = mrb_fixnum(regs_a[0]); - y = mrb_fixnum(regs_a[1]); - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } +#define OP_MATH(op_name) \ + /* need to check if op is overridden */ \ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \ + OP_MATH_CASE_FIXNUM(op_name); \ + OP_MATH_CASE_FLOAT(op_name, fixnum, float); \ + OP_MATH_CASE_FLOAT(op_name, float, fixnum); \ + OP_MATH_CASE_FLOAT(op_name, float, float); \ + OP_MATH_CASE_STRING_##op_name(); \ + default: \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATH_CASE_FIXNUM(op_name) \ + case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0 +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z) #else - OP_MATH_BODY(+,mrb_float,mrb_float); +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \ + case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \ + { \ + mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \ + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y) #endif - break; -#endif - case TYPES2(MRB_TT_STRING,MRB_TT_STRING): - regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - goto L_SEND; - } - mrb_gc_arena_restore(mrb, ai); - NEXT; - } - - CASE(OP_SUB) { - /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ - int a = GETARG_A(i); - - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; +#define OP_MATH_CASE_STRING_add() \ + case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \ + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \ + mrb_gc_arena_restore(mrb, ai); \ + break +#define OP_MATH_CASE_STRING_sub() (void)0 +#define OP_MATH_CASE_STRING_mul() (void)0 +#define OP_MATH_OP_add + +#define OP_MATH_OP_sub - +#define OP_MATH_OP_mul * +#define OP_MATH_TT_fixnum MRB_TT_FIXNUM +#define OP_MATH_TT_float MRB_TT_FLOAT - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_float); -#endif - break; -#endif - default: - goto L_SEND; - } - NEXT; + CASE(OP_ADD, B) { + OP_MATH(add); } - CASE(OP_MUL) { - /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ - int a = GETARG_A(i); - - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; + CASE(OP_SUB, B) { + OP_MATH(sub); + } - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_mul_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_float); -#endif - break; -#endif - default: - goto L_SEND; - } - NEXT; + CASE(OP_MUL, B) { + OP_MATH(mul); } - CASE(OP_DIV) { - /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ - int a = GETARG_A(i); + CASE(OP_DIV, B) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2457,7 +2284,9 @@ RETRY_TRY_BLOCK: break; #endif default: - goto L_SEND; + c = 1; + mid = mrb_intern_lit(mrb, "/"); + goto L_SEND_SYM; } #ifndef MRB_WITHOUT_FLOAT @@ -2474,87 +2303,46 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI) { - /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ - int a = GETARG_A(i); - - /* need to check if + is overridden */ - switch (mrb_type(regs[a])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = GETARG_C(i); - mrb_int z; - - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i)); - } +#define OP_MATHI(op_name) \ + /* need to check if op is overridden */ \ + switch (mrb_type(regs[a])) { \ + OP_MATHI_CASE_FIXNUM(op_name); \ + OP_MATHI_CASE_FLOAT(op_name); \ + default: \ + SET_INT_VALUE(regs[a+1], b); \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATHI_CASE_FIXNUM(op_name) \ + case MRB_TT_FIXNUM: \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATHI_CASE_FLOAT(op_name) (void)0 #else - mrb_float(regs[a]) += GETARG_C(i); -#endif - break; +#define OP_MATHI_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break #endif - default: - SET_INT_VALUE(regs[a+1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); - goto L_SEND; - } - NEXT; - } - - CASE(OP_SUBI) { - /* A B C R(A) := R(A)-C (Syms[B]=:-)*/ - int a = GETARG_A(i); - mrb_value *regs_a = regs + a; - /* need to check if + is overridden */ - switch (mrb_type(regs_a[0])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = GETARG_C(i); - mrb_int z; + CASE(OP_ADDI, BB) { + OP_MATHI(add); + } - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs_a[0], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); - } -#else - mrb_float(regs_a[0]) -= GETARG_C(i); -#endif - break; -#endif - default: - SET_INT_VALUE(regs_a[1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); - goto L_SEND; - } - NEXT; + CASE(OP_SUBI, BB) { + OP_MATHI(sub); } #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) @@ -2568,7 +2356,9 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\ break;\ default:\ - goto L_SEND;\ + c = 1;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2595,7 +2385,9 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_float,mrb_float);\ break;\ default:\ - goto L_SEND;\ + c = 1;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2606,9 +2398,7 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ) { - /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ - int a = GETARG_A(i); + CASE(OP_EQ, B) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } @@ -2618,68 +2408,64 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LT) { - /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ - int a = GETARG_A(i); + CASE(OP_LT, B) { OP_CMP(<); NEXT; } - CASE(OP_LE) { - /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_LE, B) { OP_CMP(<=); NEXT; } - CASE(OP_GT) { - /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GT, B) { OP_CMP(>); NEXT; } - CASE(OP_GE) { - /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GE, B) { OP_CMP(>=); NEXT; } - CASE(OP_ARRAY) { - /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARRAY, BB) { + mrb_value v = mrb_ary_new_from_values(mrb, b, ®s[a]); + regs[a] = v; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_ARRAY2, BBB) { mrb_value v = mrb_ary_new_from_values(mrb, c, ®s[b]); regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYCAT) { - /* A B mrb_ary_concat(R(A),R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_value splat = mrb_ary_splat(mrb, regs[b]); + CASE(OP_ARYCAT, B) { + mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); mrb_ary_concat(mrb, regs[a], splat); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYPUSH) { - /* A B R(A).push(R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_ary_push(mrb, regs[a], regs[b]); + CASE(OP_ARYPUSH, B) { + mrb_ary_push(mrb, regs[a], regs[a+1]); NEXT; } - CASE(OP_AREF) { - /* A B C R(A) := R(B)[C] */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARYDUP, B) { + mrb_value ary = regs[a]; + if (mrb_array_p(ary)) { + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + } + else { + ary = mrb_ary_new_from_values(mrb, 1, &ary); + } + regs[a] = ary; + NEXT; + } + + CASE(OP_AREF, BBB) { mrb_value v = regs[b]; if (!mrb_array_p(v)) { @@ -2697,21 +2483,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ASET) { - /* A B C R(B)[C] := R(A) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ASET, BBB) { mrb_ary_set(mrb, regs[b], c, regs[a]); NEXT; } - CASE(OP_APOST) { - /* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - int a = GETARG_A(i); + CASE(OP_APOST, BBB) { mrb_value v = regs[a]; - int pre = GETARG_B(i); - int post = GETARG_C(i); + int pre = b; + int post = c; struct RArray *ary; int len, idx; @@ -2742,48 +2522,65 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STRING) { - /* A Bx R(A) := str_new(Lit(Bx)) */ - mrb_int a = GETARG_A(i); - mrb_int bx = GETARG_Bx(i); - mrb_value str = mrb_str_dup(mrb, pool[bx]); + CASE(OP_INTERN, B) { + mrb_sym sym = mrb_intern_str(mrb, regs[a]); + + regs[a] = mrb_symbol_value(sym); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRING, BB) { + mrb_value str = mrb_str_dup(mrb, pool[b]); regs[a] = str; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_STRCAT) { - /* A B R(A).concat(R(B)) */ - mrb_int a = GETARG_A(i); - mrb_int b = GETARG_B(i); + CASE(OP_STRCAT, B) { + mrb_str_concat(mrb, regs[a], regs[a+1]); + NEXT; + } + + CASE(OP_HASH, BB) { + mrb_value hash = mrb_hash_new_capa(mrb, b); + int i; + int lim = a+b*2; - mrb_str_concat(mrb, regs[a], regs[b]); + for (i=a; i<lim; i+=2) { + mrb_hash_set(mrb, hash, regs[i], regs[i+1]); + } + regs[a] = hash; + mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_HASH) { - /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - int b = GETARG_B(i); - int c = GETARG_C(i); - int lim = b+c*2; - mrb_value hash = mrb_hash_new_capa(mrb, c); + CASE(OP_HASHADD, BB) { + mrb_value hash; + int i; + int lim = a+b*2+1; - while (b < lim) { - mrb_hash_set(mrb, hash, regs[b], regs[b+1]); - b+=2; + hash = mrb_ensure_hash_type(mrb, regs[a]); + for (i=a+1; i<lim; i+=2) { + mrb_hash_set(mrb, hash, regs[i], regs[i+1]); } - regs[GETARG_A(i)] = hash; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_HASHCAT, B) { + mrb_value hash = mrb_ensure_hash_type(mrb, regs[a]); + + mrb_hash_merge(mrb, hash, regs[a+1]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_LAMBDA) { - /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */ + CASE(OP_LAMBDA, BB) + c = OP_L_LAMBDA; + L_MAKE_LAMBDA: + { struct RProc *p; - int a = GETARG_A(i); - int b = GETARG_b(i); - int c = GETARG_c(i); mrb_irep *nirep = irep->reps[b]; if (c & OP_L_CAPTURE) { @@ -2798,19 +2595,38 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_BLOCK, BB) { + c = OP_L_BLOCK; + goto L_MAKE_LAMBDA; + } + CASE(OP_METHOD, BB) { + 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); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } - CASE(OP_OCLASS) { - /* A R(A) := ::Object */ - regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); + CASE(OP_RANGE_EXC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], TRUE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_CLASS) { - /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + CASE(OP_OCLASS, B) { + regs[a] = mrb_obj_value(mrb->object_class); + NEXT; + } + + CASE(OP_CLASS, BB) { struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); mrb_value base, super; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; super = regs[a+1]; @@ -2824,32 +2640,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_MODULE) { - /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); + CASE(OP_MODULE, BB) { + struct RClass *cls = 0, *baseclass; mrb_value base; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; if (mrb_nil_p(base)) { baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); base = mrb_obj_value(baseclass); } - c = mrb_vm_define_module(mrb, base, id); - regs[a] = mrb_obj_value(c); + cls = mrb_vm_define_module(mrb, base, id); + regs[a] = mrb_obj_value(cls); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_EXEC) { - /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_EXEC, BB) { mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; - mrb_irep *nirep = irep->reps[bx]; + mrb_irep *nirep = irep->reps[b]; /* prepare closure */ p = mrb_proc_new(mrb, nirep); @@ -2860,7 +2671,7 @@ RETRY_TRY_BLOCK: /* prepare call stack */ ci = cipush(mrb); - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; ci->mid = 0; ci->stackent = mrb->c->stack; @@ -2876,63 +2687,59 @@ RETRY_TRY_BLOCK: irep = p->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); - stack_clear(regs+1, ci->nregs-1); + mrb_stack_extend(mrb, irep->nregs); + stack_clear(regs+1, irep->nregs-1); pc = irep->iseq; JUMP; } - CASE(OP_METHOD) { - /* A B R(A).newmethod(Syms(B),R(A+1)) */ - int a = GETARG_A(i); - struct RClass *c = mrb_class_ptr(regs[a]); + CASE(OP_DEF, BB) { + struct RClass *target = mrb_class_ptr(regs[a]); struct RProc *p = mrb_proc_ptr(regs[a+1]); mrb_method_t m; MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], m); + mrb_define_method_raw(mrb, target, syms[b], m); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SCLASS) { - /* A B R(A) := R(B).singleton_class */ - int a = GETARG_A(i); - int b = GETARG_B(i); - - regs[a] = mrb_singleton_class(mrb, regs[b]); + CASE(OP_SCLASS, B) { + regs[a] = mrb_singleton_class(mrb, regs[a]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_TCLASS) { - /* A R(A) := target_class */ - if (!mrb->c->ci->target_class) { - mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } - regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class); + CASE(OP_TCLASS, B) { + if (!check_target_class(mrb)) goto L_RAISE; + regs[a] = mrb_obj_value(mrb->c->ci->target_class); NEXT; } - CASE(OP_RANGE) { - /* A B C R(A) := range_new(R(B),R(B+1),C) */ - int b = GETARG_B(i); - mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); - regs[GETARG_A(i)] = val; - mrb_gc_arena_restore(mrb, ai); + CASE(OP_ALIAS, BB) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_alias_method(mrb, target, syms[a], syms[b]); + NEXT; + } + CASE(OP_UNDEF, B) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_undef_method_id(mrb, target, syms[a]); NEXT; } - CASE(OP_DEBUG) { - /* A B C debug print R(A),R(B),R(C) */ + CASE(OP_DEBUG, Z) { + FETCH_BBB(); #ifdef MRB_ENABLE_DEBUG_HOOK mrb->debug_op_hook(mrb, irep, pc, regs); #else #ifndef MRB_DISABLE_STDIO - printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); + printf("OP_DEBUG %d %d %d\n", a, b, c); #else abort(); #endif @@ -2940,12 +2747,54 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STOP) { + CASE(OP_ERR, B) { + mrb_value msg = mrb_str_dup(mrb, pool[a]); + mrb_value exc; + + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + ERR_PC_SET(mrb); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + + CASE(OP_EXT1, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); 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(); 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(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + + CASE(OP_STOP, Z) { /* stop VM */ L_STOP: while (mrb->c->eidx > 0) { ecall(mrb); } + mrb->c->cibase->ridx = 0; ERR_PC_CLR(mrb); mrb->jmp = prev_jmp; if (mrb->exc) { @@ -2953,26 +2802,9 @@ RETRY_TRY_BLOCK: } return regs[irep->nlocals]; } - - CASE(OP_ERR) { - /* Bx raise RuntimeError with message Lit(Bx) */ - mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); - mrb_value exc; - - if (GETARG_A(i) == 0) { - exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg); - } - else { - exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - } - ERR_PC_SET(mrb, pc); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } } END_DISPATCH; #undef regs - } MRB_CATCH(&c_jmp) { exc_catched = TRUE; @@ -3005,12 +2837,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); + ci->stackent = mrb->c->stack; ci->mid = 0; - ci->nregs = 1; /* protect the receiver */ ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); - cipop(mrb); return v; } |
