summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c302
-rw-r--r--src/backtrace.c205
-rw-r--r--src/cdump.c468
-rw-r--r--src/class.c1792
-rw-r--r--src/codedump.c284
-rw-r--r--src/crc.c39
-rw-r--r--src/debug.c214
-rw-r--r--src/dump.c542
-rw-r--r--src/enum.c22
-rw-r--r--src/error.c401
-rw-r--r--src/etc.c152
-rw-r--r--src/ext/.gitkeep0
-rw-r--r--src/fmt_fp.c644
-rw-r--r--src/gc.c533
-rw-r--r--src/hash.c1857
-rw-r--r--src/kernel.c431
-rw-r--r--src/load.c504
-rw-r--r--src/mruby_core.rake20
-rw-r--r--src/numeric.c1290
-rw-r--r--src/object.c315
-rw-r--r--src/pool.c2
-rw-r--r--src/print.c68
-rw-r--r--src/proc.c343
-rw-r--r--src/range.c477
-rw-r--r--src/readflt.c120
-rw-r--r--src/readint.c30
-rw-r--r--src/state.c204
-rw-r--r--src/string.c2195
-rw-r--r--src/symbol.c396
-rw-r--r--src/value_array.h1
-rw-r--r--src/variable.c465
-rw-r--r--src/vm.c1816
32 files changed, 9037 insertions, 7095 deletions
diff --git a/src/array.c b/src/array.c
index 0b039a6ec..bb7190bfd 100644
--- a/src/array.c
+++ b/src/array.c
@@ -9,6 +9,8 @@
#include <mruby/class.h>
#include <mruby/string.h>
#include <mruby/range.h>
+#include <mruby/proc.h>
+#include <mruby/presym.h>
#include "value_array.h"
#define ARY_DEFAULT_LEN 4
@@ -27,7 +29,7 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
}
blen = capa * sizeof(mrb_value);
- a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+ a = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
if (capa <= MRB_ARY_EMBED_LEN_MAX) {
ARY_SET_EMBED_LEN(a, 0);
}
@@ -54,18 +56,17 @@ mrb_ary_new(mrb_state *mrb)
}
/*
- * to copy array, use this instead of memcpy because of portability
+ * To copy array, use this instead of memcpy because of portability
* * gcc on ARM may fail optimization of memcpy
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56620
* * gcc on MIPS also fail
- * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755
* * memcpy doesn't exist on freestanding environment
*
* If you optimize for binary size, use memcpy instead of this at your own risk
* of above portability issue.
*
- * see also http://togetter.com/li/462898
- *
+ * See also https://togetter.com/li/462898 (Japanese)
*/
static inline void
array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
@@ -120,9 +121,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
@@ -280,7 +279,7 @@ static mrb_value
mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
{
mrb_value ary;
- mrb_value *vals;
+ const mrb_value *vals;
mrb_int len;
struct RArray *a;
@@ -340,7 +339,7 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
{
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
- mrb_value *ptr;
+ const mrb_value *ptr;
mrb_int blen, len1;
mrb_get_args(mrb, "a", &ptr, &blen);
@@ -388,7 +387,7 @@ ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
mrb_write_barrier(mrb, (struct RBasic*)a);
return;
}
- if (!MRB_FROZEN_P(b) && len > ARY_REPLACE_SHARED_MIN) {
+ if (!mrb_frozen_p(b) && len > ARY_REPLACE_SHARED_MIN) {
ary_make_shared(mrb, b);
goto shared_b;
}
@@ -508,22 +507,26 @@ mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
static mrb_value
mrb_ary_push_m(mrb_state *mrb, mrb_value self)
{
- mrb_value *argv;
- mrb_int len, len2, alen;
+ mrb_int argc;
+ const mrb_value *argv;
+ mrb_int len, len2;
struct RArray *a;
- mrb_get_args(mrb, "*!", &argv, &alen);
+ argc = mrb_get_argc(mrb);
+ argv = mrb_get_argv(mrb);
a = mrb_ary_ptr(self);
ary_modify(mrb, a);
len = ARY_LEN(a);
- len2 = len + alen;
+ len2 = len + argc;
if (ARY_CAPA(a) < len2) {
ary_expand_capa(mrb, a, len2);
}
- array_copy(ARY_PTR(a)+len, argv, alen);
+ array_copy(ARY_PTR(a)+len, argv, argc);
ARY_SET_LEN(a, len2);
- mrb_write_barrier(mrb, (struct RBasic*)a);
-
+ while (argc--) {
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)a, *argv);
+ argv++;
+ }
return self;
}
@@ -575,6 +578,48 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
return val;
}
+static mrb_value
+mrb_ary_shift_m(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
+ mrb_int n;
+ mrb_value val;
+
+ if (mrb_get_args(mrb, "|i", &n) == 0) {
+ return mrb_ary_shift(mrb, self);
+ };
+ ary_modify_check(mrb, a);
+ if (len == 0 || n == 0) return mrb_ary_new(mrb);
+ if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array shift");
+ if (n > len) n = len;
+ val = mrb_ary_new_from_values(mrb, n, ARY_PTR(a));
+ if (ARY_SHARED_P(a)) {
+ L_SHIFT:
+ a->as.heap.ptr+=n;
+ a->as.heap.len-=n;
+ return val;
+ }
+ if (len > ARY_SHIFT_SHARED_MIN) {
+ ary_make_shared(mrb, a);
+ goto L_SHIFT;
+ }
+ else if (len == n) {
+ ARY_SET_LEN(a, 0);
+ }
+ else {
+ mrb_value *ptr = ARY_PTR(a);
+ mrb_int size = len-n;
+
+ while (size--) {
+ *ptr = *(ptr+n);
+ ++ptr;
+ }
+ ARY_SET_LEN(a, len-n);
+ }
+ return val;
+}
+
/* self = [1,2,3]
item = 0
self.unshift item
@@ -611,7 +656,8 @@ static mrb_value
mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_value *vals, *ptr;
+ const mrb_value *vals;
+ mrb_value *ptr;
mrb_int alen, len;
mrb_get_args(mrb, "*!", &vals, &alen);
@@ -631,11 +677,13 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
ptr = a->as.heap.ptr;
}
else {
+ mrb_bool same = vals == ARY_PTR(a);
ary_modify(mrb, a);
if (ARY_CAPA(a) < len + alen)
ary_expand_capa(mrb, a, len + alen);
ptr = ARY_PTR(a);
value_move(ptr + alen, ptr, len);
+ if (same) vals = ptr;
}
array_copy(ptr, vals, alen);
ARY_SET_LEN(a, len+alen);
@@ -646,19 +694,6 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
return self;
}
-MRB_API mrb_value
-mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
-{
- struct RArray *a = mrb_ary_ptr(ary);
- mrb_int len = ARY_LEN(a);
-
- /* range check */
- if (n < 0) n += len;
- if (n < 0 || len <= n) return mrb_nil_value();
-
- return ARY_PTR(a)[n];
-}
-
MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
@@ -670,7 +705,7 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
if (n < 0) {
n += len;
if (n < 0) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of array", n - len);
}
}
if (len <= n) {
@@ -702,7 +737,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
ary_modify(mrb, a);
/* len check */
- if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len));
+ if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%i)", len);
/* range check */
if (head < 0) {
@@ -730,13 +765,17 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
argv = ARY_PTR(r);
}
}
+ else if (mrb_undef_p(rpl)) {
+ argc = 0;
+ argv = NULL;
+ }
else {
argc = 1;
argv = &rpl;
}
if (head >= alen) {
if (head > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head);
}
len = head + argc;
if (len > ARY_CAPA(a)) {
@@ -752,7 +791,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
mrb_int newlen;
if (alen - len > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len);
}
newlen = alen + argc - len;
if (newlen > ARY_CAPA(a)) {
@@ -792,7 +831,7 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg);
}
ary_make_shared(mrb, a);
- b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+ b = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
b->as.heap.ptr = a->as.heap.ptr + beg;
b->as.heap.len = len;
b->as.heap.aux.shared = a->as.heap.aux.shared;
@@ -802,20 +841,27 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
return mrb_obj_value(b);
}
+mrb_value
+mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len)
+{
+ struct RArray *a = mrb_ary_ptr(ary);
+ return ary_subseq(mrb, a, beg, len);
+}
+
static mrb_int
aget_index(mrb_state *mrb, mrb_value index)
{
- if (mrb_fixnum_p(index)) {
- return mrb_fixnum(index);
+ if (mrb_integer_p(index)) {
+ return mrb_integer(index);
}
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
else if (mrb_float_p(index)) {
return (mrb_int)mrb_float(index);
}
#endif
else {
mrb_int i, argc;
- mrb_value *argv;
+ const mrb_value *argv;
mrb_get_args(mrb, "i*!", &i, &argv, &argc);
return i;
@@ -853,26 +899,29 @@ static mrb_value
mrb_ary_aget(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int i, len, alen;
+ mrb_int i;
+ mrb_int len, alen;
mrb_value index;
- if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
+ if (mrb_get_argc(mrb) == 1) {
+ index = mrb_get_arg1(mrb);
switch (mrb_type(index)) {
/* a[n..m] */
case MRB_TT_RANGE:
- if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), 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 {
return mrb_nil_value();
}
- case MRB_TT_FIXNUM:
- return mrb_ary_ref(mrb, self, mrb_fixnum(index));
+ case MRB_TT_INTEGER:
+ return mrb_ary_ref(mrb, self, mrb_integer(index));
default:
return mrb_ary_ref(mrb, self, aget_index(mrb, index));
}
}
+ mrb_get_args(mrb, "oi", &index, &len);
i = aget_index(mrb, index);
alen = ARY_LEN(a);
if (i < 0) i += alen;
@@ -925,23 +974,27 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self)
mrb_value v1, v2, v3;
mrb_int i, len;
- mrb_ary_modify(mrb, mrb_ary_ptr(self));
- if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) {
+ ary_modify(mrb, mrb_ary_ptr(self));
+ if (mrb_get_argc(mrb) == 2) {
+ const mrb_value *vs = mrb_get_argv(mrb);
+ v1 = vs[0]; v2 = vs[1];
+
/* 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 */
- mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
+ case MRB_RANGE_OUT:
+ mrb_raisef(mrb, E_RANGE_ERROR, "%v out of range", v1);
break;
}
return v2;
}
+ mrb_get_args(mrb, "ooo", &v1, &v2, &v3);
/* a[n,m] = v */
mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3);
return v3;
@@ -1025,10 +1078,9 @@ mrb_ary_last(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_ary_index_m(mrb_state *mrb, mrb_value self)
{
- mrb_value obj;
+ mrb_value obj = mrb_get_arg1(mrb);
mrb_int i;
- mrb_get_args(mrb, "o", &obj);
for (i = 0; i < RARRAY_LEN(self); i++) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
return mrb_fixnum_value(i);
@@ -1040,10 +1092,9 @@ mrb_ary_index_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
{
- mrb_value obj;
+ mrb_value obj = mrb_get_arg1(mrb);
mrb_int i, len;
- mrb_get_args(mrb, "o", &obj);
for (i = RARRAY_LEN(self) - 1; i >= 0; i--) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
return mrb_fixnum_value(i);
@@ -1058,33 +1109,26 @@ 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 ary;
+ struct RArray *a;
if (mrb_array_p(v)) {
- return v;
+ a = ary_dup(mrb, mrb_ary_ptr(v));
+ return mrb_obj_value(a);
}
- if (!mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) {
+ if (!mrb_respond_to(mrb, v, MRB_SYM(to_a))) {
return mrb_ary_new_from_values(mrb, 1, &v);
}
- a = mrb_funcall(mrb, v, "to_a", 0);
- if (mrb_array_p(a)) {
- return a;
- }
- else if (mrb_nil_p(a)) {
+ ary = mrb_funcall_id(mrb, v, MRB_SYM(to_a), 0);
+ if (mrb_nil_p(ary)) {
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, ary);
+ a = mrb_ary_ptr(ary);
+ a = ary_dup(mrb, a);
+ return mrb_obj_value(a);
}
static mrb_value
@@ -1108,12 +1152,24 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
else if (!ARY_EMBED_P(a)){
mrb_free(mrb, a->as.heap.ptr);
}
- ARY_SET_EMBED_LEN(a, 0);
-
+ if (MRB_ARY_EMBED_LEN_MAX > 0) {
+ ARY_SET_EMBED_LEN(a, 0);
+ }
+ else {
+ a->as.heap.ptr = NULL;
+ a->as.heap.aux.capa = 0;
+ ARY_SET_LEN(a, 0);
+ }
return self;
}
static mrb_value
+mrb_ary_clear_m(mrb_state *mrb, mrb_value self)
+{
+ 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);
@@ -1122,21 +1178,16 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
}
MRB_API mrb_value
-mrb_check_array_type(mrb_state *mrb, mrb_value ary)
+mrb_ary_entry(mrb_value ary, mrb_int n)
{
- return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
-}
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
-MRB_API mrb_value
-mrb_ary_entry(mrb_value ary, mrb_int offset)
-{
- if (offset < 0) {
- offset += RARRAY_LEN(ary);
- }
- if (offset < 0 || RARRAY_LEN(ary) <= offset) {
- return mrb_nil_value();
- }
- return RARRAY_PTR(ary)[offset];
+ /* range check */
+ if (n < 0) n += len;
+ if (n < 0 || len <= n) return mrb_nil_value();
+
+ return ARY_PTR(a)[n];
}
static mrb_value
@@ -1180,7 +1231,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;
@@ -1228,9 +1279,9 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary)
static mrb_value
mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
{
- mrb_value ary2;
+ mrb_value ary2 = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &ary2);
+ mrb->c->ci->mid = 0;
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
if (!mrb_array_p(ary2)) {
return mrb_false_value();
@@ -1243,9 +1294,9 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
static mrb_value
mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
{
- mrb_value ary2;
+ mrb_value ary2 = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &ary2);
+ mrb->c->ci->mid = 0;
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0);
if (!mrb_array_p(ary2)) {
return mrb_nil_value();
@@ -1258,7 +1309,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
static mrb_value
mrb_ary_svalue(mrb_state *mrb, mrb_value ary)
{
- mrb_get_args(mrb, "");
switch (RARRAY_LEN(ary)) {
case 0:
return mrb_nil_value();
@@ -1274,41 +1324,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_m, MRB_ARGS_OPT(1)); /* 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..65cb0da1c 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -14,128 +14,112 @@
#include <mruby/error.h>
#include <mruby/numeric.h>
#include <mruby/data.h>
+#include <mruby/presym.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 };
+mrb_value mrb_exc_inspect(mrb_state *mrb, mrb_value exc);
+mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace);
+
static void
-each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
+each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *data)
{
- ptrdiff_t i, j;
-
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
- for (i=ciidx, j=0; i >= 0; i--,j++) {
+ for (ptrdiff_t i=ciidx; i >= 0; i--) {
struct backtrace_location loc;
mrb_callinfo *ci;
- mrb_irep *irep;
- mrb_code *pc;
+ const mrb_irep *irep = 0;
+ const mrb_code *pc;
+ uint32_t idx;
ci = &mrb->c->cibase[i];
- if (!ci->proc) continue;
- if (MRB_PROC_CFUNC_P(ci->proc)) continue;
-
- irep = ci->proc->body.irep;
- if (!irep) continue;
-
- if (mrb->c->cibase[i].err) {
- pc = mrb->c->cibase[i].err;
- }
- else if (i+1 <= ciidx) {
- if (!mrb->c->cibase[i + 1].pc) continue;
- pc = &mrb->c->cibase[i+1].pc[-1];
+ if (!ci->proc || MRB_PROC_CFUNC_P(ci->proc)) {
+ if (!ci->mid) continue;
+ loc.lineno = -1;
+ idx = 0;
}
else {
- pc = pc0;
+ irep = ci->proc->body.irep;
+ if (!irep) continue;
+ if (mrb->c->cibase[i].pc) {
+ pc = &mrb->c->cibase[i].pc[-1];
+ }
+ else {
+ continue;
+ }
+ idx = (uint32_t)(pc - irep->iseq);
+ loc.lineno = mrb_debug_get_line(mrb, irep, idx);
+ }
+ loc.method_id = ci->mid;
+ if (loc.lineno == -1) {
+ for (ptrdiff_t j=i-1; j >= 0; j--) {
+ ci = &mrb->c->cibase[j];
+
+ if (!ci->proc) continue;
+ if (MRB_PROC_CFUNC_P(ci->proc)) continue;
+
+ irep = ci->proc->body.irep;
+ if (!irep) continue;
+
+ if (mrb->c->cibase[j].pc) {
+ pc = &mrb->c->cibase[j].pc[-1];
+ }
+ else {
+ continue;
+ }
+
+ idx = (uint32_t)(pc - irep->iseq);
+ loc.lineno = mrb_debug_get_line(mrb, irep, idx);
+ if (loc.lineno > 0) break;
+ }
}
- loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq);
- loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq);
-
- if (loc.lineno == -1) continue;
+ loc.filename = mrb_debug_get_filename(mrb, irep, idx);
if (!loc.filename) {
loc.filename = "(unknown)";
}
- loc.method_id = ci->mid;
func(mrb, &loc, data);
}
}
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
static void
-print_backtrace(mrb_state *mrb, mrb_value backtrace)
+print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace)
{
- int i;
- mrb_int n;
+ mrb_int i;
+ mrb_int n = RARRAY_LEN(backtrace);
+ mrb_value *loc, mesg;
FILE *stream = stderr;
- if (!mrb_array_p(backtrace)) return;
-
- n = RARRAY_LEN(backtrace) - 1;
- if (n == 0) return;
-
- fprintf(stream, "trace (most recent call last):\n");
- for (i=0; i<n; i++) {
- mrb_value entry = RARRAY_PTR(backtrace)[n-i-1];
-
- if (mrb_string_p(entry)) {
- fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+ if (n != 0) {
+ if (n > 1) {
+ fprintf(stream, "trace (most recent call last):\n");
}
- }
-}
-
-static int
-packed_bt_len(struct backtrace_location *bt, int n)
-{
- int len = 0;
- int i;
-
- for (i=0; i<n; i++) {
- if (!bt[i].filename && !bt[i].lineno && !bt[i].method_id)
- continue;
- len++;
- }
- return len;
-}
-
-static void
-print_packed_backtrace(mrb_state *mrb, mrb_value packed)
-{
- FILE *stream = stderr;
- struct backtrace_location *bt;
- int n, i;
- int ai = mrb_gc_arena_save(mrb);
-
- bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type);
- if (bt == NULL) return;
- n = (mrb_int)RDATA(packed)->flags;
-
- if (packed_bt_len(bt, n) == 0) return;
- fprintf(stream, "trace (most recent call last):\n");
- for (i = 0; i<n; i++) {
- struct backtrace_location *entry = &bt[n-i-1];
- if (entry->filename == NULL) continue;
- fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno);
- if (entry->method_id != 0) {
- const char *method_name;
-
- method_name = mrb_sym2name(mrb, entry->method_id);
- fprintf(stream, ":in %s", method_name);
- mrb_gc_arena_restore(mrb, ai);
+ for (i=n-1,loc=&RARRAY_PTR(backtrace)[i]; i>0; i--,loc--) {
+ if (mrb_string_p(*loc)) {
+ fprintf(stream, "\t[%d] %.*s\n",
+ (int)i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
+ }
+ }
+ if (mrb_string_p(*loc)) {
+ fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
}
- fprintf(stream, "\n");
}
+ mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc));
+ fprintf(stream, "%.*s\n", (int)RSTRING_LEN(mesg), RSTRING_PTR(mesg));
}
/* mrb_print_backtrace
@@ -152,14 +136,10 @@ mrb_print_backtrace(mrb_state *mrb)
return;
}
- backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+ backtrace = mrb_obj_iv_get(mrb, mrb->exc, MRB_SYM(backtrace));
if (mrb_nil_p(backtrace)) return;
- if (mrb_array_p(backtrace)) {
- print_backtrace(mrb, backtrace);
- }
- else {
- print_packed_backtrace(mrb, backtrace);
- }
+ if (!mrb_array_p(backtrace)) backtrace = mrb_unpack_backtrace(mrb, backtrace);
+ print_backtrace(mrb, mrb->exc, backtrace);
}
#else
@@ -172,24 +152,22 @@ 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;
- if (loc->filename == NULL) return;
(*lenp)++;
}
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;
struct backtrace_location *ptr = *pptr;
- if (loc->filename == NULL) return;
*ptr = *loc;
*pptr = ptr+1;
}
@@ -203,20 +181,19 @@ packed_backtrace(mrb_state *mrb)
int size;
void *ptr;
- each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len);
+ each_backtrace(mrb, ciidx, 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);
+ backtrace->flags = (uint32_t)len;
+ each_backtrace(mrb, ciidx, pack_backtrace_i, &ptr);
return mrb_obj_value(backtrace);
}
void
mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
{
- mrb_sym sym = mrb_intern_lit(mrb, "backtrace");
+ mrb_sym sym = MRB_SYM(backtrace);
mrb_value backtrace;
int ai;
@@ -230,7 +207,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;
@@ -242,19 +219,22 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type);
if (bt == NULL) goto empty_backtrace;
n = (mrb_int)RDATA(backtrace)->flags;
+ if (n == 0) goto empty_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;
- btline = mrb_format(mrb, "%S:%S",
- mrb_str_new_cstr(mrb, entry->filename),
- mrb_fixnum_value(entry->lineno));
+ if (entry->lineno != -1) {//debug info was available
+ btline = mrb_format(mrb, "%s:%d", entry->filename, (int)entry->lineno);
+ }
+ else { //all that was left was the stack frame
+ btline = mrb_format(mrb, "%s:0", entry->filename);
+ }
if (entry->method_id != 0) {
mrb_str_cat_lit(mrb, btline, ":in ");
- mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id));
+ mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id));
}
mrb_ary_push(mrb, backtrace, btline);
mrb_gc_arena_restore(mrb, ai);
@@ -263,23 +243,22 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
return backtrace;
}
-MRB_API mrb_value
+mrb_value
mrb_exc_backtrace(mrb_state *mrb, mrb_value exc)
{
- mrb_sym attr_name;
mrb_value backtrace;
- attr_name = mrb_intern_lit(mrb, "backtrace");
- backtrace = mrb_iv_get(mrb, exc, attr_name);
+ backtrace = mrb_iv_get(mrb, exc, MRB_SYM(backtrace));
if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) {
return backtrace;
}
+ /* unpack packed-backtrace */
backtrace = mrb_unpack_backtrace(mrb, backtrace);
- mrb_iv_set(mrb, exc, attr_name, backtrace);
+ mrb_iv_set(mrb, exc, MRB_SYM(backtrace), backtrace);
return backtrace;
}
-MRB_API mrb_value
+mrb_value
mrb_get_backtrace(mrb_state *mrb)
{
return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
diff --git a/src/cdump.c b/src/cdump.c
new file mode 100644
index 000000000..ecc27d9a1
--- /dev/null
+++ b/src/cdump.c
@@ -0,0 +1,468 @@
+/*
+** dump.c - mruby binary dumper (mrbc binary format)
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+
+#include <string.h>
+
+#ifndef MRB_NO_STDIO
+
+#ifndef MRB_NO_FLOAT
+#include <mruby/endian.h>
+#define MRB_FLOAT_FMT "%.17g"
+#endif
+
+static int
+cdump_pool(mrb_state *mrb, const mrb_pool_value *p, FILE *fp)
+{
+ if (p->tt & IREP_TT_NFLAG) { /* number */
+ switch (p->tt) {
+#ifdef MRB_64BIT
+ case IREP_TT_INT64:
+ if (p->u.i64 < INT32_MIN || INT32_MAX < p->u.i64) {
+ fprintf(fp, "{IREP_TT_INT64, {.i64=%" PRId64 "}},\n", p->u.i64);
+ }
+ else {
+ fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", (int32_t)p->u.i64);
+ }
+ break;
+#endif
+ case IREP_TT_INT32:
+ fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", p->u.i32);
+ break;
+ case IREP_TT_FLOAT:
+#ifndef MRB_NO_FLOAT
+ if (p->u.f == 0) {
+ fprintf(fp, "{IREP_TT_FLOAT, {.f=%#.1f}},\n", p->u.f);
+ }
+ else {
+ fprintf(fp, "{IREP_TT_FLOAT, {.f=" MRB_FLOAT_FMT "}},\n", p->u.f);
+ }
+#endif
+ break;
+ case IREP_TT_BIGINT:
+ {
+ const char *s = p->u.str;
+ int len = s[0]+2;
+ fputs("{IREP_TT_BIGINT, {\"", fp);
+ for (int i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", (int)s[i]&0xff);
+ }
+ fputs("\"}},\n", fp);
+ }
+ break;
+ }
+ }
+ else { /* string */
+ int i, len = p->tt>>2;
+ const char *s = p->u.str;
+ fprintf(fp, "{IREP_TT_STR|(%d<<2), {\"", len);
+ for (i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", (int)s[i]&0xff);
+ }
+ fputs("\"}},\n", fp);
+ }
+ return MRB_DUMP_OK;
+}
+
+static mrb_bool
+sym_name_word_p(const char *name, mrb_int len)
+{
+ if (len == 0) return FALSE;
+ if (name[0] != '_' && !ISALPHA(name[0])) return FALSE;
+ for (int i = 1; i < len; i++) {
+ if (name[i] != '_' && !ISALNUM(name[i])) return FALSE;
+ }
+ return TRUE;
+}
+
+static mrb_bool
+sym_name_with_equal_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '=' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_with_question_mark_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '?' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_with_bang_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '!' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_ivar_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[0] == '@' && sym_name_word_p(name+1, len-1);
+}
+
+static mrb_bool
+sym_name_cvar_p(const char *name, mrb_int len)
+{
+ return len >= 3 && name[0] == '@' && sym_name_ivar_p(name+1, len-1);
+}
+
+#define OPERATOR_SYMBOL(sym_name, name) {name, sym_name, sizeof(sym_name)-1}
+struct operator_symbol {
+ const char *name;
+ const char *sym_name;
+ uint16_t sym_name_len;
+};
+static const struct operator_symbol operator_table[] = {
+ OPERATOR_SYMBOL("!", "not"),
+ OPERATOR_SYMBOL("%", "mod"),
+ OPERATOR_SYMBOL("&", "and"),
+ OPERATOR_SYMBOL("*", "mul"),
+ OPERATOR_SYMBOL("+", "add"),
+ OPERATOR_SYMBOL("-", "sub"),
+ OPERATOR_SYMBOL("/", "div"),
+ OPERATOR_SYMBOL("<", "lt"),
+ OPERATOR_SYMBOL(">", "gt"),
+ OPERATOR_SYMBOL("^", "xor"),
+ OPERATOR_SYMBOL("`", "tick"),
+ OPERATOR_SYMBOL("|", "or"),
+ OPERATOR_SYMBOL("~", "neg"),
+ OPERATOR_SYMBOL("!=", "neq"),
+ OPERATOR_SYMBOL("!~", "nmatch"),
+ OPERATOR_SYMBOL("&&", "andand"),
+ OPERATOR_SYMBOL("**", "pow"),
+ OPERATOR_SYMBOL("+@", "plus"),
+ OPERATOR_SYMBOL("-@", "minus"),
+ OPERATOR_SYMBOL("<<", "lshift"),
+ OPERATOR_SYMBOL("<=", "le"),
+ OPERATOR_SYMBOL("==", "eq"),
+ OPERATOR_SYMBOL("=~", "match"),
+ OPERATOR_SYMBOL(">=", "ge"),
+ OPERATOR_SYMBOL(">>", "rshift"),
+ OPERATOR_SYMBOL("[]", "aref"),
+ OPERATOR_SYMBOL("||", "oror"),
+ OPERATOR_SYMBOL("<=>", "cmp"),
+ OPERATOR_SYMBOL("===", "eqq"),
+ OPERATOR_SYMBOL("[]=", "aset"),
+};
+
+static const char*
+sym_operator_name(const char *sym_name, mrb_int len)
+{
+ mrb_sym table_size = sizeof(operator_table)/sizeof(struct operator_symbol);
+ if (operator_table[table_size-1].sym_name_len < len) return NULL;
+
+ mrb_sym start, idx;
+ int cmp;
+ const struct operator_symbol *op_sym;
+ for (start = 0; table_size != 0; table_size/=2) {
+ idx = start+table_size/2;
+ op_sym = &operator_table[idx];
+ cmp = (int)len-(int)op_sym->sym_name_len;
+ if (cmp == 0) {
+ cmp = memcmp(sym_name, op_sym->sym_name, len);
+ if (cmp == 0) return op_sym->name;
+ }
+ if (0 < cmp) {
+ start = ++idx;
+ --table_size;
+ }
+ }
+ return NULL;
+}
+
+static const char*
+sym_var_name(mrb_state *mrb, const char *initname, const char *key, int n)
+{
+ char buf[32];
+ mrb_value s = mrb_str_new_cstr(mrb, initname);
+ mrb_str_cat_lit(mrb, s, "_");
+ mrb_str_cat_cstr(mrb, s, key);
+ mrb_str_cat_lit(mrb, s, "_");
+ snprintf(buf, sizeof(buf), "%d", n);
+ mrb_str_cat_cstr(mrb, s, buf);
+ return RSTRING_PTR(s);
+}
+
+static int
+cdump_sym(mrb_state *mrb, mrb_sym sym, const char *var_name, int idx, mrb_value init_syms_code, FILE *fp)
+{
+ if (sym == 0) return MRB_DUMP_INVALID_ARGUMENT;
+
+ mrb_int len;
+ const char *name = mrb_sym_name_len(mrb, sym, &len), *op_name;
+ if (!name) return MRB_DUMP_INVALID_ARGUMENT;
+ if (sym_name_word_p(name, len)) {
+ fprintf(fp, "MRB_SYM(%s)", name);
+ }
+ else if (sym_name_with_equal_p(name, len)) {
+ fprintf(fp, "MRB_SYM_E(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_with_question_mark_p(name, len)) {
+ fprintf(fp, "MRB_SYM_Q(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_with_bang_p(name, len)) {
+ fprintf(fp, "MRB_SYM_B(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_ivar_p(name, len)) {
+ fprintf(fp, "MRB_IVSYM(%s)", name+1);
+ }
+ else if (sym_name_cvar_p(name, len)) {
+ fprintf(fp, "MRB_CVSYM(%s)", name+2);
+ }
+ else if ((op_name = sym_operator_name(name, len))) {
+ fprintf(fp, "MRB_OPSYM(%s)", op_name);
+ }
+ else {
+ char buf[32];
+ mrb_value name_obj = mrb_str_new(mrb, name, len);
+ mrb_str_cat_lit(mrb, init_syms_code, " ");
+ mrb_str_cat_cstr(mrb, init_syms_code, var_name);
+ snprintf(buf, sizeof(buf), "[%d] = ", idx);
+ mrb_str_cat_cstr(mrb, init_syms_code, buf);
+ mrb_str_cat_lit(mrb, init_syms_code, "mrb_intern_lit(mrb, ");
+ mrb_str_cat_str(mrb, init_syms_code, mrb_str_dump(mrb, name_obj));
+ mrb_str_cat_lit(mrb, init_syms_code, ");\n");
+ fputs("0", fp);
+ }
+ fputs(", ", fp);
+ return MRB_DUMP_OK;
+}
+
+static int
+cdump_syms(mrb_state *mrb, const char *name, const char *key, int n, int syms_len, const mrb_sym *syms, mrb_value init_syms_code, FILE *fp)
+{
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_int code_len = RSTRING_LEN(init_syms_code);
+ const char *var_name = sym_var_name(mrb, name, key, n);
+ fprintf(fp, "mrb_DEFINE_SYMS_VAR(%s, %d, (", var_name, syms_len);
+ for (int i=0; i<syms_len; i++) {
+ cdump_sym(mrb, syms[i], var_name, i, init_syms_code, fp);
+ }
+ fputs("), ", fp);
+ if (code_len == RSTRING_LEN(init_syms_code)) fputs("const", fp);
+ fputs(");\n", fp);
+ mrb_gc_arena_restore(mrb, ai);
+ return MRB_DUMP_OK;
+}
+
+//Handle the simple/common case of debug_info:
+// - 1 file associated with a single irep
+// - mrb_debug_line_ary format only
+static int
+simple_debug_info(mrb_irep_debug_info *info)
+{
+ if (!info || info->flen != 1) {
+ return 0;
+ }
+ return 1;
+}
+
+//Adds debug information to c-structs and
+//adds filenames in init_syms_code block
+static int
+cdump_debug(mrb_state *mrb, const char *name, int n, mrb_irep_debug_info *info,
+ mrb_value init_syms_code, FILE *fp)
+{
+ char buffer[256];
+ const char *filename;
+ mrb_int file_len;
+ int len, i;
+ const char *line_type = "mrb_debug_line_ary";
+
+ if (!simple_debug_info(info))
+ return MRB_DUMP_INVALID_IREP;
+
+ len = info->files[0]->line_entry_count;
+
+ filename = mrb_sym_name_len(mrb, info->files[0]->filename_sym, &file_len);
+ snprintf(buffer, sizeof(buffer), " %s_debug_file_%d.filename_sym = mrb_intern_lit(mrb,\"",
+ name, n);
+ mrb_str_cat_cstr(mrb, init_syms_code, buffer);
+ mrb_str_cat_cstr(mrb, init_syms_code, filename);
+ mrb_str_cat_cstr(mrb, init_syms_code, "\");\n");
+
+ switch (info->files[0]->line_type) {
+ case mrb_debug_line_ary:
+ fprintf(fp, "static uint16_t %s_debug_lines_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ if (i%10 == 0) fputs("\n", fp);
+ fprintf(fp, "0x%04x,", info->files[0]->lines.ary[i]);
+ }
+ fputs("};\n", fp);
+ break;
+
+ case mrb_debug_line_flat_map:
+ line_type = "mrb_debug_line_flat_map";
+ fprintf(fp, "static struct mrb_irep_debug_info_line %s_debug_lines_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ mrb_irep_debug_info_line *fmap = &info->files[0]->lines.flat_map[i];
+ fprintf(fp, "\t{.start_pos=0x%04x,.line=%d},\n", fmap->start_pos, fmap->line);
+ }
+ fputs("};\n", fp);
+ break;
+
+ case mrb_debug_line_packed_map:
+ line_type = "mrb_debug_line_packed_map";
+ fprintf(fp, "static char %s_debug_lines_%d[] = \"", name, n);
+ uint8_t *pmap = info->files[0]->lines.packed_map;
+ for (i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", pmap[i]&0xff);
+ }
+ fputs("\";\n", fp);
+ break;
+ }
+ fprintf(fp, "static mrb_irep_debug_info_file %s_debug_file_%d = {\n", name, n);
+ fprintf(fp, "%d, %d, %d, %s, {%s_debug_lines_%d}};\n",
+ info->files[0]->start_pos,
+ info->files[0]->filename_sym,
+ info->files[0]->line_entry_count,
+ line_type,
+ name,n);
+ fprintf(fp, "static mrb_irep_debug_info_file *%s_debug_file_%d_ = &%s_debug_file_%d;\n", name, n, name, n);
+
+ fprintf(fp, "static mrb_irep_debug_info %s_debug_%d = {\n", name, n);
+ fprintf(fp, "%d, %d, &%s_debug_file_%d_};\n", info->pc_count, info->flen, name, n);
+
+ return MRB_DUMP_OK;
+}
+
+static int
+cdump_irep_struct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *name, int n, mrb_value init_syms_code, int *mp)
+{
+ int i, len;
+ int max = *mp;
+ int debug_available = 0;
+
+ /* dump reps */
+ if (irep->reps) {
+ for (i=0,len=irep->rlen; i<len; i++) {
+ *mp += len;
+ if (cdump_irep_struct(mrb, irep->reps[i], flags, fp, name, max+i, init_syms_code, mp) != MRB_DUMP_OK)
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ fprintf(fp, "static const mrb_irep *%s_reps_%d[%d] = {\n", name, n, len);
+ for (i=0,len=irep->rlen; i<len; i++) {
+ fprintf(fp, " &%s_irep_%d,\n", name, max+i);
+ }
+ fputs("};\n", fp);
+ }
+ /* dump pool */
+ if (irep->pool) {
+ len=irep->plen;
+ fprintf(fp, "static const mrb_pool_value %s_pool_%d[%d] = {\n", name, n, len);
+ for (i=0; i<len; i++) {
+ if (cdump_pool(mrb, &irep->pool[i], fp) != MRB_DUMP_OK)
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ fputs("};\n", fp);
+ }
+ /* dump syms */
+ if (irep->syms) {
+ cdump_syms(mrb, name, "syms", n, irep->slen, irep->syms, init_syms_code, fp);
+ }
+ /* dump iseq */
+ len=irep->ilen+sizeof(struct mrb_irep_catch_handler)*irep->clen;
+ fprintf(fp, "static const mrb_code %s_iseq_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ if (i%20 == 0) fputs("\n", fp);
+ fprintf(fp, "0x%02x,", irep->iseq[i]);
+ }
+ fputs("};\n", fp);
+ /* dump lv */
+ if (irep->lv) {
+ cdump_syms(mrb, name, "lv", n, irep->nlocals-1, irep->lv, init_syms_code, fp);
+ }
+ /* dump debug */
+ if (flags & MRB_DUMP_DEBUG_INFO) {
+ if(cdump_debug(mrb, name, n, irep->debug_info,
+ init_syms_code, fp) == MRB_DUMP_OK) {
+ debug_available = 1;
+ }
+ }
+
+
+ /* dump irep */
+ fprintf(fp, "static const mrb_irep %s_irep_%d = {\n", name, n);
+ fprintf(fp, " %d,%d,%d,\n", irep->nlocals, irep->nregs, irep->clen);
+ fprintf(fp, " MRB_IREP_STATIC,%s_iseq_%d,\n", name, n);
+ if (irep->pool) {
+ fprintf(fp, " %s_pool_%d,", name, n);
+ }
+ else {
+ fputs( " NULL,", fp);
+ }
+ if (irep->syms) {
+ fprintf(fp, "%s_syms_%d,", name, n);
+ }
+ else {
+ fputs( "NULL,", fp);
+ }
+ if (irep->reps) {
+ fprintf(fp, "%s_reps_%d,\n", name, n);
+ }
+ else {
+ fputs( "NULL,\n", fp);
+ }
+ if (irep->lv) {
+ fprintf(fp, " %s_lv_%d,\n", name, n);
+ }
+ else {
+ fputs( " NULL,\t\t\t\t\t/* lv */\n", fp);
+ }
+ if(debug_available) {
+ fprintf(fp, " &%s_debug_%d,\n", name, n);
+ }
+ else {
+ fputs(" NULL,\t\t\t\t\t/* debug_info */\n", fp);
+ }
+ fprintf(fp, " %d,%d,%d,%d,0\n};\n", irep->ilen, irep->plen, irep->slen, irep->rlen);
+
+ return MRB_DUMP_OK;
+}
+
+int
+mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
+{
+ if (fp == NULL || initname == NULL || initname[0] == '\0') {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ if (fprintf(fp, "#include <mruby.h>\n"
+ "#include <mruby/irep.h>\n"
+ "#include <mruby/debug.h>\n"
+ "#include <mruby/proc.h>\n"
+ "#include <mruby/presym.h>\n"
+ "\n") < 0) {
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ fputs("#define mrb_BRACED(...) {__VA_ARGS__}\n", fp);
+ fputs("#define mrb_DEFINE_SYMS_VAR(name, len, syms, qualifier) \\\n", fp);
+ fputs(" static qualifier mrb_sym name[len] = mrb_BRACED syms\n", fp);
+ fputs("\n", fp);
+ mrb_value init_syms_code = mrb_str_new_capa(mrb, 0);
+ int max = 1;
+ int n = cdump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max);
+ if (n != MRB_DUMP_OK) return n;
+ fprintf(fp,
+ "%s\n"
+ "const struct RProc %s[] = {{\n",
+ (flags & MRB_DUMP_STATIC) ? "static"
+ : "#ifdef __cplusplus\n"
+ "extern\n"
+ "#endif",
+ initname);
+ fprintf(fp, "NULL,NULL,MRB_TT_PROC,MRB_GC_RED,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname);
+ fputs("static void\n", fp);
+ fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname);
+ fputs("{\n", fp);
+ fputs(RSTRING_PTR(init_syms_code), fp);
+ fputs("}\n", fp);
+ return MRB_DUMP_OK;
+}
+#endif
diff --git a/src/class.c b/src/class.c
index 50ab0ea59..33a610c26 100644
--- a/src/class.c
+++ b/src/class.c
@@ -7,6 +7,7 @@
#include <stdarg.h>
#include <mruby.h>
#include <mruby/array.h>
+#include <mruby/hash.h>
#include <mruby/class.h>
#include <mruby/numeric.h>
#include <mruby/proc.h>
@@ -15,48 +16,285 @@
#include <mruby/error.h>
#include <mruby/data.h>
#include <mruby/istruct.h>
+#include <mruby/opcode.h>
+#include <mruby/presym.h>
-KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal)
+union mt_ptr {
+ struct RProc *proc;
+ mrb_func_t func;
+};
+
+struct mt_elem {
+ union mt_ptr ptr;
+ size_t func_p:1;
+ size_t noarg_p:1;
+ mrb_sym key:sizeof(mrb_sym)*8-2;
+};
+
+/* method table structure */
+typedef struct mt_tbl {
+ size_t size;
+ size_t alloc;
+ struct mt_elem *table;
+} mt_tbl;
+
+/* Creates the method table. */
+static mt_tbl*
+mt_new(mrb_state *mrb)
+{
+ mt_tbl *t;
+
+ t = (mt_tbl*)mrb_malloc(mrb, sizeof(mt_tbl));
+ t->size = 0;
+ t->alloc = 0;
+ t->table = NULL;
+
+ return t;
+}
+
+static struct mt_elem *mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, size_t func_p, size_t noarg_p, union mt_ptr ptr);
+
+static void
+mt_rehash(mrb_state *mrb, mt_tbl *t)
+{
+ size_t old_alloc = t->alloc;
+ size_t new_alloc = old_alloc+1;
+ struct mt_elem *old_table = t->table;
+
+ khash_power2(new_alloc);
+ if (old_alloc == new_alloc) return;
+
+ t->alloc = new_alloc;
+ t->size = 0;
+ t->table = (struct mt_elem*)mrb_calloc(mrb, sizeof(struct mt_elem), new_alloc);
+
+ for (size_t i = 0; i < old_alloc; i++) {
+ struct mt_elem *slot = &old_table[i];
+
+ /* key = 0 means empty or deleted */
+ if (slot->key != 0) {
+ mt_put(mrb, t, slot->key, slot->func_p, slot->noarg_p, slot->ptr);
+ }
+ }
+ mrb_free(mrb, old_table);
+}
+
+#define slot_empty_p(slot) ((slot)->key == 0 && (slot)->func_p == 0)
+
+/* Set the value for the symbol in the method table. */
+static struct mt_elem*
+mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, size_t func_p, size_t noarg_p, union mt_ptr ptr)
+{
+ size_t hash, pos, start;
+ struct mt_elem *dslot = NULL;
+
+ if (t->alloc == 0) {
+ mt_rehash(mrb, t);
+ }
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct mt_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ slot->func_p = func_p;
+ slot->noarg_p = noarg_p;
+ slot->ptr = ptr;
+ return slot;
+ }
+ else if (slot->key == 0) { /* empty or deleted */
+ if (slot->func_p == 0) { /* empty */
+ t->size++;
+ slot->key = sym;
+ slot->func_p = func_p;
+ slot->noarg_p = noarg_p;
+ slot->ptr = ptr;
+ return slot;
+ }
+ else if (!dslot) { /* deleted */
+ dslot = slot;
+ }
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ if (dslot) {
+ t->size++;
+ dslot->key = sym;
+ dslot->func_p = func_p;
+ dslot->noarg_p = noarg_p;
+ dslot->ptr = ptr;
+ return dslot;
+ }
+ /* no room */
+ mt_rehash(mrb, t);
+ start = pos = hash & (t->alloc-1);
+ }
+ }
+}
+
+/* Get a value for a symbol from the method table. */
+static struct mt_elem*
+mt_get(mrb_state *mrb, mt_tbl *t, mrb_sym sym)
+{
+ size_t hash, pos, start;
+
+ if (t == NULL) return NULL;
+ if (t->alloc == 0) return NULL;
+ if (t->size == 0) return NULL;
+
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct mt_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ return slot;
+ }
+ else if (slot_empty_p(slot)) {
+ return NULL;
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ return NULL;
+ }
+ }
+}
+
+/* Deletes the value for the symbol from the method table. */
+static mrb_bool
+mt_del(mrb_state *mrb, mt_tbl *t, mrb_sym sym)
+{
+ size_t hash, pos, start;
+
+ if (t == NULL) return FALSE;
+ if (t->alloc == 0) return FALSE;
+ if (t->size == 0) return FALSE;
+
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct mt_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ t->size--;
+ slot->key = 0;
+ slot->func_p = 1;
+ return TRUE;
+ }
+ else if (slot_empty_p(slot)) {
+ return FALSE;
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ return FALSE;
+ }
+ }
+}
+
+/* Copy the method table. */
+static struct mt_tbl*
+mt_copy(mrb_state *mrb, mt_tbl *t)
+{
+ mt_tbl *t2;
+ size_t i;
+
+ if (t == NULL) return NULL;
+ if (t->alloc == 0) return NULL;
+ if (t->size == 0) return NULL;
+
+ t2 = mt_new(mrb);
+ for (i=0; i<t->alloc; i++) {
+ struct mt_elem *slot = &t->table[i];
+
+ if (slot->key) {
+ mt_put(mrb, t2, slot->key, slot->func_p, slot->noarg_p, slot->ptr);
+ }
+ }
+ return t2;
+}
+
+/* Free memory of the method table. */
+static void
+mt_free(mrb_state *mrb, mt_tbl *t)
+{
+ mrb_free(mrb, t->table);
+ mrb_free(mrb, t);
+}
+
+MRB_API void
+mrb_mt_foreach(mrb_state *mrb, struct RClass *c, mrb_mt_foreach_func *fn, void *p)
+{
+ mt_tbl *t = c->mt;
+ size_t i;
+
+ if (t == NULL) return;
+ if (t->alloc == 0) return;
+ if (t->size == 0) return;
+
+ for (i=0; i<t->alloc; i++) {
+ struct mt_elem *slot = &t->table[i];
+
+ if (slot->key) {
+ mrb_method_t m;
+
+ if (slot->func_p) {
+ MRB_METHOD_FROM_FUNC(m, slot->ptr.func);
+ }
+ else {
+ MRB_METHOD_FROM_PROC(m, slot->ptr.proc);
+ }
+ if (slot->noarg_p) {
+ MRB_METHOD_NOARG_SET(m);
+ }
+
+ if (fn(mrb, slot->key, m, p) != 0)
+ return;
+ }
+ }
+ return;
+}
void
mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
{
- khiter_t k;
- khash_t(mt) *h = c->mt;
+ mt_tbl *t = c->mt;
+ size_t i;
- if (!h) return;
- for (k = kh_begin(h); k != kh_end(h); k++) {
- if (kh_exist(h, k)) {
- mrb_method_t m = kh_value(h, k);
+ if (t == NULL) return;
+ if (t->alloc == 0) return;
+ if (t->size == 0) return;
- if (MRB_METHOD_PROC_P(m)) {
- struct RProc *p = MRB_METHOD_PROC(m);
- mrb_gc_mark(mrb, (struct RBasic*)p);
- }
+ for (i=0; i<t->alloc; i++) {
+ struct mt_elem *slot = &t->table[i];
+
+ if (slot->key && !slot->func_p) { /* Proc pointer */
+ struct RProc *p = slot->ptr.proc;
+ mrb_gc_mark(mrb, (struct RBasic*)p);
}
}
+ return;
}
size_t
mrb_gc_mark_mt_size(mrb_state *mrb, struct RClass *c)
{
- khash_t(mt) *h = c->mt;
+ struct mt_tbl *h = c->mt;
if (!h) return 0;
- return kh_size(h);
+ return h->size;
}
void
mrb_gc_free_mt(mrb_state *mrb, struct RClass *c)
{
- kh_destroy(mt, mrb, c->mt);
+ if (c->mt) mt_free(mrb, c->mt);
}
void
mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
{
mrb_value name;
- mrb_sym nsym = mrb_intern_lit(mrb, "__classname__");
+ mrb_sym nsym = MRB_SYM(__classname__);
if (mrb_obj_iv_defined(mrb, (struct RObject*)c, nsym)) return;
if (outer == NULL || outer == mrb->object_class) {
@@ -66,15 +304,26 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb
name = mrb_class_path(mrb, outer);
if (mrb_nil_p(name)) { /* unnamed outer class */
if (outer != mrb->object_class && outer != c) {
- mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
- mrb_obj_value(outer));
+ mrb_obj_iv_set_force(mrb, (struct RObject*)c, MRB_SYM(__outer__),
+ mrb_obj_value(outer));
}
return;
}
- mrb_str_cat_cstr(mrb, name, "::");
- mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id));
+ else {
+ mrb_int len;
+ const char *n = mrb_sym_name_len(mrb, id, &len);
+
+ mrb_str_cat_lit(mrb, name, "::");
+ mrb_str_cat(mrb, name, n, len);
+ }
}
- mrb_obj_iv_set(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
@@ -92,9 +341,9 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
struct RClass *sc, *c;
if (o->c->tt == MRB_TT_SCLASS) return;
- sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
+ sc = MRB_OBJ_ALLOC(mrb, MRB_TT_SCLASS, mrb->class_class);
sc->flags |= MRB_FL_CLASS_IS_INHERITED;
- sc->mt = kh_init(mt, mrb);
+ sc->mt = mt_new(mrb);
sc->iv = 0;
if (o->tt == MRB_TT_CLASS) {
c = (struct RClass*)o;
@@ -119,7 +368,21 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
o->c = sc;
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));
+ mrb_obj_iv_set(mrb, (struct RObject*)sc, MRB_SYM(__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_cat_str(mrb, path, mrb_ptr_to_str(mrb, c));
+ mrb_str_cat_lit(mrb, path, ">");
+ }
+ return path;
}
static struct RClass*
@@ -157,7 +420,7 @@ static void
check_if_class_or_module(mrb_state *mrb, mrb_value obj)
{
if (!class_ptr_p(obj)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj);
}
}
@@ -187,15 +450,15 @@ mrb_define_module(mrb_state *mrb, const char *name)
return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class);
}
-MRB_API struct RClass*
+struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
check_if_class_or_module(mrb, outer);
if (mrb_const_defined_at(mrb, outer, id)) {
mrb_value old = mrb_const_get(mrb, outer, id);
- if (mrb_type(old) != MRB_TT_MODULE) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
+ if (!mrb_module_p(old)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old);
}
return mrb_class_ptr(old);
}
@@ -203,6 +466,15 @@ mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
}
MRB_API struct RClass*
+mrb_define_module_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name)
+{
+ struct RClass * c = define_module(mrb, name, outer);
+
+ setup_class(mrb, outer, c, name);
+ return c;
+}
+
+MRB_API struct RClass*
mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
mrb_sym id = mrb_intern_cstr(mrb, name);
@@ -228,9 +500,8 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
c = class_from_sym(mrb, outer, name);
MRB_CLASS_ORIGIN(c);
if (super && mrb_class_real(c->super) != super) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
- mrb_sym2str(mrb, name),
- mrb_obj_value(c->super), mrb_obj_value(super));
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)",
+ name, c->super, super);
}
return c;
}
@@ -245,7 +516,7 @@ MRB_API struct RClass*
mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super)
{
if (!super) {
- mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name));
+ mrb_warn(mrb, "no super class for '%n', Object assumed", name);
}
return define_class(mrb, name, super, mrb->object_class);
}
@@ -257,14 +528,10 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
}
static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value);
-#ifdef MRB_METHOD_CACHE
-static void mc_clear_all(mrb_state *mrb);
-static void mc_clear_by_class(mrb_state *mrb, struct RClass*);
-static void mc_clear_by_id(mrb_state *mrb, struct RClass*, mrb_sym);
+#ifndef MRB_NO_METHOD_CACHE
+static void mc_clear(mrb_state *mrb);
#else
-#define mc_clear_all(mrb)
-#define mc_clear_by_class(mrb,c)
-#define mc_clear_by_id(mrb,c,s)
+#define mc_clear(mrb)
#endif
static void
@@ -277,24 +544,23 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
super = mrb->object_class;
super->flags |= MRB_FL_CLASS_IS_INHERITED;
s = mrb_obj_value(super);
- mc_clear_by_class(mrb, klass);
- mid = mrb_intern_lit(mrb, "inherited");
+ mrb_mc_clear_by_class(mrb, klass);
+ mid = MRB_SYM(inherited);
if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
mrb_value c = mrb_obj_value(klass);
mrb_funcall_argv(mrb, s, mid, 1, &c);
}
}
-MRB_API struct RClass*
+struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
struct RClass *s;
struct RClass *c;
if (!mrb_nil_p(super)) {
- if (mrb_type(super) != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)",
- mrb_inspect(mrb, super));
+ if (!mrb_class_p(super)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super);
}
s = mrb_class_ptr(super);
}
@@ -305,14 +571,14 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
if (mrb_const_defined_at(mrb, outer, id)) {
mrb_value old = mrb_const_get(mrb, outer, id);
- if (mrb_type(old) != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
+ if (!mrb_class_p(old)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", old);
}
c = mrb_class_ptr(old);
if (s) {
/* check super class */
if (mrb_class_real(c->super) != s) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old);
}
}
return c;
@@ -326,21 +592,29 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
MRB_API mrb_bool
mrb_class_defined(mrb_state *mrb, const char *name)
{
- mrb_value sym = mrb_check_intern_cstr(mrb, name);
- if (mrb_nil_p(sym)) {
- return FALSE;
- }
- return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym));
+ mrb_sym sym = mrb_intern_check_cstr(mrb, name);
+ if (!sym) return FALSE;
+ return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), sym);
+}
+
+MRB_API mrb_bool
+mrb_class_defined_id(mrb_state *mrb, mrb_sym name)
+{
+ return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), name);
}
MRB_API mrb_bool
mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
- mrb_value sym = mrb_check_intern_cstr(mrb, name);
- if (mrb_nil_p(sym)) {
- return FALSE;
- }
- return mrb_const_defined_at(mrb, mrb_obj_value(outer), mrb_symbol(sym));
+ mrb_sym sym = mrb_intern_check_cstr(mrb, name);
+ if (!sym) return FALSE;
+ return mrb_const_defined_at(mrb, mrb_obj_value(outer), sym);
+}
+
+MRB_API mrb_bool
+mrb_class_defined_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name)
+{
+ return mrb_const_defined_at(mrb, mrb_obj_value(outer), name);
}
MRB_API struct RClass*
@@ -350,19 +624,30 @@ mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
}
MRB_API struct RClass*
+mrb_class_get_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name)
+{
+ return class_from_sym(mrb, outer, name);
+}
+
+MRB_API struct RClass*
mrb_class_get(mrb_state *mrb, const char *name)
{
return mrb_class_get_under(mrb, mrb->object_class, name);
}
MRB_API struct RClass*
-mrb_exc_get(mrb_state *mrb, const char *name)
+mrb_class_get_id(mrb_state *mrb, mrb_sym name)
+{
+ return mrb_class_get_under_id(mrb, mrb->object_class, name);
+}
+
+MRB_API struct RClass*
+mrb_exc_get_id(mrb_state *mrb, mrb_sym name)
{
struct RClass *exc, *e;
- mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class),
- mrb_intern_cstr(mrb, name));
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), name);
- if (mrb_type(c) != MRB_TT_CLASS) {
+ if (!mrb_class_p(c)) {
mrb_raise(mrb, mrb->eException_class, "exception corrupted");
}
exc = e = mrb_class_ptr(c);
@@ -382,15 +667,27 @@ mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
}
MRB_API struct RClass*
+mrb_module_get_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name)
+{
+ return module_from_sym(mrb, outer, name);
+}
+
+MRB_API struct RClass*
mrb_module_get(mrb_state *mrb, const char *name)
{
return mrb_module_get_under(mrb, mrb->object_class, name);
}
+MRB_API struct RClass*
+mrb_module_get_id(mrb_state *mrb, mrb_sym name)
+{
+ return mrb_module_get_under_id(mrb, mrb->object_class, name);
+}
+
/*!
* Defines a class under the namespace of \a outer.
* \param outer a class which contains the new class.
- * \param id name of the new class
+ * \param name name of the new class
* \param super a class from which the new class will derive.
* NULL means \c Object class.
* \return the created class
@@ -404,50 +701,60 @@ mrb_module_get(mrb_state *mrb, const char *name)
* \a super, the function just returns the defined class.
*/
MRB_API struct RClass*
-mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
+mrb_define_class_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name, struct RClass *super)
{
- mrb_sym id = mrb_intern_cstr(mrb, name);
struct RClass * c;
#if 0
if (!super) {
- mrb_warn(mrb, "no super class for '%S::%S', Object assumed",
- mrb_obj_value(outer), mrb_sym2str(mrb, id));
+ mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id);
}
#endif
- c = define_class(mrb, id, super, outer);
- setup_class(mrb, outer, c, id);
+ c = define_class(mrb, name, super, outer);
+ setup_class(mrb, outer, c, name);
return c;
}
+MRB_API struct RClass*
+mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
+{
+ return mrb_define_class_under_id(mrb, outer, mrb_intern_cstr(mrb, name), super);
+}
+
MRB_API void
mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_t m)
{
- khash_t(mt) *h;
- khiter_t k;
+ mt_tbl *h;
+ union mt_ptr ptr;
+
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");
- }
- if (!h) h = c->mt = kh_init(mt, mrb);
- k = kh_put(mt, mrb, h, mid);
- kh_value(h, k) = m;
- if (MRB_METHOD_PROC_P(m) && !MRB_METHOD_UNDEF_P(m)) {
+ mrb_check_frozen(mrb, c);
+ if (!h) h = c->mt = mt_new(mrb);
+ if (MRB_METHOD_PROC_P(m)) {
struct RProc *p = MRB_METHOD_PROC(m);
- p->flags |= MRB_PROC_SCOPE;
- p->c = NULL;
- mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p);
- if (!MRB_PROC_ENV_P(p)) {
- MRB_PROC_SET_TARGET_CLASS(p, c);
+ ptr.proc = p;
+ if (p) {
+ if (p->color != MRB_GC_RED) {
+ p->flags |= MRB_PROC_SCOPE;
+ p->c = NULL;
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p);
+ if (!MRB_PROC_ENV_P(p)) {
+ MRB_PROC_SET_TARGET_CLASS(p, c);
+ }
+ }
+ else {
+ mrb_assert(MRB_FROZEN_P(p) && MRB_PROC_SCOPE_P(p));
+ mrb_assert(p->c == NULL && p->upper == NULL && p->e.target_class == NULL);
+ }
}
}
- mc_clear_by_id(mrb, c, mid);
+ else {
+ ptr.func = MRB_METHOD_FUNC(m);
+ }
+ mt_put(mrb, h, mid, MRB_METHOD_FUNC_P(m), MRB_METHOD_NOARG_P(m), ptr);
+ mc_clear(mrb);
}
MRB_API void
@@ -457,6 +764,12 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f
int ai = mrb_gc_arena_save(mrb);
MRB_METHOD_FROM_FUNC(m, func);
+#ifndef MRB_USE_METHOD_T_STRUCT
+ mrb_assert(MRB_METHOD_FUNC(m) == func);
+#endif
+ if (aspec == MRB_ARGS_NONE()) {
+ MRB_METHOD_NOARG_SET(m);
+ }
mrb_define_method_raw(mrb, c, mid, m);
mrb_gc_arena_restore(mrb, ai);
}
@@ -471,15 +784,10 @@ 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_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid);
}
}
@@ -493,33 +801,17 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self)
}
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;
-}
-
-static mrb_value
-to_str(mrb_state *mrb, mrb_value val)
-{
- return check_type(mrb, val, MRB_TT_STRING, "String", "to_str");
-}
-
-static mrb_value
to_ary(mrb_state *mrb, mrb_value val)
{
- return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
+ mrb_check_type(mrb, val, MRB_TT_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");
+ mrb_check_type(mrb, val, MRB_TT_HASH);
+ return val;
}
#define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss)
@@ -530,29 +822,56 @@ mrb_get_argc(mrb_state *mrb)
mrb_int argc = mrb->c->ci->argc;
if (argc < 0) {
- struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
+ struct RArray *a = mrb_ary_ptr(mrb->c->ci->stack[1]);
argc = ARY_LEN(a);
}
return argc;
}
-MRB_API mrb_value*
+MRB_API const mrb_value*
mrb_get_argv(mrb_state *mrb)
{
mrb_int argc = mrb->c->ci->argc;
- mrb_value *array_argv;
+ mrb_value *array_argv = mrb->c->ci->stack + 1;
if (argc < 0) {
- struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
+ struct RArray *a = mrb_ary_ptr(*array_argv);
array_argv = ARY_PTR(a);
}
- else {
- array_argv = NULL;
- }
return array_argv;
}
+MRB_API mrb_value
+mrb_get_arg1(mrb_state *mrb)
+{
+ mrb_int argc = mrb->c->ci->argc;
+ mrb_value *array_argv = mrb->c->ci->stack + 1;
+ if (argc < 0) {
+ struct RArray *a = mrb_ary_ptr(*array_argv);
+
+ argc = ARY_LEN(a);
+ array_argv = ARY_PTR(a);
+ }
+ if (argc != 1) {
+ mrb_argnum_error(mrb, argc, 1, 1);
+ }
+ return array_argv[0];
+}
+
+MRB_API mrb_bool
+mrb_block_given_p(mrb_state *mrb)
+{
+ const mrb_callinfo *ci = mrb->c->ci;
+ int argc = ci->argc;
+ int idx = (argc < 0) ? 2 : argc + 1;
+ mrb_value b = ci->stack[idx];
+
+ return !mrb_nil_p(b);
+}
+
+void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
+
/*
retrieve arguments from mrb_state.
@@ -565,23 +884,25 @@ 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
- *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
+ s: String [const char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil
+ z: String [const char*] NUL terminated string; z! gives NULL for nil
+ a: Array [const mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil
+ c: Class/Module [strcut RClass*]
+ f: Integer/Float [mrb_float]
+ i: Integer/Float [mrb_int]
+ b: boolean [mrb_bool]
+ n: String/Symbol [mrb_sym]
+ d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil
+ I: inline struct [void*]
+ &: block [mrb_value] &! raises exception if no block given
+ *: rest argument [const mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
|: optional Following arguments are optional
?: optional given [mrb_bool] true if preceding argument (optional) is given
+ ':': keyword args [mrb_kwargs const] Get keyword arguments
*/
MRB_API mrb_int
mrb_get_args(mrb_state *mrb, const char *format, ...)
@@ -590,17 +911,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
char c;
mrb_int i = 0;
va_list ap;
- mrb_int argc = mrb_get_argc(mrb);
- mrb_int arg_i = 0;
- mrb_value *array_argv = mrb_get_argv(mrb);
+ mrb_int argc = mrb->c->ci->argc;
+ mrb_value *array_argv = mrb->c->ci->stack+1;
+ mrb_bool argv_on_stack = argc >= 0;
mrb_bool opt = FALSE;
mrb_bool opt_skip = TRUE;
mrb_bool given = TRUE;
+ mrb_value kdict;
+ mrb_bool reqkarg = FALSE;
+ int argc_min = 0, argc_max = 0;
+ if (!argv_on_stack) {
+ struct RArray *a = mrb_ary_ptr(*array_argv);
+ array_argv = ARY_PTR(a);
+ argc = ARY_LEN(a);
+ }
va_start(ap, format);
-#define ARGV \
- (array_argv ? array_argv : (mrb->c->stack + 1))
+#define ARGV array_argv
while ((c = *fmt++)) {
switch (c) {
@@ -609,23 +937,41 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
break;
case '*':
opt_skip = FALSE;
+ argc_max = -1;
+ if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE;
goto check_exit;
case '!':
break;
+ case ':':
+ reqkarg = TRUE;
+ /* fall through */
case '&': case '?':
if (opt) opt_skip = FALSE;
break;
default:
+ if (!opt) argc_min++;
+ argc_max++;
break;
}
}
check_exit:
+ if (reqkarg && argc > argc_min && mrb_hash_p(kdict = ARGV[argc - 1])) {
+ mrb_hash_check_kdict(mrb, kdict);
+ argc --;
+ }
+ else {
+ kdict = mrb_nil_value();
+ }
+
opt = FALSE;
i = 0;
while ((c = *format++)) {
+ mrb_value *argv = ARGV;
+ mrb_bool altmode;
+
switch (c) {
- case '|': case '*': case '&': case '?':
+ case '|': case '*': case '&': case '?': case ':':
break;
default:
if (argc <= i) {
@@ -633,12 +979,20 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
given = FALSE;
}
else {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ mrb_argnum_error(mrb, argc, argc_min, argc_max);
}
}
break;
}
+ if (*format == '!') {
+ format ++;
+ altmode = TRUE;
+ }
+ else {
+ altmode = FALSE;
+ }
+
switch (c) {
case 'o':
{
@@ -646,8 +1000,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (i < argc) {
- *p = ARGV[arg_i++];
- i++;
+ *p = argv[i++];
}
}
break;
@@ -659,12 +1012,27 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
mrb_value ss;
- ss = ARGV[arg_i++];
+ ss = argv[i++];
if (!class_ptr_p(ss)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
}
*p = ss;
- i++;
+ }
+ }
+ break;
+ case 'c':
+ {
+ struct RClass **p;
+
+ p = va_arg(ap, struct RClass**);
+ if (i < argc) {
+ mrb_value ss;
+
+ ss = argv[i++];
+ if (!class_ptr_p(ss)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
+ }
+ *p = mrb_class_ptr(ss);
}
}
break;
@@ -673,17 +1041,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
- *p = ARGV[arg_i++];
- i++;
- break;
- }
- }
if (i < argc) {
- *p = to_str(mrb, ARGV[arg_i++]);
- i++;
+ *p = argv[i++];
+ if (!(altmode && mrb_nil_p(*p))) {
+ mrb_to_str(mrb, *p);
+ }
}
}
break;
@@ -692,17 +1054,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
- *p = ARGV[arg_i++];
- i++;
- break;
- }
- }
if (i < argc) {
- *p = to_ary(mrb, ARGV[arg_i++]);
- i++;
+ *p = argv[i++];
+ if (!(altmode && mrb_nil_p(*p))) {
+ *p = to_ary(mrb, *p);
+ }
}
}
break;
@@ -711,42 +1067,33 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
- *p = ARGV[arg_i++];
- i++;
- break;
- }
- }
if (i < argc) {
- *p = to_hash(mrb, ARGV[arg_i++]);
- i++;
+ *p = argv[i++];
+ if (!(altmode && mrb_nil_p(*p))) {
+ *p = to_hash(mrb, *p);
+ }
}
}
break;
case 's':
{
mrb_value ss;
- char **ps = 0;
+ const char **ps = 0;
mrb_int *pl = 0;
- ps = va_arg(ap, char**);
+ ps = va_arg(ap, const char**);
pl = va_arg(ap, mrb_int*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ if (i < argc) {
+ ss = argv[i++];
+ if (altmode && mrb_nil_p(ss)) {
*ps = NULL;
*pl = 0;
- i++; arg_i++;
- break;
}
- }
- if (i < argc) {
- ss = to_str(mrb, ARGV[arg_i++]);
- *ps = RSTRING_PTR(ss);
- *pl = RSTRING_LEN(ss);
- i++;
+ else {
+ mrb_to_str(mrb, ss);
+ *ps = RSTRING_PTR(ss);
+ *pl = RSTRING_LEN(ss);
+ }
}
}
break;
@@ -756,18 +1103,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
const char **ps;
ps = va_arg(ap, const char**);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ if (i < argc) {
+ ss = argv[i++];
+ if (altmode && mrb_nil_p(ss)) {
*ps = NULL;
- i++; arg_i++;
- break;
}
- }
- if (i < argc) {
- ss = to_str(mrb, ARGV[arg_i++]);
- *ps = mrb_string_value_cstr(mrb, &ss);
- i++;
+ else {
+ mrb_to_str(mrb, ss);
+ *ps = RSTRING_CSTR(mrb, ss);
+ }
}
}
break;
@@ -775,26 +1119,23 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
mrb_value aa;
struct RArray *a;
- mrb_value **pb;
+ const mrb_value **pb;
mrb_int *pl;
- pb = va_arg(ap, mrb_value**);
+ pb = va_arg(ap, const mrb_value**);
pl = va_arg(ap, mrb_int*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ if (i < argc) {
+ aa = argv[i++];
+ if (altmode && mrb_nil_p(aa)) {
*pb = 0;
*pl = 0;
- i++; arg_i++;
- break;
}
- }
- if (i < argc) {
- aa = to_ary(mrb, ARGV[arg_i++]);
- a = mrb_ary_ptr(aa);
- *pb = ARY_PTR(a);
- *pl = ARY_LEN(a);
- i++;
+ else {
+ aa = to_ary(mrb, aa);
+ a = mrb_ary_ptr(aa);
+ *pb = ARY_PTR(a);
+ *pl = ARY_LEN(a);
+ }
}
}
break;
@@ -805,27 +1146,23 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, void**);
if (i < argc) {
- ss = ARGV[arg_i];
- if (mrb_type(ss) != MRB_TT_ISTRUCT)
+ ss = argv[i++];
+ if (!mrb_istruct_p(ss))
{
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss);
}
*p = mrb_istruct_ptr(ss);
- arg_i++;
- i++;
}
}
break;
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case 'f':
{
mrb_float *p;
p = va_arg(ap, mrb_float*);
if (i < argc) {
- *p = mrb_to_flo(mrb, ARGV[arg_i]);
- arg_i++;
- i++;
+ *p = mrb_as_float(mrb, argv[i]); i++;
}
}
break;
@@ -836,31 +1173,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;
- }
- arg_i++;
- i++;
+ *p = mrb_as_int(mrb, argv[i]); i++;
}
}
break;
@@ -869,9 +1182,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_bool *boolp = va_arg(ap, mrb_bool*);
if (i < argc) {
- mrb_value b = ARGV[arg_i++];
+ mrb_value b = argv[i++];
*boolp = mrb_test(b);
- i++;
}
}
break;
@@ -883,9 +1195,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
mrb_value ss;
- ss = ARGV[arg_i++];
+ ss = argv[i++];
*symp = to_sym(mrb, ss);
- i++;
}
}
break;
@@ -896,17 +1207,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
datap = va_arg(ap, void**);
type = va_arg(ap, struct mrb_data_type const*);
- if (*format == '!') {
- format++;
- if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ if (i < argc) {
+ mrb_value dd = argv[i++];
+ if (altmode && mrb_nil_p(dd)) {
*datap = 0;
- i++; arg_i++;
- break;
}
- }
- if (i < argc) {
- *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type);
- ++i;
+ else {
+ *datap = mrb_data_get_ptr(mrb, dd, type);
+ }
}
}
break;
@@ -917,22 +1225,19 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (mrb->c->ci->argc < 0) {
- bp = mrb->c->stack + 2;
+ bp = mrb->c->ci->stack + 2;
}
else {
- bp = mrb->c->stack + mrb->c->ci->argc + 1;
+ bp = mrb->c->ci->stack + mrb->c->ci->argc + 1;
}
- if (*format == '!') {
- format ++;
- if (mrb_nil_p(*bp)) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
- }
+ if (altmode && mrb_nil_p(*bp)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
*p = *bp;
}
break;
case '|':
- if (opt_skip && i == argc) return argc;
+ if (opt_skip && i == argc) goto finish;
opt = TRUE;
break;
case '?':
@@ -946,30 +1251,25 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case '*':
{
- mrb_value **var;
+ const mrb_value **var;
mrb_int *pl;
- mrb_bool nocopy = array_argv ? TRUE : FALSE;
+ mrb_bool nocopy = (altmode || !argv_on_stack) ? TRUE : FALSE;
- if (*format == '!') {
- format++;
- nocopy = TRUE;
- }
- var = va_arg(ap, mrb_value**);
+ var = va_arg(ap, const mrb_value**);
pl = va_arg(ap, mrb_int*);
if (argc > i) {
*pl = argc-i;
if (*pl > 0) {
if (nocopy) {
- *var = ARGV+arg_i;
+ *var = argv+i;
}
else {
- mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i);
+ mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+i);
RARRAY(args)->c = NULL;
*var = RARRAY_PTR(args);
}
}
i = argc;
- arg_i += *pl;
}
else {
*pl = 0;
@@ -977,8 +1277,64 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+
+ case ':':
+ {
+ mrb_value ksrc = mrb_hash_p(kdict) ? mrb_hash_dup(mrb, kdict) : mrb_hash_new(mrb);
+ const mrb_kwargs *kwargs = va_arg(ap, const mrb_kwargs*);
+ mrb_value *rest;
+
+ if (kwargs == NULL) {
+ rest = NULL;
+ }
+ else {
+ uint32_t kwnum = kwargs->num;
+ uint32_t required = kwargs->required;
+ const mrb_sym *kname = kwargs->table;
+ mrb_value *values = kwargs->values;
+ uint32_t j;
+ const uint32_t keyword_max = 40;
+
+ if (kwnum > keyword_max || required > kwnum) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large");
+ }
+
+ for (j = required; j > 0; j --, kname ++, values ++) {
+ mrb_value k = mrb_symbol_value(*kname);
+ if (!mrb_hash_key_p(mrb, ksrc, k)) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %n", *kname);
+ }
+ *values = mrb_hash_delete_key(mrb, ksrc, k);
+ mrb_gc_protect(mrb, *values);
+ }
+
+ for (j = kwnum - required; j > 0; j --, kname ++, values ++) {
+ mrb_value k = mrb_symbol_value(*kname);
+ if (mrb_hash_key_p(mrb, ksrc, k)) {
+ *values = mrb_hash_delete_key(mrb, ksrc, k);
+ mrb_gc_protect(mrb, *values);
+ }
+ else {
+ *values = mrb_undef_value();
+ }
+ }
+
+ rest = kwargs->rest;
+ }
+
+ if (rest) {
+ *rest = ksrc;
+ }
+ else if (!mrb_hash_empty_p(mrb, ksrc)) {
+ ksrc = mrb_hash_keys(mrb, ksrc);
+ ksrc = RARRAY_PTR(ksrc)[0];
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown keyword: %v", ksrc);
+ }
+ }
+ break;
+
default:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c);
break;
}
}
@@ -986,8 +1342,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
#undef ARGV
if (!c && argc > i) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ mrb_argnum_error(mrb, argc, argc_min, argc_max);
}
+
+finish:
va_end(ap);
return i;
}
@@ -997,7 +1355,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
{
struct RClass *c;
- c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
+ c = MRB_OBJ_ALLOC(mrb, MRB_TT_CLASS, mrb->class_class);
if (super) {
c->super = super;
mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
@@ -1005,7 +1363,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
else {
c->super = mrb->object_class;
}
- c->mt = kh_init(mt, mrb);
+ c->mt = mt_new(mrb);
return c;
}
@@ -1013,14 +1371,14 @@ static void
boot_initmod(mrb_state *mrb, struct RClass *mod)
{
if (!mod->mt) {
- mod->mt = kh_init(mt, mrb);
+ mod->mt = mt_new(mrb);
}
}
static struct RClass*
include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super)
{
- struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
+ struct RClass *ic = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, mrb->class_class);
if (m->tt == MRB_TT_ICLASS) {
m = m->c;
}
@@ -1044,8 +1402,10 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
void *klass_mt = find_origin(c)->mt;
while (m) {
- int superclass_seen = 0;
+ int original_seen = FALSE;
+ int superclass_seen = FALSE;
+ if (c == ins_pos) original_seen = TRUE;
if (m->flags & MRB_FL_CLASS_IS_PREPENDED)
goto skip;
@@ -1054,16 +1414,17 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
p = c->super;
while (p) {
+ if (c == p) original_seen = TRUE;
if (p->tt == MRB_TT_ICLASS) {
if (p->mt == m->mt) {
- if (!superclass_seen) {
+ if (!superclass_seen && original_seen) {
ins_pos = p; /* move insert point */
}
goto skip;
}
} else if (p->tt == MRB_TT_CLASS) {
if (!search_super) break;
- superclass_seen = 1;
+ superclass_seen = TRUE;
}
p = p->super;
}
@@ -1072,65 +1433,123 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
m->flags |= MRB_FL_CLASS_IS_INHERITED;
ins_pos->super = ic;
mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic);
- mc_clear_by_class(mrb, ins_pos);
ins_pos = ic;
skip:
m = m->super;
}
- mc_clear_all(mrb);
+ mc_clear(mrb);
return 0;
}
+static int
+fix_include_module(mrb_state *mrb, struct RBasic *obj, void *data)
+{
+ struct RClass **m = (struct RClass**)data;
+
+ if (obj->tt == MRB_TT_ICLASS && obj->c == m[0] && !MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) {
+ struct RClass *ic = (struct RClass*)obj;
+ include_module_at(mrb, ic, ic, m[1], 1);
+ }
+ return MRB_EACH_OBJ_OK;
+}
+
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");
}
+ if (c->tt == MRB_TT_MODULE && (c->flags & MRB_FL_CLASS_IS_INHERITED)) {
+ struct RClass *data[2];
+ data[0] = c;
+ data[1] = m;
+ mrb_objspace_each_objects(mrb, fix_include_module, data);
+ }
+}
+
+static int
+fix_prepend_module(mrb_state *mrb, struct RBasic *obj, void *data)
+{
+ struct RClass **m = (struct RClass**)data;
+ struct RClass *c = (struct RClass*)obj;
+
+ if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) {
+ struct RClass *p = c->super;
+ struct RClass *ins_pos = c;
+ while (p) {
+ if (c == m[0]) break;
+ if (p == m[0]->super->c) {
+ ins_pos = c;
+ }
+ if (p->tt == MRB_TT_CLASS) break;
+ if (p->c == m[0]) {
+ include_module_at(mrb, ins_pos, ins_pos, m[1], 0);
+ break;
+ }
+ c = p;
+ p = p->super;
+ }
+ }
+ return MRB_EACH_OBJ_OK;
}
MRB_API void
mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
struct RClass *origin;
- int changed = 0;
+ mrb_check_frozen(mrb, c);
if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) {
- origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
+ struct RClass *c0;
+
+ if (c->tt == MRB_TT_ICLASS) {
+ c0 = c->c;
+ }
+ else {
+ c0 = c;
+ }
+ origin = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, c0);
origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED;
origin->super = c->super;
c->super = origin;
origin->mt = c->mt;
- c->mt = kh_init(mt, mrb);
+ c->mt = NULL;
+ origin->iv = c->iv;
mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin);
c->flags |= MRB_FL_CLASS_IS_PREPENDED;
}
- changed = include_module_at(mrb, c, c, m, 0);
- if (changed < 0) {
+ if (include_module_at(mrb, c, c, m, 0) < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected");
}
+ if (c->tt == MRB_TT_MODULE &&
+ (c->flags & (MRB_FL_CLASS_IS_INHERITED|MRB_FL_CLASS_IS_PREPENDED))) {
+ struct RClass *data[2];
+ data[0] = c;
+ data[1] = m;
+ mrb_objspace_each_objects(mrb, fix_prepend_module, data);
+ }
}
static mrb_value
mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod)
{
- mrb_value klass;
+ struct RClass *c;
mrb_check_type(mrb, mod, MRB_TT_MODULE);
- mrb_get_args(mrb, "C", &klass);
- mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
+ mrb_get_args(mrb, "c", &c);
+ mrb_prepend_module(mrb, c, mrb_class_ptr(mod));
return mod;
}
static mrb_value
mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
{
- mrb_value klass;
+ struct RClass *c;
mrb_check_type(mrb, mod, MRB_TT_MODULE);
- mrb_get_args(mrb, "C", &klass);
- mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
+ mrb_get_args(mrb, "c", &c);
+ mrb_include_module(mrb, c, mrb_class_ptr(mod));
return mod;
}
@@ -1193,10 +1612,9 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_mod_extend_object(mrb_state *mrb, mrb_value mod)
{
- mrb_value obj;
+ mrb_value obj = mrb_get_arg1(mrb);
mrb_check_type(mrb, mod, MRB_TT_MODULE);
- mrb_get_args(mrb, "o", &obj);
mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod));
return mod;
}
@@ -1223,33 +1641,44 @@ mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod)
return mod;
}
-MRB_API mrb_value
-mrb_singleton_class(mrb_state *mrb, mrb_value v)
+/* returns mrb_class_ptr(mrb_singleton_class()) */
+/* except that it return NULL for immediate values */
+MRB_API struct RClass*
+mrb_singleton_class_ptr(mrb_state *mrb, mrb_value v)
{
struct RBasic *obj;
switch (mrb_type(v)) {
case MRB_TT_FALSE:
if (mrb_nil_p(v))
- return mrb_obj_value(mrb->nil_class);
- return mrb_obj_value(mrb->false_class);
+ return mrb->nil_class;
+ return mrb->false_class;
case MRB_TT_TRUE:
- return mrb_obj_value(mrb->true_class);
+ return mrb->true_class;
case MRB_TT_CPTR:
- return mrb_obj_value(mrb->object_class);
case MRB_TT_SYMBOL:
- case MRB_TT_FIXNUM:
-#ifndef MRB_WITHOUT_FLOAT
+ case MRB_TT_INTEGER:
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
#endif
- mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
- return mrb_nil_value(); /* not reached */
+ return NULL;
default:
break;
}
obj = mrb_basic_ptr(v);
prepare_singleton_class(mrb, obj);
- return mrb_obj_value(obj->c);
+ return obj->c;
+}
+
+MRB_API mrb_value
+mrb_singleton_class(mrb_state *mrb, mrb_value v)
+{
+ struct RClass *c = mrb_singleton_class_ptr(mrb, v);
+
+ if (c == NULL) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
+ }
+ return mrb_obj_value(c);
}
MRB_API void
@@ -1260,60 +1689,56 @@ mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name,
}
MRB_API void
+mrb_define_singleton_method_id(mrb_state *mrb, struct RObject *o, mrb_sym name, mrb_func_t func, mrb_aspec aspec)
+{
+ prepare_singleton_class(mrb, (struct RBasic*)o);
+ mrb_define_method_id(mrb, o->c, name, func, aspec);
+}
+
+MRB_API void
mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
{
mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec);
}
MRB_API void
-mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
+mrb_define_class_method_id(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_func_t func, mrb_aspec aspec)
{
- mrb_define_class_method(mrb, c, name, func, aspec);
- mrb_define_method(mrb, c, name, func, aspec);
+ mrb_define_singleton_method_id(mrb, (struct RObject*)c, name, func, aspec);
}
-#ifdef MRB_METHOD_CACHE
-static void
-mc_clear_all(mrb_state *mrb)
+MRB_API void
+mrb_define_module_function_id(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_func_t func, mrb_aspec aspec)
{
- struct mrb_cache_entry *mc = mrb->cache;
- int i;
+ mrb_define_class_method_id(mrb, c, name, func, aspec);
+ mrb_define_method_id(mrb, c, name, func, aspec);
+}
- for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
- mc[i].c = 0;
- }
+MRB_API void
+mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
+{
+ mrb_define_module_function_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec);
}
+#ifndef MRB_NO_METHOD_CACHE
static void
-mc_clear_by_class(mrb_state *mrb, struct RClass *c)
+mc_clear(mrb_state *mrb)
{
- struct mrb_cache_entry *mc = mrb->cache;
- int i;
-
- if (c->flags & MRB_FL_CLASS_IS_INHERITED) {
- mc_clear_all(mrb);
- c->flags &= ~MRB_FL_CLASS_IS_INHERITED;
- return;
- }
- for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
- if (mc[i].c == c) mc[i].c = 0;
- }
+ memset(mrb->cache, 0, MRB_METHOD_CACHE_SIZE*sizeof(mrb->cache[0]));
}
-static void
-mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+void
+mrb_mc_clear_by_class(mrb_state *mrb, struct RClass *c)
{
struct mrb_cache_entry *mc = mrb->cache;
int i;
if (c->flags & MRB_FL_CLASS_IS_INHERITED) {
- mc_clear_all(mrb);
- c->flags &= ~MRB_FL_CLASS_IS_INHERITED;
+ mc_clear(mrb);
return;
}
for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
- if (mc[i].c == c || mc[i].mid == mid)
- mc[i].c = 0;
+ if (mc[i].c == c) mc[i].c = 0;
}
}
#endif
@@ -1321,10 +1746,9 @@ mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid)
MRB_API mrb_method_t
mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
{
- khiter_t k;
mrb_method_t m;
struct RClass *c = *cp;
-#ifdef MRB_METHOD_CACHE
+#ifndef MRB_NO_METHOD_CACHE
struct RClass *oc = c;
int h = kh_int_hash_func(mrb, ((intptr_t)oc) ^ mid) & (MRB_METHOD_CACHE_SIZE-1);
struct mrb_cache_entry *mc = &mrb->cache[h];
@@ -1336,15 +1760,23 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
#endif
while (c) {
- khash_t(mt) *h = c->mt;
+ mt_tbl *h = c->mt;
if (h) {
- k = kh_get(mt, mrb, h, mid);
- if (k != kh_end(h)) {
- m = kh_value(h, k);
- if (MRB_METHOD_UNDEF_P(m)) break;
+ struct mt_elem *e = mt_get(mrb, h, mid);
+ if (e) {
+ if (e->ptr.proc == 0) break;
*cp = c;
-#ifdef MRB_METHOD_CACHE
+ if (e->func_p) {
+ MRB_METHOD_FROM_FUNC(m, e->ptr.func);
+ }
+ else {
+ MRB_METHOD_FROM_PROC(m, e->ptr.proc);
+ }
+ if (e->noarg_p) {
+ MRB_METHOD_NOARG_SET(m);
+ }
+#ifndef MRB_NO_METHOD_CACHE
mc->c = oc;
mc->c0 = c;
mc->mid = mid;
@@ -1366,48 +1798,78 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
m = mrb_method_search_vm(mrb, &c, mid);
if (MRB_METHOD_UNDEF_P(m)) {
- mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0);
- if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) {
- inspect = mrb_any_to_s(mrb, mrb_obj_value(c));
- }
- mrb_name_error(mrb, mid, "undefined method '%S' for class %S",
- mrb_sym2str(mrb, mid), inspect);
+ mrb_name_error(mrb, mid, "undefined method '%n' for class %C", mid, c);
}
return m;
}
+#define ONSTACK_ALLOC_MAX 32
+
+static mrb_sym
+prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix)
+{
+ char onstack[ONSTACK_ALLOC_MAX];
+ mrb_int sym_len;
+ const char *sym_str = mrb_sym_name_len(mrb, sym, &sym_len);
+ size_t prefix_len = prefix ? strlen(prefix) : 0;
+ size_t suffix_len = suffix ? strlen(suffix) : 0;
+ size_t name_len = sym_len + prefix_len + suffix_len;
+ char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack;
+ char *p = buf;
+
+ if (prefix_len > 0) {
+ memcpy(p, prefix, prefix_len);
+ p += prefix_len;
+ }
+
+ memcpy(p, sym_str, sym_len);
+ p += sym_len;
+
+ if (suffix_len > 0) {
+ memcpy(p, suffix, suffix_len);
+ p += suffix_len;
+ }
+
+ return mrb_intern(mrb, buf, name_len);
+}
+
static mrb_value
-attr_reader(mrb_state *mrb, mrb_value obj)
+prepare_ivar_name(mrb_state *mrb, mrb_sym sym)
{
- mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
- return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+ sym = prepare_name_common(mrb, sym, "@", NULL);
+ mrb_iv_name_sym_check(mrb, sym);
+ return mrb_symbol_value(sym);
+}
+
+static mrb_sym
+prepare_writer_name(mrb_state *mrb, mrb_sym sym)
+{
+ return prepare_name_common(mrb, sym, NULL, "=");
}
static mrb_value
-mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym))
{
struct RClass *c = mrb_class_ptr(mod);
- mrb_value *argv;
+ const mrb_value *argv;
mrb_int argc, i;
int ai;
mrb_get_args(mrb, "*", &argv, &argc);
ai = mrb_gc_arena_save(mrb);
for (i=0; i<argc; i++) {
- mrb_value name, str;
- mrb_sym method, sym;
+ mrb_value name;
+ mrb_sym method;
struct RProc *p;
mrb_method_t m;
method = to_sym(mrb, argv[i]);
- name = mrb_sym2str(mrb, method);
- str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1);
- mrb_str_cat_lit(mrb, str, "@");
- mrb_str_cat_str(mrb, str, name);
- sym = mrb_intern_str(mrb, str);
- mrb_iv_name_sym_check(mrb, sym);
- name = mrb_symbol_value(sym);
- p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name);
+ name = prepare_ivar_name(mrb, method);
+ if (access_name) {
+ method = access_name(mrb, method);
+ }
+
+ p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name);
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, c, method, m);
mrb_gc_arena_restore(mrb, ai);
@@ -1416,12 +1878,24 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
}
static mrb_value
+attr_reader(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+}
+
+static mrb_value
+mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+{
+ return mod_attr_define(mrb, mod, attr_reader, NULL);
+}
+
+static mrb_value
attr_writer(mrb_state *mrb, mrb_value obj)
{
mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
- mrb_value val;
+ mrb_value val = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &val);
mrb_iv_set(mrb, obj, to_sym(mrb, name), val);
return val;
}
@@ -1429,42 +1903,7 @@ attr_writer(mrb_state *mrb, mrb_value obj)
static mrb_value
mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
{
- struct RClass *c = mrb_class_ptr(mod);
- mrb_value *argv;
- mrb_int argc, i;
- int ai;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- ai = mrb_gc_arena_save(mrb);
- for (i=0; i<argc; i++) {
- mrb_value name, str, attr;
- mrb_sym method, sym;
- struct RProc *p;
- mrb_method_t m;
-
- method = to_sym(mrb, argv[i]);
-
- /* prepare iv name (@name) */
- name = mrb_sym2str(mrb, method);
- str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1);
- mrb_str_cat_lit(mrb, str, "@");
- mrb_str_cat_str(mrb, str, name);
- sym = mrb_intern_str(mrb, str);
- mrb_iv_name_sym_check(mrb, sym);
- attr = mrb_symbol_value(sym);
-
- /* prepare method name (name=) */
- str = mrb_str_new_capa(mrb, RSTRING_LEN(str));
- mrb_str_cat_str(mrb, str, name);
- mrb_str_cat_lit(mrb, str, "=");
- method = mrb_intern_str(mrb, str);
-
- p = mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr);
- MRB_METHOD_FROM_PROC(m, p);
- mrb_define_method_raw(mrb, c, method, m);
- mrb_gc_arena_restore(mrb, ai);
- }
- return mrb_nil_value();
+ return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name);
}
static mrb_value
@@ -1479,7 +1918,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
if (ttype == 0) ttype = MRB_TT_OBJECT;
if (ttype <= MRB_TT_CPTR) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv);
}
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
return mrb_obj_value(o);
@@ -1497,29 +1936,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;
+ const mrb_value *argv;
mrb_int argc;
mrb_sym init;
- mrb_method_t m;
- mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+ 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 {
+ init = MRB_SYM(initialize);
+ if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
mrb_funcall_with_block(mrb, obj, init, argc, argv, blk);
}
-
return obj;
}
@@ -1530,7 +1960,7 @@ mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *arg
mrb_sym mid;
obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
- mid = mrb_intern_lit(mrb, "initialize");
+ mid = MRB_SYM(initialize);
if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) {
mrb_funcall_argv(mrb, obj, mid, argc, argv);
}
@@ -1562,8 +1992,11 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
- mid = mrb_intern_lit(mrb, "initialize");
- if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
+ mid = MRB_SYM(initialize);
+ if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) {
+ mrb_class_initialize(mrb, new_class);
+ }
+ else {
mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
}
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
@@ -1630,21 +2063,11 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv)
mrb_value
mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
{
- mrb_value arg;
+ mrb_value arg = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
}
-static mrb_value
-mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
-{
- mrb_value arg;
-
- mrb_get_args(mrb, "o", &arg);
- return mrb_bool_value(!mrb_equal(mrb, self, arg));
-}
-
MRB_API mrb_bool
mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
{
@@ -1667,7 +2090,7 @@ MRB_API mrb_value
mrb_class_path(mrb_state *mrb, struct RClass *c)
{
mrb_value path;
- mrb_sym nsym = mrb_intern_lit(mrb, "__classname__");
+ mrb_sym nsym = MRB_SYM(__classname__);
path = mrb_obj_iv_get(mrb, (struct RObject*)c, nsym);
if (mrb_nil_p(path)) {
@@ -1676,11 +2099,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_sym_str(mrb, mrb_symbol(path));
}
return mrb_str_dup(mrb, path);
}
@@ -1699,14 +2118,11 @@ 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 = 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 RSTRING_PTR(path);
+ mrb_value name;
+
+ if (c == NULL) return NULL;
+ name = class_name_str(mrb, c);
+ return RSTRING_PTR(name);
}
MRB_API const char*
@@ -1725,7 +2141,7 @@ static void
mrb_check_inheritable(mrb_state *mrb, struct RClass *super)
{
if (super->tt != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super));
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super);
}
if (super->tt == MRB_TT_SCLASS) {
mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class");
@@ -1764,7 +2180,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super)
MRB_API struct RClass*
mrb_module_new(mrb_state *mrb)
{
- struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class);
+ struct RClass *m = MRB_OBJ_ALLOC(mrb, MRB_TT_MODULE, mrb->module_class);
boot_initmod(mrb, m);
return m;
}
@@ -1779,7 +2195,7 @@ mrb_module_new(mrb_state *mrb)
* called with an explicit receiver, as <code>class</code> is also a
* reserved word in Ruby.
*
- * 1.class #=> Fixnum
+ * 1.class #=> Integer
* self.class #=> Object
*/
@@ -1792,13 +2208,35 @@ mrb_obj_class(mrb_state *mrb, mrb_value obj)
MRB_API void
mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
{
+ if (a == b) return;
mrb_method_t m = mrb_method_search(mrb, c, b);
+ if (!MRB_METHOD_CFUNC_P(m)) {
+ struct RProc *p = MRB_METHOD_PROC(m);
+
+ if (MRB_PROC_ENV_P(p)) {
+ MRB_PROC_ENV(p)->mid = b;
+ }
+ else if (p->color != MRB_GC_RED) {
+ struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
+ struct REnv *e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL);
+
+ e->mid = b;
+ if (tc) {
+ e->c = tc;
+ 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);
+ }
+ }
mrb_define_method_raw(mrb, c, a, m);
}
/*!
* Defines an alias of a method.
+ * \param mrb the mruby state
* \param klass the class which the original method belongs to
* \param name1 a new name for the method
* \param name2 the original name of the method
@@ -1809,6 +2247,12 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const
mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2));
}
+MRB_API void
+mrb_define_alias_id(mrb_state *mrb, struct RClass *klass, mrb_sym a, mrb_sym b)
+{
+ mrb_alias_method(mrb, klass, a, b);
+}
+
/*
* call-seq:
* mod.to_s -> string
@@ -1818,15 +2262,12 @@ 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:");
+ if (mrb_sclass_p(klass)) {
+ mrb_value v = mrb_iv_get(mrb, klass, MRB_SYM(__attached__));
+ mrb_value str = mrb_str_new_lit(mrb, "#<Class:");
if (class_ptr_p(v)) {
mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
@@ -1837,37 +2278,12 @@ 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));
}
}
+void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid);
+
static mrb_value
mrb_mod_alias(mrb_state *mrb, mrb_value mod)
{
@@ -1876,27 +2292,38 @@ 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();
+ mrb_method_added(mrb, c, new_name);
+ return mod;
}
-void
+static void
+undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
+{
+ mrb_method_t m;
+
+ MRB_METHOD_FROM_PROC(m, NULL);
+ mrb_define_method_raw(mrb, c, a, m);
+}
+
+MRB_API 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));
- }
- else {
- mrb_method_t m;
-
- MRB_METHOD_FROM_PROC(m, NULL);
- mrb_define_method_raw(mrb, c, a, m);
+ mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c);
}
+ undef_method(mrb, c, a);
}
MRB_API void
mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
{
- mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name));
+ undef_method(mrb, c, mrb_intern_cstr(mrb, name));
+}
+
+MRB_API void
+mrb_undef_class_method_id(mrb_state *mrb, struct RClass *c, mrb_sym name)
+{
+ mrb_undef_method_id(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name);
}
MRB_API void
@@ -1905,12 +2332,24 @@ mrb_undef_class_method(mrb_state *mrb, struct RClass *c, const char *name)
mrb_undef_method(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name);
}
+MRB_API void
+mrb_remove_method(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+{
+ mt_tbl *h;
+
+ MRB_CLASS_ORIGIN(c);
+ h = c->mt;
+
+ if (h && mt_del(mrb, h, mid)) return;
+ mrb_name_error(mrb, mid, "method '%n' not defined in %C", mid, c);
+}
+
static mrb_value
mrb_mod_undef(mrb_state *mrb, mrb_value mod)
{
struct RClass *c = mrb_class_ptr(mod);
mrb_int argc;
- mrb_value *argv;
+ const mrb_value *argv;
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
@@ -1921,17 +2360,13 @@ mrb_mod_undef(mrb_state *mrb, mrb_value 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));
+ mrb_int len;
+ const char *name = mrb_sym_name_len(mrb, id, &len);
+ if (!mrb_const_name_p(mrb, name, len)) {
+ mrb_name_error(mrb, id, "wrong constant name %n", id);
+ }
}
static mrb_value
@@ -1958,13 +2393,11 @@ mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id)
static mrb_value
mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
{
- mrb_value path;
+ mrb_value path = mrb_get_arg1(mrb);
mrb_sym id;
char *ptr;
mrb_int off, end, len;
- mrb_get_args(mrb, "o", &path);
-
if (mrb_symbol_p(path)) {
/* const get with symbol */
id = mrb_symbol(path);
@@ -1972,7 +2405,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;
@@ -1987,7 +2420,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
else {
off = end + 2;
if (off == len) { /* trailing "::" */
- mrb_name_error(mrb, id, "wrong constant name '%S'", path);
+ mrb_name_error(mrb, id, "wrong constant name '%v'", path);
}
}
}
@@ -2017,7 +2450,7 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
check_const_name_sym(mrb, id);
val = mrb_iv_remove(mrb, mod, id);
if (mrb_undef_p(val)) {
- mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id));
+ mrb_name_error(mrb, id, "constant %n not defined", id);
}
return val;
}
@@ -2030,13 +2463,10 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "n", &sym);
if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
- mrb_name_error(mrb, sym, "uninitialized constant %S::%S",
- mod,
- mrb_sym2str(mrb, sym));
+ mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym);
}
else {
- mrb_name_error(mrb, sym, "uninitialized constant %S",
- mrb_sym2str(mrb, sym));
+ mrb_name_error(mrb, sym, "uninitialized constant %n", sym);
}
/* not reached */
return mrb_nil_value();
@@ -2078,10 +2508,25 @@ mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
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)
+void
+mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+{
+ mrb_sym added;
+ mrb_value recv = mrb_obj_value(c);
+
+ if (c->tt == MRB_TT_SCLASS) {
+ added = MRB_SYM(singleton_method_added);
+ recv = mrb_iv_get(mrb, recv, MRB_SYM(__attached__));
+ }
+ else {
+ added = MRB_SYM(method_added);
+ }
+ mrb_funcall_id(mrb, recv, added, 1, mrb_symbol_value(mid));
+}
+
+mrb_value
+mrb_mod_define_method_m(mrb_state *mrb, struct RClass *c)
{
- struct RClass *c = mrb_class_ptr(self);
struct RProc *p;
mrb_method_t m;
mrb_sym mid;
@@ -2097,42 +2542,56 @@ mod_define_method(mrb_state *mrb, mrb_value self)
/* ignored */
break;
default:
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", 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);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
mrb_proc_copy(p, mrb_proc_ptr(blk));
p->flags |= MRB_PROC_STRICT;
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, c, mid, m);
+ mrb_method_added(mrb, c, mid);
return mrb_symbol_value(mid);
}
static mrb_value
+mod_define_method(mrb_state *mrb, mrb_value self)
+{
+ return mrb_mod_define_method_m(mrb, mrb_class_ptr(self));
+}
+
+static mrb_value
top_define_method(mrb_state *mrb, mrb_value self)
{
- return mod_define_method(mrb, mrb_obj_value(mrb->object_class));
+ return mrb_mod_define_method_m(mrb, mrb->object_class);
}
static mrb_value
mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
{
- mrb_value obj;
+ mrb_value obj = mrb_get_arg1(mrb);
mrb_bool eqq;
- mrb_get_args(mrb, "o", &obj);
eqq = mrb_obj_is_kind_of(mrb, obj, mrb_class_ptr(mod));
return mrb_bool_value(eqq);
}
-MRB_API mrb_value
+static mrb_value
+mrb_mod_dup(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mod = mrb_obj_clone(mrb, self);
+ MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod));
+ return mod;
+}
+
+static mrb_value
mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
{
- mrb_value *argv;
+ const mrb_value *argv;
mrb_int argc, i;
mrb_sym mid;
mrb_method_t m;
@@ -2166,6 +2625,202 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
return mod;
}
+static struct RClass*
+mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
+{
+ struct RClass *klass = mrb_basic_ptr(obj)->c;
+
+ if (klass->tt != MRB_TT_SCLASS)
+ return klass;
+ else {
+ /* copy singleton(unnamed) class */
+ struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class);
+
+ switch (mrb_type(obj)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ break;
+ default:
+ clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass));
+ break;
+ }
+ clone->super = klass->super;
+ if (klass->iv) {
+ mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
+ mrb_obj_iv_set(mrb, (struct RObject*)clone, MRB_SYM(__attached__), obj);
+ }
+ if (klass->mt) {
+ clone->mt = mt_copy(mrb, klass->mt);
+ }
+ else {
+ clone->mt = mt_new(mrb);
+ }
+ clone->tt = MRB_TT_SCLASS;
+ return clone;
+ }
+}
+
+static void
+copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
+{
+ struct RClass *dc = mrb_class_ptr(dst);
+ 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_FL_CLASS_IS_PREPENDED) {
+ struct RClass *c0 = sc->super;
+ struct RClass *c1 = dc;
+
+ /* copy prepended iclasses */
+ 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_FL_CLASS_IS_ORIGIN;
+ }
+ if (sc->mt) {
+ dc->mt = mt_copy(mrb, sc->mt);
+ }
+ else {
+ dc->mt = mt_new(mrb);
+ }
+ dc->super = sc->super;
+ MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc));
+}
+
+/* 15.3.1.3.16 */
+static mrb_value
+mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
+{
+ mrb_value orig = mrb_get_arg1(mrb);
+
+ if (mrb_obj_equal(mrb, self, orig)) return self;
+ if ((mrb_type(self) != mrb_type(orig)) || (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig))) {
+ mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object");
+ }
+ return self;
+}
+
+static void
+init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
+{
+ switch (mrb_type(obj)) {
+ case MRB_TT_ICLASS:
+ copy_class(mrb, dest, obj);
+ return;
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ copy_class(mrb, dest, obj);
+ mrb_iv_copy(mrb, dest, obj);
+ mrb_iv_remove(mrb, dest, MRB_SYM(__classname__));
+ break;
+ case MRB_TT_OBJECT:
+ case MRB_TT_SCLASS:
+ case MRB_TT_HASH:
+ case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
+ mrb_iv_copy(mrb, dest, obj);
+ break;
+ case MRB_TT_ISTRUCT:
+ mrb_istruct_copy(dest, obj);
+ break;
+
+ default:
+ break;
+ }
+ if (!mrb_func_basic_p(mrb, dest, MRB_SYM(initialize_copy), mrb_obj_init_copy)) {
+ mrb_funcall_id(mrb, dest, MRB_SYM(initialize_copy), 1, obj);
+ }
+}
+
+/* 15.3.1.3.8 */
+/*
+ * call-seq:
+ * obj.clone -> an_object
+ *
+ * Produces a shallow copy of <i>obj</i>---the instance variables of
+ * <i>obj</i> are copied, but not the objects they reference. Copies
+ * the frozen state of <i>obj</i>. See also the discussion
+ * under <code>Object#dup</code>.
+ *
+ * class Klass
+ * attr_accessor :str
+ * end
+ * s1 = Klass.new #=> #<Klass:0x401b3a38>
+ * s1.str = "Hello" #=> "Hello"
+ * s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello">
+ * s2.str[1,4] = "i" #=> "i"
+ * s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">"
+ * s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">"
+ *
+ * This method may have class-specific behavior. If so, that
+ * behavior will be documented under the #+initialize_copy+ method of
+ * the class.
+ *
+ * Some Class(True False Nil Symbol Integer Float) Object cannot clone.
+ */
+MRB_API mrb_value
+mrb_obj_clone(mrb_state *mrb, mrb_value self)
+{
+ struct RObject *p;
+ mrb_value clone;
+
+ if (mrb_immediate_p(self)) {
+ return self;
+ }
+ if (mrb_sclass_p(self)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class");
+ }
+ p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self));
+ p->c = mrb_singleton_class_clone(mrb, 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 & MRB_FL_OBJ_IS_FROZEN;
+
+ return clone;
+}
+
+/* 15.3.1.3.9 */
+/*
+ * call-seq:
+ * obj.dup -> an_object
+ *
+ * Produces a shallow copy of <i>obj</i>---the instance variables of
+ * <i>obj</i> are copied, but not the objects they reference.
+ * <code>dup</code> copies the frozen state of <i>obj</i>. See also
+ * the discussion under <code>Object#clone</code>. In general,
+ * <code>clone</code> and <code>dup</code> may have different semantics
+ * in descendant classes. While <code>clone</code> is used to duplicate
+ * an object, including its internal state, <code>dup</code> typically
+ * uses the class of the descendant object to create the new instance.
+ *
+ * This method may have class-specific behavior. If so, that
+ * behavior will be documented under the #+initialize_copy+ method of
+ * the class.
+ */
+
+MRB_API mrb_value
+mrb_obj_dup(mrb_state *mrb, mrb_value obj)
+{
+ struct RBasic *p;
+ mrb_value dup;
+
+ if (mrb_immediate_p(obj)) {
+ return obj;
+ }
+ if (mrb_sclass_p(obj)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class");
+ }
+ p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj));
+ dup = mrb_obj_value(p);
+ init_copy(mrb, dup, obj);
+
+ return dup;
+}
+
/* implementation of __id__ */
mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
/* implementation of instance_eval */
@@ -2177,6 +2832,43 @@ inspect_main(mrb_state *mrb, mrb_value mod)
return mrb_str_new_lit(mrb, "main");
}
+static const mrb_code new_iseq[] = {
+ OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */
+ OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */
+ OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */
+ OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */
+ OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */
+ OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */
+ OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R3 :initialize */
+ OP_RETURN, 0x0 /* OP_RETURN R0 */
+};
+
+MRB_PRESYM_DEFINE_VAR_AND_INITER(new_syms, 2, MRB_SYM(allocate), MRB_SYM(initialize))
+
+static const mrb_irep new_irep = {
+ 3, 6, 0, MRB_IREP_STATIC,
+ new_iseq, NULL, new_syms, NULL, NULL, NULL,
+ sizeof(new_iseq), 0, 2, 0, 0,
+};
+
+static const struct RProc new_proc = {
+ NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT,
+ { &new_irep }, NULL, { NULL }
+};
+
+static void
+init_class_new(mrb_state *mrb, struct RClass *cls)
+{
+ mrb_method_t m;
+
+ MRB_PRESYM_INIT_SYMBOLS(mrb, new_syms);
+ MRB_METHOD_FROM_PROC(m, &new_proc);
+ mrb_define_method_raw(mrb, cls, MRB_SYM(new), m);
+}
+
+/* implementation of #send method */
+mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
+
void
mrb_init_class(mrb_state *mrb)
{
@@ -2198,17 +2890,16 @@ mrb_init_class(mrb_state *mrb)
make_metaclass(mrb, cls);
/* name basic classes */
- mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob));
- mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob));
- mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj));
- mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod));
- mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls));
+ mrb_define_const_id(mrb, bob, MRB_SYM(BasicObject), mrb_obj_value(bob));
+ mrb_define_const_id(mrb, obj, MRB_SYM(Object), mrb_obj_value(obj));
+ mrb_define_const_id(mrb, obj, MRB_SYM(Module), mrb_obj_value(mod));
+ mrb_define_const_id(mrb, obj, MRB_SYM(Class), mrb_obj_value(cls));
/* name each classes */
- mrb_class_name_class(mrb, NULL, bob, mrb_intern_lit(mrb, "BasicObject"));
- mrb_class_name_class(mrb, NULL, obj, mrb_intern_lit(mrb, "Object")); /* 15.2.1 */
- mrb_class_name_class(mrb, NULL, mod, mrb_intern_lit(mrb, "Module")); /* 15.2.2 */
- mrb_class_name_class(mrb, NULL, cls, mrb_intern_lit(mrb, "Class")); /* 15.2.3 */
+ mrb_class_name_class(mrb, NULL, bob, MRB_SYM(BasicObject));
+ mrb_class_name_class(mrb, NULL, obj, MRB_SYM(Object)); /* 15.2.1 */
+ mrb_class_name_class(mrb, NULL, mod, MRB_SYM(Module)); /* 15.2.2 */
+ mrb_class_name_class(mrb, NULL, cls, MRB_SYM(Class)); /* 15.2.3 */
mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class); /* 15.2.17 */
MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC);
@@ -2217,17 +2908,20 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
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.4 */
- mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */
- mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
+ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.5 */
+ mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
+ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */
+ mrb_define_method(mrb, bob, "singleton_method_added", mrb_bob_init, MRB_ARGS_REQ(1));
- mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
+ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK());
+ mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE());
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
- mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */
mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */
mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1));
+ init_class_new(mrb, cls);
+
MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
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 */
@@ -2257,12 +2951,16 @@ mrb_init_class(mrb_state *mrb)
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, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */
+ mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE());
+ mrb_define_method(mrb, bob, "method_added", mrb_bob_init, MRB_ARGS_REQ(1));
mrb_undef_method(mrb, cls, "append_features");
+ mrb_undef_method(mrb, cls, "prepend_features");
mrb_undef_method(mrb, cls, "extend_object");
+ mrb_undef_method(mrb, cls, "module_function");
- mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class);
+ mrb->top_self = MRB_OBJ_ALLOC(mrb, MRB_TT_OBJECT, mrb->object_class);
mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE());
mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE());
mrb_define_singleton_method(mrb, mrb->top_self, "define_method", top_define_method, MRB_ARGS_ARG(1,1));
diff --git a/src/codedump.c b/src/codedump.c
index 30a14f937..4d1d96171 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -4,25 +4,20 @@
#include <mruby/opcode.h>
#include <mruby/string.h>
#include <mruby/proc.h>
+#include <mruby/dump.h>
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
static void
-print_r(mrb_state *mrb, mrb_irep *irep, size_t n)
+print_r(mrb_state *mrb, const mrb_irep *irep, size_t n)
{
- size_t i;
-
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;
- printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym));
- }
- }
+ if (n >= irep->nlocals) return;
+ if (!irep->lv[n-1]) return;
+ printf(" R%d:%s", (int)n, mrb_sym_dump(mrb, irep->lv[n-1]));
}
static void
-print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a)
+print_lv_a(mrb_state *mrb, const mrb_irep *irep, uint16_t a)
{
if (!irep->lv || a >= irep->nlocals || a == 0) {
printf("\n");
@@ -34,7 +29,7 @@ print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a)
}
static void
-print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b)
+print_lv_ab(mrb_state *mrb, const mrb_irep *irep, uint16_t a, uint16_t b)
{
if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) {
printf("\n");
@@ -47,11 +42,11 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b)
}
static void
-print_header(mrb_irep *irep, ptrdiff_t i)
+print_header(mrb_state *mrb, const mrb_irep *irep, uint32_t i)
{
int32_t line;
- line = mrb_debug_get_line(irep, i);
+ line = mrb_debug_get_line(mrb, irep, i);
if (line < 0) {
printf(" ");
}
@@ -65,24 +60,52 @@ print_header(mrb_irep *irep, ptrdiff_t i)
#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn
static void
-codedump(mrb_state *mrb, mrb_irep *irep)
+codedump(mrb_state *mrb, const mrb_irep *irep)
{
int ai;
- mrb_code *pc, *pcend;
+ const mrb_code *pc, *pcend;
mrb_code ins;
const char *file = NULL, *next_file;
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 *n = mrb_sym2name(mrb, irep->lv[i - 1].name);
- printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : "");
+ char const *s = mrb_sym_dump(mrb, irep->lv[i - 1]);
+ printf(" R%d:%s\n", i, s ? s : "");
+ }
+ }
+
+ if (irep->clen > 0) {
+ int i = irep->clen;
+ const struct mrb_irep_catch_handler *e = mrb_irep_catch_handler_table(irep);
+
+ for (; i > 0; i --, e ++) {
+ uint32_t begin = mrb_irep_catch_handler_unpack(e->begin);
+ uint32_t end = mrb_irep_catch_handler_unpack(e->end);
+ uint32_t target = mrb_irep_catch_handler_unpack(e->target);
+ char buf[20];
+ const char *type;
+
+ switch (e->type) {
+ case MRB_CATCH_RESCUE:
+ type = "rescue";
+ break;
+ case MRB_CATCH_ENSURE:
+ type = "ensure";
+ break;
+ default:
+ buf[0] = '\0';
+ snprintf(buf, sizeof(buf), "0x%02x <unknown>", (int)e->type);
+ type = buf;
+ break;
+ }
+ printf("catch type: %-8s begin: %04" PRIu32 " end: %04" PRIu32 " target: %04" PRIu32 "\n", type, begin, end, target);
}
}
@@ -92,17 +115,17 @@ codedump(mrb_state *mrb, mrb_irep *irep)
ptrdiff_t i;
uint32_t a;
uint16_t b;
- uint8_t c;
+ uint16_t c;
ai = mrb_gc_arena_save(mrb);
i = pc - irep->iseq;
- next_file = mrb_debug_get_filename(irep, i);
+ next_file = mrb_debug_get_filename(mrb, irep, (uint32_t)i);
if (next_file && file != next_file) {
printf("file: %s\n", next_file);
file = next_file;
}
- print_header(irep, i);
+ print_header(mrb, irep, (uint32_t)i);
ins = READ_B();
switch (ins) {
CASE(OP_NOP, Z):
@@ -112,11 +135,25 @@ codedump(mrb_state *mrb, mrb_irep *irep)
printf("OP_MOVE\tR%d\tR%d\t", a, b);
print_lv_ab(mrb, irep, a, b);
break;
+
CASE(OP_LOADL, BB):
- {
- mrb_value v = irep->pool[b];
- mrb_value s = mrb_inspect(mrb, v);
- printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s));
+ switch (irep->pool[b].tt) {
+#ifndef MRB_NO_FLOAT
+ case IREP_TT_FLOAT:
+ printf("OP_LOADL\tR%d\tL(%d)\t; %f", a, b, (double)irep->pool[b].u.f);
+ break;
+#endif
+ case IREP_TT_INT32:
+ printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId32, a, b, irep->pool[b].u.i32);
+ break;
+#ifdef MRB_64BIT
+ case IREP_TT_INT64:
+ printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId64, a, b, irep->pool[b].u.i64);
+ break;
+#endif
+ default:
+ printf("OP_LOADL\tR%d\tL(%d)\t", a, b);
+ break;
}
print_lv_a(mrb, irep, a);
break;
@@ -128,6 +165,14 @@ codedump(mrb_state *mrb, mrb_irep *irep)
printf("OP_LOADI\tR%d\t-%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
+ CASE(OP_LOADI16, BS):
+ printf("OP_LOADI16\tR%d\t%d\t", a, (int)(int16_t)b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADI32, BSS):
+ printf("OP_LOADI32\tR%d\t%d\t", a, (int32_t)(((uint32_t)b<<16)+c));
+ print_lv_a(mrb, irep, a);
+ break;
CASE(OP_LOADI__1, B):
printf("OP_LOADI__1\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
@@ -145,7 +190,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv_a(mrb, irep, a);
break;
CASE(OP_LOADSYM, BB):
- printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_LOADNIL, B):
@@ -165,43 +210,43 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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]));
+ printf("OP_GETGV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETGV, BB):
- printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETGV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_GETSV, BB):
- printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_GETSV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETSV, BB):
- printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETSV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_GETCONST, BB):
- printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETCONST, BB):
- printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETCONST\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_GETMCNST, BB):
- printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETMCNST, BB):
- printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_GETIV, BB):
- printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_GETIV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETIV, BB):
- printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETIV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_GETUPVAR, BBB):
@@ -213,39 +258,50 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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]));
+ printf("OP_GETCV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_SETCV, BB):
- printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ printf("OP_SETCV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_JMP, S):
- printf("OP_JMP\t\t%03d\n", a);
+ i = pc - irep->iseq;
+ printf("OP_JMP\t\t%03d\n", (int)i+(int16_t)a);
+ break;
+ CASE(OP_JMPUW, S):
+ i = pc - irep->iseq;
+ printf("OP_JMPUW\t\t%03d\n", (int)i+(int16_t)a);
break;
CASE(OP_JMPIF, BS):
- printf("OP_JMPIF\tR%d\t%03d\t", a, b);
+ i = pc - irep->iseq;
+ printf("OP_JMPIF\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
CASE(OP_JMPNOT, BS):
- printf("OP_JMPNOT\tR%d\t%03d\t", a, b);
+ i = pc - irep->iseq;
+ printf("OP_JMPNOT\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
CASE(OP_JMPNIL, BS):
- printf("OP_JMPNIL\tR%d\t%03d\t", a, b);
+ i = pc - irep->iseq;
+ printf("OP_JMPNIL\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
CASE(OP_SENDV, BB):
- printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
CASE(OP_SENDVB, BB):
- printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym_dump(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);
+ printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym_dump(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);
+ printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c);
+ break;
+ CASE(OP_SENDVK, BB):
+ printf("OP_SENDVK\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
CASE(OP_CALL, Z):
printf("OP_CALL\n");
@@ -264,23 +320,23 @@ codedump(mrb_state *mrb, mrb_irep *irep)
break;
CASE(OP_ENTER, W):
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
- (a>>18)&0x1f,
- (a>>13)&0x1f,
- (a>>12)&0x1,
- (a>>7)&0x1f,
- (a>>2)&0x1f,
- (a>>1)&0x1,
- a & 0x1);
+ 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_KEY_P, BB):
- printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_KEYEND, Z):
printf("OP_KEYEND\n");
break;
CASE(OP_KARG, BB):
- printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_RETURN, B):
@@ -305,13 +361,13 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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]);
+ printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_BLOCK, BB):
- printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
+ printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_METHOD, BB):
- printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
+ printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_RANGE_INC, B):
printf("OP_RANGE_INC\tR%d\n", a);
@@ -320,46 +376,46 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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]));
+ printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
CASE(OP_UNDEF, B):
- printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a]));
+ printf("OP_UNDEF\t:%s\n", mrb_sym_dump(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]));
+ printf("OP_ALIAS\t:%s\t%s\n", mrb_sym_dump(mrb, irep->syms[a]), mrb_sym_dump(mrb, irep->syms[b]));
break;
- CASE(OP_ADD, BB):
- printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_ADD, B):
+ printf("OP_ADD\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_ADDI, BBB):
- printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ CASE(OP_ADDI, BB):
+ printf("OP_ADDI\tR%d\t%d\n", a, b);
break;
- CASE(OP_SUB, BB):
- printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_SUB, B):
+ printf("OP_SUB\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_SUBI, BBB):
- printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ CASE(OP_SUBI, BB):
+ printf("OP_SUBI\tR%d\t%d\n", a, b);
break;
- CASE(OP_MUL, BB):
- printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_MUL, B):
+ printf("OP_MUL\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_DIV, BB):
- printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_DIV, B):
+ printf("OP_DIV\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_LT, BB):
- printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_LT, B):
+ printf("OP_LT\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_LE, BB):
- printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_LE, B):
+ printf("OP_LE\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_GT, BB):
- printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_GT, B):
+ printf("OP_GT\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_GE, BB):
- printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_GE, B):
+ printf("OP_GE\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_EQ, BB):
- printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ CASE(OP_EQ, B):
+ printf("OP_EQ\t\tR%d\tR%d\n", a, a+1);
break;
CASE(OP_ARRAY, BB):
printf("OP_ARRAY\tR%d\t%d\t", a, b);
@@ -398,10 +454,11 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv_a(mrb, irep, a);
break;
CASE(OP_STRING, BB):
- {
- 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", a, b, RSTRING_PTR(s));
+ if ((irep->pool[b].tt & IREP_TT_NFLAG) == 0) {
+ printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str);
+ }
+ else {
+ printf("OP_STRING\tR%d\tL(%d)\t", a, b);
}
print_lv_a(mrb, irep, a);
break;
@@ -427,15 +484,15 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv_a(mrb, irep, a);
break;
CASE(OP_CLASS, BB):
- printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_CLASS\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_MODULE, BB):
- printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ printf("OP_MODULE\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
CASE(OP_EXEC, BB):
- printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]);
+ printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, (void*)irep->reps[b]);
print_lv_a(mrb, irep, a);
break;
CASE(OP_SCLASS, B):
@@ -447,17 +504,12 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv_a(mrb, irep, a);
break;
CASE(OP_ERR, B):
- {
- 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));
+ if ((irep->pool[a].tt & IREP_TT_NFLAG) == 0) {
+ printf("OP_ERR\t%s\n", irep->pool[a].u.str);
+ }
+ else {
+ printf("OP_ERR\tL(%d)\n", a);
}
- break;
- CASE(OP_EPUSH, B):
- printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]);
- break;
- CASE(OP_ONERR, S):
- printf("OP_ONERR\t%03d\n", a);
break;
CASE(OP_EXCEPT, B):
printf("OP_EXCEPT\tR%d\t\t", a);
@@ -467,16 +519,10 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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);
+ CASE(OP_RAISEIF, B):
+ printf("OP_RAISEIF\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_DEBUG, BBB):
printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c);
@@ -489,7 +535,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT1, Z):
ins = READ_B();
printf("OP_EXT1\n");
- print_header(irep, pc-irep->iseq-2);
+ 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"
@@ -499,7 +545,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT2, Z):
ins = READ_B();
printf("OP_EXT2\n");
- print_header(irep, pc-irep->iseq-2);
+ 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"
@@ -509,7 +555,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT3, Z):
ins = READ_B();
printf("OP_EXT3\n");
- print_header(irep, pc-irep->iseq-2);
+ 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"
@@ -527,13 +573,15 @@ codedump(mrb_state *mrb, mrb_irep *irep)
}
static void
-codedump_recur(mrb_state *mrb, mrb_irep *irep)
+codedump_recur(mrb_state *mrb, const mrb_irep *irep)
{
int i;
codedump(mrb, irep);
- for (i=0; i<irep->rlen; i++) {
- codedump_recur(mrb, irep->reps[i]);
+ if (irep->reps) {
+ for (i=0; i<irep->rlen; i++) {
+ codedump_recur(mrb, irep->reps[i]);
+ }
}
}
#endif
@@ -541,7 +589,7 @@ codedump_recur(mrb_state *mrb, mrb_irep *irep)
void
mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
{
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
codedump_recur(mrb, proc->body.irep);
#endif
}
diff --git a/src/crc.c b/src/crc.c
deleted file mode 100644
index 290b2ca0e..000000000
--- a/src/crc.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-** crc.c - calculate CRC
-**
-** See Copyright Notice in mruby.h
-*/
-
-#include <limits.h>
-#include <stdint.h>
-#include <stddef.h>
-
-/* Calculate CRC (CRC-16-CCITT)
-**
-** 0000_0000_0000_0000_0000_0000_0000_0000
-** ^|------- CRC -------|- work --|
-** carry
-*/
-#define CRC_16_CCITT 0x11021ul /* x^16+x^12+x^5+1 */
-#define CRC_XOR_PATTERN (CRC_16_CCITT << 8)
-#define CRC_CARRY_BIT (0x01000000)
-
-uint16_t
-calc_crc_16_ccitt(const uint8_t *src, size_t nbytes, uint16_t crc)
-{
- size_t ibyte;
- uint32_t ibit;
- uint32_t crcwk = crc << 8;
-
- for (ibyte = 0; ibyte < nbytes; ibyte++) {
- crcwk |= *src++;
- for (ibit = 0; ibit < CHAR_BIT; ibit++) {
- crcwk <<= 1;
- if (crcwk & CRC_CARRY_BIT) {
- crcwk ^= CRC_XOR_PATTERN;
- }
- }
- }
- return (uint16_t)(crcwk >> 8);
-}
-
diff --git a/src/debug.c b/src/debug.c
index e55f11d4f..203dcf981 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -35,43 +35,96 @@ get_file(mrb_irep_debug_info *info, uint32_t pc)
return *ret;
}
+static size_t
+packed_int_len(uint32_t num)
+{
+ size_t llen = 0;
+
+ do {
+ llen++;
+ } while (num >>= 7);
+ return llen;
+}
+
+static size_t
+packed_int_encode(uint32_t num, uint8_t *p, uint8_t *pend)
+{
+ size_t llen = 0;
+
+ do {
+ uint8_t byte = num & 0x7f;
+ num >>= 7;
+ if (num != 0) byte |= 0x80;
+ if (p < pend) *p++ = byte;
+ llen++;
+ } while (num != 0);
+
+ return llen;
+}
+
+static uint32_t
+packed_int_decode(uint8_t *p, uint8_t **newpos)
+{
+ size_t i = 0, shift = 0;
+ uint32_t n = 0;
+
+ do {
+ n |= ((uint32_t)(p[i] & 0x7f)) << shift;
+ i++;
+ shift += 7;
+ } while (shift < sizeof(uint32_t) * 8 && (p[i - 1] & 0x80));
+ if (newpos) *newpos = p + i;
+ return n;
+}
+
static mrb_debug_line_type
select_line_type(const uint16_t *lines, size_t lines_len)
{
size_t line_count = 0;
- int prev_line = -1;
+ size_t packed_map_len = 0;
+ uint32_t prev_line = 0;
+ uint32_t prev_pc = 0;
size_t i;
for (i = 0; i < lines_len; ++i) {
if (lines[i] != prev_line) {
+ packed_map_len += packed_int_len(lines[i]-prev_line);
+ prev_line = lines[i];
+ packed_map_len += packed_int_len(i-prev_pc);
+ prev_pc = i;
++line_count;
}
}
- return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count)
- ? mrb_debug_line_ary : mrb_debug_line_flat_map;
+ size_t line_ary_len = sizeof(uint16_t) * lines_len;
+ size_t flat_map_len = sizeof(mrb_irep_debug_info_line) * line_count;
+ if (line_ary_len < flat_map_len && line_ary_len < packed_map_len) {
+ return mrb_debug_line_ary;
+ }
+ if (flat_map_len < packed_map_len) return mrb_debug_line_flat_map;
+ return mrb_debug_line_packed_map;
}
MRB_API char const*
-mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc)
+mrb_debug_get_filename(mrb_state *mrb, const mrb_irep *irep, uint32_t pc)
{
- if (irep && pc >= 0 && pc < irep->ilen) {
+ if (irep && pc < irep->ilen) {
mrb_irep_debug_info_file* f = NULL;
- if (!irep->debug_info) { return irep->filename; }
- else if ((f = get_file(irep->debug_info, (uint32_t)pc))) {
- return f->filename;
+ if (!irep->debug_info) return NULL;
+ else if ((f = get_file(irep->debug_info, pc))) {
+ return mrb_sym_name_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, const mrb_irep *irep, uint32_t pc)
{
- if (irep && pc >= 0 && pc < irep->ilen) {
+ if (irep && 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))) {
+ else if ((f = get_file(irep->debug_info, pc))) {
switch (f->line_type) {
case mrb_debug_line_ary:
mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count));
@@ -102,6 +155,19 @@ mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc)
return ret->line;
}
+
+ case mrb_debug_line_packed_map: {
+ uint8_t *p = f->lines.packed_map;
+ uint8_t *pend = p + f->line_entry_count;
+ uint32_t pos = 0, line = 0, line_diff;
+ while (p < pend) {
+ pos += packed_int_decode(p, &p);
+ line_diff = packed_int_decode(p, &p);
+ if (pc < pos) break;
+ line += line_diff;
+ }
+ return line;
+ }
}
}
}
@@ -122,82 +188,111 @@ 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; }
-
- mrb_assert(irep->filename);
- mrb_assert(irep->lines);
+ if (!d) return NULL;
+ if (start_pos == end_pos) return NULL;
- info = irep->debug_info;
+ mrb_assert(filename);
+ mrb_assert(lines);
- if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) {
- return NULL;
+ if (d->flen > 0) {
+ const char *fn = mrb_sym_name_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->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; }
+ ++f->line_entry_count;
+ prev_line = lines[start_pos + i];
+ }
+ f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * f->line_entry_count);
+ prev_line = 0;
+ for (i = 0; i < file_pc_count; ++i) {
+ 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));
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];
+ prev_line = lines[start_pos + i];
}
- } break;
+ break;
+ }
+
+ case mrb_debug_line_packed_map: {
+ uint32_t prev_line = 0;
+ uint32_t prev_pc = 0;
+ size_t packed_size = 0;
+ uint8_t *p, *pend;
+
+ for (i = 0; i < file_pc_count; ++i) {
+ if (lines[start_pos + i] == prev_line) { continue; }
+
+ packed_size += packed_int_len(start_pos+i-prev_pc);
+ prev_pc = start_pos+i;
+ packed_size += packed_int_len(lines[start_pos+i]-prev_line);
+ prev_line = lines[start_pos + i];
+ }
+ p = f->lines.packed_map = (uint8_t*)mrb_malloc(mrb, packed_size);
+ pend = p + packed_size;
+ prev_line = 0; prev_pc = 0;
+ for (i = 0; i < file_pc_count; ++i) {
+ if (lines[start_pos + i] == prev_line) { continue; }
+ p += packed_int_encode(start_pos+i-prev_pc, p, pend);
+ prev_pc = start_pos + i;
+ p += packed_int_encode(lines[start_pos + i]-prev_line, p, pend);
+ prev_line = lines[start_pos + i];
+ /* update */
+ }
+ f->line_entry_count = (uint32_t)packed_size;
+ break;
+ }
default: mrb_assert(0); break;
}
- return ret;
+ return f;
}
MRB_API void
@@ -207,11 +302,14 @@ mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
if (!d) { return; }
- for (i = 0; i < d->flen; ++i) {
- mrb_assert(d->files[i]);
- mrb_free(mrb, d->files[i]->lines.ptr);
- mrb_free(mrb, d->files[i]);
+ if (d->files) {
+ for (i = 0; i < d->flen; ++i) {
+ if (d->files[i]) {
+ mrb_free(mrb, d->files[i]->lines.ptr);
+ mrb_free(mrb, d->files[i]);
+ }
+ }
+ mrb_free(mrb, d->files);
}
- mrb_free(mrb, d->files);
mrb_free(mrb, d);
}
diff --git a/src/dump.c b/src/dump.c
index df1e171e4..628c3dbc4 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1,46 +1,28 @@
/*
-** dump.c - mruby binary dumper (mrbc binary format)
+** cdump.c - mruby binary dumper (in C)
**
** See Copyright Notice in mruby.h
*/
#include <string.h>
#include <limits.h>
+#include <math.h>
#include <mruby/dump.h>
#include <mruby/string.h>
#include <mruby/irep.h>
-#include <mruby/numeric.h>
#include <mruby/debug.h>
-#define FLAG_BYTEORDER_NATIVE 2
-#define FLAG_BYTEORDER_NONATIVE 0
-
-#ifndef MRB_WITHOUT_FLOAT
-#ifdef MRB_USE_FLOAT
-#define MRB_FLOAT_FMT "%.8e"
-#else
-#define MRB_FLOAT_FMT "%.16e"
-#endif
+#ifndef MRB_NO_FLOAT
+#include <mruby/endian.h>
#endif
-static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
+static size_t get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep);
#if UINT32_MAX > SIZE_MAX
# error This code cannot be built on your environment.
#endif
static size_t
-write_padding(uint8_t *buf)
-{
- const size_t align = MRB_DUMP_ALIGNMENT;
- size_t pad_len = -(intptr_t)buf & (align-1);
- if (pad_len > 0) {
- memset(buf, 0, pad_len);
- }
- return pad_len;
-}
-
-static size_t
get_irep_header_size(mrb_state *mrb)
{
size_t size = 0;
@@ -52,7 +34,7 @@ get_irep_header_size(mrb_state *mrb)
}
static ptrdiff_t
-write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+write_irep_header(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
@@ -64,95 +46,112 @@ write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
return cur - buf;
}
-
static size_t
-get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
+get_iseq_block_size(mrb_state *mrb, const mrb_irep *irep)
{
size_t size = 0;
- size += sizeof(uint32_t); /* ilen */
- size += sizeof(uint32_t); /* max padding */
- size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
+ size += sizeof(uint16_t); /* clen */
+ size += sizeof(uint16_t); /* ilen */
+ size += irep->ilen * sizeof(mrb_code); /* iseq(n) */
+ size += irep->clen * sizeof(struct mrb_irep_catch_handler);
return size;
}
static ptrdiff_t
-write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
+write_iseq_block(mrb_state *mrb, const 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;
+ size_t seqlen = irep->ilen * sizeof(mrb_code) +
+ irep->clen * sizeof(struct mrb_irep_catch_handler);
- native:
- case DUMP_ENDIAN_NAT:
- memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
- cur += irep->ilen * sizeof(mrb_code);
- break;
- }
+ cur += uint16_to_bin(irep->clen, cur); /* number of catch handlers */
+ cur += uint16_to_bin(irep->ilen, cur); /* number of opcode */
+ memcpy(cur, irep->iseq, seqlen);
+ cur += seqlen;
return cur - buf;
}
+#ifndef MRB_NO_FLOAT
+static void
+dump_float(mrb_state *mrb, uint8_t *buf, mrb_float f)
+{
+ /* dump IEEE754 binary in little endian */
+ union {
+ double f;
+ char s[sizeof(double)];
+ } u = {.f = (double)f};
+
+ if (littleendian) {
+ memcpy(buf, u.s, sizeof(double));
+ }
+ else {
+ size_t i;
+
+ for (i=0; i<sizeof(double); i++) {
+ buf[i] = u.s[sizeof(double)-i-1];
+ }
+ }
+}
+#endif
static size_t
-get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
+get_pool_block_size(mrb_state *mrb, const mrb_irep *irep)
{
int pool_no;
size_t size = 0;
- mrb_value str;
- size += sizeof(uint32_t); /* plen */
- size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */
+ size += sizeof(uint16_t); /* plen */
+ size += irep->plen * sizeof(uint8_t); /* len(n) */
for (pool_no = 0; pool_no < irep->plen; pool_no++) {
int ai = mrb_gc_arena_save(mrb);
- switch (mrb_type(irep->pool[pool_no])) {
- case MRB_TT_FIXNUM:
- str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
+ switch (irep->pool[pool_no].tt) {
+ case IREP_TT_INT64:
+#ifdef MRB_64BIT
{
- mrb_int len = RSTRING_LEN(str);
- mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
- size += (size_t)len;
+ int64_t i = irep->pool[pool_no].u.i64;
+
+ if (i < INT32_MIN || INT32_MAX < i)
+ size += 8;
+ else
+ size += 4;
}
break;
+#else
+ /* fall through */
+#endif
+ case IREP_TT_INT32:
+ size += 4; /* 32bits = 4bytes */
+ break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
- str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
+ case IREP_TT_BIGINT:
{
- mrb_int len = RSTRING_LEN(str);
+ mrb_int len = irep->pool[pool_no].u.str[0];
mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
- size += (size_t)len;
+ size += sizeof(uint8_t);
+ size += (size_t)len+2;
}
break;
-#endif
- case MRB_TT_STRING:
+ case IREP_TT_FLOAT:
+#ifndef MRB_NO_FLOAT
{
- mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
- mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
- size += (size_t)len;
+ size += sizeof(double);
}
+#endif
break;
- default:
+ default: /* packed IREP_TT_STRING */
+ {
+ mrb_int len = irep->pool[pool_no].tt >> 2; /* unpack length */
+ mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
+ size += sizeof(uint16_t);
+ size += (size_t)len+1;
+ }
break;
}
mrb_gc_arena_restore(mrb, ai);
@@ -162,71 +161,89 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
}
static ptrdiff_t
-write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+write_pool_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf)
{
int pool_no;
uint8_t *cur = buf;
- uint16_t len;
- mrb_value str;
- const char *char_ptr;
+ mrb_int len;
+ const char *ptr;
- cur += uint32_to_bin(irep->plen, cur); /* number of pool */
+ cur += uint16_to_bin(irep->plen, cur); /* number of pool */
for (pool_no = 0; pool_no < irep->plen; pool_no++) {
int ai = mrb_gc_arena_save(mrb);
- switch (mrb_type(irep->pool[pool_no])) {
- case MRB_TT_FIXNUM:
- cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
- str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
- break;
-
-#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);
+ switch (irep->pool[pool_no].tt) {
+#ifdef MRB_64BIT
+ case IREP_TT_INT64:
+ {
+ int64_t i = irep->pool[pool_no].u.i64;
+ if (i < INT32_MIN || INT32_MAX < i) {
+ cur += uint8_to_bin(IREP_TT_INT64, cur); /* data type */
+ cur += uint32_to_bin((uint32_t)((i>>32) & 0xffffffff), cur); /* i64 hi */
+ cur += uint32_to_bin((uint32_t)((i ) & 0xffffffff), cur); /* i64 lo */
+ }
+ else {
+ cur += uint8_to_bin(IREP_TT_INT32, cur); /* data type */
+ cur += uint32_to_bin(irep->pool[pool_no].u.i32, cur); /* i32 */
+ }
+ }
break;
#endif
+ case IREP_TT_INT32:
+ cur += uint8_to_bin(IREP_TT_INT32, cur); /* data type */
+ cur += uint32_to_bin(irep->pool[pool_no].u.i32, cur); /* i32 */
+ break;
- case MRB_TT_STRING:
- cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
- str = irep->pool[pool_no];
+ case IREP_TT_BIGINT:
+ cur += uint8_to_bin(IREP_TT_BIGINT, cur); /* data type */
+ len = irep->pool[pool_no].u.str[0];
+ memcpy(cur, irep->pool[pool_no].u.str, (size_t)len+2);
+ cur += len+2;
+ *cur++ = '\0';
break;
- default:
- continue;
- }
+ case IREP_TT_FLOAT:
+ cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
+#ifndef MRB_NO_FLOAT
+ {
+ dump_float(mrb, cur,irep->pool[pool_no].u.f);
+ cur += sizeof(double);
+ }
+#else
+ cur += uint16_to_bin(0, cur); /* zero length */
+#endif
+ break;
- char_ptr = RSTRING_PTR(str);
- {
- mrb_int tlen = RSTRING_LEN(str);
- mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
- len = (uint16_t)tlen;
+ default: /* string */
+ cur += uint8_to_bin(IREP_TT_STR, cur); /* data type */
+ ptr = irep->pool[pool_no].u.str;
+ len = irep->pool[pool_no].tt>>2;
+ mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)len, cur); /* data length */
+ memcpy(cur, ptr, (size_t)len);
+ cur += len;
+ *cur++ = '\0';
+ break;
}
-
- cur += uint16_to_bin(len, cur); /* data length */
- memcpy(cur, char_ptr, (size_t)len);
- cur += len;
-
mrb_gc_arena_restore(mrb, ai);
}
return cur - buf;
}
-
static size_t
-get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
+get_syms_block_size(mrb_state *mrb, const mrb_irep *irep)
{
size_t size = 0;
int sym_no;
mrb_int len;
- size += sizeof(uint32_t); /* slen */
+ size += sizeof(uint16_t); /* slen */
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
size += sizeof(uint16_t); /* snl(n) */
if (irep->syms[sym_no] != 0) {
- mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
+ mrb_sym_name_len(mrb, irep->syms[sym_no], &len);
size += len + 1; /* sn(n) + null char */
}
}
@@ -235,19 +252,19 @@ get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
}
static ptrdiff_t
-write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+write_syms_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf)
{
int sym_no;
uint8_t *cur = buf;
const char *name;
- cur += uint32_to_bin(irep->slen, cur); /* number of symbol */
+ cur += uint16_to_bin(irep->slen, cur); /* number of symbol */
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
if (irep->syms[sym_no] != 0) {
mrb_int len;
- name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
+ name = mrb_sym_name_len(mrb, irep->syms[sym_no], &len);
mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX);
cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
@@ -264,7 +281,7 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
}
static size_t
-get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
+get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep)
{
size_t size = 0;
@@ -276,7 +293,7 @@ get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
}
static size_t
-get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
+get_irep_record_size(mrb_state *mrb, const mrb_irep *irep)
{
size_t size = 0;
int irep_no;
@@ -289,7 +306,7 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
}
static int
-write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
+write_irep_record(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
{
int i;
uint8_t *src = bin;
@@ -298,11 +315,6 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_rec
return MRB_DUMP_INVALID_IREP;
}
- *irep_record_size = get_irep_record_size_1(mrb, irep);
- if (*irep_record_size == 0) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
-
bin += write_irep_header(mrb, irep, bin);
bin += write_iseq_block(mrb, irep, bin, flags);
bin += write_pool_block(mrb, irep, bin);
@@ -350,7 +362,7 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
}
static int
-write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
+write_section_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
{
int result;
size_t rsize = 0;
@@ -366,126 +378,15 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p,
if (result != MRB_DUMP_OK) {
return result;
}
+ mrb_assert(rsize == get_irep_record_size(mrb, irep));
*len_p = cur - bin + rsize;
write_section_irep_header(mrb, *len_p, bin);
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)
+get_debug_record_size(mrb_state *mrb, const mrb_irep *irep)
{
size_t ret = 0;
uint16_t f_idx;
@@ -512,6 +413,10 @@ get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
break;
+ case mrb_debug_line_packed_map:
+ ret += (size_t)(file->line_entry_count);
+ break;
+
default: mrb_assert(0); break;
}
}
@@ -534,11 +439,11 @@ find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s)
}
static size_t
-get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
+get_filename_table_size(mrb_state *mrb, const mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
{
mrb_sym *filenames = *fp;
size_t size = 0;
- mrb_irep_debug_info *di = irep->debug_info;
+ const mrb_irep_debug_info *di = irep->debug_info;
int i;
mrb_assert(lp);
@@ -554,7 +459,7 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *
filenames[*lp - 1] = file->filename_sym;
/* filename */
- mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
+ mrb_sym_name_len(mrb, file->filename_sym, &filename_len);
size += sizeof(uint16_t) + (size_t)filename_len;
}
}
@@ -565,7 +470,7 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *
}
static size_t
-write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+write_debug_record_1(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
{
uint8_t *cur;
uint16_t f_idx;
@@ -606,6 +511,11 @@ write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const
}
} break;
+ case mrb_debug_line_packed_map: {
+ memcpy(cur, file->lines.packed_map, file->line_entry_count);
+ cur += file->line_entry_count;
+ } break;
+
default: mrb_assert(0); break;
}
}
@@ -619,7 +529,7 @@ write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const
}
static size_t
-write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+write_debug_record(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
{
size_t size, len;
int irep_no;
@@ -637,7 +547,7 @@ write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const*
}
static int
-write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
+write_section_debug(mrb_state *mrb, const mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
{
size_t section_size = 0;
const uint8_t *bin = cur;
@@ -658,7 +568,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const
cur += uint16_to_bin(filenames_len, cur);
section_size += sizeof(uint16_t);
for (i = 0; i < filenames_len; ++i) {
- sym = mrb_sym2name_len(mrb, filenames[i], &sym_len);
+ sym = mrb_sym_name_len(mrb, filenames[i], &sym_len);
mrb_assert(sym);
cur += uint16_to_bin((uint16_t)sym_len, cur);
memcpy(cur, sym, sym_len);
@@ -687,7 +597,7 @@ create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32
}
for (i = 0; i + 1 < irep->nlocals; ++i) {
- mrb_sym const name = irep->lv[i].name;
+ mrb_sym const name = irep->lv[i];
if (name == 0) continue;
if (find_filename_index(*syms, *syms_len, name) != -1) continue;
@@ -712,7 +622,7 @@ write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_
cur += uint32_to_bin(syms_len, cur);
for (i = 0; i < syms_len; ++i) {
- str = mrb_sym2name_len(mrb, syms[i], &str_len);
+ str = mrb_sym_name_len(mrb, syms[i], &str_len);
cur += uint16_to_bin((uint16_t)str_len, cur);
memcpy(cur, str, str_len);
cur += str_len;
@@ -730,16 +640,14 @@ write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym c
int i;
for (i = 0; i + 1 < irep->nlocals; ++i) {
- if (irep->lv[i].name == 0) {
+ if (irep->lv[i] == 0) {
cur += uint16_to_bin(RITE_LV_NULL_MARK, cur);
- cur += uint16_to_bin(0, cur);
}
else {
- int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name);
+ int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i]);
mrb_assert(sym_idx != -1); /* local variable name must be in syms */
cur += uint16_to_bin(sym_idx, cur);
- cur += uint16_to_bin(irep->lv[i].r, cur);
}
}
@@ -753,12 +661,12 @@ write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym c
}
static size_t
-get_lv_record_size(mrb_state *mrb, mrb_irep *irep)
+get_lv_record_size(mrb_state *mrb, const mrb_irep *irep)
{
size_t ret = 0;
int i;
- ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1);
+ ret += sizeof(uint16_t) * (irep->nlocals - 1);
for (i = 0; i < irep->rlen; ++i) {
ret += get_lv_record_size(mrb, irep->reps[i]);
@@ -768,7 +676,7 @@ get_lv_record_size(mrb_state *mrb, mrb_irep *irep)
}
static size_t
-get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len)
+get_lv_section_size(mrb_state *mrb, const mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len)
{
size_t ret = 0, i;
@@ -776,7 +684,7 @@ get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_
ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */
for (i = 0; i < syms_len; ++i) {
mrb_int str_len;
- mrb_sym2name_len(mrb, syms[i], &str_len);
+ mrb_sym_name_len(mrb, syms[i], &str_len);
ret += str_len;
}
@@ -786,7 +694,7 @@ get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_
}
static int
-write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len)
+write_section_lv(mrb_state *mrb, const mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len)
{
uint8_t *cur = start;
struct rite_section_lv_header *header;
@@ -824,88 +732,53 @@ static int
write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags)
{
struct rite_binary_header *header = (struct rite_binary_header *)bin;
- uint16_t crc;
- uint32_t offset;
-
- switch (flags & DUMP_ENDIAN_NAT) {
- endian_big:
- case DUMP_ENDIAN_BIG:
- memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident));
- break;
- endian_little:
- case DUMP_ENDIAN_LIL:
- memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident));
- break;
-
- case DUMP_ENDIAN_NAT:
- if (bigendian_p()) goto endian_big;
- goto endian_little;
- break;
- }
- memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
+ memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident));
+ memcpy(header->major_version, RITE_BINARY_MAJOR_VER, sizeof(header->major_version));
+ memcpy(header->minor_version, RITE_BINARY_MINOR_VER, sizeof(header->minor_version));
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
mrb_assert(binary_size <= UINT32_MAX);
uint32_to_bin((uint32_t)binary_size, header->binary_size);
- offset = (uint32_t)((&(header->binary_crc[0]) - bin) + sizeof(uint16_t));
- crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
- uint16_to_bin(crc, header->binary_crc);
-
return MRB_DUMP_OK;
}
static mrb_bool
-is_debug_info_defined(mrb_irep *irep)
+debug_info_defined_p(const 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(const 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;
}
-static uint8_t
-dump_flags(uint8_t flags, uint8_t native)
-{
- if (native == FLAG_BYTEORDER_NATIVE) {
- if ((flags & DUMP_ENDIAN_NAT) == 0) {
- return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT;
- }
- return flags;
- }
- if ((flags & DUMP_ENDIAN_NAT) == 0) {
- return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG;
- }
- return flags;
-}
-
static int
-dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
+dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
{
int result = MRB_DUMP_GENERAL_FAILURE;
size_t malloc_size;
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;
@@ -918,7 +791,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *
section_irep_size += get_irep_record_size(mrb, irep);
/* DEBUG section size */
- if (flags & DUMP_DEBUG_INFO) {
+ if (flags & MRB_DUMP_DEBUG_INFO) {
if (debug_info_defined) {
section_lineno_size += sizeof(struct rite_section_debug_header);
/* filename table */
@@ -930,10 +803,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) {
@@ -958,15 +827,12 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *
sizeof(struct rite_binary_footer);
/* write DEBUG section */
- if (flags & DUMP_DEBUG_INFO) {
+ if (flags & MRB_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;
}
@@ -993,15 +859,15 @@ error_exit:
}
int
-mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
+mrb_dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
{
- return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size);
+ return dump_irep(mrb, irep, flags, bin, bin_size);
}
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
int
-mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
+mrb_dump_irep_binary(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE* fp)
{
uint8_t *bin = NULL;
size_t bin_size = 0;
@@ -1011,7 +877,7 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
return MRB_DUMP_INVALID_ARGUMENT;
}
- result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size);
+ result = dump_irep(mrb, irep, flags, &bin, &bin_size);
if (result == MRB_DUMP_OK) {
if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
result = MRB_DUMP_WRITE_FAULT;
@@ -1022,22 +888,8 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
return result;
}
-static mrb_bool
-dump_bigendian_p(uint8_t flags)
-{
- switch (flags & DUMP_ENDIAN_NAT) {
- case DUMP_ENDIAN_BIG:
- return TRUE;
- case DUMP_ENDIAN_LIL:
- return FALSE;
- default:
- case DUMP_ENDIAN_NAT:
- return bigendian_p();
- }
-}
-
int
-mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
+mrb_dump_irep_cfunc(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
{
uint8_t *bin = NULL;
size_t bin_size = 0, bin_idx = 0;
@@ -1046,38 +898,20 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
if (fp == NULL || initname == NULL || initname[0] == '\0') {
return MRB_DUMP_INVALID_ARGUMENT;
}
- flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE);
result = dump_irep(mrb, irep, flags, &bin, &bin_size);
if (result == MRB_DUMP_OK) {
- if (!dump_bigendian_p(flags)) {
- if (fprintf(fp, "/* dumped in little endian order.\n"
- " use `mrbc -E` option for big endian CPU. */\n") < 0) {
- mrb_free(mrb, bin);
- return MRB_DUMP_WRITE_FAULT;
- }
- }
- else {
- if (fprintf(fp, "/* dumped in big endian order.\n"
- " use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) {
- mrb_free(mrb, bin);
- return MRB_DUMP_WRITE_FAULT;
- }
- }
if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
}
if (fprintf(fp,
- "extern const uint8_t %s[];\n"
- "const uint8_t\n"
- "#if defined __GNUC__\n"
- "__attribute__((aligned(%u)))\n"
- "#elif defined _MSC_VER\n"
- "__declspec(align(%u))\n"
- "#endif\n"
- "%s[] = {",
- initname,
- (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
+ "%s\n"
+ "const uint8_t %s[] = {",
+ (flags & MRB_DUMP_STATIC) ? "static"
+ : "#ifdef __cplusplus\n"
+ "extern\n"
+ "#endif",
+ initname) < 0) {
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
}
@@ -1103,4 +937,4 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
return result;
}
-#endif /* MRB_DISABLE_STDIO */
+#endif /* MRB_NO_STDIO */
diff --git a/src/enum.c b/src/enum.c
index 03508953e..b95956715 100644
--- a/src/enum.c
+++ b/src/enum.c
@@ -14,25 +14,11 @@ 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");
- /* not reached */
- hv = 0;
- }
- hash ^= (hv << (index % 16));
+ mrb_get_args(mrb, "iii", &hash, &index, &hv);
+ hash ^= ((uint32_t)hv << (index % 16));
- return mrb_fixnum_value(hash);
+ return mrb_int_value(mrb, hash);
}
void
@@ -40,5 +26,5 @@ mrb_init_enumerable(mrb_state *mrb)
{
struct RClass *enumerable;
enumerable = mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */
- mrb_define_module_function(mrb, enumerable, "__update_hash", enum_update_hash, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, enumerable, "__update_hash", enum_update_hash, MRB_ARGS_REQ(3));
}
diff --git a/src/error.c b/src/error.c
index 599612b97..7953deea7 100644
--- a/src/error.c
+++ b/src/error.c
@@ -13,10 +13,10 @@
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/variable.h>
-#include <mruby/debug.h>
#include <mruby/error.h>
#include <mruby/class.h>
#include <mruby/throw.h>
+#include <mruby/presym.h>
MRB_API mrb_value
mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
@@ -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);
}
@@ -44,11 +44,9 @@ static mrb_value
exc_initialize(mrb_state *mrb, mrb_value exc)
{
mrb_value mesg;
- mrb_int argc;
- mrb_value *argv;
- if (mrb_get_args(mrb, "|o*!", &mesg, &argv, &argc) >= 1) {
- mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
+ if (mrb_get_args(mrb, "|o", &mesg) == 1) {
+ mrb_iv_set(mrb, exc, MRB_SYM(mesg), mesg);
}
return exc;
}
@@ -77,7 +75,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
if (argc == 0) return self;
if (mrb_obj_equal(mrb, self, a)) return self;
exc = mrb_obj_clone(mrb, self);
- mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
+ mrb_iv_set(mrb, exc, MRB_SYM(mesg), a);
return exc;
}
@@ -93,7 +91,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
static mrb_value
exc_to_s(mrb_state *mrb, mrb_value exc)
{
- mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
+ mrb_value mesg = mrb_attr_get(mrb, exc, MRB_SYM(mesg));
struct RObject *p;
if (!mrb_string_p(mesg)) {
@@ -117,7 +115,7 @@ exc_to_s(mrb_state *mrb, mrb_value exc)
static mrb_value
exc_message(mrb_state *mrb, mrb_value exc)
{
- return mrb_funcall(mrb, exc, "to_s", 0);
+ return mrb_funcall_id(mrb, exc, MRB_SYM(to_s), 0);
}
/*
@@ -130,37 +128,13 @@ exc_message(mrb_state *mrb, mrb_value exc)
* returns message and class name.
*/
-static mrb_value
-exc_inspect(mrb_state *mrb, mrb_value exc)
+mrb_value
+mrb_exc_inspect(mrb_state *mrb, mrb_value exc)
{
- mrb_value str, mesg, file, line;
- mrb_bool append_mesg;
- const char *cname;
-
- mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
- file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
- line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
-
- append_mesg = !mrb_nil_p(mesg);
- if (append_mesg) {
- mesg = mrb_obj_as_string(mrb, mesg);
- append_mesg = RSTRING_LEN(mesg) > 0;
- }
-
- cname = mrb_obj_classname(mrb, exc);
- str = mrb_str_new_cstr(mrb, cname);
- if (mrb_string_p(file) && mrb_fixnum_p(line)) {
- if (append_mesg) {
- str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str);
- }
- else {
- str = mrb_format(mrb, "%S:%S: %S", file, line, str);
- }
- }
- else if (append_mesg) {
- str = mrb_format(mrb, "%S: %S", str, mesg);
- }
- return str;
+ mrb_value mesg = mrb_attr_get(mrb, exc, MRB_SYM(mesg));
+ mrb_value cname = mrb_mod_to_s(mrb, mrb_obj_value(mrb_obj_class(mrb, exc)));
+ mesg = mrb_obj_as_string(mrb, mesg);
+ return RSTRING_LEN(mesg) == 0 ? cname : mrb_format(mrb, "%v (%v)", mesg, cname);
}
void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
@@ -181,46 +155,18 @@ set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
p++;
}
}
- mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+ mrb_iv_set(mrb, exc, MRB_SYM(backtrace), backtrace);
}
static mrb_value
exc_set_backtrace(mrb_state *mrb, mrb_value exc)
{
- mrb_value backtrace;
+ mrb_value backtrace = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &backtrace);
set_backtrace(mrb, exc, backtrace);
return backtrace;
}
-static void
-exc_debug_info(mrb_state *mrb, struct RObject *exc)
-{
- mrb_callinfo *ci = mrb->c->ci;
- mrb_code *pc = ci->pc;
-
- if (mrb_obj_iv_defined(mrb, exc, mrb_intern_lit(mrb, "file"))) return;
- while (ci >= mrb->c->cibase) {
- mrb_code *err = ci->err;
-
- if (!err && pc) err = pc - 1;
- if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
- mrb_irep *irep = ci->proc->body.irep;
-
- int32_t const line = mrb_debug_get_line(irep, err - irep->iseq);
- char const* file = mrb_debug_get_filename(irep, err - irep->iseq);
- if (line != -1 && file) {
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
- return;
- }
- }
- pc = ci->pc;
- ci--;
- }
-}
-
void
mrb_exc_set(mrb_state *mrb, mrb_value exc)
{
@@ -233,20 +179,15 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
(struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
mrb->gc.arena_idx--;
}
- if (!mrb->gc.out_of_memory && !MRB_FROZEN_P(mrb->exc)) {
- exc_debug_info(mrb, mrb->exc);
+ if (!mrb->gc.out_of_memory && !mrb_frozen_p(mrb->exc)) {
mrb_keep_backtrace(mrb, exc);
}
}
}
-MRB_API mrb_noreturn void
-mrb_exc_raise(mrb_state *mrb, mrb_value exc)
+static mrb_noreturn void
+exc_throw(mrb_state *mrb, mrb_value exc)
{
- if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
- mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
- }
- mrb_exc_set(mrb, exc);
if (!mrb->jmp) {
mrb_p(mrb, exc);
abort();
@@ -255,64 +196,182 @@ mrb_exc_raise(mrb_state *mrb, mrb_value exc)
}
MRB_API mrb_noreturn void
+mrb_exc_raise(mrb_state *mrb, mrb_value exc)
+{
+ if (mrb_break_p(exc)) {
+ mrb->exc = mrb_obj_ptr(exc);
+ }
+ else {
+ if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
+ }
+ mrb_exc_set(mrb, exc);
+ }
+ exc_throw(mrb, exc);
+}
+
+MRB_API mrb_noreturn void
mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
{
mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg)));
}
+/*
+ * <code>vsprintf</code> like formatting.
+ *
+ * The syntax of a format sequence is as follows.
+ *
+ * %[modifier]specifier
+ *
+ * The modifiers are:
+ *
+ * ----------+------------------------------------------------------------
+ * Modifier | Meaning
+ * ----------+------------------------------------------------------------
+ * ! | Convert to string by corresponding `inspect` instead of
+ * | corresponding `to_s`.
+ * ----------+------------------------------------------------------------
+ *
+ * The specifiers are:
+ *
+ * ----------+----------------+--------------------------------------------
+ * Specifier | Argument Type | Note
+ * ----------+----------------+--------------------------------------------
+ * c | char |
+ * d | int |
+ * f | mrb_float |
+ * i | mrb_int |
+ * l | char*, size_t | Arguments are string and length.
+ * n | mrb_sym |
+ * s | char* | Argument is NUL terminated string.
+ * t | mrb_value | Convert to type (class) of object.
+ * v,S | mrb_value |
+ * C | struct RClass* |
+ * T | mrb_value | Convert to real type (class) of object.
+ * Y | mrb_value | Same as `!v` if argument is `true`, `false`
+ * | | or `nil`, otherwise same as `T`.
+ * % | - | Convert to percent sign itself (no argument
+ * | | taken).
+ * ----------+----------------+--------------------------------------------
+ */
MRB_API mrb_value
mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
{
- const char *p = format;
- const char *b = p;
- ptrdiff_t size;
- int ai0 = mrb_gc_arena_save(mrb);
- mrb_value ary = mrb_ary_new_capa(mrb, 4);
+ const char *chars, *p = format, *b = format, *e;
+ char ch;
+ size_t len;
+ mrb_int i;
+ struct RClass *cls;
+ mrb_bool inspect = FALSE;
+ mrb_value result = mrb_str_new_capa(mrb, 128), obj, str;
int ai = mrb_gc_arena_save(mrb);
while (*p) {
const char c = *p++;
-
+ e = p;
if (c == '%') {
- if (*p == 'S') {
- mrb_value val;
-
- size = p - b - 1;
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
- val = va_arg(ap, mrb_value);
- mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val));
- b = p + 1;
- }
- }
- else if (c == '\\') {
- if (*p) {
- size = p - b - 1;
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
- b = ++p;
+ if (*p == '!') {
+ inspect = TRUE;
+ ++p;
}
- else {
- break;
+ if (!*p) break;
+ switch (*p) {
+ case 'c':
+ ch = (char)va_arg(ap, int);
+ chars = &ch;
+ len = 1;
+ goto L_cat;
+ case 'd': case 'i':
+#if MRB_INT_MAX < INT_MAX
+ i = (mrb_int)va_arg(ap, int);
+#else
+ i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int);
+#endif
+ obj = mrb_fixnum_value(i);
+ goto L_cat_obj;
+#ifndef MRB_NO_FLOAT
+ case 'f':
+ obj = mrb_float_value(mrb, (mrb_float)va_arg(ap, double));
+ goto L_cat_obj;
+#endif
+ case 'l':
+ chars = va_arg(ap, char*);
+ len = va_arg(ap, size_t);
+ L_cat:
+ if (inspect) {
+ obj = mrb_str_new(mrb, chars, len);
+ goto L_cat_obj;
+ }
+ L_cat_plain:
+ mrb_str_cat(mrb, result, b, e - b - 1);
+ mrb_str_cat(mrb, result, chars, len);
+ b = ++p;
+ mrb_gc_arena_restore(mrb, ai);
+ break;
+ case 'n':
+#if UINT32_MAX < INT_MAX
+ obj = mrb_symbol_value((mrb_sym)va_arg(ap, int));
+#else
+ obj = mrb_symbol_value(va_arg(ap, mrb_sym));
+#endif
+ goto L_cat_obj;
+ case 's':
+ chars = va_arg(ap, char*);
+ len = strlen(chars);
+ goto L_cat;
+ case 't':
+ cls = mrb_class(mrb, va_arg(ap, mrb_value));
+ goto L_cat_class;
+ case 'v': case 'S':
+ obj = va_arg(ap, mrb_value);
+ L_cat_obj:
+ str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj);
+ if (mrb_type(str) != MRB_TT_STRING) {
+ chars = "void (no string conversion)";
+ len = strlen(chars);
+ }
+ else {
+ chars = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+ }
+ goto L_cat_plain;
+ case 'C':
+ cls = va_arg(ap, struct RClass*);
+ L_cat_class:
+ obj = mrb_obj_value(cls);
+ goto L_cat_obj;
+ case 'T':
+ obj = va_arg(ap, mrb_value);
+ L_cat_real_class_of:
+ cls = mrb_obj_class(mrb, obj);
+ goto L_cat_class;
+ case 'Y':
+ obj = va_arg(ap, mrb_value);
+ if (!mrb_test(obj) || mrb_true_p(obj)) {
+ inspect = TRUE;
+ goto L_cat_obj;
+ }
+ else {
+ goto L_cat_real_class_of;
+ }
+ case '%':
+ L_cat_current:
+ chars = p;
+ len = 1;
+ goto L_cat_plain;
+ default:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p);
}
}
- mrb_gc_arena_restore(mrb, ai);
- }
- if (b == format) {
- mrb_gc_arena_restore(mrb, ai0);
- return mrb_str_new_cstr(mrb, format);
- }
- else {
- mrb_value val;
+ else if (c == '\\') {
+ if (!*p) break;
+ goto L_cat_current;
- size = p - b;
- if (size > 0) {
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
}
- val = mrb_ary_join(mrb, ary, mrb_nil_value());
- mrb_gc_arena_restore(mrb, ai0);
- mrb_gc_protect(mrb, val);
- return val;
}
+
+ mrb_str_cat(mrb, result, b, p - b);
+ return result;
}
MRB_API mrb_value
@@ -368,7 +427,7 @@ mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
MRB_API void
mrb_warn(mrb_state *mrb, const char *fmt, ...)
{
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
va_list ap;
mrb_value str;
@@ -376,6 +435,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
}
@@ -383,7 +443,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...)
MRB_API mrb_noreturn void
mrb_bug(mrb_state *mrb, const char *fmt, ...)
{
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
va_list ap;
mrb_value str;
@@ -421,7 +481,7 @@ mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv)
n = 1;
exception_call:
{
- mrb_sym exc = mrb_intern_lit(mrb, "exception");
+ mrb_sym exc = MRB_SYM(exception);
if (mrb_respond_to(mrb, argv[0], exc)) {
mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
}
@@ -433,7 +493,7 @@ exception_call:
break;
default:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
+ mrb_argnum_error(mrb, argc, 0, 3);
break;
}
if (argc > 0) {
@@ -483,6 +543,93 @@ 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 %t", mrb_obj_value(frozen_obj));
+}
+
+MRB_API mrb_noreturn void
+mrb_argnum_error(mrb_state *mrb, mrb_int argc, int min, int max)
+{
+#define FMT(exp) "wrong number of arguments (given %i, expected " exp ")"
+ if (min == max)
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d"), argc, min);
+ else if (max < 0)
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d+"), argc, min);
+ else
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, FMT("%d..%d"), argc, min, max);
+#undef FMT
+}
+
+void mrb_core_init_printabort(void);
+
+int
+mrb_core_init_protect(mrb_state *mrb, void (*body)(mrb_state *, void *), void *opaque)
+{
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+ int err = 1;
+
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ body(mrb, opaque);
+ err = 0;
+ } MRB_CATCH(&c_jmp) {
+ if (mrb->exc) {
+ mrb_p(mrb, mrb_obj_value(mrb->exc));
+ mrb->exc = NULL;
+ }
+ else {
+ mrb_core_init_printabort();
+ }
+ } MRB_END_EXC(&c_jmp);
+
+ mrb->jmp = prev_jmp;
+
+ return err;
+}
+
+mrb_noreturn void
+mrb_core_init_abort(mrb_state *mrb)
+{
+ mrb->exc = NULL;
+ exc_throw(mrb, mrb_nil_value());
+}
+
+void
+mrb_protect_atexit(mrb_state *mrb)
+{
+ if (mrb->atexit_stack_len > 0) {
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+ for (int i = mrb->atexit_stack_len; i > 0; --i) {
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ mrb->atexit_stack[i - 1](mrb);
+ mrb->jmp = prev_jmp;
+ } MRB_CATCH(&c_jmp) {
+ /* ignore atexit errors */
+ } MRB_END_EXC(&c_jmp);
+ }
+#ifndef MRB_FIXED_STATE_ATEXIT_STACK
+ mrb_free(mrb, mrb->atexit_stack);
+#endif
+ mrb->jmp = prev_jmp;
+ }
+}
+
+mrb_noreturn void
+mrb_raise_nomemory(mrb_state *mrb)
+{
+ if (mrb->nomem_err) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
+ }
+ else {
+ mrb_core_init_abort(mrb);
+ }
+}
+
void
mrb_init_exception(mrb_state *mrb)
{
@@ -490,12 +637,12 @@ mrb_init_exception(mrb_state *mrb)
mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
- mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
- mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
- mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
+ mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_OPT(1));
mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
- mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
+ mrb_define_method(mrb, exception, "inspect", mrb_exc_inspect, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1));
@@ -504,11 +651,11 @@ mrb_init_exception(mrb_state *mrb)
script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
stack_error = mrb_define_class(mrb, "SystemStackError", exception);
- mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
+ mrb->stack_err = mrb_obj_ptr(mrb_exc_new_lit(mrb, stack_error, "stack level too deep"));
nomem_error = mrb_define_class(mrb, "NoMemoryError", exception);
- mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "Out of memory"));
+ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_lit(mrb, nomem_error, "Out of memory"));
#ifdef MRB_GC_FIXED_ARENA
- mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error"));
+ mrb->arena_err = mrb_obj_ptr(mrb_exc_new_lit(mrb, nomem_error, "arena overflow error"));
#endif
}
diff --git a/src/etc.c b/src/etc.c
index 12d948a55..a5c48bbe3 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -1,5 +1,5 @@
/*
-** etc.c -
+** etc.c
**
** See Copyright Notice in mruby.h
*/
@@ -8,15 +8,14 @@
#include <mruby/string.h>
#include <mruby/data.h>
#include <mruby/class.h>
-#include <mruby/re.h>
-#include <mruby/irep.h>
+#include <mruby/numeric.h>
MRB_API struct RData*
mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
{
struct RData *data;
- data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass);
+ data = MRB_OBJ_ALLOC(mrb, MRB_TT_DATA, klass);
data->data = ptr;
data->type = type;
@@ -26,21 +25,19 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb
MRB_API void
mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
- if (mrb_type(obj) != MRB_TT_DATA) {
+ if (!mrb_data_p(obj)) {
mrb_check_type(mrb, obj, MRB_TT_DATA);
}
if (DATA_TYPE(obj) != type) {
const mrb_data_type *t2 = DATA_TYPE(obj);
if (t2) {
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)",
- mrb_str_new_cstr(mrb, t2->struct_name), mrb_str_new_cstr(mrb, type->struct_name));
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)",
+ t2->struct_name, type->struct_name);
}
else {
- struct RClass *c = mrb_class(mrb, obj);
-
- mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)",
- mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name));
+ mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)",
+ obj, type->struct_name);
}
}
}
@@ -48,7 +45,7 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
MRB_API void*
mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
- if (mrb_type(obj) != MRB_TT_DATA) {
+ if (!mrb_data_p(obj)) {
return NULL;
}
if (DATA_TYPE(obj) != type) {
@@ -67,41 +64,17 @@ 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);
- /* not reached */
- }
- /* 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, "%!v is not a symbol nor a string", name);
+ return 0; /* not reached */
}
-MRB_API mrb_int
-#ifdef MRB_WITHOUT_FLOAT
-mrb_fixnum_id(mrb_int f)
-#else
-mrb_float_id(mrb_float f)
-#endif
+static mrb_int
+make_num_id(const char *p, size_t len)
{
- const char *p = (const char*)&f;
- int len = sizeof(f);
uint32_t id = 0;
-#ifndef MRB_WITHOUT_FLOAT
- /* normalize -0.0 to 0.0 */
- if (f == 0) f = 0.0;
-#endif
while (len--) {
id = id*65599 + *p;
p++;
@@ -112,6 +85,22 @@ mrb_float_id(mrb_float f)
}
MRB_API mrb_int
+mrb_int_id(mrb_int n)
+{
+ return make_num_id((const char*)&n, sizeof(n));
+}
+
+#ifndef MRB_NO_FLOAT
+MRB_API mrb_int
+mrb_float_id(mrb_float f)
+{
+ /* normalize -0.0 to 0.0 */
+ if (f == 0) f = 0.0;
+ return make_num_id((const char*)&f, sizeof(f));
+}
+#endif
+
+MRB_API mrb_int
mrb_obj_id(mrb_value obj)
{
mrb_int tt = mrb_type(obj);
@@ -125,17 +114,16 @@ mrb_obj_id(mrb_value obj)
return MakeID(0); /* not define */
case MRB_TT_FALSE:
if (mrb_nil_p(obj))
- return MakeID(1);
- return MakeID(0);
+ return MakeID(4);
+ else
+ return MakeID(0);
case MRB_TT_TRUE:
- return MakeID(1);
+ return MakeID(2);
case MRB_TT_SYMBOL:
return MakeID(mrb_symbol(obj));
- case MRB_TT_FIXNUM:
-#ifdef MRB_WITHOUT_FLOAT
- return MakeID(mrb_fixnum_id(mrb_fixnum(obj)));
-#else
- return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
+ case MRB_TT_INTEGER:
+ return MakeID(mrb_int_id(mrb_integer(obj)));
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
return MakeID(mrb_float_id(mrb_float(obj)));
#endif
@@ -150,7 +138,6 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_HASH:
case MRB_TT_RANGE:
case MRB_TT_EXCEPTION:
- case MRB_TT_FILE:
case MRB_TT_DATA:
case MRB_TT_ISTRUCT:
default:
@@ -158,56 +145,53 @@ mrb_obj_id(mrb_value obj)
}
}
+#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT)
+#define mrb_xxx_boxing_cptr_value mrb_nan_boxing_cptr_value
+#endif
+
#ifdef MRB_WORD_BOXING
-#ifndef MRB_WITHOUT_FLOAT
+#define mrb_xxx_boxing_cptr_value mrb_word_boxing_cptr_value
+
+#ifndef MRB_NO_FLOAT
MRB_API mrb_value
mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
{
- mrb_value v;
+ union mrb_value_ v;
- v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
- v.value.fp->f = f;
- return v;
+ v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
+ v.fp->f = f;
+ MRB_SET_FROZEN_FLAG(v.bp);
+ return v.value;
}
+#endif /* MRB_NO_FLOAT */
MRB_API mrb_value
-mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f)
+mrb_word_boxing_int_value(mrb_state *mrb, mrb_int n)
{
- struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat));
- nf->tt = MRB_TT_FLOAT;
- nf->c = mrb->float_class;
- nf->f = f;
- return mrb_obj_value(nf);
+ if (FIXABLE(n)) return mrb_fixnum_value(n);
+ else {
+ union mrb_value_ v;
+
+ v.p = mrb_obj_alloc(mrb, MRB_TT_INTEGER, mrb->integer_class);
+ v.ip->i = n;
+ MRB_SET_FROZEN_FLAG(v.ip);
+ return v.value;
+ }
}
-#endif /* MRB_WITHOUT_FLOAT */
+#endif /* MRB_WORD_BOXING */
+#if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_64BIT))
MRB_API mrb_value
-mrb_word_boxing_cptr_value(mrb_state *mrb, void *p)
+mrb_xxx_boxing_cptr_value(mrb_state *mrb, void *p)
{
mrb_value v;
+ struct RCptr *cptr = MRB_OBJ_ALLOC(mrb, MRB_TT_CPTR, mrb->object_class);
- v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class);
- v.value.vp->p = p;
+ SET_OBJ_VALUE(v, cptr);
+ cptr->p = p;
return v;
}
-#endif /* MRB_WORD_BOXING */
-
-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;
-}
+#endif
#if defined _MSC_VER && _MSC_VER < 1900
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 783cc6c02..43daf2307 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -1,388 +1,364 @@
-#ifndef MRB_WITHOUT_FLOAT
-#ifdef MRB_DISABLE_STDIO
-/*
-
-Most code in this file originates from musl (src/stdio/vfprintf.c)
-which, just like mruby itself, is licensed under the MIT license.
+#include <mruby.h>
+#include <string.h>
+#include <stdlib.h>
-Copyright (c) 2005-2014 Rich Felker, et al.
+#ifndef MRB_NO_FLOAT
+/***********************************************************************
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
+ Routine for converting a single-precision
+ floating point number into a string.
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+ The code in this function was inspired from Fred Bayer's pdouble.c.
+ Since pdouble.c was released as Public Domain, I'm releasing this
+ code as public domain as well.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Dave Hylands
-*/
+ The original code can be found in https://github.com/dhylands/format-float
+***********************************************************************/
-#include <limits.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-#include <float.h>
-#include <ctype.h>
+/***********************************************************************
-#include <mruby.h>
-#include <mruby/string.h>
+ I modified the routine for mruby:
-struct fmt_args {
- mrb_state *mrb;
- mrb_value str;
-};
+ * support `double`
+ * support `#` (alt_form) modifier
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#define MIN(a,b) ((a)<(b) ? (a) : (b))
+ My modifications in this file are also placed in the public domain.
-/* Convenient bit representation for modifier flags, which all fall
- * within 31 codepoints of the space character. */
+ Matz (Yukihiro Matsumoto)
-#define ALT_FORM (1U<<('#'-' '))
-#define ZERO_PAD (1U<<('0'-' '))
-#define LEFT_ADJ (1U<<('-'-' '))
-#define PAD_POS (1U<<(' '-' '))
-#define MARK_POS (1U<<('+'-' '))
+***********************************************************************/
-static void
-out(struct fmt_args *f, const char *s, size_t l)
-{
- mrb_str_cat(f->mrb, f->str, s, l);
-}
+#include <math.h>
-#define PAD_SIZE 256
-static void
-pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint8_t fl)
-{
- char pad[PAD_SIZE];
- if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
- l = w - l;
- memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l);
- for (; l >= PAD_SIZE; l -= PAD_SIZE)
- out(f, pad, PAD_SIZE);
- out(f, pad, l);
-}
+#ifdef MRB_USE_FLOAT32
-static const char xdigits[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-};
+// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
+// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
+// exponent is stored with a bias of 127.
+// The min and max floats are on the order of 1x10^37 and 1x10^-37
-static char*
-fmt_u(uint32_t x, char *s)
-{
- for (; x; x /= 10) *--s = '0' + x % 10;
- return s;
-}
+#define FLT_DECEXP 32
+#define FLT_ROUND_TO_ONE 0.9999995F
+#define FLT_MIN_BUF_SIZE 6 // -9e+99
-/* Do not override this check. The floating point printing code below
- * depends on the float.h constants being right. If they are wrong, it
- * may overflow the stack. */
-#if LDBL_MANT_DIG == 53
-typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
-#endif
+#else
-static int
-fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t)
-{
- uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
- + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
- uint32_t *a, *d, *r, *z;
- uint32_t i;
- int e2=0, e, j;
- ptrdiff_t l;
- char buf[9+LDBL_MANT_DIG/4], *s;
- const char *prefix="-0X+0X 0X-0x+0x 0x";
- ptrdiff_t pl;
- char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
-
- pl=1;
- if (signbit(y)) {
- y=-y;
- } else if (fl & MARK_POS) {
- prefix+=3;
- } else if (fl & PAD_POS) {
- prefix+=6;
- } else prefix++, pl=0;
-
- if (!isfinite(y)) {
- const char *ss = (t&32)?"inf":"INF";
- if (y!=y) ss=(t&32)?"nan":"NAN";
- pad(f, ' ', 0, 3+pl, fl&~ZERO_PAD);
- out(f, prefix, pl);
- out(f, ss, 3);
- pad(f, ' ', 0, 3+pl, fl^LEFT_ADJ);
- return 3+(int)pl;
- }
+// 1 sign bit, 11 exponent bits, and 52 mantissa bits.
- y = frexp((double)y, &e2) * 2;
- if (y) e2--;
+#define FLT_DECEXP 256
+#define FLT_ROUND_TO_ONE 0.999999999995
+#define FLT_MIN_BUF_SIZE 7 // -9e+199
- if ((t|32)=='a') {
- long double round = 8.0;
- ptrdiff_t re;
+#endif /* MRB_USE_FLOAT32 */
- if (t&32) prefix += 9;
- pl += 2;
+static const mrb_float g_pos_pow[] = {
+#ifndef MRB_USE_FLOAT32
+ 1e256, 1e128, 1e64,
+#endif
+ 1e32, 1e16, 1e8, 1e4, 1e2, 1e1
+};
+static const mrb_float g_neg_pow[] = {
+#ifndef MRB_USE_FLOAT32
+ 1e-256, 1e-128, 1e-64,
+#endif
+ 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
+};
- if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
- else re=LDBL_MANT_DIG/4-1-p;
+/*
+ * mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign)
+ *
+ * fmt: should be one of 'e', 'E', 'f', 'F', 'g', or 'G'. (|0x80 for '#')
+ * prec: is the precision (as specified in printf)
+ * sign: should be '\0', '+', or ' ' ('\0' is the normal one - only print
+ * a sign if ```f``` is negative. Anything else is printed as the
+ * sign character for positive numbers.
+ */
+
+int
+mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
+ char *s = buf;
+ int buf_remaining = buf_size - 1;
+ int alt_form = 0;
+
+ if ((uint8_t)fmt & 0x80) {
+ fmt &= 0x7f; /* turn off alt_form flag */
+ alt_form = 1;
+ }
+ if (buf_size <= FLT_MIN_BUF_SIZE) {
+ // Smallest exp notion is -9e+99 (-9e+199) which is 6 (7) chars plus terminating
+ // null.
- if (re) {
- while (re--) round*=16;
- if (*prefix=='-') {
- y=-y;
- y-=round;
- y+=round;
- y=-y;
- }
- else {
- y+=round;
- y-=round;
- }
+ if (buf_size >= 2) {
+ *s++ = '?';
+ }
+ if (buf_size >= 1) {
+ *s++ = '\0';
+ }
+ return buf_size >= 2;
+ }
+ if (signbit(f)) {
+ *s++ = '-';
+ f = -f;
+ } else if (sign) {
+ *s++ = sign;
+ }
+ buf_remaining -= (s - buf); // Adjust for sign
+
+ {
+ char uc = fmt & 0x20;
+ if (isinf(f)) {
+ *s++ = 'I' ^ uc;
+ *s++ = 'N' ^ uc;
+ *s++ = 'F' ^ uc;
+ goto ret;
+ } else if (isnan(f)) {
+ *s++ = 'N' ^ uc;
+ *s++ = 'A' ^ uc;
+ *s++ = 'N' ^ uc;
+ ret:
+ *s = '\0';
+ return s - buf;
}
+ }
- estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
- if (estr==ebuf) *--estr='0';
- *--estr = (e2<0 ? '-' : '+');
- *--estr = t+('p'-'a');
-
- s=buf;
- do {
- int x=(int)y;
- *s++=xdigits[x]|(t&32);
- y=16*(y-x);
- if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
- } while (y);
-
- if (p && s-buf-2 < p)
- l = (p+2) + (ebuf-estr);
- else
- l = (s-buf) + (ebuf-estr);
-
- pad(f, ' ', 0, pl+l, fl);
- out(f, prefix, pl);
- pad(f, '0', 0, pl+l, fl^ZERO_PAD);
- out(f, buf, s-buf);
- pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
- out(f, estr, ebuf-estr);
- pad(f, ' ', 0, pl+l, fl^LEFT_ADJ);
- return (int)pl+(int)l;
+ if (prec < 0) {
+ prec = 6;
}
- if (p<0) p=6;
+ char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt
+ fmt |= 0x20; // Force fmt to be lowercase
+ char org_fmt = fmt;
+ if (fmt == 'g' && prec == 0) {
+ prec = 1;
+ }
+ int e, e1;
+ int dec = 0;
+ char e_sign = '\0';
+ int num_digits = 0;
+ const mrb_float *pos_pow = g_pos_pow;
+ const mrb_float *neg_pow = g_neg_pow;
+
+ if (f == 0.0) {
+ e = 0;
+ if (fmt == 'e') {
+ e_sign = '+';
+ } else if (fmt == 'f') {
+ num_digits = prec + 1;
+ }
+ } else if (f < 1.0) { // f < 1.0
+ char first_dig = '0';
+ if (f >= FLT_ROUND_TO_ONE) {
+ first_dig = '1';
+ }
- if (y) y *= 268435456.0, e2-=28;
+ // Build negative exponent
+ for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+ if (*neg_pow > f) {
+ e += e1;
+ f *= *pos_pow;
+ }
+ }
+ char e_sign_char = '-';
+ if (f < 1.0) {
+ if (f >= FLT_ROUND_TO_ONE) {
+ f = 1.0;
+ if (e == 0) {
+ e_sign_char = '+';
+ }
+ } else {
+ e++;
+ f *= 10.0;
+ }
+ }
- if (e2<0) a=r=z=big;
- else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+ // If the user specified 'g' format, and e is <= 4, then we'll switch
+ // to the fixed format ('f')
- do {
- *z = (uint32_t)y;
- y = 1000000000*(y-*z++);
- } while (y);
+ if (fmt == 'f' || (fmt == 'g' && e <= 4)) {
+ fmt = 'f';
+ dec = -1;
+ *s++ = first_dig;
- while (e2>0) {
- uint32_t carry=0;
- int sh=MIN(29,e2);
- for (d=z-1; d>=a; d--) {
- uint64_t x = ((uint64_t)*d<<sh)+carry;
- *d = x % 1000000000;
- carry = (uint32_t)(x / 1000000000);
+ if (org_fmt == 'g') {
+ prec += (e - 1);
+ }
+ // truncate precision to prevent buffer overflow
+ if (prec + 2 > buf_remaining) {
+ prec = buf_remaining - 2;
+ }
+ num_digits = prec;
+ if (num_digits || alt_form) {
+ *s++ = '.';
+ while (--e && num_digits) {
+ *s++ = '0';
+ num_digits--;
+ }
+ }
+ } else {
+ // For e & g formats, we'll be printing the exponent, so set the
+ // sign.
+ e_sign = e_sign_char;
+ dec = 0;
+
+ if (prec > (buf_remaining - FLT_MIN_BUF_SIZE)) {
+ prec = buf_remaining - FLT_MIN_BUF_SIZE;
+ if (fmt == 'g') {
+ prec++;
+ }
+ }
}
- if (carry) *--a = carry;
- while (z>a && !z[-1]) z--;
- e2-=sh;
- }
- while (e2<0) {
- uint32_t carry=0, *b;
- int sh=MIN(9,-e2), need=1+((int)p+LDBL_MANT_DIG/3+8)/9;
- for (d=a; d<z; d++) {
- uint32_t rm = *d & ((1<<sh)-1);
- *d = (*d>>sh) + carry;
- carry = (1000000000>>sh) * rm;
+ } else {
+ // Build positive exponent
+ for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+ if (*pos_pow <= f) {
+ e += e1;
+ f *= *neg_pow;
+ }
}
- if (!*a) a++;
- if (carry) *z++ = carry;
- /* Avoid (slow!) computation past requested precision */
- b = (t|32)=='f' ? r : a;
- if (z-b > need) z = b+need;
- e2+=sh;
- }
- if (a<z) for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
- else e=0;
-
- /* Perform rounding: j is precision after the radix (possibly neg) */
- j = (int)p - ((t|32)!='f')*e - ((t|32)=='g' && p);
- if (j < 9*(z-r-1)) {
- uint32_t x;
- /* We avoid C's broken division of negative numbers */
- d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
- j += 9*LDBL_MAX_EXP;
- j %= 9;
- for (i=10, j++; j<9; i*=10, j++);
- x = *d % i;
- /* Are there any significant digits past j? */
- if (x || d+1!=z) {
- long double round = 2/LDBL_EPSILON;
- long double small;
- if (*d/i & 1) round += 2;
- if (x<i/2) small=0.5;
- else if (x==i/2 && d+1==z) small=1.0;
- else small=1.5;
- if (pl && *prefix=='-') round*=-1, small*=-1;
- *d -= x;
- /* Decide whether to round by probing round+small */
- if (round+small != round) {
- *d = *d + i;
- while (*d > 999999999) {
- *d--=0;
- if (d<a) *--a=0;
- (*d)++;
+ // If the user specified fixed format (fmt == 'f') and e makes the
+ // number too big to fit into the available buffer, then we'll
+ // switch to the 'e' format.
+
+ if (fmt == 'f') {
+ if (e >= buf_remaining) {
+ fmt = 'e';
+ } else if ((e + prec + 2) > buf_remaining) {
+ prec = buf_remaining - e - 2;
+ if (prec < 0) {
+ // This means no decimal point, so we can add one back
+ // for the decimal.
+ prec++;
}
- for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
}
}
- if (z>d+1) z=d+1;
- }
- for (; z>a && !z[-1]; z--);
-
- if ((t|32)=='g') {
- if (!p) p++;
- if (p>e && e>=-4) {
- t--;
- p-=e+1;
+ if (fmt == 'e' && prec > (buf_remaining - 6)) {
+ prec = buf_remaining - 6;
}
- else {
- t-=2;
- p--;
+ // If the user specified 'g' format, and e is < prec, then we'll switch
+ // to the fixed format.
+
+ if (fmt == 'g' && e < prec) {
+ fmt = 'f';
+ prec -= (e + 1);
}
- if (!(fl&ALT_FORM)) {
- /* Count trailing zeros in last place */
- if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
- else j=9;
- if ((t|32)=='f')
- p = MIN(p,MAX(0,9*(z-r-1)-j));
- else
- p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ if (fmt == 'f') {
+ dec = e;
+ num_digits = prec + e + 1;
+ } else {
+ e_sign = '+';
}
}
- l = 1 + p + (p || (fl&ALT_FORM));
- if ((t|32)=='f') {
- if (e>0) l+=e;
- }
- else {
- estr=fmt_u(e<0 ? -e : e, ebuf);
- while(ebuf-estr<2) *--estr='0';
- *--estr = (e<0 ? '-' : '+');
- *--estr = t;
- l += ebuf-estr;
+ if (prec < 0) {
+ // This can happen when the prec is trimmed to prevent buffer overflow
+ prec = 0;
}
- pad(f, ' ', 0, pl+l, fl);
- out(f, prefix, pl);
- pad(f, '0', 0, pl+l, fl^ZERO_PAD);
-
- if ((t|32)=='f') {
- if (a>r) a=r;
- for (d=a; d<=r; d++) {
- char *ss = fmt_u(*d, buf+9);
- if (d!=a) while (ss>buf) *--ss='0';
- else if (ss==buf+9) *--ss='0';
- out(f, ss, buf+9-ss);
+ // We now have f as a floating point number between >= 1 and < 10
+ // (or equal to zero), and e contains the absolute value of the power of
+ // 10 exponent. and (dec + 1) == the number of dgits before the decimal.
+
+ // For e, prec is # digits after the decimal
+ // For f, prec is # digits after the decimal
+ // For g, prec is the max number of significant digits
+ //
+ // For e & g there will be a single digit before the decimal
+ // for f there will be e digits before the decimal
+
+ if (fmt == 'e') {
+ num_digits = prec + 1;
+ } else if (fmt == 'g') {
+ if (prec == 0) {
+ prec = 1;
}
- if (p || (fl&ALT_FORM)) out(f, ".", 1);
- for (; d<z && p>0; d++, p-=9) {
- char *ss = fmt_u(*d, buf+9);
- while (ss>buf) *--ss='0';
- out(f, ss, MIN(9,p));
- }
- pad(f, '0', p+9, 9, 0);
+ num_digits = prec;
}
- else {
- if (z<=a) z=a+1;
- for (d=a; d<z && p>=0; d++) {
- char *ss = fmt_u(*d, buf+9);
- if (ss==buf+9) *--ss='0';
- if (d!=a) while (ss>buf) *--ss='0';
- else {
- out(f, ss++, 1);
- if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
- }
- out(f, ss, MIN(buf+9-ss, p));
- p -= (int)(buf+9-ss);
- }
- pad(f, '0', p+18, 18, 0);
- out(f, estr, ebuf-estr);
- }
-
- pad(f, ' ', 0, pl+l, fl^LEFT_ADJ);
- return (int)pl+(int)l;
-}
-
-static int
-fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo)
-{
- ptrdiff_t p;
-
- if (*fmt != '%') {
- return -1;
+ // Print the digits of the mantissa
+ for (int i = 0; i < num_digits; ++i, --dec) {
+ int8_t d = f;
+ *s++ = '0' + d;
+ if (dec == 0 && (prec > 0 || alt_form)) {
+ *s++ = '.';
+ }
+ f -= (mrb_float)d;
+ f *= 10.0;
}
- ++fmt;
- if (*fmt == '.') {
- ++fmt;
- for (p = 0; ISDIGIT(*fmt); ++fmt) {
- p = 10 * p + (*fmt - '0');
+ // Round
+ if (f >= 5.0) {
+ char *rs = s;
+ rs--;
+ while (1) {
+ if (*rs == '.') {
+ rs--;
+ continue;
+ }
+ if (*rs < '0' || *rs > '9') {
+ // + or -
+ rs++; // So we sit on the digit to the right of the sign
+ break;
+ }
+ if (*rs < '9') {
+ (*rs)++;
+ break;
+ }
+ *rs = '0';
+ if (rs == buf) {
+ break;
+ }
+ rs--;
+ }
+ if (*rs == '0') {
+ // We need to insert a 1
+ if (rs[1] == '.' && fmt != 'f') {
+ // We're going to round 9.99 to 10.00
+ // Move the decimal point
+ rs[0] = '.';
+ rs[1] = '0';
+ if (e_sign == '-') {
+ e--;
+ } else {
+ e++;
+ }
+ }
+ s++;
+ char *ss = s;
+ while (ss > rs) {
+ *ss = ss[-1];
+ ss--;
+ }
+ *rs = '1';
+ if (f < 1.0 && fmt == 'f') {
+ // We rounded up to 1.0
+ prec--;
+ }
}
- }
- else {
- p = -1;
}
- switch (*fmt) {
- case 'e': case 'f': case 'g': case 'a':
- case 'E': case 'F': case 'G': case 'A':
- return fmt_fp(f, flo, p, 0, *fmt);
- default:
- return -1;
+ if (org_fmt == 'g' && prec > 0 && !alt_form) {
+ // Remove trailing zeros and a trailing decimal point
+ while (s[-1] == '0') {
+ s--;
+ }
+ if (s[-1] == '.') {
+ s--;
+ }
}
-}
-
-mrb_value
-mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
-{
- struct fmt_args f;
-
- f.mrb = mrb;
- f.str = mrb_str_new_capa(mrb, 24);
- if (fmt_core(&f, fmt, mrb_float(flo)) < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string");
+ // Append the exponent
+ if (e_sign) {
+ *s++ = e_char;
+ *s++ = e_sign;
+ if (e >= 100) {
+ *s++ = '0' + (e / 100);
+ e %= 100;
+ }
+ *s++ = '0' + (e / 10);
+ *s++ = '0' + (e % 10);
}
- return f.str;
-}
-#else /* MRB_DISABLE_STDIO */
-#include <mruby.h>
-#include <stdio.h>
-
-mrb_value
-mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
-{
- char buf[24];
+ *s = '\0';
- snprintf(buf, sizeof(buf), fmt, mrb_float(flo));
- return mrb_str_new_cstr(mrb, buf);
+ return s - buf;
}
-#endif /* MRB_DISABLE_STDIO */
#endif
diff --git a/src/gc.c b/src/gc.c
index e429603dd..bcd0b29b6 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -6,10 +6,14 @@
#include <string.h>
#include <stdlib.h>
+#ifdef MRB_USE_MALLOC_TRIM
+#include <malloc.h>
+#endif
#include <mruby.h>
#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>
@@ -18,6 +22,7 @@
#include <mruby/gc.h>
#include <mruby/error.h>
#include <mruby/throw.h>
+#include <mruby/presym.h>
/*
= Tri-color Incremental Garbage Collection
@@ -34,9 +39,14 @@
* Gray - Marked, But the child objects are unmarked.
* Black - Marked, the child objects are also marked.
+ Extra color
+
+ * Red - Static (ROM object) no need to be collected.
+ - All child objects should be Red as well.
+
== Two White Types
- There're two white color types in a flip-flop fashion: White-A and White-B,
+ There are two white color types in a flip-flop fashion: White-A and White-B,
which respectively represent the Current White color (the newly allocated
objects in the current GC cycle) and the Sweep Target White color (the
dead objects to be swept).
@@ -98,8 +108,14 @@ struct free_obj {
struct RBasic *next;
};
+struct RVALUE_initializer {
+ MRB_OBJECT_HEADER;
+ char padding[sizeof(void*) * 4 - sizeof(uint32_t)];
+};
+
typedef struct {
union {
+ struct RVALUE_initializer init; /* must be first member to ensure initialization */
struct free_obj free;
struct RBasic basic;
struct RObject object;
@@ -109,12 +125,14 @@ 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
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
struct RFloat floatv;
#endif
struct RCptr cptr;
@@ -182,8 +200,10 @@ gettimeofday_time(void)
#define GC_WHITE_A 1
#define GC_WHITE_B (1 << 1)
#define GC_BLACK (1 << 2)
+#define GC_RED MRB_GC_RED
#define GC_WHITES (GC_WHITE_A | GC_WHITE_B)
#define GC_COLOR_MASK 7
+mrb_static_assert1(MRB_GC_RED <= GC_COLOR_MASK);
#define paint_gray(o) ((o)->color = GC_GRAY)
#define paint_black(o) ((o)->color = GC_BLACK)
@@ -191,13 +211,16 @@ gettimeofday_time(void)
#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part)
#define is_gray(o) ((o)->color == GC_GRAY)
#define is_white(o) ((o)->color & GC_WHITES)
-#define is_black(o) ((o)->color & GC_BLACK)
+#define is_black(o) ((o)->color == GC_BLACK)
+#define is_red(o) ((o)->color == GC_RED)
#define flip_white_part(s) ((s)->current_white_part = other_white_part(s))
#define other_white_part(s) ((s)->current_white_part ^ GC_WHITES)
#define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE)
#define objects(p) ((RVALUE *)p->objects)
+mrb_noreturn void mrb_raise_nomemory(mrb_state *mrb);
+
MRB_API void*
mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
{
@@ -220,14 +243,8 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
p2 = mrb_realloc_simple(mrb, p, len);
if (len == 0) return p2;
if (p2 == NULL) {
- if (mrb->gc.out_of_memory) {
- mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
- /* mrb_panic(mrb); */
- }
- else {
- mrb->gc.out_of_memory = TRUE;
- mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
- }
+ mrb->gc.out_of_memory = TRUE;
+ mrb_raise_nomemory(mrb);
}
else {
mrb->gc.out_of_memory = FALSE;
@@ -274,9 +291,37 @@ 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)
+{
+ struct RString *s;
+ s = MRB_OBJ_ALLOC(mrb, MRB_TT_STRING, mrb->string_class);
+ return s->as.heap.ptr = (char*)mrb_malloc(mrb, size);
+}
+
+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 +421,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;
@@ -430,7 +475,7 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj)
gc_protect(mrb, &mrb->gc, mrb_basic_ptr(obj));
}
-#define GC_ROOT_NAME "_gc_root_"
+#define GC_ROOT_SYM MRB_SYM(_gc_root_)
/* mrb_gc_register() keeps the object from GC.
@@ -443,10 +488,13 @@ 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_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) {
+ if (mrb_immediate_p(obj)) return;
+ root = GC_ROOT_SYM;
+ table = mrb_gv_get(mrb, root);
+ if (mrb_nil_p(table) || !mrb_array_p(table)) {
table = mrb_ary_new(mrb);
mrb_gv_set(mrb, root, table);
}
@@ -457,20 +505,23 @@ 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 = GC_ROOT_SYM;
+ table = mrb_gv_get(mrb, root);
if (mrb_nil_p(table)) return;
- if (mrb_type(table) != MRB_TT_ARRAY) {
+ if (!mrb_array_p(table)) {
mrb_gv_set(mrb, root, mrb_nil_value());
return;
}
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);
@@ -485,7 +536,7 @@ MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{
struct RBasic *p;
- static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
+ static const RVALUE RVALUE_zero = { { { NULL, NULL, MRB_TT_FALSE } } };
mrb_gc *gc = &mrb->gc;
if (cls) {
@@ -506,9 +557,12 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != tt) {
- mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
+ mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls);
}
}
+ if (ttype <= MRB_TT_FREE) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C (type %d)", cls, (int)ttype);
+ }
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
@@ -548,11 +602,11 @@ add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
gc->gray_list = obj;
}
-static int
+static mrb_int
ci_nregs(mrb_callinfo *ci)
{
- struct RProc *p = ci->proc;
- int n = 0;
+ const struct RProc *p = ci->proc;
+ mrb_int n = 0;
if (!p) {
if (ci->argc < 0) return 3;
@@ -577,11 +631,14 @@ mark_context_stack(mrb_state *mrb, struct mrb_context *c)
size_t e;
mrb_value nil;
- if (c->stack == NULL) return;
- e = c->stack - c->stbase;
+ if (c->stbase == NULL) return;
if (c->ci) {
+ e = (c->ci->stack ? c->ci->stack - c->stbase : 0);
e += ci_nregs(c->ci);
}
+ else {
+ e = 0;
+ }
if (c->stbase + e > c->stend) e = c->stend - c->stbase;
for (i=0; i<e; i++) {
mrb_value v = c->stbase[i];
@@ -600,7 +657,6 @@ mark_context_stack(mrb_state *mrb, struct mrb_context *c)
static void
mark_context(mrb_state *mrb, struct mrb_context *c)
{
- int i;
mrb_callinfo *ci;
start:
@@ -612,15 +668,10 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
/* mark call stack */
if (c->cibase) {
for (ci = c->cibase; ci <= c->ci; ci++) {
- mrb_gc_mark(mrb, (struct RBasic*)ci->env);
mrb_gc_mark(mrb, (struct RBasic*)ci->proc);
- mrb_gc_mark(mrb, (struct RBasic*)ci->target_class);
+ mrb_gc_mark(mrb, (struct RBasic*)ci->u.target_class);
}
}
- /* mark ensure stack */
- for (i=0; i<c->eidx; i++) {
- mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
- }
/* mark fibers */
mrb_gc_mark(mrb, (struct RBasic*)c->fib);
if (c->prev) {
@@ -634,7 +685,6 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
mrb_assert(is_gray(obj));
paint_black(obj);
- gc->gray_list = obj->gcnext;
mrb_gc_mark(mrb, (struct RBasic*)obj->c);
switch (obj->tt) {
case MRB_TT_ICLASS:
@@ -677,10 +727,10 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct REnv *e = (struct REnv*)obj;
mrb_int i, len;
- if (MRB_ENV_STACK_SHARED_P(e) && e->cxt && e->cxt->fib) {
+ if (MRB_ENV_ONSTACK_P(e) && e->cxt && e->cxt->fib) {
mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib);
}
- len = MRB_ENV_STACK_LEN(e);
+ len = MRB_ENV_LEN(e);
for (i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
}
@@ -698,10 +748,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_ARRAY:
{
struct RArray *a = (struct RArray*)obj;
- size_t i, e;
+ size_t i, e=ARY_LEN(a);
+ mrb_value *p = ARY_PTR(a);
- for (i=0,e=ARY_LEN(a); i<e; i++) {
- mrb_gc_mark_value(mrb, ARY_PTR(a)[i]);
+ for (i=0; i<e; i++) {
+ mrb_gc_mark_value(mrb, p[i]);
}
}
break;
@@ -712,20 +763,21 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
break;
case MRB_TT_STRING:
- if (RSTR_FSHARED_P(obj) && !RSTR_NOFREE_P(obj)) {
+ if (RSTR_FSHARED_P(obj)) {
struct RString *s = (struct RString*)obj;
mrb_gc_mark(mrb, (struct RBasic*)s->as.heap.aux.fshared);
}
break;
case MRB_TT_RANGE:
- {
- struct RRange *r = (struct RRange*)obj;
+ mrb_gc_mark_range(mrb, (struct RRange*)obj);
+ break;
- if (r->edges) {
- mrb_gc_mark_value(mrb, r->edges->beg);
- mrb_gc_mark_value(mrb, r->edges->end);
- }
+ case MRB_TT_BREAK:
+ {
+ struct RBreak *brk = (struct RBreak*)obj;
+ mrb_gc_mark(mrb, (struct RBasic*)mrb_break_proc_get(brk));
+ mrb_gc_mark_value(mrb, mrb_break_value_get(brk));
}
break;
@@ -739,6 +791,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
{
if (obj == 0) return;
if (!is_white(obj)) return;
+ if (is_red(obj)) return;
mrb_assert((obj)->tt != MRB_TT_FREE);
add_gray_list(mrb, &mrb->gc, obj);
}
@@ -748,22 +801,6 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
{
DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt));
switch (obj->tt) {
- /* immediate - no mark */
- case MRB_TT_TRUE:
- case MRB_TT_FIXNUM:
- case MRB_TT_SYMBOL:
- /* cannot happen */
- return;
-
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- break;
-#else
- return;
-#endif
-#endif
-
case MRB_TT_OBJECT:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
break;
@@ -777,18 +814,23 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
case MRB_TT_SCLASS:
mrb_gc_free_mt(mrb, (struct RClass*)obj);
mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ if (!end)
+ mrb_mc_clear_by_class(mrb, (struct RClass*)obj);
break;
case MRB_TT_ICLASS:
if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN))
mrb_gc_free_mt(mrb, (struct RClass*)obj);
+ if (!end)
+ mrb_mc_clear_by_class(mrb, (struct RClass*)obj);
break;
case MRB_TT_ENV:
{
struct REnv *e = (struct REnv*)obj;
- if (MRB_ENV_STACK_SHARED_P(e)) {
+ if (MRB_ENV_ONSTACK_P(e)) {
/* cannot be freed */
- return;
+ e->stack = NULL;
+ break;
}
mrb_free(mrb, e->stack);
e->stack = NULL;
@@ -800,14 +842,14 @@ 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) &&
- e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) {
+ struct REnv *e = ci->u.env;
+ if (e && !mrb_object_dead_p(mrb, (struct RBasic*)e) &&
+ e->tt == MRB_TT_ENV && MRB_ENV_ONSTACK_P(e)) {
mrb_env_unshare(mrb, e);
}
ci--;
@@ -839,7 +881,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
struct RProc *p = (struct RProc*)obj;
if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
- mrb_irep *irep = p->body.irep;
+ mrb_irep *irep = (mrb_irep*)p->body.irep;
if (end) {
mrb_irep_cutref(mrb, irep);
}
@@ -849,7 +891,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:
@@ -862,6 +904,24 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
}
break;
+#if defined(MRB_USE_RATIONAL) && defined(MRB_INT64) && defined(MRB_32BIT)
+ case MRB_TT_RATIONAL:
+ {
+ struct RData *o = (struct RData*)obj;
+ mrb_free(mrb, o->iv);
+ }
+ break;
+#endif
+
+#if defined(MRB_USE_COMPLEX) && defined(MRB_32BIT) && !defined(MRB_USE_FLOAT32)
+ case MRB_TT_COMPLEX:
+ {
+ struct RData *o = (struct RData*)obj;
+ mrb_free(mrb, o->iv);
+ }
+ break;
+#endif
+
default:
break;
}
@@ -895,10 +955,10 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->range_class);
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class);
#endif
- mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->integer_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class);
@@ -925,13 +985,12 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
}
}
+/* rough estimation of number of GC marks (non recursive) */
static size_t
-gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
+gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
size_t children = 0;
- gc_mark_children(mrb, gc, obj);
-
switch (obj->tt) {
case MRB_TT_ICLASS:
children++;
@@ -956,7 +1015,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
break;
case MRB_TT_ENV:
- children += MRB_ENV_STACK_LEN(obj);
+ children += MRB_ENV_LEN(obj);
break;
case MRB_TT_FIBER:
@@ -968,7 +1027,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
if (!c || c->status == MRB_FIBER_TERMINATED) break;
/* mark stack */
- i = c->stack - c->stbase;
+ i = c->ci->stack - c->stbase;
if (c->ci) {
i += ci_nregs(c->ci);
@@ -976,9 +1035,6 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
if (c->stbase + i > c->stend) i = c->stend - c->stbase;
children += i;
- /* mark ensure stack */
- children += c->eidx;
-
/* mark closure */
if (c->cibase) {
for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++)
@@ -1002,6 +1058,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_PROC:
case MRB_TT_RANGE:
+ case MRB_TT_BREAK:
children+=2;
break;
@@ -1015,10 +1072,9 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
static void
gc_mark_gray_list(mrb_state *mrb, mrb_gc *gc) {
while (gc->gray_list) {
- if (is_gray(gc->gray_list))
- gc_mark_children(mrb, gc, gc->gray_list);
- else
- gc->gray_list = gc->gray_list->gcnext;
+ struct RBasic *obj = gc->gray_list;
+ gc->gray_list = obj->gcnext;
+ gc_mark_children(mrb, gc, obj);
}
}
@@ -1029,7 +1085,10 @@ incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
size_t tried_marks = 0;
while (gc->gray_list && tried_marks < limit) {
- tried_marks += gc_gray_mark(mrb, gc, gc->gray_list);
+ struct RBasic *obj = gc->gray_list;
+ gc->gray_list = obj->gcnext;
+ gc_mark_children(mrb, gc, obj);
+ tried_marks += gc_gray_counts(mrb, gc, obj);
}
return tried_marks;
@@ -1046,7 +1105,9 @@ final_marking_phase(mrb_state *mrb, mrb_gc *gc)
}
mrb_gc_mark_gv(mrb);
mark_context(mrb, mrb->c);
- mark_context(mrb, mrb->root_c);
+ if (mrb->c != mrb->root_c) {
+ mark_context(mrb, mrb->root_c);
+ }
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
gc_mark_gray_list(mrb, gc);
mrb_assert(gc->gray_list == NULL);
@@ -1261,6 +1322,7 @@ mrb_full_gc(mrb_state *mrb)
{
mrb_gc *gc = &mrb->gc;
+ if (!mrb->c) return;
if (gc->disabled || gc->iterating) return;
GC_INVOKE_TIME_REPORT("mrb_full_gc()");
@@ -1284,6 +1346,9 @@ mrb_full_gc(mrb_state *mrb)
gc->full = FALSE;
}
+#ifdef MRB_USE_MALLOC_TRIM
+ malloc_trim(0);
+#endif
GC_TIME_STOP_AND_REPORT;
}
@@ -1568,17 +1633,21 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo
}
}
-#ifdef GC_TEST
-#ifdef GC_DEBUG
-static mrb_value gc_test(mrb_state *, mrb_value);
-#endif
-#endif
+size_t
+mrb_objspace_page_slot_size(void)
+{
+ return sizeof(RVALUE);
+}
+
void
mrb_init_gc(mrb_state *mrb)
{
struct RClass *gc;
+ mrb_static_assert(sizeof(RVALUE) <= sizeof(void*) * 6,
+ "RVALUE size must be within 6 words");
+
gc = mrb_define_module(mrb, "GC");
mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE());
@@ -1590,278 +1659,4 @@ mrb_init_gc(mrb_state *mrb)
mrb_define_class_method(mrb, gc, "step_ratio=", gc_step_ratio_set, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, gc, "generational_mode=", gc_generational_mode_set, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, gc, "generational_mode", gc_generational_mode_get, MRB_ARGS_NONE());
-#ifdef GC_TEST
-#ifdef GC_DEBUG
- mrb_define_class_method(mrb, gc, "test", gc_test, MRB_ARGS_NONE());
-#endif
-#endif
-}
-
-#ifdef GC_TEST
-#ifdef GC_DEBUG
-void
-test_mrb_field_write_barrier(void)
-{
- mrb_state *mrb = mrb_open();
- struct RBasic *obj, *value;
- mrb_gc *gc = &mrb->gc;
-
- puts("test_mrb_field_write_barrier");
- gc->generational = FALSE;
- obj = mrb_basic_ptr(mrb_ary_new(mrb));
- value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value"));
- paint_black(obj);
- paint_partial_white(gc, value);
-
-
- puts(" in MRB_GC_STATE_MARK");
- gc->state = MRB_GC_STATE_MARK;
- mrb_field_write_barrier(mrb, obj, value);
-
- mrb_assert(is_gray(value));
-
-
- puts(" in MRB_GC_STATE_SWEEP");
- paint_partial_white(gc, value);
- gc->state = MRB_GC_STATE_SWEEP;
- mrb_field_write_barrier(mrb, obj, value);
-
- mrb_assert(obj->color & gc->current_white_part);
- mrb_assert(value->color & gc->current_white_part);
-
-
- puts(" fail with black");
- gc->state = MRB_GC_STATE_MARK;
- paint_white(obj);
- paint_partial_white(gc, value);
- mrb_field_write_barrier(mrb, obj, value);
-
- mrb_assert(obj->color & gc->current_white_part);
-
-
- puts(" fail with gray");
- gc->state = MRB_GC_STATE_MARK;
- paint_black(obj);
- paint_gray(value);
- mrb_field_write_barrier(mrb, obj, value);
-
- mrb_assert(is_gray(value));
-
-
- {
- puts("test_mrb_field_write_barrier_value");
- obj = mrb_basic_ptr(mrb_ary_new(mrb));
- mrb_value value = mrb_str_new_lit(mrb, "value");
- paint_black(obj);
- paint_partial_white(gc, mrb_basic_ptr(value));
-
- gc->state = MRB_GC_STATE_MARK;
- mrb_field_write_barrier_value(mrb, obj, value);
-
- mrb_assert(is_gray(mrb_basic_ptr(value)));
- }
-
- mrb_close(mrb);
-}
-
-void
-test_mrb_write_barrier(void)
-{
- mrb_state *mrb = mrb_open();
- struct RBasic *obj;
- mrb_gc *gc = &mrb->gc;
-
- puts("test_mrb_write_barrier");
- obj = mrb_basic_ptr(mrb_ary_new(mrb));
- paint_black(obj);
-
- puts(" in MRB_GC_STATE_MARK");
- gc->state = MRB_GC_STATE_MARK;
- mrb_write_barrier(mrb, obj);
-
- mrb_assert(is_gray(obj));
- mrb_assert(gc->atomic_gray_list == obj);
-
-
- puts(" fail with gray");
- paint_gray(obj);
- mrb_write_barrier(mrb, obj);
-
- mrb_assert(is_gray(obj));
-
- mrb_close(mrb);
-}
-
-void
-test_add_gray_list(void)
-{
- mrb_state *mrb = mrb_open();
- struct RBasic *obj1, *obj2;
- mrb_gc *gc = &mrb->gc;
-
- puts("test_add_gray_list");
- change_gen_gc_mode(mrb, gc, FALSE);
- mrb_assert(gc->gray_list == NULL);
- obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
- add_gray_list(mrb, gc, obj1);
- mrb_assert(gc->gray_list == obj1);
- mrb_assert(is_gray(obj1));
-
- obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
- add_gray_list(mrb, gc, obj2);
- mrb_assert(gc->gray_list == obj2);
- mrb_assert(gc->gray_list->gcnext == obj1);
- mrb_assert(is_gray(obj2));
-
- mrb_close(mrb);
-}
-
-void
-test_gc_gray_mark(void)
-{
- mrb_state *mrb = mrb_open();
- mrb_value obj_v, value_v;
- struct RBasic *obj;
- size_t gray_num = 0;
- mrb_gc *gc = &mrb->gc;
-
- puts("test_gc_gray_mark");
-
- puts(" in MRB_TT_CLASS");
- obj = (struct RBasic*)mrb->object_class;
- paint_gray(obj);
- gray_num = gc_gray_mark(mrb, gc, obj);
- mrb_assert(is_black(obj));
- mrb_assert(gray_num > 1);
-
- puts(" in MRB_TT_ARRAY");
- obj_v = mrb_ary_new(mrb);
- value_v = mrb_str_new_lit(mrb, "test");
- paint_gray(mrb_basic_ptr(obj_v));
- paint_partial_white(gc, mrb_basic_ptr(value_v));
- mrb_ary_push(mrb, obj_v, value_v);
- gray_num = gc_gray_mark(mrb, gc, mrb_basic_ptr(obj_v));
- mrb_assert(is_black(mrb_basic_ptr(obj_v)));
- mrb_assert(is_gray(mrb_basic_ptr(value_v)));
- mrb_assert(gray_num == 1);
-
- mrb_close(mrb);
-}
-
-void
-test_incremental_gc(void)
-{
- mrb_state *mrb = mrb_open();
- size_t max = ~0, live = 0, total = 0, freed = 0;
- RVALUE *free;
- mrb_heap_page *page;
- mrb_gc *gc = &mrb->gc;
-
- puts("test_incremental_gc");
- change_gen_gc_mode(mrb, gc, FALSE);
-
- puts(" in mrb_full_gc");
- mrb_full_gc(mrb);
-
- mrb_assert(gc->state == MRB_GC_STATE_ROOT);
- puts(" in MRB_GC_STATE_ROOT");
- incremental_gc(mrb, gc, max);
- mrb_assert(gc->state == MRB_GC_STATE_MARK);
- puts(" in MRB_GC_STATE_MARK");
- incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP);
- mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
-
- puts(" in MRB_GC_STATE_SWEEP");
- page = gc->heaps;
- while (page) {
- RVALUE *p = objects(page);
- RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
- while (p<e) {
- if (is_black(&p->as.basic)) {
- live++;
- }
- if (is_gray(&p->as.basic) && !is_dead(gc, &p->as.basic)) {
- printf("%p\n", &p->as.basic);
- }
- p++;
- }
- page = page->next;
- total += MRB_HEAP_PAGE_SIZE;
- }
-
- mrb_assert(gc->gray_list == NULL);
-
- incremental_gc(mrb, gc, max);
- mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
-
- incremental_gc(mrb, gc, max);
- mrb_assert(gc->state == MRB_GC_STATE_ROOT);
-
- free = (RVALUE*)gc->heaps->freelist;
- while (free) {
- freed++;
- free = (RVALUE*)free->as.free.next;
- }
-
- mrb_assert(gc->live == live);
- mrb_assert(gc->live == total-freed);
-
- puts("test_incremental_gc(gen)");
- incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP);
- change_gen_gc_mode(mrb, gc, TRUE);
-
- mrb_assert(gc->full == FALSE);
- mrb_assert(gc->state == MRB_GC_STATE_ROOT);
-
- puts(" in minor");
- mrb_assert(is_minor_gc(gc));
- mrb_assert(gc->majorgc_old_threshold > 0);
- gc->majorgc_old_threshold = 0;
- mrb_incremental_gc(mrb);
- mrb_assert(gc->full == TRUE);
- mrb_assert(gc->state == MRB_GC_STATE_ROOT);
-
- puts(" in major");
- mrb_assert(is_major_gc(gc));
- do {
- mrb_incremental_gc(mrb);
- } while (gc->state != MRB_GC_STATE_ROOT);
- mrb_assert(gc->full == FALSE);
-
- mrb_close(mrb);
-}
-
-void
-test_incremental_sweep_phase(void)
-{
- mrb_state *mrb = mrb_open();
- mrb_gc *gc = &mrb->gc;
-
- puts("test_incremental_sweep_phase");
-
- add_heap(mrb, gc);
- gc->sweeps = gc->heaps;
-
- mrb_assert(gc->heaps->next->next == NULL);
- mrb_assert(gc->free_heaps->next->next == NULL);
- incremental_sweep_phase(mrb, gc, MRB_HEAP_PAGE_SIZE * 3);
-
- mrb_assert(gc->heaps->next == NULL);
- mrb_assert(gc->heaps == gc->free_heaps);
-
- mrb_close(mrb);
-}
-
-static mrb_value
-gc_test(mrb_state *mrb, mrb_value self)
-{
- test_mrb_field_write_barrier();
- test_mrb_write_barrier();
- test_add_gray_list();
- test_gc_gray_mark();
- test_incremental_gc();
- test_incremental_sweep_phase();
- return mrb_nil_value();
}
-#endif /* GC_DEBUG */
-#endif /* GC_TEST */
diff --git a/src/hash.c b/src/hash.c
index e1ceec489..918722a2b 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -4,682 +4,1208 @@
** See Copyright Notice in mruby.h
*/
+#include <string.h>
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/hash.h>
#include <mruby/string.h>
#include <mruby/variable.h>
+#include <mruby/presym.h>
-#ifndef MRB_WITHOUT_FLOAT
-/* a function to get hash value of a float number */
-mrb_int mrb_float_id(mrb_float f);
+/*
+ * === Glossary
+ *
+ * [EA]
+ * Entry Array. Store `Hash' entries in insertion order.
+ *
+ * [AR]
+ * Array Table Implementation. The structure of `Hash` that doesn't have a
+ * hash table and linearly searches EA. It is used when `Hash` size <= 16.
+ *
+ * [IB]
+ * Index Buckets. The buckets of hash table, where the bucket value is EA
+ * index. The index is represented by variable length bits according to
+ * the capacity.
+ *
+ * [HT]
+ * Hash Table Implementation. The structure of `Hash` that has IB and is
+ * searched by hash table algorithm. It is used when `Hash` size > 16.
+ * Collision resolution strategy is open addressing method.
+ *
+ * [size]
+ * The number of `Hash` entries (value of `Hash#size`).
+ *
+ * [slot]
+ * The generic term for EA or IB elements.
+ *
+ * [active]
+ * The state in which a slot is recognized as a `Hash` entry.
+ *
+ * [deleted]
+ * The state in which a slot is marked as deleted.
+ *
+ * [used]
+ * The state in which a slot is active or deleted.
+ *
+ * [empty]
+ * The state in which a slot is not used. Capacity is equal to the sum of
+ * the number of used slots and the number of empty slots.
+ */
+
+#define EA_N_RESERVED_INDICES 2 /* empty and deleted */
+#define EA_INCREASE_RATIO 6 / 5 + 6
+#define EA_MAX_INCREASE UINT16_MAX
+#define EA_MAX_CAPA U32(lesser(IB_MAX_CAPA - EA_N_RESERVED_INDICES, MRB_INT_MAX))
+#define IB_MAX_CAPA (U32(1) << IB_MAX_BIT)
+#define IB_TYPE_BIT 32
+#define IB_INIT_BIT ( \
+ ib_upper_bound_for(32) <= AR_MAX_SIZE ? 6 : \
+ ib_upper_bound_for(16) <= AR_MAX_SIZE ? 5 : \
+ 4 \
+)
+#define IB_MAX_BIT (IB_TYPE_BIT - 1)
+#define AR_DEFAULT_CAPA 4
+#define AR_MAX_SIZE 16
+#define H_MAX_SIZE EA_MAX_CAPA
+
+mrb_static_assert1(offsetof(struct RHash, iv) == offsetof(struct RObject, iv));
+mrb_static_assert1(AR_MAX_SIZE < (1 << MRB_HASH_AR_EA_CAPA_BIT));
+
+typedef struct hash_entry {
+ mrb_value key;
+ mrb_value val;
+} hash_entry;
+
+typedef struct hash_table {
+ hash_entry *ea;
+#ifdef MRB_32BIT
+ uint32_t ea_capa;
+ uint32_t ea_n_used;
#endif
+ uint32_t ib[];
+} hash_table;
+
+typedef struct index_buckets_iter {
+ struct RHash *h;
+ uint32_t bit;
+ uint32_t mask;
+ uint32_t pos;
+ uint32_t ary_index;
+ uint32_t ea_index;
+ uint32_t shift1;
+ uint32_t shift2;
+ uint32_t step;
+} index_buckets_iter;
-/* return non zero to break the loop */
-typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data);
+/*
+ * `c_` :: receiver class (category)
+ * `n_` :: attribute name
+ * `t_` :: attribute type
+ * `p_` :: struct member path
+ * `k_` :: macro key
+ */
+#define DEFINE_GETTER(c_, n_, t_, p_) \
+ MRB_INLINE t_ c_##_##n_(const struct RHash *h) {return h->p_;}
+#define DEFINE_SETTER(c_, n_, t_, p_) \
+ MRB_INLINE void c_##_set_##n_(struct RHash *h, t_ v) {h->p_ = v;}
+#define DEFINE_ACCESSOR(c_, n_, t_, p_) \
+ DEFINE_GETTER(c_, n_, t_, p_) \
+ DEFINE_SETTER(c_, n_, t_, p_)
+#define DEFINE_FLAG_GETTER(c_, n_, t_, k_) \
+ MRB_INLINE t_ c_##_##n_(const struct RHash *h) { \
+ return (t_)((h->flags & MRB_HASH_##k_##_MASK) >> MRB_HASH_##k_##_SHIFT); \
+ }
+#define DEFINE_FLAG_SETTER(c_, n_, t_, k_) \
+ MRB_INLINE void c_##_set_##n_(struct RHash *h, t_ v) { \
+ h->flags &= ~MRB_HASH_##k_##_MASK; \
+ h->flags |= v << MRB_HASH_##k_##_SHIFT; \
+ }
+#define DEFINE_FLAG_ACCESSOR(c_, n_, t_, k_) \
+ DEFINE_FLAG_GETTER(c_, n_, t_, k_) \
+ DEFINE_FLAG_SETTER(c_, n_, t_, k_)
+#define DEFINE_INCREMENTER(c_, n_) \
+ MRB_INLINE void c_##_inc_##n_(struct RHash *h) { \
+ c_##_set_##n_(h, c_##_##n_(h) + 1); \
+ }
+#define DEFINE_DECREMENTER(c_, n_) \
+ MRB_INLINE void c_##_dec_##n_(struct RHash *h) { \
+ c_##_set_##n_(h, c_##_##n_(h) - 1); \
+ }
+#define DEFINE_SWITCHER(n_, k_) \
+ MRB_INLINE void h_##n_##_on(struct RHash *h) { \
+ h->flags |= MRB_HASH_##k_; \
+ } \
+ MRB_INLINE void h_##n_##_off(struct RHash *h) { \
+ h->flags &= ~MRB_HASH_##k_; \
+ } \
+ MRB_INLINE mrb_bool h_##n_##_p(const struct RHash *h) { \
+ return (h->flags & MRB_HASH_##k_) == MRB_HASH_##k_; \
+ }
-#ifndef MRB_SG_SEGMENT_SIZE
-#define MRB_SG_SEGMENT_SIZE 5
+#ifdef MRB_64BIT
+DEFINE_ACCESSOR(ar, ea_capa, uint32_t, ea_capa)
+DEFINE_ACCESSOR(ar, ea_n_used, uint32_t, ea_n_used)
+DEFINE_ACCESSOR(ht, ea_capa, uint32_t, ea_capa)
+DEFINE_ACCESSOR(ht, ea_n_used, uint32_t, ea_n_used)
+#else
+DEFINE_FLAG_ACCESSOR(ar, ea_capa, uint32_t, AR_EA_CAPA)
+DEFINE_FLAG_ACCESSOR(ar, ea_n_used, uint32_t, AR_EA_N_USED)
+DEFINE_ACCESSOR(ht, ea_capa, uint32_t, hsh.ht->ea_capa)
+DEFINE_ACCESSOR(ht, ea_n_used, uint32_t, hsh.ht->ea_n_used)
#endif
+DEFINE_FLAG_ACCESSOR(ib, bit, uint32_t, IB_BIT)
+DEFINE_ACCESSOR(ar, size, uint32_t, size)
+DEFINE_ACCESSOR(ar, ea, hash_entry*, hsh.ea)
+DEFINE_DECREMENTER(ar, size)
+DEFINE_ACCESSOR(ht, size, uint32_t, size)
+DEFINE_ACCESSOR(ht, ea, hash_entry*, hsh.ht->ea)
+DEFINE_GETTER(ht, ib, uint32_t*, hsh.ht->ib)
+DEFINE_INCREMENTER(ht, size)
+DEFINE_DECREMENTER(ht, size)
+DEFINE_GETTER(h, size, uint32_t, size)
+DEFINE_ACCESSOR(h, ht, hash_table*, hsh.ht)
+DEFINE_SWITCHER(ht, HT)
+
+#define ea_each_used(ea, n_used, entry_var, code) do { \
+ hash_entry *entry_var = ea, *ea_end__ = entry_var + (n_used); \
+ for (; entry_var < ea_end__; ++entry_var) { \
+ code; \
+ } \
+} while (0)
-struct segkv {
- mrb_value key;
- mrb_value val;
-};
-
-typedef struct segment {
- struct segment *next;
- struct segkv e[MRB_SG_SEGMENT_SIZE];
-} segment;
-
-typedef struct segindex {
- size_t size;
- size_t capa;
- struct segkv *table[];
-} segindex;
-
-/* Instance variable table structure */
-typedef struct seglist {
- segment *rootseg;
- segment *lastseg;
- mrb_int size;
- mrb_int last_len;
- segindex *index;
-} seglist;
-
-static /* inline */ size_t
-sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key)
+#define ea_each(ea, size, entry_var, code) do { \
+ hash_entry *entry_var = ea; \
+ uint32_t size__ = size; \
+ for (; 0 < size__; ++entry_var) { \
+ if (entry_deleted_p(entry_var)) continue; \
+ --size__; \
+ code; \
+ } \
+} while (0)
+
+#define ib_cycle_by_key(mrb, h, key, it_var, code) do { \
+ index_buckets_iter it_var[1]; \
+ ib_it_init(mrb, it_var, h, key); \
+ for (;;) { \
+ ib_it_next(it_var); \
+ code; \
+ } \
+} while (0)
+
+#define ib_find_by_key(mrb, h_, key_, it_var, code) do { \
+ mrb_value ib_fbk_key__ = key_; \
+ ib_cycle_by_key(mrb, h_, ib_fbk_key__, it_var, { \
+ if (ib_it_empty_p(it_var)) break; \
+ if (ib_it_deleted_p(it_var)) continue; \
+ if (obj_eql(mrb, ib_fbk_key__, ib_it_entry(it_var)->key, it_var->h)) { \
+ code; \
+ break; \
+ } \
+ }); \
+} while (0)
+
+#define h_each(h, entry_var, code) do { \
+ struct RHash *h__ = h; \
+ hash_entry *h_e_ea__; \
+ uint32_t h_e_size__; \
+ h_ar_p(h) ? (h_e_ea__ = ar_ea(h__), h_e_size__ = ar_size(h__)) : \
+ (h_e_ea__ = ht_ea(h__), h_e_size__ = ht_size(h__)); \
+ ea_each(h_e_ea__, h_e_size__, entry_var, code); \
+} while (0)
+
+/*
+ * In `h_check_modified()`, in the case of `MRB_NO_BOXING`, `ht_ea()` or
+ * `ht_ea_capa()` for AR may read uninitialized area (#5332). Therefore, do
+ * not use those macros for AR in `MRB_NO_BOXING` (but in the case of
+ * `MRB_64BIT`, `ht_ea_capa()` is the same as `ar_ea_capa()`, so use it).
+ */
+#ifdef MRB_NO_BOXING
+# define H_CHECK_MODIFIED_USE_HT_EA_FOR_AR FALSE
+# ifdef MRB_64BIT
+# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR TRUE
+# else
+# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR FALSE
+# endif /* MRB_64BIT */
+#else
+# define H_CHECK_MODIFIED_USE_HT_EA_FOR_AR TRUE
+# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR TRUE
+ /*
+ * `h_check_modified` raises an exception when a dangerous modification is
+ * made to `h` by executing `code`.
+ *
+ * `h_check_modified` macro is not called if `h->hsh.ht` (`h->hsh.ea`) is `NULL`
+ * (`Hash` size is zero). And because the `hash_entry` is rather large,
+ * `h->hsh.ht->ea` and `h->hsh.ht->ea_capa` are able to be safely accessed even for
+ * AR. This nature is used to eliminate branch of AR or HT.
+ *
+ * `HT_ASSERT_SAFE_READ` checks if members can be accessed according to its
+ * assumptions.
+ */
+# define HT_ASSERT_SAFE_READ(attr_name) \
+ mrb_static_assert1( \
+ offsetof(hash_table, attr_name) + sizeof(((hash_table*)0)->attr_name) <= \
+ sizeof(hash_entry))
+HT_ASSERT_SAFE_READ(ea);
+# ifdef MRB_32BIT
+HT_ASSERT_SAFE_READ(ea_capa);
+# endif
+# undef HT_ASSERT_SAFE_READ
+#endif /* MRB_NO_BOXING */
+
+/*
+ * `h_check_modified` raises an exception when a dangerous modification is
+ * made to `h` by executing `code`.
+ */
+#define h_check_modified(mrb, h, code) do { \
+ struct RHash *h__ = h; \
+ uint32_t mask__ = MRB_HASH_HT|MRB_HASH_IB_BIT_MASK|MRB_HASH_AR_EA_CAPA_MASK; \
+ uint32_t flags__ = h__->flags & mask__; \
+ void* tbl__ = (mrb_assert(h__->hsh.ht), h__->hsh.ht); \
+ uint32_t ht_ea_capa__ = 0; \
+ hash_entry *ht_ea__ = NULL; \
+ if (H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR || h_ht_p(h__)) { \
+ ht_ea_capa__ = ht_ea_capa(h__); \
+ } \
+ if (H_CHECK_MODIFIED_USE_HT_EA_FOR_AR || h_ht_p(h__)) { \
+ ht_ea__ = ht_ea(h__); \
+ } \
+ code; \
+ if (flags__ != (h__->flags & mask__) || \
+ tbl__ != h__->hsh.ht || \
+ ((H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR || h_ht_p(h__)) && \
+ ht_ea_capa__ != ht_ea_capa(h__)) || \
+ ((H_CHECK_MODIFIED_USE_HT_EA_FOR_AR || h_ht_p(h__)) && \
+ ht_ea__ != ht_ea(h__))) { \
+ mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); \
+ } \
+} while (0)
+
+#define U32(v) ((uint32_t)(v))
+#define h_ar_p(h) (!h_ht_p(h))
+#define h_ar_on(h) h_ht_off(h)
+#define lesser(a, b) ((a) < (b) ? (a) : (b))
+#define RHASH_IFNONE(hash) mrb_iv_get(mrb, (hash), MRB_SYM(ifnone))
+#define RHASH_PROCDEFAULT(hash) RHASH_IFNONE(hash)
+
+static uint32_t ib_upper_bound_for(uint32_t capa);
+static uint32_t ib_bit_to_capa(uint32_t bit);
+static void ht_init(
+ mrb_state *mrb, struct RHash *h, uint32_t size,
+ hash_entry *ea, uint32_t ea_capa, hash_table *ht, uint32_t ib_bit);
+static void ht_set_without_ib_adjustment(
+ mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val);
+
+static uint32_t
+next_power2(uint32_t v)
{
- enum mrb_vtype tt = mrb_type(key);
- mrb_value hv;
- size_t h;
- segindex *index = t->index;
- size_t capa = index ? index->capa : 0;
+ mrb_assert(v != 0);
+#ifdef __GNUC__
+ return U32(1) << ((sizeof(unsigned) * CHAR_BIT) - __builtin_clz(v));
+#else
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+#endif
+}
+static uint32_t
+obj_hash_code(mrb_state *mrb, mrb_value key, struct RHash *h)
+{
+ enum mrb_vtype tt = mrb_type(key);
+ uint32_t hash_code;
+ mrb_value hash_code_obj;
switch (tt) {
case MRB_TT_STRING:
- h = mrb_str_hash(mrb, key);
+ hash_code = mrb_str_hash(mrb, key);
break;
-
case MRB_TT_TRUE:
case MRB_TT_FALSE:
case MRB_TT_SYMBOL:
- case MRB_TT_FIXNUM:
-#ifndef MRB_WITHOUT_FLOAT
+ case MRB_TT_INTEGER:
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
#endif
- h = (size_t)mrb_obj_id(key);
+ hash_code = U32(mrb_obj_id(key));
break;
-
default:
- hv = mrb_funcall(mrb, key, "hash", 0);
- h = (size_t)t ^ (size_t)mrb_fixnum(hv);
+ h_check_modified(mrb, h, {
+ hash_code_obj = mrb_funcall_argv(mrb, key, MRB_SYM(hash), 0, NULL);
+ });
+
+ hash_code = U32(tt) ^ U32(mrb_integer(hash_code_obj));
break;
}
- if (index && (index != t->index || capa != index->capa)) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified");
- }
- return ((h)^((h)<<2)^((h)>>2));
+ return hash_code ^ (hash_code << 2) ^ (hash_code >> 2);
}
-static inline mrb_bool
-sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b)
+static mrb_bool
+obj_eql(mrb_state *mrb, mrb_value a, mrb_value b, struct RHash *h)
{
enum mrb_vtype tt = mrb_type(a);
+ mrb_bool eql;
switch (tt) {
case MRB_TT_STRING:
return mrb_str_equal(mrb, a, b);
case MRB_TT_SYMBOL:
- if (mrb_type(b) != MRB_TT_SYMBOL) return FALSE;
+ if (!mrb_symbol_p(b)) return FALSE;
return mrb_symbol(a) == mrb_symbol(b);
- case MRB_TT_FIXNUM:
- switch (mrb_type(b)) {
- case MRB_TT_FIXNUM:
- return mrb_fixnum(a) == mrb_fixnum(b);
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
- return (mrb_float)mrb_fixnum(a) == mrb_float(b);
-#endif
- default:
- return FALSE;
- }
+ case MRB_TT_INTEGER:
+ if (!mrb_integer_p(b)) return FALSE;
+ return mrb_integer(a) == mrb_integer(b);
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
- switch (mrb_type(b)) {
- case MRB_TT_FIXNUM:
- return mrb_float(a) == (mrb_float)mrb_fixnum(b);
- case MRB_TT_FLOAT:
- return mrb_float(a) == mrb_float(b);
- default:
- return FALSE;
- }
+ if (!mrb_float_p(b)) return FALSE;
+ return mrb_float(a) == mrb_float(b);
#endif
default:
- {
- 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;
- }
- }
+ h_check_modified(mrb, h, {eql = mrb_eql(mrb, a, b);});
+ return eql;
+ }
}
-/* Creates the instance variable table. */
-static seglist*
-sg_new(mrb_state *mrb)
+static mrb_bool
+entry_deleted_p(const hash_entry* entry)
{
- seglist *t;
+ return mrb_undef_p(entry->key);
+}
- t = (seglist*)mrb_malloc(mrb, sizeof(seglist));
- t->size = 0;
- t->rootseg = NULL;
- t->lastseg = NULL;
- t->last_len = 0;
- t->index = NULL;
+static void
+entry_delete(hash_entry* entry)
+{
+ entry->key = mrb_undef_value();
+}
- return t;
+static uint32_t
+ea_next_capa_for(uint32_t size, uint32_t max_capa)
+{
+ if (size < AR_DEFAULT_CAPA) {
+ return AR_DEFAULT_CAPA;
+ }
+ else {
+ /*
+ * For 32-bit CPU, the theoretical value of maximum EA capacity is
+ * `UINT32_MAX / sizeof (hash_entry)`. At this time, if
+ * `EA_INCREASE_RATIO` is the current value, 32-bit range will not be
+ * exceeded during the calculation of `capa`, so `size_t` is used.
+ */
+ size_t capa = (size_t)size * EA_INCREASE_RATIO, inc = capa - size;
+ if (EA_MAX_INCREASE < inc) capa = size + EA_MAX_INCREASE;
+ return capa <= max_capa ? U32(capa) : max_capa;
+ }
}
-#define power2(v) do { \
- v--;\
- v |= v >> 1;\
- v |= v >> 2;\
- v |= v >> 4;\
- v |= v >> 8;\
- v |= v >> 16;\
- v++;\
-} while (0)
+static hash_entry*
+ea_resize(mrb_state *mrb, hash_entry *ea, uint32_t capa)
+{
+ return (hash_entry*)mrb_realloc(mrb, ea, sizeof(hash_entry) * capa);
+}
-#ifndef UPPER_BOUND
-#define UPPER_BOUND(x) ((x)>>2|(x)>>1)
-#endif
+static void
+ea_compress(hash_entry *ea, uint32_t n_used)
+{
+ hash_entry *w_entry = ea;
+ ea_each_used(ea, n_used, r_entry, {
+ if (entry_deleted_p(r_entry)) continue;
+ if (r_entry != w_entry) *w_entry = *r_entry;
+ ++w_entry;
+ });
+}
+
+/*
+ * Increase or decrease capacity of `ea` to a standard size that can
+ * accommodate `*capap + 1` entries (but, not exceed `max_capa`). Set the
+ * changed capacity to `*capap` and return a pointer to `mrb_realloc`ed EA.
+ */
+static hash_entry*
+ea_adjust(mrb_state *mrb, hash_entry *ea, uint32_t *capap, uint32_t max_capa)
+{
+ *capap = ea_next_capa_for(*capap, max_capa);
+ return ea_resize(mrb, ea, *capap);
+}
-#define SG_MASK(index) ((index->capa)-1)
+static hash_entry*
+ea_dup(mrb_state *mrb, const hash_entry *ea, uint32_t capa)
+{
+ size_t byte_size = sizeof(hash_entry) * capa;
+ hash_entry *new_ea = (hash_entry*)mrb_malloc(mrb, byte_size);
+ return (hash_entry*)memcpy(new_ea, ea, byte_size);
+}
+
+static hash_entry*
+ea_get_by_key(mrb_state *mrb, hash_entry *ea, uint32_t size, mrb_value key,
+ struct RHash *h)
+{
+ ea_each(ea, size, entry, {
+ if (obj_eql(mrb, key, entry->key, h)) return entry;
+ });
+ return NULL;
+}
+
+static hash_entry*
+ea_get(hash_entry *ea, uint32_t index)
+{
+ return &ea[index];
+}
-/* Build index for the segment list */
static void
-sg_index(mrb_state *mrb, seglist *t)
-{
- size_t size = (size_t)t->size;
- size_t mask;
- segindex *index = t->index;
- segment *seg;
- size_t i;
-
- if (size < MRB_SG_SEGMENT_SIZE) {
- if (index) {
- failed:
- mrb_free(mrb, index);
- t->index = NULL;
- }
- return;
- }
- /* 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) goto failed;
- t->index = index;
- }
- index->size = t->size;
- index->capa = size;
- for (i=0; i<size; i++) {
- index->table[i] = NULL;
- }
+ea_set(hash_entry *ea, uint32_t index, mrb_value key, mrb_value val)
+{
+ ea[index].key = key;
+ ea[index].val = val;
+}
- /* rebuld index */
- mask = SG_MASK(index);
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- mrb_value key;
- size_t k, step = 0;
+static void
+ar_init(struct RHash *h, uint32_t size,
+ hash_entry *ea, uint32_t ea_capa, uint32_t ea_n_used)
+{
+ h_ar_on(h);
+ ar_set_size(h, size);
+ ar_set_ea(h, ea);
+ ar_set_ea_capa(h, ea_capa);
+ ar_set_ea_n_used(h, ea_n_used);
+}
- if (!seg->next && i >= (size_t)t->last_len) {
- return;
- }
- key = seg->e[i].key;
- if (mrb_undef_p(key)) continue;
- k = sg_hash_func(mrb, t, key) & mask;
- while (index->table[k]) {
- k = (k+(++step)) & mask;
- }
- index->table[k] = &seg->e[i];
- }
- seg = seg->next;
- }
+static void
+ar_free(mrb_state *mrb, struct RHash *h)
+{
+ mrb_free(mrb, ar_ea(h));
}
-/* Compacts the segment list removing deleted entries. */
static void
-sg_compact(mrb_state *mrb, seglist *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) {
- sg_index(mrb, t);
- return;
- }
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- mrb_value k = seg->e[i].key;
+ar_adjust_ea(mrb_state *mrb, struct RHash *h, uint32_t size, uint32_t max_ea_capa)
+{
+ uint32_t ea_capa = size;
+ hash_entry *ea = ea_adjust(mrb, ar_ea(h), &ea_capa, max_ea_capa);
+ ar_set_ea(h, ea);
+ ar_set_ea_capa(h, ea_capa);
+}
- if (!seg->next && i >= t->last_len) {
- goto exit;
- }
- if (mrb_undef_p(k)) { /* found delete key */
- if (seg2 == NULL) {
- seg2 = seg;
- i2 = i;
+static void
+ar_compress(mrb_state *mrb, struct RHash *h)
+{
+ uint32_t size = ar_size(h);
+ ea_compress(ar_ea(h), ar_ea_n_used(h));
+ ar_set_ea_n_used(h, size);
+ ar_adjust_ea(mrb, h, size, lesser(ar_ea_capa(h), AR_MAX_SIZE));
+}
+
+static mrb_bool
+ar_get(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
+{
+ ea_each(ar_ea(h), ar_size(h), entry, {
+ if (!obj_eql(mrb, key, entry->key, h)) continue;
+ *valp = entry->val;
+ return TRUE;
+ });
+ return FALSE;
+}
+
+static void
+ar_set(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val)
+{
+ uint32_t size = ar_size(h);
+ hash_entry *entry;
+ if ((entry = ea_get_by_key(mrb, ar_ea(h), size, key, h))) {
+ entry->val = val;
+ }
+ else {
+ uint32_t ea_capa = ar_ea_capa(h), ea_n_used = ar_ea_n_used(h);
+ if (ea_capa == ea_n_used) {
+ if (size == ea_n_used) {
+ if (size == AR_MAX_SIZE) {
+ hash_entry *ea = ea_adjust(mrb, ar_ea(h), &ea_capa, EA_MAX_CAPA);
+ ea_set(ea, ea_n_used, key, val);
+ ht_init(mrb, h, ++size, ea, ea_capa, NULL, IB_INIT_BIT);
+ return;
+ }
+ else {
+ ar_adjust_ea(mrb, h, size, AR_MAX_SIZE);
}
}
else {
- size++;
- if (seg2 != NULL) {
- seg2->e[i2++] = seg->e[i];
- if (i2 >= MRB_SG_SEGMENT_SIZE) {
- seg2 = seg2->next;
- i2 = 0;
- }
- }
+ ar_compress(mrb, h);
+ ea_n_used = size;
}
}
- 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) {
- sg_index(mrb, t);
+ ea_set(ar_ea(h), ea_n_used, key, val);
+ ar_set_size(h, ++size);
+ ar_set_ea_n_used(h, ++ea_n_used);
}
}
-/* Set the value for the key in the indexed segment list. */
+static mrb_bool
+ar_delete(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
+{
+ hash_entry *entry = ea_get_by_key(mrb, ar_ea(h), ar_size(h), key, h);
+ if (!entry) return FALSE;
+ *valp = entry->val;
+ entry_delete(entry);
+ ar_dec_size(h);
+ return TRUE;
+}
+
static void
-sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
+ar_shift(mrb_state *mrb, struct RHash *h, mrb_value *keyp, mrb_value *valp)
{
- segindex *index = t->index;
- size_t k, sp, step = 0, mask;
- segment *seg;
+ uint32_t size = ar_size(h);
+ ea_each(ar_ea(h), size, entry, {
+ *keyp = entry->key;
+ *valp = entry->val;
+ entry_delete(entry);
+ ar_set_size(h, --size);
+ return;
+ });
+}
- if (index->size >= UPPER_BOUND(index->capa)) {
- /* need to expand table */
- sg_compact(mrb, t);
- index = t->index;
- }
- mask = SG_MASK(index);
- sp = index->capa;
- k = sg_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;
+static void
+ar_rehash(mrb_state *mrb, struct RHash *h)
+{
+ /* see comments in `h_rehash` */
+ uint32_t size = ar_size(h), w_size = 0, ea_capa = ar_ea_capa(h);
+ hash_entry *ea = ar_ea(h), *w_entry;
+ ea_each(ea, size, r_entry, {
+ if ((w_entry = ea_get_by_key(mrb, ea, w_size, r_entry->key, h))) {
+ w_entry->val = r_entry->val;
+ ar_set_size(h, --size);
+ entry_delete(r_entry);
}
- else if (sg_hash_equal(mrb, t, key, key2)) {
- index->table[k]->val = val;
- return;
+ else {
+ if (w_size != U32(r_entry - ea)) {
+ ea_set(ea, w_size, r_entry->key, r_entry->val);
+ entry_delete(r_entry);
+ }
+ ++w_size;
}
- k = (k+(++step)) & mask;
- }
- if (sp < index->capa) {
- k = sp;
- }
+ });
+ mrb_assert(size == w_size);
+ ar_set_ea_n_used(h, size);
+ ar_adjust_ea(mrb, h, size, ea_capa);
+}
- /* put the value at the last */
- seg = t->lastseg;
- if (t->last_len < MRB_SG_SEGMENT_SIZE) {
- index->table[k] = &seg->e[t->last_len++];
- }
- else { /* append a new segment */
- seg->next = (segment*)mrb_malloc(mrb, sizeof(segment));
- 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++;
+static uint32_t
+ib_it_pos_for(index_buckets_iter *it, uint32_t v)
+{
+ return v & it->mask;
}
-/* Set the value for the key in the segment list. */
-static void
-sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
+static uint32_t
+ib_it_empty_value(const index_buckets_iter *it)
{
- segment *seg;
- mrb_int i, deleted = 0;
+ return it->mask;
+}
- if (t == NULL) return;
- if (t->index) {
- sg_index_put(mrb, t, key, val);
- return;
- }
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_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 (sg_hash_equal(mrb, t, k, key)) {
- seg->e[i].val = val;
- return;
- }
- }
- seg = seg->next;
- }
+static uint32_t
+ib_it_deleted_value(const index_buckets_iter *it)
+{
+ return it->mask - 1;
+}
- /* Not found */
- if (deleted > MRB_SG_SEGMENT_SIZE) {
- sg_compact(mrb, t);
- }
- t->size++;
-
- seg = (segment*)mrb_malloc(mrb, sizeof(segment));
- seg->next = NULL;
- seg->e[0].key = key;
- seg->e[0].val = val;
- t->last_len = 1;
- if (t->rootseg == NULL) {
- t->rootseg = seg;
- }
- else {
- t->lastseg->next = seg;
- }
- t->lastseg = seg;
- if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) {
- sg_index(mrb, t);
- }
+static mrb_bool
+ib_it_empty_p(const index_buckets_iter *it)
+{
+ return it->ea_index == ib_it_empty_value(it);
}
-/* Get a value for a key from the indexed segment list. */
static mrb_bool
-sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
-{
- segindex *index = t->index;
- size_t mask = SG_MASK(index);
- size_t k = sg_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) && sg_hash_equal(mrb, t, key, key2)) {
- if (vp) *vp = index->table[k]->val;
- return TRUE;
- }
- k = (k+(++step)) & mask;
- }
- return FALSE;
+ib_it_deleted_p(const index_buckets_iter *it)
+{
+ return it->ea_index == ib_it_deleted_value(it);
}
-/* Get a value for a key from the segment list. */
static mrb_bool
-sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
+ib_it_active_p(const index_buckets_iter *it)
+{
+ return it->ea_index < ib_it_deleted_value(it);
+}
+
+static void
+ib_it_init(mrb_state *mrb, index_buckets_iter *it, struct RHash *h, mrb_value key)
{
- segment *seg;
- mrb_int i;
+ it->h = h;
+ it->bit = ib_bit(h);
+ it->mask = ib_bit_to_capa(it->bit) - 1;
+ it->pos = ib_it_pos_for(it, obj_hash_code(mrb, key, h));
+ it->step = 0;
+}
- if (t == NULL) return FALSE;
- if (t->index) {
- return sg_index_get(mrb, t, key, vp);
+static void
+ib_it_next(index_buckets_iter *it)
+{
+ /*
+ * [IB image]
+ *
+ * ary_index(1) --.
+ * \ .-- shift1(3) .-- shift2(29)
+ * pos(6) --. \ / /
+ * View | \ \ <-o-> <----------o---------->
+ * -------- +---------------------\----\--+-----------------------------+-----
+ * array | 0 `--. `-|--- o 1 | ...
+ * +---------+---------+-----+\--+-----+---------+---------+---+-----
+ * buckets | 0 | 1 | ... | o 6 | 7 | 8 | ...
+ * +---------+---------+-----+=========+---------+---------+---------
+ * bit set |1 1 1 0 0|0 0 0 1 1| ... |0 1 0 1 1|0 1 1 1 0|0 1 0 1 0| ...
+ * +---------+---------+-----+========*+---------+---------+---------
+ * <---o---> \
+ * \ `-- bit_pos(34)
+ * `-- bit(5)
+ */
+
+ /* Slide to handle as `capa == 32` to avoid 64-bit operations */
+ uint32_t slid_pos = it->pos & (IB_TYPE_BIT - 1);
+ uint32_t slid_bit_pos = it->bit * (slid_pos + 1) - 1;
+ uint32_t slid_ary_index = slid_bit_pos / IB_TYPE_BIT;
+ it->ary_index = slid_ary_index + it->pos / IB_TYPE_BIT * it->bit;
+ it->shift2 = (slid_ary_index + 1) * IB_TYPE_BIT - slid_bit_pos - 1;
+ it->ea_index = (ht_ib(it->h)[it->ary_index] >> it->shift2) & it->mask;
+ if (IB_TYPE_BIT - it->bit < it->shift2) {
+ it->shift1 = IB_TYPE_BIT - it->shift2;
+ it->ea_index |= (ht_ib(it->h)[it->ary_index - 1] << it->shift1) & it->mask;
+ }
+ else {
+ it->shift1 = 0;
}
+ it->pos = ib_it_pos_for(it, it->pos + (++it->step));
+}
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- mrb_value k = seg->e[i].key;
+static uint32_t
+ib_it_get(const index_buckets_iter *it)
+{
+ return it->ea_index;
+}
- if (!seg->next && i >= t->last_len) {
- return FALSE;
- }
- if (mrb_undef_p(k)) continue;
- if (sg_hash_equal(mrb, t, k, key)) {
- if (vp) *vp = seg->e[i].val;
- return TRUE;
- }
- }
- seg = seg->next;
+static void
+ib_it_set(index_buckets_iter *it, uint32_t ea_index)
+{
+ uint32_t mask, i;
+ it->ea_index = ea_index;
+ if (it->shift1) {
+ i = it->ary_index - 1;
+ mask = it->mask >> it->shift1;
+ ht_ib(it->h)[i] = (ht_ib(it->h)[i] & ~mask) | (ea_index >> it->shift1);
}
- return FALSE;
+ i = it->ary_index;
+ mask = it->mask << it->shift2;
+ ht_ib(it->h)[i] = (ht_ib(it->h)[i] & ~mask) | (ea_index << it->shift2);
+}
+
+static void
+ib_it_delete(index_buckets_iter *it)
+{
+ ib_it_set(it, ib_it_deleted_value(it));
+}
+
+static hash_entry*
+ib_it_entry(index_buckets_iter *it)
+{
+ return ea_get(ht_ea(it->h), it->ea_index);
+}
+
+static uint32_t
+ib_capa_to_bit(uint32_t capa)
+{
+#ifdef __GNUC__
+ return U32(__builtin_ctz(capa));
+#else
+ /* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn */
+ static const uint32_t MultiplyDeBruijnBitPosition2[] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+ return MultiplyDeBruijnBitPosition2[U32(capa * 0x077CB531U) >> 27];
+#endif
+}
+
+static uint32_t
+ib_bit_to_capa(uint32_t bit)
+{
+ return U32(1) << bit;
+}
+
+static uint32_t
+ib_upper_bound_for(uint32_t capa)
+{
+ return (capa >> 2) | (capa >> 1); /* 3/4 */
+}
+
+static uint32_t
+ib_bit_for(uint32_t size)
+{
+ uint32_t capa = next_power2(size);
+ if (capa != IB_MAX_CAPA && ib_upper_bound_for(capa) < size) capa *= 2;
+ return ib_capa_to_bit(capa);
+}
+
+static uint32_t
+ib_byte_size_for(uint32_t ib_bit)
+{
+ mrb_assert(IB_INIT_BIT <= ib_bit);
+ uint32_t ary_size = IB_INIT_BIT == 4 ?
+ ib_bit_to_capa(ib_bit) * 2 / IB_TYPE_BIT * ib_bit / 2 :
+ ib_bit_to_capa(ib_bit) / IB_TYPE_BIT * ib_bit;
+ return U32(sizeof(uint32_t) * ary_size);
+}
+
+static void
+ib_init(mrb_state *mrb, struct RHash *h, uint32_t ib_bit, size_t ib_byte_size)
+{
+ hash_entry *ea = ht_ea(h);
+ memset(ht_ib(h), 0xff, ib_byte_size);
+ ib_set_bit(h, ib_bit);
+ ea_each_used(ea, ht_ea_n_used(h), entry, {
+ ib_cycle_by_key(mrb, h, entry->key, it, {
+ if (!ib_it_empty_p(it)) continue;
+ ib_it_set(it, U32(entry - ea));
+ break;
+ });
+ });
+}
+
+static void
+ht_init(mrb_state *mrb, struct RHash *h, uint32_t size,
+ hash_entry *ea, uint32_t ea_capa, hash_table *ht, uint32_t ib_bit)
+{
+ size_t ib_byte_size = ib_byte_size_for(ib_bit);
+ size_t ht_byte_size = sizeof(hash_table) + ib_byte_size;
+ h_ht_on(h);
+ h_set_ht(h, (hash_table*)mrb_realloc(mrb, ht, ht_byte_size));
+ ht_set_size(h, size);
+ ht_set_ea(h, ea);
+ ht_set_ea_capa(h, ea_capa);
+ ht_set_ea_n_used(h, size);
+ ib_init(mrb, h, ib_bit, ib_byte_size);
+}
+
+static void
+ht_free(mrb_state *mrb, struct RHash *h)
+{
+ mrb_free(mrb, ht_ea(h));
+ mrb_free(mrb, h_ht(h));
+}
+
+static hash_table*
+ht_dup(mrb_state *mrb, const struct RHash *h)
+{
+ size_t ib_byte_size = ib_byte_size_for(ib_bit(h));
+ size_t ht_byte_size = sizeof(hash_table) + ib_byte_size;
+ hash_table *new_ht = (hash_table*)mrb_malloc(mrb, ht_byte_size);
+ return (hash_table*)memcpy(new_ht, h_ht(h), ht_byte_size);
+}
+
+static void
+ht_adjust_ea(mrb_state *mrb, struct RHash *h, uint32_t size, uint32_t max_ea_capa)
+{
+ uint32_t ea_capa = size;
+ hash_entry *ea = ea_adjust(mrb, ht_ea(h), &ea_capa, max_ea_capa);
+ ht_set_ea(h, ea);
+ ht_set_ea_capa(h, ea_capa);
+}
+
+static void
+ht_to_ar(mrb_state *mrb, struct RHash *h)
+{
+ uint32_t size = ht_size(h), ea_capa = size;
+ hash_entry *ea = ht_ea(h);
+ ea_compress(ea, ht_ea_n_used(h));
+ ea = ea_adjust(mrb, ea, &ea_capa, AR_MAX_SIZE);
+ mrb_free(mrb, h_ht(h));
+ ar_init(h, size, ea, ea_capa, size);
}
-/* Deletes the value for the symbol from the instance variable table. */
-/* Deletion is done by overwriting keys by `undef`. */
static mrb_bool
-sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
+ht_get(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
{
- segment *seg;
- mrb_int i;
+ ib_find_by_key(mrb, h, key, it, {
+ *valp = ib_it_entry(it)->val;
+ return TRUE;
+ });
+ return FALSE;
+}
- if (t == NULL) return FALSE;
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- mrb_value key2;
+static void
+ht_set_as_ar(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val)
+{
+ ht_to_ar(mrb, h);
+ ar_set(mrb, h, key, val);
+}
- if (!seg->next && i >= t->last_len) {
- /* not found */
- return FALSE;
+static void
+ht_set_without_ib_adjustment(mrb_state *mrb, struct RHash *h,
+ mrb_value key, mrb_value val)
+{
+ mrb_assert(ht_size(h) < ib_bit_to_capa(ib_bit(h)));
+ ib_cycle_by_key(mrb, h, key, it, {
+ if (ib_it_active_p(it)) {
+ if (!obj_eql(mrb, key, ib_it_entry(it)->key, h)) continue;
+ ib_it_entry(it)->val = val;
+ }
+ else {
+ uint32_t ea_n_used = ht_ea_n_used(h);
+ if (ea_n_used == H_MAX_SIZE) {
+ mrb_assert(ht_size(h) == ea_n_used);
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "hash too big");
}
- key2 = seg->e[i].key;
- if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) {
- if (vp) *vp = seg->e[i].val;
- seg->e[i].key = mrb_undef_value();
- t->size--;
- return TRUE;
+ if (ea_n_used == ht_ea_capa(h)) ht_adjust_ea(mrb, h, ea_n_used, EA_MAX_CAPA);
+ ib_it_set(it, ea_n_used);
+ ea_set(ht_ea(h), ea_n_used, key, val);
+ ht_inc_size(h);
+ ht_set_ea_n_used(h, ++ea_n_used);
+ }
+ return;
+ });
+}
+
+static void
+ht_set(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val)
+{
+ uint32_t size = ht_size(h);
+ uint32_t ib_bit_width = ib_bit(h), ib_capa = ib_bit_to_capa(ib_bit_width);
+ if (ib_upper_bound_for(ib_capa) <= size) {
+ if (size != ht_ea_n_used(h)) ea_compress(ht_ea(h), ht_ea_n_used(h));
+ ht_init(mrb, h, size, ht_ea(h), ht_ea_capa(h), h_ht(h), ++ib_bit_width);
+ }
+ else if (size != ht_ea_n_used(h)) {
+ if (ib_capa - EA_N_RESERVED_INDICES <= ht_ea_n_used(h)) goto compress;
+ if (ht_ea_capa(h) == ht_ea_n_used(h)) {
+ if (size <= AR_MAX_SIZE) {ht_set_as_ar(mrb, h, key, val); return;}
+ if (ea_next_capa_for(size, EA_MAX_CAPA) <= ht_ea_capa(h)) {
+ compress:
+ ea_compress(ht_ea(h), ht_ea_n_used(h));
+ ht_adjust_ea(mrb, h, size, ht_ea_capa(h));
+ ht_init(mrb, h, size, ht_ea(h), ht_ea_capa(h), h_ht(h), ib_bit_width);
}
}
- seg = seg->next;
}
+ ht_set_without_ib_adjustment(mrb, h, key, val);
+}
+
+static mrb_bool
+ht_delete(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
+{
+ ib_find_by_key(mrb, h, key, it, {
+ hash_entry *entry = ib_it_entry(it);
+ *valp = entry->val;
+ ib_it_delete(it);
+ entry_delete(entry);
+ ht_dec_size(h);
+ return TRUE;
+ });
return FALSE;
}
-/* Iterates over the instance variable table. */
static void
-sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p)
+ht_shift(mrb_state *mrb, struct RHash *h, mrb_value *keyp, mrb_value *valp)
{
- segment *seg;
- mrb_int i;
+ hash_entry *ea = ht_ea(h);
+ ea_each(ea, ht_size(h), entry, {
+ ib_cycle_by_key(mrb, h, entry->key, it, {
+ if (ib_it_get(it) != U32(entry - ea)) continue;
+ *keyp = entry->key;
+ *valp = entry->val;
+ ib_it_delete(it);
+ entry_delete(entry);
+ ht_dec_size(h);
+ return;
+ });
+ });
+}
- if (t == NULL) return;
- if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) {
- sg_compact(mrb, t);
+static void
+ht_rehash(mrb_state *mrb, struct RHash *h)
+{
+ /* see comments in `h_rehash` */
+ uint32_t size = ht_size(h);
+ if (size <= AR_MAX_SIZE) {
+ ht_to_ar(mrb, h);
+ ar_rehash(mrb, h);
+ return;
}
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- /* no value in last segment after last_len */
- if (!seg->next && i >= t->last_len) {
- return;
+ uint32_t w_size = 0, ea_capa = ht_ea_capa(h);
+ hash_entry *ea = ht_ea(h);
+ ht_init(mrb, h, 0, ea, ea_capa, h_ht(h), ib_bit_for(size));
+ ht_set_size(h, size);
+ ht_set_ea_n_used(h, ht_ea_n_used(h));
+ ea_each(ea, size, r_entry, {
+ ib_cycle_by_key(mrb, h, r_entry->key, it, {
+ if (ib_it_active_p(it)) {
+ if (!obj_eql(mrb, r_entry->key, ib_it_entry(it)->key, h)) continue;
+ ib_it_entry(it)->val = r_entry->val;
+ ht_set_size(h, --size);
+ entry_delete(r_entry);
}
- 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;
+ else {
+ if (w_size != U32(r_entry - ea)) {
+ ea_set(ea, w_size, r_entry->key, r_entry->val);
+ entry_delete(r_entry);
+ }
+ ib_it_set(it, w_size++);
+ }
+ break;
+ });
+ });
+ mrb_assert(size == w_size);
+ ht_set_ea_n_used(h, size);
+ size <= AR_MAX_SIZE ? ht_to_ar(mrb, h) : ht_adjust_ea(mrb, h, size, ea_capa);
+}
+
+static mrb_value
+h_key_for(mrb_state *mrb, mrb_value key)
+{
+ if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) {
+ key = mrb_str_dup(mrb, key);
+ MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
}
+ return key;
}
-/* Get the size of the instance variable table. */
-static mrb_int
-sg_size(mrb_state *mrb, seglist *t)
+static struct RHash*
+h_alloc(mrb_state *mrb)
{
- if (t == NULL) return 0;
- return t->size;
+ return MRB_OBJ_ALLOC(mrb, MRB_TT_HASH, mrb->hash_class);
}
-/* Copy the instance variable table. */
-static seglist*
-sg_copy(mrb_state *mrb, seglist *t)
+static void
+h_init(struct RHash *h)
{
- segment *seg;
- seglist *t2;
- mrb_int i;
+ ar_init(h, 0, NULL, 0, 0);
+}
- seg = t->rootseg;
- t2 = sg_new(mrb);
+static void
+h_free_table(mrb_state *mrb, struct RHash *h)
+{
+ (h_ar_p(h) ? ar_free : ht_free)(mrb, h);
+}
- while (seg != NULL) {
- for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
- mrb_value key = seg->e[i].key;
- mrb_value val = seg->e[i].val;
+static void
+h_clear(mrb_state *mrb, struct RHash *h)
+{
+ h_free_table(mrb, h);
+ h_init(h);
+}
- if ((seg->next == NULL) && (i >= t->last_len)) {
- return t2;
- }
- sg_put(mrb, t2, key, val);
- }
- seg = seg->next;
- }
- return t2;
+static mrb_bool
+h_get(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
+{
+ return (h_ar_p(h) ? ar_get : ht_get)(mrb, h, key, valp);
}
-/* Free memory of the instance variable table. */
static void
-sg_free(mrb_state *mrb, seglist *t)
+h_set(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val)
{
- segment *seg;
+ (h_ar_p(h) ? ar_set : ht_set)(mrb, h, key, val);
+}
- 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 mrb_bool
+h_delete(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value *valp)
+{
+ return (h_ar_p(h) ? ar_delete : ht_delete)(mrb, h, key, valp);
}
-static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
+/* find first element in the table, and remove it. */
+static void
+h_shift(mrb_state *mrb, struct RHash *h, mrb_value *keyp, mrb_value *valp)
+{
+ (h_ar_p(h) ? ar_shift : ht_shift)(mrb, h, keyp, valp);
+}
-static inline mrb_value
-ht_key(mrb_state *mrb, mrb_value key)
+static void
+h_rehash(mrb_state *mrb, struct RHash *h)
{
- if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) {
- key = mrb_str_dup(mrb, key);
- MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
+ /*
+ * ==== Comments common to `ar_rehash` and `ht_rehash`
+ *
+ * - Because reindex (such as elimination of duplicate keys) must be
+ * guaranteed, it is necessary to set one by one.
+ *
+ * - To prevent EA from breaking if an exception occurs in the middle,
+ * delete the slot before moving when moving the entry, and update size
+ * at any time when overwriting.
+ */
+ (h_size(h) == 0 ? h_clear : h_ar_p(h) ? ar_rehash : ht_rehash)(mrb, h);
+}
+
+static void
+h_replace(mrb_state *mrb, struct RHash *h, struct RHash *orig_h)
+{
+ uint32_t size = h_size(orig_h);
+ if (size == 0) {
+ h_clear(mrb, h);
+ }
+ else if (h_ar_p(orig_h)) {
+ uint32_t ea_capa = ar_ea_capa(orig_h);
+ hash_entry *ea = ea_dup(mrb, ar_ea(orig_h), ea_capa);
+ h_free_table(mrb, h);
+ ar_init(h, size, ea, ea_capa, ar_ea_n_used(orig_h));
+ }
+ else { /* HT */
+ uint32_t ea_capa = ht_ea_capa(orig_h);
+ hash_entry *ea = ea_dup(mrb, ht_ea(orig_h), ea_capa);
+ hash_table *ht = ht_dup(mrb, orig_h);
+ h_free_table(mrb, h);
+ h_ht_on(h);
+ h_set_ht(h, ht);
+ ht_set_size(h, size);
+ ht_set_ea(h, ea);
+#ifdef MRB_64BIT
+ ht_set_ea_capa(h, ea_capa);
+ ht_set_ea_n_used(h, ht_ea_n_used(orig_h));
+#endif
+ ib_set_bit(h, ib_bit(orig_h));
}
- return key;
}
-#define KEY(key) ht_key(mrb, key)
+void
+mrb_gc_mark_hash(mrb_state *mrb, struct RHash *h)
+{
+ h_each(h, entry, {
+ mrb_gc_mark_value(mrb, entry->key);
+ mrb_gc_mark_value(mrb, entry->val);
+ });
+}
-static int
-hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
+size_t
+mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *h)
{
- mrb_gc_mark_value(mrb, key);
- mrb_gc_mark_value(mrb, val);
- return 0;
+ return h_size(h) * 2;
}
void
-mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash)
+mrb_gc_free_hash(mrb_state *mrb, struct RHash *h)
{
- sg_foreach(mrb, hash->ht, hash_mark_i, NULL);
+ h_free_table(mrb, h);
}
size_t
-mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash)
+mrb_hash_memsize(mrb_value self)
{
- if (!hash->ht) return 0;
- return sg_size(mrb, hash->ht)*2;
+ struct RHash *h = mrb_hash_ptr(self);
+ return mrb_obj_iv_tbl_memsize(self) +
+ (h_ar_p(h) ? (ar_ea_capa(h) * sizeof(hash_entry)) :
+ (ht_ea_capa(h) * sizeof(hash_entry) +
+ sizeof(hash_table) +
+ ib_byte_size_for(ib_bit(h))));
}
-void
-mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
+/* Iterates over the key/value pairs. */
+MRB_API void
+mrb_hash_foreach(mrb_state *mrb, struct RHash *h, mrb_hash_foreach_func *func, void *data)
{
- sg_free(mrb, hash->ht);
+ h_each(h, entry, {
+ if (func(mrb, entry->key, entry->val, data) != 0) return;
+ });
}
MRB_API mrb_value
mrb_hash_new(mrb_state *mrb)
{
- struct RHash *h;
-
- h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
- h->ht = 0;
- h->iv = 0;
+ struct RHash *h = h_alloc(mrb);
return mrb_obj_value(h);
}
+/*
+ * Set the capacity of EA and IB to minimum capacity (and appropriate load
+ * factor) that does not cause expansion when inserting `capa` elements.
+ */
MRB_API mrb_value
mrb_hash_new_capa(mrb_state *mrb, mrb_int capa)
{
- struct RHash *h;
-
- h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
- /* preallocate segment list */
- h->ht = sg_new(mrb);
- /* capacity ignored */
- h->iv = 0;
- return mrb_obj_value(h);
+ if (capa < 0 || EA_MAX_CAPA < capa) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "hash too big");
+ return mrb_nil_value(); /* not reached */
+ }
+ else if (capa == 0) {
+ return mrb_hash_new(mrb);
+ }
+ else {
+ uint32_t size = U32(capa);
+ struct RHash *h = h_alloc(mrb);
+ hash_entry *ea = ea_resize(mrb, NULL, size);
+ if (size <= AR_MAX_SIZE) {
+ ar_init(h, 0, ea, size, 0);
+ }
+ else {
+ ht_init(mrb, h, 0, ea, size, NULL, ib_bit_for(size));
+ }
+ return mrb_obj_value(h);
+ }
}
static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
-static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
+
+static void
+hash_modify(mrb_state *mrb, mrb_value hash)
+{
+ mrb_check_frozen(mrb, mrb_hash_ptr(hash));
+}
static mrb_value
-mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
+hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
{
- mrb_value orig;
- struct RHash* copy;
- seglist *orig_h;
- mrb_value ifnone, vret;
-
- mrb_get_args(mrb, "o", &orig);
- if (mrb_obj_equal(mrb, self, orig)) return self;
- if ((mrb_type(self) != mrb_type(orig)) || (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig))) {
- mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object");
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ return mrb_funcall_id(mrb, RHASH_PROCDEFAULT(hash), MRB_SYM(call), 2, hash, key);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
}
+ return mrb_nil_value();
+}
- orig_h = RHASH_TBL(self);
- copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
- copy->ht = sg_copy(mrb, orig_h);
-
- if (MRB_RHASH_DEFAULT_P(self)) {
- copy->flags |= MRB_HASH_DEFAULT;
- }
- if (MRB_RHASH_PROCDEFAULT_P(self)) {
- copy->flags |= MRB_HASH_PROC_DEFAULT;
+static void
+hash_replace(mrb_state *mrb, mrb_value self, mrb_value orig)
+{
+ struct RHash *h = mrb_hash_ptr(self), *orig_h = mrb_hash_ptr(orig);
+ uint32_t mask = MRB_HASH_DEFAULT | MRB_HASH_PROC_DEFAULT;
+ mrb_sym name;
+ h_replace(mrb, h, orig_h);
+ name = MRB_SYM(ifnone);
+ if (orig_h->flags & MRB_HASH_DEFAULT) {
+ mrb_iv_set(mrb, self, name, mrb_iv_get(mrb, orig, name));
}
- vret = mrb_obj_value(copy);
- ifnone = RHASH_IFNONE(self);
- if (!mrb_nil_p(ifnone)) {
- mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ else {
+ mrb_iv_remove(mrb, self, name);
}
- return vret;
+ h->flags &= ~mask;
+ h->flags |= orig_h->flags & mask;
}
-static int
-check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
+static mrb_value
+mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
{
- if (!mrb_symbol_p(key)) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys");
- }
- return 0;
+ mrb_value orig;
+ mrb_get_args(mrb, "H", &orig);
+ hash_modify(mrb, self);
+ if (mrb_hash_ptr(self) != mrb_hash_ptr(orig)) hash_replace(mrb, self, orig);
+ return self;
}
void
mrb_hash_check_kdict(mrb_state *mrb, mrb_value self)
{
- seglist *sg;
-
- sg = RHASH_TBL(self);
- if (!sg || sg_size(mrb, sg) == 0) return;
- sg_foreach(mrb, sg, check_kdict_i, NULL);
+ h_each(mrb_hash_ptr(self), entry, {
+ if (mrb_symbol_p(entry->key)) continue;
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys");
+ });
}
MRB_API mrb_value
mrb_hash_dup(mrb_state *mrb, mrb_value self)
{
- struct RHash* copy;
- seglist *orig_h;
-
- orig_h = RHASH_TBL(self);
- copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
- copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL;
- return mrb_obj_value(copy);
+ struct RHash* copy_h = h_alloc(mrb);
+ mrb_value copy = mrb_obj_value(copy_h);
+ copy_h->c = mrb_hash_ptr(self)->c;
+ hash_replace(mrb, copy, self);
+ return copy;
}
MRB_API mrb_value
@@ -688,11 +1214,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
mrb_value val;
mrb_sym mid;
- if (sg_get(mrb, RHASH_TBL(hash), key, &val)) {
+ if (h_get(mrb, mrb_hash_ptr(hash), key, &val)) {
return val;
}
- mid = mrb_intern_lit(mrb, "default");
+ mid = MRB_SYM(default);
if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
return hash_default(mrb, hash, key);
}
@@ -705,7 +1231,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
{
mrb_value val;
- if (sg_get(mrb, RHASH_TBL(hash), key, &val)) {
+ if (h_get(mrb, mrb_hash_ptr(hash), key, &val)) {
return val;
}
/* not found */
@@ -715,36 +1241,11 @@ 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)
{
- mrb_hash_modify(mrb, hash);
-
- sg_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_ensure_hash_type(mrb_state *mrb, mrb_value hash)
-{
- return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash");
-}
-
-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");
-}
-
-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");
- }
-
- if (!RHASH_TBL(hash)) {
- RHASH_TBL(hash) = sg_new(mrb);
- }
+ hash_modify(mrb, hash);
+ key = h_key_for(mrb, key);
+ h_set(mrb, mrb_hash_ptr(hash), key, val);
+ mrb_field_write_barrier_value(mrb, mrb_basic_ptr(hash), key);
+ mrb_field_write_barrier_value(mrb, mrb_basic_ptr(hash), val);
}
/* 15.2.13.4.16 */
@@ -791,17 +1292,17 @@ mrb_hash_init(mrb_state *mrb, mrb_value hash)
ifnone = mrb_nil_value();
mrb_get_args(mrb, "&|o?", &block, &ifnone, &ifnone_p);
- mrb_hash_modify(mrb, hash);
+ hash_modify(mrb, hash);
if (!mrb_nil_p(block)) {
if (ifnone_p) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ mrb_argnum_error(mrb, 1, 0, 0);
}
RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
ifnone = block;
}
if (!mrb_nil_p(ifnone)) {
RHASH(hash)->flags |= MRB_HASH_DEFAULT;
- mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ mrb_iv_set(mrb, hash, MRB_SYM(ifnone), ifnone);
}
return hash;
}
@@ -823,26 +1324,11 @@ mrb_hash_init(mrb_state *mrb, mrb_value hash)
static mrb_value
mrb_hash_aget(mrb_state *mrb, mrb_value self)
{
- mrb_value key;
+ mrb_value key = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &key);
return mrb_hash_get(mrb, self, key);
}
-static mrb_value
-hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
-{
- if (MRB_RHASH_DEFAULT_P(hash)) {
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
- }
- else {
- return RHASH_IFNONE(hash);
- }
- }
- return mrb_nil_value();
-}
-
/* 15.2.13.4.5 */
/*
* call-seq:
@@ -875,7 +1361,7 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash)
if (MRB_RHASH_DEFAULT_P(hash)) {
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
if (!given) return mrb_nil_value();
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
+ return mrb_funcall_id(mrb, RHASH_PROCDEFAULT(hash), MRB_SYM(call), 2, hash, key);
}
else {
return RHASH_IFNONE(hash);
@@ -908,11 +1394,10 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash)
static mrb_value
mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
{
- mrb_value ifnone;
+ mrb_value ifnone = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &ifnone);
- mrb_hash_modify(mrb, hash);
- mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ hash_modify(mrb, hash);
+ mrb_iv_set(mrb, hash, MRB_SYM(ifnone), ifnone);
RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT;
if (!mrb_nil_p(ifnone)) {
RHASH(hash)->flags |= MRB_HASH_DEFAULT;
@@ -938,7 +1423,6 @@ mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
* a #=> [nil, nil, 4]
*/
-
static mrb_value
mrb_hash_default_proc(mrb_state *mrb, mrb_value hash)
{
@@ -964,11 +1448,10 @@ mrb_hash_default_proc(mrb_state *mrb, mrb_value hash)
static mrb_value
mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
{
- mrb_value ifnone;
+ mrb_value ifnone = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &ifnone);
- mrb_hash_modify(mrb, hash);
- mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ hash_modify(mrb, hash);
+ mrb_iv_set(mrb, hash, MRB_SYM(ifnone), ifnone);
if (!mrb_nil_p(ifnone)) {
RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
RHASH(hash)->flags |= MRB_HASH_DEFAULT;
@@ -984,10 +1467,10 @@ 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)
{
- seglist *sg = RHASH_TBL(hash);
mrb_value del_val;
- if (sg_del(mrb, sg, key, &del_val)) {
+ hash_modify(mrb, hash);
+ if (h_delete(mrb, mrb_hash_ptr(hash), key, &del_val)) {
return del_val;
}
@@ -998,40 +1481,11 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
static mrb_value
mrb_hash_delete(mrb_state *mrb, mrb_value self)
{
- mrb_value key;
-
- mrb_get_args(mrb, "o", &key);
- mrb_hash_modify(mrb, self);
+ mrb_value key = mrb_get_arg1(mrb);
+ mrb->c->ci->mid = 0;
return mrb_hash_delete_key(mrb, self, key);
}
-/* find first element in segment list, and remove it. */
-static void
-sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp)
-{
- segment *seg = t->rootseg;
- mrb_int i;
-
- while (seg) {
- for (i=0; i<MRB_SG_SEGMENT_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:
@@ -1049,25 +1503,19 @@ sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp)
static mrb_value
mrb_hash_shift(mrb_state *mrb, mrb_value hash)
{
- seglist *sg = RHASH_TBL(hash);
+ struct RHash *h = mrb_hash_ptr(hash);
- mrb_hash_modify(mrb, hash);
- if (sg && sg_size(mrb, sg) > 0) {
+ hash_modify(mrb, hash);
+ if (h_size(h) == 0) {
+ return mrb_nil_value();
+ }
+ else {
mrb_value del_key, del_val;
-
- sg_shift(mrb, sg, &del_key, &del_val);
+ h_shift(mrb, h, &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)) {
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, mrb_nil_value());
- }
- else {
- return RHASH_IFNONE(hash);
- }
- }
- return mrb_nil_value();
}
/* 15.2.13.4.4 */
@@ -1085,13 +1533,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
MRB_API mrb_value
mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
- seglist *sg = RHASH_TBL(hash);
-
- mrb_hash_modify(mrb, hash);
- if (sg) {
- sg_free(mrb, sg);
- RHASH_TBL(hash) = NULL;
- }
+ hash_modify(mrb, hash);
+ h_clear(mrb, mrb_hash_ptr(hash));
return hash;
}
@@ -1124,12 +1567,18 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
return val;
}
+MRB_API mrb_int
+mrb_hash_size(mrb_state *mrb, mrb_value hash)
+{
+ return (mrb_int)h_size(mrb_hash_ptr(hash));
+}
+
/* 15.2.13.4.20 */
/* 15.2.13.4.25 */
/*
* call-seq:
- * hsh.length -> fixnum
- * hsh.size -> fixnum
+ * hsh.length -> integer
+ * hsh.size -> integer
*
* Returns the number of key-value pairs in the hash.
*
@@ -1141,19 +1590,14 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_hash_size_m(mrb_state *mrb, mrb_value self)
{
- seglist *sg = RHASH_TBL(self);
-
- if (!sg) return mrb_fixnum_value(0);
- return mrb_fixnum_value(sg_size(mrb, sg));
+ mrb_int size = mrb_hash_size(mrb, self);
+ return mrb_int_value(mrb, size);
}
MRB_API mrb_bool
mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
{
- seglist *sg = RHASH_TBL(self);
-
- if (!sg) return TRUE;
- return sg_size(mrb, sg) == 0;
+ return h_size(mrb_hash_ptr(self)) == 0;
}
/* 15.2.13.4.12 */
@@ -1172,27 +1616,6 @@ mrb_hash_empty_m(mrb_state *mrb, mrb_value self)
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)
-{
- return hash;
-}
-
-static int
-hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
-{
- mrb_ary_push(mrb, *(mrb_value*)p, key);
- return 0;
-}
-
/* 15.2.13.4.19 */
/*
* call-seq:
@@ -1209,24 +1632,14 @@ hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
MRB_API mrb_value
mrb_hash_keys(mrb_state *mrb, mrb_value hash)
{
- seglist *sg = RHASH_TBL(hash);
- size_t size;
- mrb_value ary;
-
- if (!sg || (size = sg_size(mrb, sg)) == 0)
- return mrb_ary_new(mrb);
- ary = mrb_ary_new_capa(mrb, size);
- sg_foreach(mrb, sg, hash_keys_i, (void*)&ary);
+ struct RHash *h = mrb_hash_ptr(hash);
+ mrb_value ary = mrb_ary_new_capa(mrb, (mrb_int)h_size(h));
+ h_each(h, entry, {
+ mrb_ary_push(mrb, ary, entry->key);
+ });
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:
@@ -1243,14 +1656,11 @@ hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
MRB_API mrb_value
mrb_hash_values(mrb_state *mrb, mrb_value hash)
{
- seglist *sg = RHASH_TBL(hash);
- size_t size;
- mrb_value ary;
-
- if (!sg || (size = sg_size(mrb, sg)) == 0)
- return mrb_ary_new(mrb);
- ary = mrb_ary_new_capa(mrb, size);
- sg_foreach(mrb, sg, hash_vals_i, (void*)&ary);
+ struct RHash *h = mrb_hash_ptr(hash);
+ mrb_value ary = mrb_ary_new_capa(mrb, (mrb_int)h_size(h));
+ h_each(h, entry, {
+ mrb_ary_push(mrb, ary, entry->val);
+ });
return ary;
}
@@ -1276,43 +1686,20 @@ 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)
{
- seglist *sg;
-
- sg = RHASH_TBL(hash);
- if (sg_get(mrb, sg, key, NULL)) {
- return TRUE;
- }
- return FALSE;
+ mrb_value val;
+ return h_get(mrb, mrb_hash_ptr(hash), key, &val);
}
static mrb_value
mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
{
- mrb_value key;
+ mrb_value key = mrb_get_arg1(mrb);
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);
}
-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 0;
-}
-
/* 15.2.13.4.14 */
/* 15.2.13.4.27 */
/*
@@ -1331,43 +1718,33 @@ hash_has_value_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
static mrb_value
mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
{
- mrb_value val;
- struct has_v_arg arg;
-
- mrb_get_args(mrb, "o", &val);
- arg.found = FALSE;
- arg.val = val;
- sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg);
- return mrb_bool_value(arg.found);
-}
-
-static int
-merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
-{
- seglist *h1 = (seglist*)data;
-
- sg_put(mrb, h1, key, val);
- return 0;
+ mrb_value val = mrb_get_arg1(mrb);
+ struct RHash *h = mrb_hash_ptr(hash);
+ h_each(h, entry, {
+ h_check_modified(mrb, h, {
+ if (mrb_equal(mrb, val, entry->val)) return mrb_true_value();
+ });
+ });
+ return mrb_false_value();
}
MRB_API void
mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
{
- seglist *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) = sg_copy(mrb, h2);
- return;
- }
- sg_foreach(mrb, h2, merge_i, h1);
- mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1));
- return;
+ struct RHash *h1, *h2;
+
+ hash_modify(mrb, hash1);
+ mrb_ensure_hash_type(mrb, hash2);
+ h1 = mrb_hash_ptr(hash1);
+ h2 = mrb_hash_ptr(hash2);
+
+ if (h1 == h2) return;
+ if (h_size(h2) == 0) return;
+ h_each(h2, entry, {
+ h_check_modified(mrb, h2, {h_set(mrb, h1, entry->key, entry->val);});
+ mrb_field_write_barrier_value(mrb, (struct RBasic *)h1, entry->key);
+ mrb_field_write_barrier_value(mrb, (struct RBasic *)h1, entry->val);
+ });
}
/*
@@ -1378,15 +1755,22 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
* values of key objects have changed since they were inserted, this
* method will reindex <i>hsh</i>.
*
- * h = {"AAA" => "b"}
- * h.keys[0].chop!
- * h.rehash #=> {"AA"=>"b"}
- * h["AA"] #=> "b"
+ * keys = (1..17).map{|n| [n]}
+ * k = keys[0]
+ * h = {}
+ * keys.each{|key| h[key] = key[0]}
+ * h #=> { [1]=>1, [2]=>2, ... [16]=>16, [17]=>17}
+ * h[k] #=> 1
+ * k[0] = keys.size + 1
+ * h #=> {[18]=>1, [2]=>2, ... [16]=>16, [17]=>17}
+ * h[k] #=> nil
+ * h.rehash
+ * h[k] #=> 1
*/
static mrb_value
mrb_hash_rehash(mrb_state *mrb, mrb_value self)
{
- sg_compact(mrb, RHASH_TBL(self));
+ h_rehash(mrb, mrb_hash_ptr(self));
return self;
}
@@ -1398,11 +1782,10 @@ mrb_init_hash(mrb_state *mrb)
mrb->hash_class = h = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
MRB_SET_INSTANCE_TT(h, MRB_TT_HASH);
- mrb_define_method(mrb, h, "initialize_copy", mrb_hash_init_copy, MRB_ARGS_REQ(1));
mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */
mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */
mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */
- mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_ANY()); /* 15.2.13.4.5 */
+ mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_OPT(1)); /* 15.2.13.4.5 */
mrb_define_method(mrb, h, "default=", mrb_hash_set_default, MRB_ARGS_REQ(1)); /* 15.2.13.4.6 */
mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */
mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */
@@ -1411,17 +1794,17 @@ mrb_init_hash(mrb_state *mrb)
mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */
mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */
mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */
- mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)); /* 15.2.13.4.16 */
+ mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.2.13.4.16 */
+ mrb_define_method(mrb, h, "initialize_copy", mrb_hash_init_copy, MRB_ARGS_REQ(1)); /* 15.2.13.4.17 */
mrb_define_method(mrb, h, "key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.18 */
mrb_define_method(mrb, h, "keys", mrb_hash_keys, MRB_ARGS_NONE()); /* 15.2.13.4.19 */
mrb_define_method(mrb, h, "length", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.20 */
mrb_define_method(mrb, h, "member?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.21 */
+ mrb_define_method(mrb, h, "replace", mrb_hash_init_copy, MRB_ARGS_REQ(1)); /* 15.2.13.4.23 */
mrb_define_method(mrb, h, "shift", mrb_hash_shift, MRB_ARGS_NONE()); /* 15.2.13.4.24 */
mrb_define_method(mrb, h, "size", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.25 */
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, "rehash", mrb_hash_rehash, MRB_ARGS_NONE());
-
- mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/
}
diff --git a/src/kernel.c b/src/kernel.c
index db681d510..4dcf6261b 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -13,13 +13,14 @@
#include <mruby/variable.h>
#include <mruby/error.h>
#include <mruby/istruct.h>
+#include <mruby/presym.h>
MRB_API mrb_bool
mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
{
struct RClass *c = mrb_class(mrb, obj);
mrb_method_t m = mrb_method_search_vm(mrb, &c, mid);
- struct RProc *p;
+ const struct RProc *p;
if (MRB_METHOD_UNDEF_P(m)) return FALSE;
if (MRB_METHOD_FUNC_P(m))
@@ -33,7 +34,7 @@ mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
static mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
- return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s);
+ return mrb_func_basic_p(mrb, obj, MRB_SYM(to_s), mrb_any_to_s);
}
/* 15.3.1.3.17 */
@@ -53,7 +54,7 @@ mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
MRB_API mrb_value
mrb_obj_inspect(mrb_state *mrb, mrb_value obj)
{
- if ((mrb_type(obj) == MRB_TT_OBJECT) && mrb_obj_basic_to_s_p(mrb, obj)) {
+ if (mrb_object_p(obj) && mrb_obj_basic_to_s_p(mrb, obj)) {
return mrb_obj_iv_inspect(mrb, mrb_obj_ptr(obj));
}
return mrb_any_to_s(mrb, obj);
@@ -71,9 +72,8 @@ mrb_obj_inspect(mrb_state *mrb, mrb_value obj)
static mrb_value
mrb_equal_m(mrb_state *mrb, mrb_value self)
{
- mrb_value arg;
+ mrb_value arg = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(mrb_equal(mrb, self, arg));
}
@@ -97,7 +97,19 @@ mrb_equal_m(mrb_state *mrb, mrb_value self)
mrb_value
mrb_obj_id_m(mrb_state *mrb, mrb_value self)
{
- return mrb_fixnum_value(mrb_obj_id(self));
+ return mrb_int_value(mrb, mrb_obj_id(self));
+}
+
+static int
+env_bidx(struct REnv *e)
+{
+ int bidx;
+
+ /* use saved block arg position */
+ bidx = MRB_ENV_BIDX(e);
+ /* bidx may be useless (e.g. define_method) */
+ if (bidx >= MRB_ENV_LEN(e)) return -1;
+ return bidx;
}
/* 15.3.1.2.2 */
@@ -130,7 +142,9 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
mrb_callinfo *ci = &mrb->c->ci[-1];
mrb_callinfo *cibase = mrb->c->cibase;
mrb_value *bp;
- struct RProc *p;
+ int bidx;
+ struct REnv *e = NULL;
+ const struct RProc *p;
if (ci <= cibase) {
/* toplevel does not have block */
@@ -140,33 +154,39 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
/* search method/class/module proc */
while (p) {
if (MRB_PROC_SCOPE_P(p)) break;
+ e = MRB_PROC_ENV(p);
p = p->upper;
}
if (p == NULL) return mrb_false_value();
+ if (e) {
+ bidx = env_bidx(e);
+ if (bidx < 0) return mrb_false_value();
+ bp = &e->stack[bidx];
+ goto block_given;
+ }
/* search ci corresponding to proc */
while (cibase < ci) {
if (ci->proc == p) break;
ci--;
}
if (ci == cibase) {
- return mrb_false_value();
+ /* proc is closure */
+ if (!MRB_PROC_ENV_P(p)) return mrb_false_value();
+ e = MRB_PROC_ENV(p);
+ bidx = env_bidx(e);
+ if (bidx < 0) return mrb_false_value();
+ bp = &e->stack[bidx];
}
- else if (ci->env) {
- struct REnv *e = ci->env;
- int bidx;
-
+ else if ((e = mrb_vm_ci_env(ci)) != NULL) {
/* top-level does not have block slot (always false) */
- if (e->stack == mrb->c->stbase)
- return mrb_false_value();
- /* use saved block arg position */
- bidx = MRB_ENV_BIDX(e);
+ if (e->stack == mrb->c->stbase) return mrb_false_value();
+ bidx = env_bidx(e);
/* bidx may be useless (e.g. define_method) */
- if (bidx >= MRB_ENV_STACK_LEN(e))
- return mrb_false_value();
+ if (bidx < 0) return mrb_false_value();
bp = &e->stack[bidx];
}
else {
- bp = ci[1].stackent+1;
+ bp = ci->stack+1;
if (ci->argc >= 0) {
bp += ci->argc;
}
@@ -174,6 +194,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
bp++;
}
}
+ block_given:
if (mrb_nil_p(*bp))
return mrb_false_value();
return mrb_true_value();
@@ -188,7 +209,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
* called with an explicit receiver, as <code>class</code> is also a
* reserved word in Ruby.
*
- * 1.class #=> Fixnum
+ * 1.class #=> Integer
* self.class #=> Object
*/
static mrb_value
@@ -197,201 +218,20 @@ mrb_obj_class_m(mrb_state *mrb, mrb_value self)
return mrb_obj_value(mrb_obj_class(mrb, self));
}
-static struct RClass*
-mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
-{
- struct RClass *klass = mrb_basic_ptr(obj)->c;
-
- if (klass->tt != MRB_TT_SCLASS)
- return klass;
- else {
- /* copy singleton(unnamed) class */
- struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class);
-
- switch (mrb_type(obj)) {
- case MRB_TT_CLASS:
- case MRB_TT_SCLASS:
- break;
- default:
- clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass));
- break;
- }
- clone->super = klass->super;
- if (klass->iv) {
- mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
- mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern_lit(mrb, "__attached__"), obj);
- }
- if (klass->mt) {
- clone->mt = kh_copy(mt, mrb, klass->mt);
- }
- else {
- clone->mt = kh_init(mt, mrb);
- }
- clone->tt = MRB_TT_SCLASS;
- return clone;
- }
-}
-
-static void
-copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
-{
- struct RClass *dc = mrb_class_ptr(dst);
- 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_FL_CLASS_IS_PREPENDED) {
- struct RClass *c0 = sc->super;
- struct RClass *c1 = dc;
-
- /* copy prepended iclasses */
- 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_FL_CLASS_IS_ORIGIN;
- }
- if (sc->mt) {
- dc->mt = kh_copy(mt, mrb, sc->mt);
- }
- else {
- dc->mt = kh_init(mt, mrb);
- }
- dc->super = sc->super;
- MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc));
-}
-
-static void
-init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
-{
- switch (mrb_type(obj)) {
- case MRB_TT_ICLASS:
- copy_class(mrb, dest, obj);
- return;
- case MRB_TT_CLASS:
- case MRB_TT_MODULE:
- copy_class(mrb, dest, obj);
- mrb_iv_copy(mrb, dest, obj);
- mrb_iv_remove(mrb, dest, mrb_intern_lit(mrb, "__classname__"));
- break;
- case MRB_TT_OBJECT:
- case MRB_TT_SCLASS:
- case MRB_TT_HASH:
- case MRB_TT_DATA:
- case MRB_TT_EXCEPTION:
- mrb_iv_copy(mrb, dest, obj);
- break;
- case MRB_TT_ISTRUCT:
- mrb_istruct_copy(dest, obj);
- break;
-
- default:
- break;
- }
- mrb_funcall(mrb, dest, "initialize_copy", 1, obj);
-}
-
-/* 15.3.1.3.8 */
-/*
- * call-seq:
- * obj.clone -> an_object
- *
- * Produces a shallow copy of <i>obj</i>---the instance variables of
- * <i>obj</i> are copied, but not the objects they reference. Copies
- * the frozen state of <i>obj</i>. See also the discussion
- * under <code>Object#dup</code>.
- *
- * class Klass
- * attr_accessor :str
- * end
- * s1 = Klass.new #=> #<Klass:0x401b3a38>
- * s1.str = "Hello" #=> "Hello"
- * s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello">
- * s2.str[1,4] = "i" #=> "i"
- * s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">"
- * s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">"
- *
- * This method may have class-specific behavior. If so, that
- * behavior will be documented under the #+initialize_copy+ method of
- * the class.
- *
- * Some Class(True False Nil Symbol Fixnum Float) Object cannot clone.
- */
-MRB_API mrb_value
-mrb_obj_clone(mrb_state *mrb, mrb_value self)
-{
- struct RObject *p;
- mrb_value clone;
-
- if (mrb_immediate_p(self)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self);
- }
- if (mrb_type(self) == MRB_TT_SCLASS) {
- mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class");
- }
- p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self));
- p->c = mrb_singleton_class_clone(mrb, 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 & MRB_FL_OBJ_IS_FROZEN;
-
- return clone;
-}
-
-/* 15.3.1.3.9 */
-/*
- * call-seq:
- * obj.dup -> an_object
- *
- * Produces a shallow copy of <i>obj</i>---the instance variables of
- * <i>obj</i> are copied, but not the objects they reference.
- * <code>dup</code> copies the frozen state of <i>obj</i>. See also
- * the discussion under <code>Object#clone</code>. In general,
- * <code>clone</code> and <code>dup</code> may have different semantics
- * in descendant classes. While <code>clone</code> is used to duplicate
- * an object, including its internal state, <code>dup</code> typically
- * uses the class of the descendant object to create the new instance.
- *
- * This method may have class-specific behavior. If so, that
- * behavior will be documented under the #+initialize_copy+ method of
- * the class.
- */
-
-MRB_API mrb_value
-mrb_obj_dup(mrb_state *mrb, mrb_value obj)
-{
- struct RBasic *p;
- mrb_value dup;
-
- if (mrb_immediate_p(obj)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj);
- }
- if (mrb_type(obj) == MRB_TT_SCLASS) {
- mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class");
- }
- p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj));
- dup = mrb_obj_value(p);
- init_copy(mrb, dup, obj);
-
- return dup;
-}
-
static mrb_value
-mrb_obj_extend(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value obj)
+mrb_obj_extend(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value obj)
{
mrb_int i;
if (argc == 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (at least 1)");
+ mrb_argnum_error(mrb, argc, 1, -1);
}
for (i = 0; i < argc; i++) {
mrb_check_type(mrb, argv[i], MRB_TT_MODULE);
}
while (argc--) {
- mrb_funcall(mrb, argv[argc], "extend_object", 1, obj);
- mrb_funcall(mrb, argv[argc], "extended", 1, obj);
+ mrb_funcall_id(mrb, argv[argc], MRB_SYM(extend_object), 1, obj);
+ mrb_funcall_id(mrb, argv[argc], MRB_SYM(extended), 1, obj);
}
return obj;
}
@@ -424,34 +264,22 @@ mrb_obj_extend(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value obj)
static mrb_value
mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
{
- mrb_value *argv;
+ const mrb_value *argv;
mrb_int argc;
mrb_get_args(mrb, "*", &argv, &argc);
return mrb_obj_extend(mrb, argc, argv, self);
}
-static mrb_value
+MRB_API 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;
}
@@ -459,26 +287,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 */
@@ -486,25 +295,24 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self)
* call-seq:
* obj.hash -> fixnum
*
- * Generates a <code>Fixnum</code> hash value for this object. This
+ * Generates a <code>Integer</code> hash value for this object. This
* function must have the property that <code>a.eql?(b)</code> implies
* <code>a.hash == b.hash</code>. The hash value is used by class
* <code>Hash</code>. Any hash value that exceeds the capacity of a
- * <code>Fixnum</code> will be truncated before being used.
+ * <code>Integer</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));
+ return mrb_int_value(mrb, mrb_obj_id(self));
}
/* 15.3.1.3.16 */
-static mrb_value
+mrb_value
mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
{
- mrb_value orig;
+ mrb_value orig = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &orig);
if (mrb_obj_equal(mrb, self, orig)) return self;
if ((mrb_type(self) != mrb_type(orig)) || (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig))) {
mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object");
@@ -512,7 +320,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
return self;
}
-
MRB_API mrb_bool
mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
{
@@ -531,11 +338,11 @@ mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
static mrb_value
obj_is_instance_of(mrb_state *mrb, mrb_value self)
{
- mrb_value arg;
+ struct RClass *c;
- mrb_get_args(mrb, "C", &arg);
+ mrb_get_args(mrb, "c", &c);
- return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg)));
+ return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, c));
}
/* 15.3.1.3.24 */
@@ -568,16 +375,13 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
{
- mrb_value arg;
+ struct RClass *c;
- mrb_get_args(mrb, "C", &arg);
+ mrb_get_args(mrb, "c", &c);
- return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg)));
+ return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, c));
}
-KHASH_DECLARE(st, mrb_sym, char, FALSE)
-KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal)
-
/* 15.3.1.3.32 */
/*
* call_seq:
@@ -619,8 +423,8 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
mrb_value a[2], exc;
mrb_int argc;
-
argc = mrb_get_args(mrb, "|oo", &a[0], &a[1]);
+ mrb->c->ci->mid = 0;
switch (argc) {
case 0:
mrb_raise(mrb, E_RUNTIME_ERROR, "");
@@ -640,16 +444,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:
@@ -682,7 +476,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
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));
+ mrb_name_error(mrb, sym, "instance variable %n not defined", sym);
}
return val;
}
@@ -690,7 +484,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
void
mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
{
- mrb_no_method_error(mrb, name, args, "undefined method '%S'", mrb_sym2str(mrb, name));
+ mrb_no_method_error(mrb, name, args, "undefined method '%n'", name);
}
/* 15.3.1.3.30 */
@@ -716,7 +510,7 @@ mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
* # ...
* end
* def method_missing(methId)
- * str = methId.id2name
+ * str = methId.to_s
* romanToInt(str)
* end
* end
@@ -726,26 +520,26 @@ mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
* r.xxiii #=> 23
* r.mm #=> 2000
*/
-#ifdef MRB_DEFAULT_METHOD_MISSING
-static mrb_value
+mrb_value
mrb_obj_missing(mrb_state *mrb, mrb_value mod)
{
mrb_sym name;
- mrb_value *a;
+ const mrb_value *a;
mrb_int alen;
+ mrb->c->ci->mid = 0;
mrb_get_args(mrb, "n*!", &name, &a, &alen);
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
return mrb_nil_value();
}
-#endif
static inline mrb_bool
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:
@@ -765,45 +559,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?");
+ rtm_id = MRB_SYM_Q(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));
@@ -815,12 +580,30 @@ obj_respond_to(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
{
- mrb_value v;
+ mrb_value v = mrb_get_arg1(mrb);
mrb_int i, len;
- mrb_sym eqq = mrb_intern_lit(mrb, "===");
- mrb_value ary = mrb_ary_splat(mrb, self);
+ mrb_sym eqq = MRB_OPSYM(eqq);
+ mrb_value ary;
- mrb_get_args(mrb, "o", &v);
+ mrb->c->ci->mid = 0;
+ if (mrb_array_p(self)) {
+ ary = self;
+ }
+ else if (mrb_nil_p(self)) {
+ return mrb_false_value();
+ }
+ else if (!mrb_respond_to(mrb, self, mrb_intern_lit(mrb, "to_a"))) {
+ mrb_value c = mrb_funcall_argv(mrb, self, eqq, 1, &v);
+ if (mrb_test(c)) return mrb_true_value();
+ return mrb_false_value();
+ }
+ else {
+ ary = mrb_funcall(mrb, self, "to_a", 0);
+ if (mrb_nil_p(ary)) {
+ return mrb_funcall_argv(mrb, self, eqq, 1, &v);
+ }
+ mrb_ensure_array_type(mrb, ary);
+ }
len = RARRAY_LEN(ary);
for (i=0; i<len; i++) {
mrb_value c = mrb_funcall_argv(mrb, mrb_ary_entry(ary, i), eqq, 1, &v);
@@ -830,6 +613,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
}
mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value);
+
void
mrb_init_kernel(mrb_state *mrb)
{
@@ -848,11 +632,9 @@ 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 */
@@ -861,19 +643,16 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */
mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
-#ifdef MRB_DEFAULT_METHOD_MISSING
mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
-#endif
mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */
mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */
- mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */
+ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ARG(1,1)); /* 15.3.1.3.43 */
mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */
mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */
-
- mrb_define_method(mrb, krn, "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_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */
}
diff --git a/src/load.c b/src/load.c
index 54b50b14d..bd0811743 100644
--- a/src/load.c
+++ b/src/load.c
@@ -7,50 +7,74 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include <mruby/dump.h>
#include <mruby/irep.h>
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/debug.h>
#include <mruby/error.h>
+#include <mruby/data.h>
+#include <mruby/endian.h>
#if SIZE_MAX < UINT32_MAX
# error size_t must be at least 32 bits wide
#endif
-#define FLAG_BYTEORDER_BIG 2
-#define FLAG_BYTEORDER_LIL 4
-#define FLAG_BYTEORDER_NATIVE 8
#define FLAG_SRC_MALLOC 1
#define FLAG_SRC_STATIC 0
#define SIZE_ERROR_MUL(nmemb, size) ((size_t)(nmemb) > SIZE_MAX / (size))
-static size_t
-skip_padding(const uint8_t *buf)
-{
- const size_t align = MRB_DUMP_ALIGNMENT;
- return -(intptr_t)buf & (align-1);
-}
+#define DEFINE_READ_IREP_FUNC(funcdecl, basecall) \
+ funcdecl \
+ { \
+ int ai = mrb_gc_arena_save(mrb); \
+ struct RProc *proc = basecall; \
+ struct mrb_irep *irep = (mrb_irep*)(proc ? proc->body.irep : NULL); \
+ if (irep) proc->body.irep = NULL; \
+ mrb_gc_arena_restore(mrb, ai); \
+ return irep; \
+ }
-static size_t
-offset_crc_body(void)
+#ifndef MRB_NO_FLOAT
+static double
+str_to_double(mrb_state *mrb, const char *p)
{
- struct rite_binary_header header;
- return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc);
+ /* dump IEEE754 little endian binary */
+ union {
+ char s[sizeof(double)];
+ double f;
+ } u;
+
+ if (littleendian) {
+ memcpy(u.s, p, sizeof(double));
+ }
+ else {
+ size_t i;
+ for (i=0; i<sizeof(double); i++) {
+ u.s[i] = p[sizeof(double)-i-1];
+ }
+ }
+ return u.f;
}
+#endif
-static mrb_irep*
-read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
+static mrb_bool
+read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp)
{
int i;
const uint8_t *src = bin;
ptrdiff_t diff;
uint16_t tt, pool_data_len, snl;
int plen;
+ mrb_pool_value *pool;
+ mrb_sym *syms;
int ai = mrb_gc_arena_save(mrb);
mrb_irep *irep = mrb_add_irep(mrb);
+ *irepp = irep;
+
/* skip record size */
src += sizeof(uint32_t);
@@ -63,237 +87,213 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
src += sizeof(uint16_t);
/* number of child irep */
- irep->rlen = (size_t)bin_to_uint16(src);
+ irep->rlen = (uint8_t)bin_to_uint16(src);
src += sizeof(uint16_t);
/* Binary Data Section */
- /* ISEQ BLOCK */
- irep->ilen = (uint16_t)bin_to_uint32(src);
- src += sizeof(uint32_t);
- src += skip_padding(src);
+ /* ISEQ BLOCK (and CATCH HANDLER TABLE BLOCK) */
+ irep->clen = bin_to_uint16(src); /* number of catch handler */
+ src += sizeof(uint16_t);
+ irep->ilen = bin_to_uint16(src);
+ src += sizeof(uint16_t);
if (irep->ilen > 0) {
+ size_t data_len = sizeof(mrb_code) * irep->ilen +
+ sizeof(struct mrb_irep_catch_handler) * irep->clen;
+ mrb_static_assert1(sizeof(struct mrb_irep_catch_handler) == 13);
if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
- return NULL;
+ return FALSE;
}
- if ((flags & FLAG_SRC_MALLOC) == 0 &&
- (flags & FLAG_BYTEORDER_NATIVE)) {
+ if ((flags & FLAG_SRC_MALLOC) == 0) {
irep->iseq = (mrb_code*)src;
- src += sizeof(mrb_code) * irep->ilen;
irep->flags |= MRB_ISEQ_NO_FREE;
}
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);
- }
- }
+ void *buf = mrb_malloc(mrb, data_len);
+ irep->iseq = (mrb_code *)buf;
+ memcpy(buf, src, data_len);
}
+ src += data_len;
}
/* POOL BLOCK */
- plen = bin_to_uint32(src); /* number of pool */
- src += sizeof(uint32_t);
+ plen = bin_to_uint16(src); /* number of pool */
+ src += sizeof(uint16_t);
if (plen > 0) {
if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
- return NULL;
+ return FALSE;
}
- irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen);
+ irep->pool = pool = (mrb_pool_value*)mrb_calloc(mrb, sizeof(mrb_pool_value), plen);
for (i = 0; i < plen; i++) {
- mrb_value s;
+ mrb_bool st = (flags & FLAG_SRC_MALLOC)==0;
tt = *src++; /* pool TT */
- pool_data_len = bin_to_uint16(src); /* pool data length */
- src += sizeof(uint16_t);
- if (flags & FLAG_SRC_MALLOC) {
- s = mrb_str_new(mrb, (char *)src, pool_data_len);
- }
- else {
- s = mrb_str_new_static(mrb, (char *)src, pool_data_len);
- }
- src += pool_data_len;
switch (tt) { /* pool data */
- case IREP_TT_FIXNUM: {
- mrb_value num = mrb_str_to_inum(mrb, s, 10, FALSE);
-#ifdef MRB_WITHOUT_FLOAT
- irep->pool[i] = num;
+ case IREP_TT_INT32:
+ {
+ mrb_int v = (int32_t)bin_to_uint32(src);
+ src += sizeof(uint32_t);
+#ifdef MRB_64BIT
+ pool[i].tt = IREP_TT_INT64;
+ pool[i].u.i64 = (int64_t)v;
#else
- irep->pool[i] = mrb_float_p(num)? mrb_float_pool(mrb, mrb_float(num)) : num;
+ pool[i].tt = IREP_TT_INT32;
+ pool[i].u.i32 = v;
#endif
}
break;
+ case IREP_TT_INT64:
+#ifdef MRB_INT64
+ {
+ uint64_t i64 = bin_to_uint32(src);
+ src += sizeof(uint32_t);
+ i64 <<= 32;
+ i64 |= bin_to_uint32(src);
+ src += sizeof(uint32_t);
+ pool[i].tt = tt;
+ pool[i].u.i64 = (int64_t)i64;
+ }
+ break;
+#else
+ return FALSE;
+#endif
+
+ case IREP_TT_BIGINT:
+ pool_data_len = bin_to_uint8(src); /* pool data length */
+ src += sizeof(uint8_t);
+ {
+ char *p;
+ pool[i].tt = IREP_TT_BIGINT;
+ p = (char*)mrb_malloc(mrb, pool_data_len+2);
+ memcpy(p, src, pool_data_len+2);
+ pool[i].u.str = (const char*)p;
+ }
+ src += pool_data_len + 2;
+ break;
-#ifndef MRB_WITHOUT_FLOAT
case IREP_TT_FLOAT:
- irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE));
+#ifndef MRB_NO_FLOAT
+ pool[i].tt = tt;
+ pool[i].u.f = str_to_double(mrb, (const char*)src);
+ src += sizeof(double);
break;
+#else
+ return FALSE; /* MRB_NO_FLOAT */
#endif
- case IREP_TT_STRING:
- irep->pool[i] = mrb_str_pool(mrb, s);
+ case IREP_TT_STR:
+ pool_data_len = bin_to_uint16(src); /* pool data length */
+ src += sizeof(uint16_t);
+ if (st) {
+ pool[i].tt = (pool_data_len<<2) | IREP_TT_SSTR;
+ pool[i].u.str = (const char*)src;
+ }
+ else {
+ char *p;
+ pool[i].tt = (pool_data_len<<2) | IREP_TT_STR;
+ p = (char*)mrb_malloc(mrb, pool_data_len+1);
+ memcpy(p, src, pool_data_len+1);
+ pool[i].u.str = (const char*)p;
+ }
+ src += pool_data_len + 1;
break;
default:
/* should not happen */
- irep->pool[i] = mrb_nil_value();
- break;
+ return FALSE;
}
- irep->plen++;
- mrb_gc_arena_restore(mrb, ai);
+ irep->plen = i+1;
}
}
/* SYMS BLOCK */
- irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */
- src += sizeof(uint32_t);
+ irep->slen = bin_to_uint16(src); /* syms length */
+ src += sizeof(uint16_t);
if (irep->slen > 0) {
if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
- return NULL;
+ return FALSE;
}
- irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
+ irep->syms = syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
for (i = 0; i < irep->slen; i++) {
snl = bin_to_uint16(src); /* symbol name length */
src += sizeof(uint16_t);
if (snl == MRB_DUMP_NULL_SYM_LEN) {
- irep->syms[i] = 0;
+ syms[i] = 0;
continue;
}
if (flags & FLAG_SRC_MALLOC) {
- irep->syms[i] = mrb_intern(mrb, (char *)src, snl);
+ syms[i] = mrb_intern(mrb, (char *)src, snl);
}
else {
- irep->syms[i] = mrb_intern_static(mrb, (char *)src, snl);
+ syms[i] = mrb_intern_static(mrb, (char *)src, snl);
}
src += snl + 1;
-
mrb_gc_arena_restore(mrb, ai);
}
}
- irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*irep->rlen);
-
diff = src - bin;
mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
*len = (size_t)diff;
- return irep;
+ return TRUE;
}
-static mrb_irep*
-read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
+static mrb_bool
+read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp)
{
- mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags);
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_bool readsuccess = read_irep_record_1(mrb, bin, len, flags, irepp);
+ mrb_irep **reps;
int i;
- if (irep == NULL) {
- return NULL;
+ mrb_gc_arena_restore(mrb, ai);
+ if (!readsuccess) {
+ return FALSE;
}
+ reps = (mrb_irep**)mrb_calloc(mrb, (*irepp)->rlen, sizeof(mrb_irep*));
+ (*irepp)->reps = (const mrb_irep**)reps;
+
bin += *len;
- for (i=0; i<irep->rlen; i++) {
+ for (i=0; i<(*irepp)->rlen; i++) {
size_t rlen;
- irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags);
- if (irep->reps[i] == NULL) {
- return NULL;
+ readsuccess = read_irep_record(mrb, bin, &rlen, flags, &reps[i]);
+ mrb_gc_arena_restore(mrb, ai);
+ if (!readsuccess) {
+ return FALSE;
}
bin += rlen;
*len += rlen;
}
- return irep;
+
+ return TRUE;
}
static mrb_irep*
-read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
+read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags, struct RProc **proc)
{
size_t len;
- bin += sizeof(struct rite_section_irep_header);
- return read_irep_record(mrb, bin, &len, flags);
-}
+ /*
+ * This proc object keeps all the data in progress to avoid memory leaks
+ * if something goes wrong while reading irep.
+ */
+ *proc = mrb_proc_new(mrb, NULL);
-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);
+ mrb_irep **irepp = (mrb_irep**)&(*proc)->body.irep;
+ bin += sizeof(struct rite_section_irep_header);
+ if (read_irep_record(mrb, bin, &len, flags, irepp)) {
+ return *irepp;
}
-
- 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;
+ else {
+ return NULL;
}
- 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
@@ -304,26 +304,26 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
size_t record_size;
uint16_t f_idx;
int i;
+ mrb_irep_debug_info *debug;
if (irep->debug_info) { return MRB_DUMP_INVALID_IREP; }
- irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
- irep->debug_info->pc_count = (uint32_t)irep->ilen;
+ irep->debug_info = debug = (mrb_irep_debug_info*)mrb_calloc(mrb, 1, sizeof(mrb_irep_debug_info));
+ debug->pc_count = (uint32_t)irep->ilen;
record_size = (size_t)bin_to_uint32(bin);
bin += sizeof(uint32_t);
- irep->debug_info->flen = bin_to_uint16(bin);
- irep->debug_info->files = (mrb_irep_debug_info_file**)mrb_malloc(mrb, sizeof(mrb_irep_debug_info*) * irep->debug_info->flen);
+ debug->flen = bin_to_uint16(bin);
+ debug->files = (mrb_irep_debug_info_file**)mrb_calloc(mrb, irep->debug_info->flen, sizeof(mrb_irep_debug_info*));
bin += sizeof(uint16_t);
- for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ for (f_idx = 0; f_idx < debug->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;
+ file = (mrb_irep_debug_info_file *)mrb_calloc(mrb, 1, sizeof(*file));
+ debug->files[f_idx] = file;
file->start_pos = bin_to_uint32(bin);
bin += sizeof(uint32_t);
@@ -333,8 +333,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);
@@ -354,8 +352,8 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
case mrb_debug_line_flat_map: {
uint32_t l;
- file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(
- mrb, sizeof(mrb_irep_debug_info_line) * (size_t)(file->line_entry_count));
+ file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_calloc(
+ mrb, (size_t)(file->line_entry_count), sizeof(mrb_irep_debug_info_line));
for (l = 0; l < file->line_entry_count; ++l) {
file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
bin += sizeof(uint32_t);
@@ -364,6 +362,12 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
}
} break;
+ case mrb_debug_line_packed_map: {
+ file->lines.packed_map = (uint8_t*)mrb_calloc(mrb, 1, (size_t)file->line_entry_count);
+ memcpy(file->lines.packed_map, bin, file->line_entry_count);
+ bin += file->line_entry_count;
+ } break;
+
default: return MRB_DUMP_GENERAL_FAILURE;
}
}
@@ -379,7 +383,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
size_t len;
int ret;
- ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
+ ret = read_debug_record(mrb, bin, (mrb_irep*)irep->reps[i], &len, filenames, filenames_len);
if (ret != MRB_DUMP_OK) return ret;
bin += len;
}
@@ -402,6 +406,7 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t
int result;
uint16_t filenames_len;
mrb_sym *filenames;
+ mrb_value filenames_obj;
bin = start;
header = (struct rite_section_debug_header *)bin;
@@ -409,7 +414,8 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t
filenames_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
- filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len);
+ filenames_obj = mrb_str_new(mrb, NULL, sizeof(mrb_sym) * (size_t)filenames_len);
+ filenames = (mrb_sym*)RSTRING_PTR(filenames_obj);
for (i = 0; i < filenames_len; ++i) {
uint16_t f_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
@@ -433,7 +439,7 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t
}
debug_exit:
- mrb_free(mrb, filenames);
+ mrb_str_resize(mrb, filenames_obj, 0);
return result;
}
@@ -441,34 +447,31 @@ static int
read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *record_len, mrb_sym const *syms, uint32_t syms_len)
{
const uint8_t *bin = start;
+ mrb_sym *lv;
ptrdiff_t diff;
int i;
- irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (irep->nlocals - 1));
+ irep->lv = lv = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (irep->nlocals - 1));
- for (i = 0; i + 1< irep->nlocals; ++i) {
+ for (i = 0; i + 1 < irep->nlocals; ++i) {
uint16_t const sym_idx = bin_to_uint16(bin);
bin += sizeof(uint16_t);
if (sym_idx == RITE_LV_NULL_MARK) {
- irep->lv[i].name = 0;
- irep->lv[i].r = 0;
+ lv[i] = 0;
}
else {
if (sym_idx >= syms_len) {
return MRB_DUMP_GENERAL_FAILURE;
}
- irep->lv[i].name = syms[sym_idx];
-
- irep->lv[i].r = bin_to_uint16(bin);
+ lv[i] = syms[sym_idx];
}
- bin += sizeof(uint16_t);
}
for (i = 0; i < irep->rlen; ++i) {
size_t len;
int ret;
- ret = read_lv_record(mrb, bin, irep->reps[i], &len, syms, syms_len);
+ ret = read_lv_record(mrb, bin, (mrb_irep*)irep->reps[i], &len, syms, syms_len);
if (ret != MRB_DUMP_OK) return ret;
bin += len;
}
@@ -491,6 +494,7 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t fl
int result;
uint32_t syms_len;
mrb_sym *syms;
+ mrb_value syms_obj;
mrb_sym (*intern_func)(mrb_state*, const char*, size_t) =
(flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static;
@@ -500,7 +504,8 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t fl
syms_len = bin_to_uint32(bin);
bin += sizeof(uint32_t);
- syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)syms_len);
+ syms_obj = mrb_str_new(mrb, NULL, sizeof(mrb_sym) * (size_t)syms_len);
+ syms = (mrb_sym*)RSTRING_PTR(syms_obj);
for (i = 0; i < syms_len; ++i) {
uint16_t const str_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
@@ -520,77 +525,66 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t fl
}
lv_exit:
- mrb_free(mrb, syms);
+ mrb_str_resize(mrb, syms_obj, 0);
return result;
}
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, uint8_t *flags)
{
const struct rite_binary_header *header = (const struct rite_binary_header *)bin;
- if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) {
- if (bigendian_p())
- *flags |= FLAG_BYTEORDER_NATIVE;
- else
- *flags |= FLAG_BYTEORDER_BIG;
+ if (bufsize < sizeof(struct rite_binary_header)) {
+ return MRB_DUMP_READ_FAULT;
}
- else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) {
- if (bigendian_p())
- *flags |= FLAG_BYTEORDER_LIL;
- else
- *flags |= FLAG_BYTEORDER_NATIVE;
- }
- else {
+
+ if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) != 0) {
return MRB_DUMP_INVALID_FILE_HEADER;
}
- if (crc) {
- *crc = bin_to_uint16(header->binary_crc);
+ /* if major version is different, they are incompatible */
+ if (memcmp(header->major_version, RITE_BINARY_MAJOR_VER, sizeof(header->major_version)) != 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER;
}
+ /* if minor version is different, we can accept the older version */
+ if (memcmp(header->minor_version, RITE_BINARY_MINOR_VER, sizeof(header->minor_version)) > 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER;
+ }
+
*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)
+static struct RProc*
+read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags)
{
int result;
+ struct RProc *proc = NULL;
mrb_irep *irep = NULL;
const struct rite_section_header *section_header;
- uint16_t crc;
size_t bin_size = 0;
- size_t n;
if ((mrb == NULL) || (bin == NULL)) {
return NULL;
}
- result = read_binary_header(bin, &bin_size, &crc, &flags);
+ result = read_binary_header(bin, bufsize, &bin_size, &flags);
if (result != MRB_DUMP_OK) {
return NULL;
}
- n = offset_crc_body();
- if (crc != calc_crc_16_ccitt(bin + n, bin_size - n, 0)) {
- return NULL;
- }
-
bin += sizeof(struct rite_binary_header);
do {
section_header = (const struct rite_section_header *)bin;
if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) {
- irep = read_section_irep(mrb, bin, flags);
+ irep = read_section_irep(mrb, bin, flags, &proc);
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);
@@ -608,43 +602,53 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
bin += bin_to_uint32(section_header->section_size);
} while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0);
- return irep;
+ return proc;
}
-mrb_irep*
-mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
+static struct RProc*
+mrb_proc_read_irep(mrb_state *mrb, const uint8_t *bin)
{
-#ifdef MRB_USE_ETEXT_EDATA
+#if defined(MRB_USE_LINK_TIME_RO_DATA_P) || defined(MRB_USE_CUSTOM_RO_DATA_P)
uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
#else
uint8_t flags = FLAG_SRC_STATIC;
#endif
- return read_irep(mrb, bin, flags);
+ return read_irep(mrb, bin, (size_t)-1, flags);
+}
+
+DEFINE_READ_IREP_FUNC(
+ mrb_irep *mrb_read_irep(mrb_state *mrb, const uint8_t *bin),
+ mrb_proc_read_irep(mrb, bin))
+
+static struct RProc*
+mrb_proc_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize)
+{
+ return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC);
}
+DEFINE_READ_IREP_FUNC(
+ MRB_API mrb_irep *mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize),
+ mrb_proc_read_irep_buf(mrb, buf, bufsize))
+
void mrb_exc_set(mrb_state *mrb, mrb_value exc);
static void
irep_error(mrb_state *mrb)
{
- mrb_exc_set(mrb, mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
+ mrb_exc_set(mrb, mrb_exc_new_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
void mrb_codedump_all(mrb_state*, struct RProc*);
static mrb_value
-load_irep(mrb_state *mrb, mrb_irep *irep, mrbc_context *c)
+load_irep(mrb_state *mrb, struct RProc *proc, mrbc_context *c)
{
- struct RProc *proc;
-
- if (!irep) {
+ if (!proc || !proc->body.irep) {
irep_error(mrb);
return mrb_nil_value();
}
- proc = mrb_proc_new(mrb, irep);
proc->c = NULL;
- mrb_irep_decref(mrb, irep);
if (c && c->dump_result) mrb_codedump_all(mrb, proc);
if (c && c->no_exec) return mrb_obj_value(proc);
return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
@@ -653,7 +657,15 @@ load_irep(mrb_state *mrb, mrb_irep *irep, mrbc_context *c)
MRB_API mrb_value
mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
{
- return load_irep(mrb, mrb_read_irep(mrb, bin), c);
+ struct RProc *proc = mrb_proc_read_irep(mrb, bin);
+ if (!proc) return mrb_undef_value();
+ return load_irep(mrb, proc, 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_proc_read_irep_buf(mrb, buf, bufsize), c);
}
MRB_API mrb_value
@@ -662,12 +674,24 @@ mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
return mrb_load_irep_cxt(mrb, bin, NULL);
}
-#ifndef MRB_DISABLE_STDIO
+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);
+}
-mrb_irep*
-mrb_read_irep_file(mrb_state *mrb, FILE* fp)
+MRB_API mrb_value
+mrb_load_proc(mrb_state *mrb, const struct RProc *proc)
{
- mrb_irep *irep = NULL;
+ return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
+}
+
+#ifndef MRB_NO_STDIO
+
+static struct RProc*
+mrb_proc_read_irep_file(mrb_state *mrb, FILE *fp)
+{
+ struct RProc *proc = NULL;
uint8_t *buf;
const size_t header_size = sizeof(struct rite_binary_header);
size_t buf_size = 0;
@@ -682,7 +706,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, &flags);
if (result != MRB_DUMP_OK || buf_size <= header_size) {
goto irep_exit;
}
@@ -691,17 +715,21 @@ 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);
+ proc = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC);
irep_exit:
mrb_free(mrb, buf);
- return irep;
+ return proc;
}
+DEFINE_READ_IREP_FUNC(
+ mrb_irep *mrb_read_irep_file(mrb_state *mrb, FILE *fp),
+ mrb_proc_read_irep_file(mrb, fp))
+
MRB_API mrb_value
mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
{
- return load_irep(mrb, mrb_read_irep_file(mrb, fp), c);
+ return load_irep(mrb, mrb_proc_read_irep_file(mrb, fp), c);
}
MRB_API mrb_value
@@ -709,4 +737,4 @@ mrb_load_irep_file(mrb_state *mrb, FILE* fp)
{
return mrb_load_irep_file_cxt(mrb, fp, NULL);
}
-#endif /* MRB_DISABLE_STDIO */
+#endif /* MRB_NO_STDIO */
diff --git a/src/mruby_core.rake b/src/mruby_core.rake
deleted file mode 100644
index bb3d7b633..000000000
--- a/src/mruby_core.rake
+++ /dev/null
@@ -1,20 +0,0 @@
-MRuby.each_target do
- current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd)
- relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT)
- current_build_dir = "#{build_dir}/#{relative_from_root}"
-
- 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
-
- file libfile("#{build_dir}/lib/libmruby_core") => objs do |t|
- archiver.run t.name, t.prerequisites
- end
-end
diff --git a/src/numeric.c b/src/numeric.c
index f7f0318e8..b22026ebb 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -1,50 +1,65 @@
/*
-** numeric.c - Numeric, Integer, Float, Fixnum class
+** numeric.c - Numeric, Integer, Float class
**
** See Copyright Notice in mruby.h
*/
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
#include <float.h>
#include <math.h>
#endif
#include <limits.h>
#include <stdlib.h>
+#include <string.h>
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
+#include <mruby/presym.h>
-#ifndef MRB_WITHOUT_FLOAT
-#ifdef MRB_USE_FLOAT
+#ifndef MRB_NO_FLOAT
+#ifdef MRB_USE_FLOAT32
#define trunc(f) truncf(f)
-#define floor(f) floorf(f)
-#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define MRB_FLO_TO_STR_FMT "%.8g"
#else
-#define MRB_FLO_TO_STR_FMT "%.16g"
#endif
#endif
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
MRB_API mrb_float
-mrb_to_flo(mrb_state *mrb, mrb_value val)
+mrb_as_float(mrb_state *mrb, mrb_value val)
{
switch (mrb_type(val)) {
- case MRB_TT_FIXNUM:
- return (mrb_float)mrb_fixnum(val);
+ case MRB_TT_INTEGER:
+ return (mrb_float)mrb_integer(val);
case MRB_TT_FLOAT:
break;
- default:
+ case MRB_TT_STRING:
+ case MRB_TT_FALSE:
+ case MRB_TT_TRUE:
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
+ default:
+ val = mrb_type_convert(mrb, val, MRB_TT_FLOAT, MRB_SYM(to_f));
+ break;
}
return mrb_float(val);
}
#endif
+static void
+int_overflow(mrb_state *mrb, const char *reason)
+{
+ mrb_raisef(mrb, E_RANGE_ERROR, "integer overflow in %s", reason);
+}
+
+static void
+int_zerodiv(mrb_state *mrb)
+{
+ mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
+}
+
/*
* call-seq:
*
@@ -55,74 +70,93 @@ 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)
+int_pow(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
-#ifndef MRB_WITHOUT_FLOAT
- mrb_float d;
-#endif
+ mrb_int base = mrb_integer(x);
+ mrb_int result = 1;
+ mrb_int exp;
- mrb_get_args(mrb, "o", &y);
- if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) {
- /* try ipow() */
- mrb_int base = mrb_fixnum(x);
- mrb_int exp = mrb_fixnum(y);
- mrb_int result = 1;
+#ifndef MRB_NO_FLOAT
+ mrb_value y = mrb_get_arg1(mrb);
- if (exp < 0)
-#ifdef MRB_WITHOUT_FLOAT
- return mrb_fixnum_value(0);
-#else
- goto float_pow;
-#endif
- for (;;) {
- if (exp & 1) {
- if (mrb_int_mul_overflow(result, base, &result)) {
-#ifndef MRB_WITHOUT_FLOAT
- goto float_pow;
+ if (mrb_float_p(y)) {
+ return mrb_float_value(mrb, pow((double)base, mrb_float(y)));
+ }
+ else if (mrb_integer_p(y)) {
+ exp = mrb_integer(y);
+ }
+ else
#endif
- }
- }
- exp >>= 1;
- if (exp == 0) break;
- if (mrb_int_mul_overflow(base, base, &base)) {
-#ifndef MRB_WITHOUT_FLOAT
- goto float_pow;
+ {
+ mrb_get_args(mrb, "i", &exp);
+ }
+ if (exp < 0) {
+#ifndef MRB_NO_FLOAT
+ return mrb_float_value(mrb, pow((double)base, (double)exp));
+#else
+ int_overflow(mrb, "negative power");
#endif
+ }
+ for (;;) {
+ if (exp & 1) {
+ if (mrb_int_mul_overflow(result, base, &result)) {
+ int_overflow(mrb, "power");
}
}
- return mrb_fixnum_value(result);
+ exp >>= 1;
+ if (exp == 0) break;
+ if (mrb_int_mul_overflow(base, base, &base)) {
+ int_overflow(mrb, "power");
+ }
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
-#else
- float_pow:
- d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
- return mrb_float_value(mrb, d);
-#endif
+ return mrb_int_value(mrb, result);
+}
+
+mrb_int
+mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
+{
+ if (y == 0) {
+ int_zerodiv(mrb);
+ }
+ else if(x == MRB_INT_MIN && y == -1) {
+ int_overflow(mrb, "division");
+ }
+ else {
+ mrb_int div = x / y;
+
+ if ((x ^ y) < 0 && x != div * y) {
+ div -= 1;
+ }
+ return div;
+ }
+ /* not reached */
+ return 0;
}
/* 15.2.8.3.4 */
/* 15.2.9.3.4 */
/*
* call-seq:
- * num / other -> num
+ * int / other -> num
*
* Performs division: the class of the resulting object depends on
* the class of <code>num</code> and on the magnitude of the
* result.
*/
-
-mrb_value
-mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
+static mrb_value
+int_div(mrb_state *mrb, mrb_value x)
{
-#ifdef MRB_WITHOUT_FLOAT
- if (!mrb_fixnum_p(y)) {
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_int a = mrb_integer(x);
+
+ if (mrb_integer_p(y)) {
+ mrb_int div = mrb_div_int(mrb, a, mrb_integer(y));
+ return mrb_int_value(mrb, div);
}
- return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer division");
#else
- return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_div_float((mrb_float)a, mrb_as_float(mrb, y)));
#endif
}
@@ -134,53 +168,199 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
* Returns most exact division.
*/
+/*
+ * call-seq:
+ * int.div(other) -> int
+ *
+ * Performs division: resulting integer.
+ */
static mrb_value
-num_div(mrb_state *mrb, mrb_value x)
+int_idiv(mrb_state *mrb, mrb_value x)
{
-#ifdef MRB_WITHOUT_FLOAT
- mrb_value y;
+ mrb_int y;
- mrb_get_args(mrb, "o", &y);
- if (!mrb_fixnum_p(y)) {
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+ mrb_get_args(mrb, "i", &y);
+ if (y == 0) {
+ int_zerodiv(mrb);
}
- return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
+ return mrb_fixnum_value(mrb_integer(x) / y);
+}
+
+static mrb_value
+int_quo(mrb_state *mrb, mrb_value xv)
+{
+#ifdef MRB_NO_FLOAT
+ return int_idiv(mrb, xv);
#else
mrb_float y;
mrb_get_args(mrb, "f", &y);
- return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
+ if (y == 0) {
+ int_zerodiv(mrb);
+ }
+ return mrb_float_value(mrb, mrb_integer(xv) / y);
#endif
}
-#ifndef MRB_WITHOUT_FLOAT
+static mrb_value
+coerce_step_counter(mrb_state *mrb, mrb_value self)
+{
+ mrb_value num, step;
+
+ mrb_get_args(mrb, "oo", &num, &step);
+
+#ifndef MRB_NO_FLOAT
+ mrb->c->ci->mid = 0;
+ if (mrb_float_p(num) || mrb_float_p(step)) {
+ return mrb_to_float(mrb, self);
+ }
+#endif
+
+ return self;
+}
+
+#ifndef MRB_NO_FLOAT
/********************************************************************
*
* Document-class: Float
*
* <code>Float</code> objects represent inexact real numbers using
- * the native architecture's double-precision floating point
+ * the native architecture's double-precision floating-point
* representation.
*/
+static mrb_value
+flo_pow(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_float d = pow(mrb_as_float(mrb, x), mrb_as_float(mrb, y));
+ return mrb_float_value(mrb, d);
+}
+
+static mrb_value
+flo_idiv(mrb_state *mrb, mrb_value xv)
+{
+ mrb_int y, div;
+
+ mrb_get_args(mrb, "i", &y);
+ div = mrb_div_int(mrb, (mrb_int)mrb_float(xv), y);
+ return mrb_int_value(mrb, (mrb_int)div);
+}
+
+mrb_float
+mrb_div_float(mrb_float x, mrb_float y)
+{
+ if (y != 0.0) {
+ return x / y;
+ }
+ else if (x == 0.0) {
+ return NAN;
+ }
+ else {
+ return x * (signbit(y) ? -1.0 : 1.0) * INFINITY;
+ }
+}
+
+static mrb_value
+flo_div(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_float a = mrb_float(x);
+
+ if (mrb_float_p(y)) {
+ a = mrb_div_float(a, mrb_float(y));
+ }
+ else {
+ a = mrb_div_float(a, mrb_as_float(mrb, y));
+ }
+ return mrb_float_value(mrb, a);
+}
+
+/* the argument `fmt` is no longer used; you can pass `NULL` */
+mrb_value
+mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
+{
+ char buf[25];
+#ifdef MRB_USE_FLOAT32
+ const int prec = 7;
+#else
+ const int prec = 15;
+#endif
+
+ mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', prec, '\0');
+ for (char *p = buf; *p; p++) {
+ if (*p == '.') goto exit;
+ if (*p == 'e') {
+ memmove(p+2, p, strlen(p)+1);
+ memcpy(p, ".0", 2);
+ goto exit;
+ }
+ }
+ strcat(buf, ".0");
+ exit:
+ return mrb_str_new_cstr(mrb, buf);
+}
+
/* 15.2.9.3.16(x) */
/*
* call-seq:
* flt.to_s -> string
+ * flt.inspect -> string
*
* Returns a string containing a representation of self. As well as a
* fixed or exponential form of the number, the call may return
* "<code>NaN</code>", "<code>Infinity</code>", and
* "<code>-Infinity</code>".
+ *
+ * 3.0.to_s #=> 3.0
+ * 3.25.to_s #=> 3.25
*/
static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
- if (isnan(mrb_float(flt))) {
- return mrb_str_new_lit(mrb, "NaN");
+ mrb_float f = mrb_float(flt);
+ mrb_value str;
+
+ if (isinf(f)) {
+ str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
+ : mrb_str_new_lit(mrb, "Infinity");
+ }
+ else if (isnan(f)) {
+ str = mrb_str_new_lit(mrb, "NaN");
+ }
+ else {
+ str = mrb_float_to_str(mrb, flt, NULL);
+ }
+
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
+}
+
+/* 15.2.9.3.1 */
+/*
+ * call-seq:
+ * float + other -> float
+ *
+ * Returns a new float which is the sum of <code>float</code>
+ * and <code>other</code>.
+ */
+static mrb_value
+flo_add(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_float a = mrb_float(x);
+
+ switch (mrb_type(y)) {
+ case MRB_TT_FLOAT:
+ return mrb_float_value(mrb, a + mrb_float(y));
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x);
+#endif
+ default:
+ return mrb_float_value(mrb, a + mrb_as_float(mrb, y));
}
- return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
}
/* 15.2.9.3.2 */
@@ -193,12 +373,22 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
*/
static mrb_value
-flo_minus(mrb_state *mrb, mrb_value x)
+flo_sub(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_float a = mrb_float(x);
- mrb_get_args(mrb, "o", &y);
- return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
+ switch (mrb_type(y)) {
+ case MRB_TT_FLOAT:
+ return mrb_float_value(mrb, a - mrb_float(y));
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ x = mrb_funcall_id(mrb, y, MRB_OPSYM(sub), 1, x);
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0);
+#endif
+ default:
+ return mrb_float_value(mrb, a - mrb_as_float(mrb, y));
+ }
}
/* 15.2.9.3.3 */
@@ -213,10 +403,19 @@ flo_minus(mrb_state *mrb, mrb_value x)
static mrb_value
flo_mul(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_float a = mrb_float(x);
- mrb_get_args(mrb, "o", &y);
- return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
+ switch (mrb_type(y)) {
+ case MRB_TT_FLOAT:
+ return mrb_float_value(mrb, a * mrb_float(y));
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x);
+#endif
+ default:
+ return mrb_float_value(mrb, a * mrb_as_float(mrb, y));
+ }
}
static void
@@ -230,13 +429,9 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
goto exit;
}
if (y == 0.0) {
- if (x == 0) div = NAN;
- else if (x > 0.0) div = INFINITY;
- else div = -INFINITY; /* x < 0.0 */
- mod = NAN;
- goto exit;
+ int_zerodiv(mrb);
}
- if ((x == 0.0) || (isinf(y) && !isinf(x))) {
+ if (isinf(y) && !isinf(x)) {
mod = x;
}
else {
@@ -249,6 +444,8 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
div = (x - mod) / y;
if (modp && divp) div = round(div);
}
+ if (div == 0) div = 0.0;
+ if (mod == 0) mod = 0.0;
if (y*mod < 0) {
mod += y;
div -= 1.0;
@@ -273,12 +470,10 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
static mrb_value
flo_mod(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
mrb_float mod;
- mrb_get_args(mrb, "o", &y);
-
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), 0, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -296,24 +491,22 @@ flo_mod(mrb_state *mrb, mrb_value x)
* (1.0).eql?(1.0) #=> true
*/
static mrb_value
-fix_eql(mrb_state *mrb, mrb_value x)
+int_eql(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
- if (!mrb_fixnum_p(y)) return mrb_false_value();
- return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
+ if (!mrb_integer_p(y)) return mrb_false_value();
+ return mrb_bool_value(mrb_integer(x) == mrb_integer(y));
}
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
static mrb_value
flo_eql(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- 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 */
@@ -332,14 +525,21 @@ flo_eql(mrb_state *mrb, mrb_value x)
static mrb_value
flo_eq(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
- mrb_get_args(mrb, "o", &y);
+ mrb_value y = mrb_get_arg1(mrb);
switch (mrb_type(y)) {
- case MRB_TT_FIXNUM:
- return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
+ case MRB_TT_INTEGER:
+ return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_integer(y));
case MRB_TT_FLOAT:
return mrb_bool_value(mrb_float(x) == mrb_float(y));
+#ifdef MRB_USE_RATIONAL
+ case MRB_TT_RATIONAL:
+ return mrb_bool_value(mrb_float(x) == mrb_as_float(mrb, y));
+#endif
+#ifdef MRB_USE_COMPLEX
+ case MRB_TT_COMPLEX:
+ return mrb_bool_value(mrb_equal(mrb, y, x));
+#endif
default:
return mrb_false_value();
}
@@ -349,11 +549,15 @@ static int64_t
value_int64(mrb_state *mrb, mrb_value x)
{
switch (mrb_type(x)) {
- case MRB_TT_FIXNUM:
- return (int64_t)mrb_fixnum(x);
- break;
+ case MRB_TT_INTEGER:
+ return (int64_t)mrb_integer(x);
case MRB_TT_FLOAT:
- return (int64_t)mrb_float(x);
+ {
+ double f = mrb_float(x);
+
+ if ((mrb_float)INT64_MAX >= f && f >= (mrb_float)INT64_MIN)
+ return (int64_t)f;
+ }
default:
mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
break;
@@ -365,29 +569,26 @@ value_int64(mrb_state *mrb, mrb_value x)
static mrb_value
int64_value(mrb_state *mrb, int64_t v)
{
- if (FIXABLE(v)) {
- return mrb_fixnum_value((mrb_int)v);
+ if (!TYPED_FIXABLE(v,int64_t)) {
+ int_overflow(mrb, "bit operation");
}
- return mrb_float_value(mrb, (mrb_float)v);
+ return mrb_fixnum_value((mrb_int)v);
}
static mrb_value
flo_rev(mrb_state *mrb, mrb_value x)
{
- int64_t v1;
- mrb_get_args(mrb, "");
- v1 = (int64_t)mrb_float(x);
+ int64_t v1 = value_int64(mrb, x);
return int64_value(mrb, ~v1);
}
static mrb_value
flo_and(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
int64_t v1, v2;
- mrb_get_args(mrb, "o", &y);
- v1 = (int64_t)mrb_float(x);
+ v1 = value_int64(mrb, x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 & v2);
}
@@ -395,11 +596,10 @@ flo_and(mrb_state *mrb, mrb_value x)
static mrb_value
flo_or(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
int64_t v1, v2;
- mrb_get_args(mrb, "o", &y);
- v1 = (int64_t)mrb_float(x);
+ v1 = value_int64(mrb, x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 | v2);
}
@@ -407,11 +607,10 @@ flo_or(mrb_state *mrb, mrb_value x)
static mrb_value
flo_xor(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
int64_t v1, v2;
- mrb_get_args(mrb, "o", &y);
- v1 = (int64_t)mrb_float(x);
+ v1 = value_int64(mrb, x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 ^ v2);
}
@@ -425,9 +624,17 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
return x;
}
val = mrb_float(x);
+ if (width < -MRB_INT_BIT/2) {
+ if (val < 0) return mrb_fixnum_value(-1);
+ return mrb_fixnum_value(0);
+ }
if (width < 0) {
while (width++) {
val /= 2;
+ if (val < 1.0) {
+ val = 0;
+ break;
+ }
}
#if defined(_ISOC99_SOURCE)
val = trunc(val);
@@ -447,23 +654,23 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
val *= 2;
}
}
- if (FIXABLE_FLOAT(val)) {
- return mrb_fixnum_value((mrb_int)val);
- }
+ if (FIXABLE_FLOAT(val))
+ return mrb_int_value(mrb, (mrb_int)val);
return mrb_float_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;
mrb_get_args(mrb, "i", &width);
+ if (width == MRB_INT_MIN) return flo_shift(mrb, x, -MRB_INT_BIT);
return flo_shift(mrb, x, -width);
}
static mrb_value
-flo_rshift(mrb_state *mrb, mrb_value x)
+flo_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
@@ -537,55 +744,127 @@ mrb_check_num_exact(mrb_state *mrb, mrb_float num)
}
}
+static mrb_value
+flo_ceil_floor(mrb_state *mrb, mrb_value num, double (*func)(double))
+{
+ mrb_float f = mrb_float(num);
+ mrb_int ndigits = 0;
+#ifdef MRB_USE_FLOAT32
+ const int fprec = 7;
+#else
+ const int fprec = 15;
+#endif
+
+ mrb_get_args(mrb, "|i", &ndigits);
+ if (f == 0.0) {
+ return ndigits > 0 ? mrb_float_value(mrb, f) : mrb_fixnum_value(0);
+ }
+ if (ndigits > 0) {
+ if (ndigits > fprec) return num;
+ mrb_float d = pow(10, ndigits);
+ f = func(f * d) / d;
+ return mrb_float_value(mrb, f);
+ }
+ if (ndigits < 0) {
+ mrb_float d = pow(10, -ndigits);
+ f = func(f / d) * d;
+ }
+ else { /* ndigits == 0 */
+ f = func(f);
+ }
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.10 */
/*
* call-seq:
- * flt.floor -> integer
+ * float.floor([ndigits]) -> integer or float
*
- * Returns the largest integer less than or equal to <i>flt</i>.
+ * Returns the largest number less than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
+ *
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.floor #=> 1
* 2.0.floor #=> 2
* (-1.2).floor #=> -2
* (-2.0).floor #=> -2
+ *
+ * 1.234567.floor(2) #=> 1.23
+ * 1.234567.floor(3) #=> 1.234
+ * 1.234567.floor(4) #=> 1.2345
+ * 1.234567.floor(5) #=> 1.23456
+ *
+ * 34567.89.floor(-5) #=> 0
+ * 34567.89.floor(-4) #=> 30000
+ * 34567.89.floor(-3) #=> 34000
+ * 34567.89.floor(-2) #=> 34500
+ * 34567.89.floor(-1) #=> 34560
+ * 34567.89.floor(0) #=> 34567
+ * 34567.89.floor(1) #=> 34567.8
+ * 34567.89.floor(2) #=> 34567.89
+ * 34567.89.floor(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (0.3 / 0.1).floor #=> 2 (!)
*/
-
static mrb_value
flo_floor(mrb_state *mrb, mrb_value num)
{
- mrb_float f = floor(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- if (!FIXABLE_FLOAT(f)) {
- return mrb_float_value(mrb, f);
- }
- return mrb_fixnum_value((mrb_int)f);
+ return flo_ceil_floor(mrb, num, floor);
}
/* 15.2.9.3.8 */
/*
* call-seq:
- * flt.ceil -> integer
+ * float.ceil([ndigits]) -> integer or float
+ *
+ * Returns the smallest number greater than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
*
- * Returns the smallest <code>Integer</code> greater than or equal to
- * <i>flt</i>.
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.ceil #=> 2
* 2.0.ceil #=> 2
* (-1.2).ceil #=> -1
* (-2.0).ceil #=> -2
+ *
+ * 1.234567.ceil(2) #=> 1.24
+ * 1.234567.ceil(3) #=> 1.235
+ * 1.234567.ceil(4) #=> 1.2346
+ * 1.234567.ceil(5) #=> 1.23457
+ *
+ * 34567.89.ceil(-5) #=> 100000
+ * 34567.89.ceil(-4) #=> 40000
+ * 34567.89.ceil(-3) #=> 35000
+ * 34567.89.ceil(-2) #=> 34600
+ * 34567.89.ceil(-1) #=> 34570
+ * 34567.89.ceil(0) #=> 34568
+ * 34567.89.ceil(1) #=> 34567.9
+ * 34567.89.ceil(2) #=> 34567.89
+ * 34567.89.ceil(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (2.1 / 0.7).ceil #=> 4 (!)
*/
static mrb_value
flo_ceil(mrb_state *mrb, mrb_value num)
{
- mrb_float f = ceil(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- if (!FIXABLE_FLOAT(f)) {
- return mrb_float_value(mrb, f);
- }
- return mrb_fixnum_value((mrb_int)f);
+ return flo_ceil_floor(mrb, num, ceil);
}
/* 15.2.9.3.12 */
@@ -594,7 +873,7 @@ flo_ceil(mrb_state *mrb, mrb_value num)
* flt.round([ndigits]) -> integer or float
*
* Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
- * Precision may be negative. Returns a floating point number when ndigits
+ * Precision may be negative. Returns a floating-point number when ndigits
* is more than zero.
*
* 1.4.round #=> 1
@@ -636,6 +915,7 @@ flo_round(mrb_state *mrb, mrb_value num)
f = 1.0;
i = ndigits >= 0 ? ndigits : -ndigits;
+ if (ndigits > DBL_DIG+2) return num;
while (--i >= 0)
f = f*10.0;
@@ -666,15 +946,28 @@ 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);
+ if (!FIXABLE_FLOAT(number))
+ return mrb_float_value(mrb, number);
+ return mrb_int_value(mrb, (mrb_int)number);
}
/* 15.2.9.3.14 */
+static mrb_value
+flo_to_i(mrb_state *mrb, mrb_value num)
+{
+ mrb_float f = mrb_float(num);
+
+ if (f > 0.0) f = floor(f);
+ if (f < 0.0) f = ceil(f);
+
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.15 */
/*
* call-seq:
* flt.to_i -> integer
- * flt.to_int -> integer
* flt.truncate -> integer
*
* Returns <i>flt</i> truncated to an <code>Integer</code>.
@@ -683,16 +976,8 @@ flo_round(mrb_state *mrb, mrb_value num)
static mrb_value
flo_truncate(mrb_state *mrb, mrb_value num)
{
- mrb_float f = mrb_float(num);
-
- if (f > 0.0) f = floor(f);
- if (f < 0.0) f = ceil(f);
-
- mrb_check_num_exact(mrb, f);
- if (!FIXABLE_FLOAT(f)) {
- return mrb_float_value(mrb, f);
- }
- return mrb_fixnum_value((mrb_int)f);
+ if (signbit(mrb_float(num))) return flo_ceil(mrb, num);
+ return flo_floor(mrb, num);
}
static mrb_value
@@ -705,8 +990,7 @@ flo_nan_p(mrb_state *mrb, mrb_value num)
/*
* Document-class: Integer
*
- * <code>Integer</code> is the basis for the two concrete classes that
- * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
+ * <code>Integer</code> is hold whole numbers.
*
*/
@@ -714,7 +998,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.
@@ -726,29 +1009,59 @@ 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;
- a = mrb_fixnum(x);
- if (mrb_fixnum_p(y)) {
+ a = mrb_integer(x);
+ if (mrb_integer_p(y)) {
mrb_int b, c;
if (a == 0) return x;
- b = mrb_fixnum(y);
+ b = mrb_integer(y);
if (mrb_int_mul_overflow(a, b, &c)) {
-#ifndef MRB_WITHOUT_FLOAT
- return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
-#endif
+ int_overflow(mrb, "multiplication");
}
- return mrb_fixnum_value(c);
+ return mrb_int_value(mrb, c);
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+ switch (mrb_type(y)) {
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x);
+#endif
+ default:
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication");
#else
- return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a * mrb_as_float(mrb, y));
#endif
+ }
+}
+
+MRB_API mrb_value
+mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ if (mrb_integer_p(x)) {
+ return fixnum_mul(mrb, x, y);
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(x)) {
+ return mrb_float_value(mrb, mrb_float(x) * mrb_as_float(mrb, y));
+ }
+#endif
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ switch (mrb_type(x)) {
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(mul), 1, y);
+ default:
+ break;
+ }
+#endif
+ mrb_raise(mrb, E_TYPE_ERROR, "no number multiply");
+ return mrb_nil_value(); /* not reached */
}
/* 15.2.8.3.3 */
@@ -762,40 +1075,33 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
*/
static mrb_value
-fix_mul(mrb_state *mrb, mrb_value x)
+int_mul(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
- return mrb_fixnum_mul(mrb, x, y);
+ return fixnum_mul(mrb, x, y);
}
static void
fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
{
- mrb_int div, mod;
-
- /* TODO: add mrb_assert(y != 0) to make sure */
-
- if (y < 0) {
- if (x < 0)
- div = -x / -y;
- else
- div = - (x / -y);
+ if (y == 0) {
+ int_zerodiv(mrb);
}
- else {
- if (x < 0)
- div = - (-x / y);
- else
- div = x / y;
+ else if(x == MRB_INT_MIN && y == -1) {
+ int_overflow(mrb, "division");
}
- mod = x - div*y;
- if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
- mod += y;
- div -= 1;
+ else {
+ mrb_int div = x / y;
+ mrb_int mod = x - div * y;
+
+ if ((x ^ y) < 0 && x != div * y) {
+ mod += y;
+ div -= 1;
+ }
+ if (divp) *divp = div;
+ if (modp) *modp = mod;
}
- if (divp) *divp = div;
- if (modp) *modp = mod;
}
/* 15.2.8.3.5 */
@@ -809,34 +1115,25 @@ fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
*/
static mrb_value
-fix_mod(mrb_state *mrb, mrb_value x)
+int_mod(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
- mrb_int a;
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_int a, b;
- mrb_get_args(mrb, "o", &y);
- a = mrb_fixnum(x);
- if (mrb_fixnum_p(y)) {
- mrb_int b, mod;
+ a = mrb_integer(x);
+ if (mrb_integer_p(y) && a != MRB_INT_MIN && (b=mrb_integer(y)) != MRB_INT_MIN) {
+ mrb_int mod;
- if ((b=mrb_fixnum(y)) == 0) {
-#ifdef MRB_WITHOUT_FLOAT
- /* ZeroDivisionError */
- return mrb_fixnum_value(0);
-#else
- return mrb_float_value(mrb, NAN);
-#endif
- }
- fixdivmod(mrb, a, b, 0, &mod);
+ fixdivmod(mrb, a, b, NULL, &mod);
return mrb_fixnum_value(mod);
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo");
#else
else {
mrb_float mod;
- flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
+ flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -849,55 +1146,44 @@ fix_mod(mrb_state *mrb, mrb_value x)
* See <code>Numeric#divmod</code>.
*/
static mrb_value
-fix_divmod(mrb_state *mrb, mrb_value x)
+int_divmod(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
-
- if (mrb_fixnum_p(y)) {
+ if (mrb_integer_p(y)) {
mrb_int div, mod;
- if (mrb_fixnum(y) == 0) {
-#ifdef MRB_WITHOUT_FLOAT
- return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0));
-#else
- return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
- mrb_float_value(mrb, NAN):
- mrb_float_value(mrb, INFINITY)),
- mrb_float_value(mrb, NAN));
-#endif
- }
- fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
- return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
+ fixdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
+ return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod));
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer divmod");
#else
else {
mrb_float div, mod;
mrb_value a, b;
- flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
- a = mrb_float_value(mrb, div);
+ flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_as_float(mrb, y), &div, &mod);
+ a = mrb_int_value(mrb, (mrb_int)div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
}
#endif
}
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
static mrb_value
flo_divmod(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
mrb_float div, mod;
mrb_value a, b;
- mrb_get_args(mrb, "o", &y);
-
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
- a = mrb_float_value(mrb, div);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), &div, &mod);
+ if (!FIXABLE_FLOAT(div))
+ a = mrb_float_value(mrb, div);
+ else
+ a = mrb_int_value(mrb, (mrb_int)div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
}
@@ -916,17 +1202,24 @@ flo_divmod(mrb_state *mrb, mrb_value x)
*/
static mrb_value
-fix_equal(mrb_state *mrb, mrb_value x)
+int_equal(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
switch (mrb_type(y)) {
- case MRB_TT_FIXNUM:
- return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
-#ifndef MRB_WITHOUT_FLOAT
+ case MRB_TT_INTEGER:
+ return mrb_bool_value(mrb_integer(x) == mrb_integer(y));
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
- return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
+ return mrb_bool_value((mrb_float)mrb_integer(x) == mrb_float(y));
+#endif
+#ifdef MRB_USE_RATIONAL
+ case MRB_TT_RATIONAL:
+ return mrb_bool_value(mrb_equal(mrb, y, x));
+#endif
+#ifdef MRB_USE_COMPLEX
+ case MRB_TT_COMPLEX:
+ return mrb_bool_value(mrb_equal(mrb, y, x));
#endif
default:
return mrb_false_value();
@@ -945,24 +1238,24 @@ fix_equal(mrb_state *mrb, mrb_value x)
*/
static mrb_value
-fix_rev(mrb_state *mrb, mrb_value num)
+int_rev(mrb_state *mrb, mrb_value num)
{
- mrb_int val = mrb_fixnum(num);
+ mrb_int val = mrb_integer(num);
- return mrb_fixnum_value(~val);
+ return mrb_int_value(mrb, ~val);
}
-#ifdef MRB_WITHOUT_FLOAT
+#ifdef MRB_NO_FLOAT
#define bit_op(x,y,op1,op2) do {\
- return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
+ return mrb_int_value(mrb, (mrb_integer(x) op2 mrb_integer(y)));\
} while(0)
#else
static mrb_value flo_and(mrb_state *mrb, mrb_value x);
static mrb_value flo_or(mrb_state *mrb, mrb_value x);
static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
#define bit_op(x,y,op1,op2) do {\
- if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
- return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
+ if (mrb_integer_p(y)) return mrb_int_value(mrb, (mrb_integer(x) op2 mrb_integer(y))); \
+ return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_integer(x)));\
} while(0)
#endif
@@ -975,11 +1268,10 @@ static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
*/
static mrb_value
-fix_and(mrb_state *mrb, mrb_value x)
+int_and(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
bit_op(x, y, and, &);
}
@@ -992,11 +1284,10 @@ fix_and(mrb_state *mrb, mrb_value x)
*/
static mrb_value
-fix_or(mrb_state *mrb, mrb_value x)
+int_or(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
bit_op(x, y, or, |);
}
@@ -1009,11 +1300,10 @@ fix_or(mrb_state *mrb, mrb_value x)
*/
static mrb_value
-fix_xor(mrb_state *mrb, mrb_value x)
+int_xor(mrb_state *mrb, mrb_value x)
{
- mrb_value y;
+ mrb_value y = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &y);
bit_op(x, y, or, ^);
}
@@ -1022,61 +1312,34 @@ fix_xor(mrb_state *mrb, mrb_value x)
static mrb_value
lshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
- if (width < 0) { /* mrb_int overflow */
-#ifdef MRB_WITHOUT_FLOAT
- return mrb_fixnum_value(0);
-#else
- return mrb_float_value(mrb, INFINITY);
-#endif
- }
+ mrb_assert(width >= 0);
if (val > 0) {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
(val > (MRB_INT_MAX >> width))) {
-#ifdef MRB_WITHOUT_FLOAT
- return mrb_fixnum_value(-1);
-#else
- goto bit_overflow;
-#endif
+ int_overflow(mrb, "bit shift");
}
- return mrb_fixnum_value(val << width);
+ return mrb_int_value(mrb, val << width);
}
else {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
- (val < (MRB_INT_MIN >> width))) {
-#ifdef MRB_WITHOUT_FLOAT
- return mrb_fixnum_value(0);
-#else
- goto bit_overflow;
-#endif
- }
- return mrb_fixnum_value(val * ((mrb_int)1 << width));
- }
-
-#ifndef MRB_WITHOUT_FLOAT
-bit_overflow:
- {
- mrb_float f = (mrb_float)val;
- while (width--) {
- f *= 2;
+ (val <= (MRB_INT_MIN >> width))) {
+ int_overflow(mrb, "bit shift");
}
- return mrb_float_value(mrb, f);
+ return mrb_int_value(mrb, (val * ((mrb_int)1 << width)));
}
-#endif
}
static mrb_value
-rshift(mrb_int val, mrb_int width)
+rshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
- if (width < 0) { /* mrb_int overflow */
- return mrb_fixnum_value(0);
- }
+ mrb_assert(width >= 0);
if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
if (val < 0) {
return mrb_fixnum_value(-1);
}
return mrb_fixnum_value(0);
}
- return mrb_fixnum_value(val >> width);
+ return mrb_int_value(mrb, val >> width);
}
/* 15.2.8.3.12 */
@@ -1088,7 +1351,7 @@ rshift(mrb_int val, mrb_int width)
*/
static mrb_value
-fix_lshift(mrb_state *mrb, mrb_value x)
+int_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
@@ -1096,10 +1359,11 @@ fix_lshift(mrb_state *mrb, mrb_value x)
if (width == 0) {
return x;
}
- val = mrb_fixnum(x);
+ val = mrb_integer(x);
if (val == 0) return x;
if (width < 0) {
- return rshift(val, -width);
+ if (width == MRB_INT_MIN) return rshift(mrb, val, MRB_INT_BIT);
+ return rshift(mrb, val, -width);
}
return lshift(mrb, val, width);
}
@@ -1113,7 +1377,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
*/
static mrb_value
-fix_rshift(mrb_state *mrb, mrb_value x)
+int_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
@@ -1121,12 +1385,13 @@ fix_rshift(mrb_state *mrb, mrb_value x)
if (width == 0) {
return x;
}
- val = mrb_fixnum(x);
+ val = mrb_integer(x);
if (val == 0) return x;
if (width < 0) {
+ if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift");
return lshift(mrb, val, -width);
}
- return rshift(val, width);
+ return rshift(mrb, val, width);
}
/* 15.2.8.3.23 */
@@ -1138,11 +1403,11 @@ fix_rshift(mrb_state *mrb, mrb_value x)
*
*/
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
static mrb_value
-fix_to_f(mrb_state *mrb, mrb_value num)
+int_to_f(mrb_state *mrb, mrb_value num)
{
- return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
+ return mrb_float_value(mrb, (mrb_float)mrb_integer(num));
}
/*
@@ -1152,7 +1417,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,57 +1425,81 @@ fix_to_f(mrb_state *mrb, mrb_value num)
*/
/* ------------------------------------------------------------------------*/
MRB_API mrb_value
-mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
+mrb_float_to_integer(mrb_state *mrb, mrb_value x)
{
mrb_int z = 0;
if (!mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- z = 0; /* not reached. just suppress warnings. */
}
else {
mrb_float d = mrb_float(x);
- 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 (%v) too big for integer", x);
}
}
- return mrb_fixnum_value(z);
+ return mrb_int_value(mrb, z);
}
#endif
-mrb_value
-mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+static mrb_value
+int_plus(mrb_state *mrb, mrb_value x, mrb_value y)
{
mrb_int a;
- a = mrb_fixnum(x);
- if (mrb_fixnum_p(y)) {
+ a = mrb_integer(x);
+ if (mrb_integer_p(y)) {
mrb_int b, c;
if (a == 0) return y;
- b = mrb_fixnum(y);
+ b = mrb_integer(y);
if (mrb_int_add_overflow(a, b, &c)) {
-#ifndef MRB_WITHOUT_FLOAT
- return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
-#endif
+ int_overflow(mrb, "addition");
}
- return mrb_fixnum_value(c);
+ return mrb_int_value(mrb, c);
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+ switch (mrb_type(y)) {
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x);
+#endif
+ default:
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer addition");
#else
- return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a + mrb_as_float(mrb, y));
#endif
+ }
+}
+
+MRB_API mrb_value
+mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ if (mrb_integer_p(x)) {
+ return int_plus(mrb, x, y);
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(x)) {
+ return mrb_float_value(mrb, mrb_float(x) + mrb_as_float(mrb, y));
+ }
+#endif
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ switch (mrb_type(x)) {
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(add), 1, y);
+ default:
+ break;
+ }
+#endif
+ mrb_raise(mrb, E_TYPE_ERROR, "no number addition");
+ return mrb_nil_value(); /* not reached */
}
/* 15.2.8.3.1 */
@@ -1223,36 +1512,66 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
* result.
*/
static mrb_value
-fix_plus(mrb_state *mrb, mrb_value self)
+int_add(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &other);
- return mrb_fixnum_plus(mrb, self, other);
+ return int_plus(mrb, self, other);
}
-mrb_value
-mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+static mrb_value
+int_minus(mrb_state *mrb, mrb_value x, mrb_value y)
{
mrb_int a;
- a = mrb_fixnum(x);
- if (mrb_fixnum_p(y)) {
+ a = mrb_integer(x);
+ if (mrb_integer_p(y)) {
mrb_int b, c;
- b = mrb_fixnum(y);
+ b = mrb_integer(y);
if (mrb_int_sub_overflow(a, b, &c)) {
-#ifndef MRB_WITHOUT_FLOAT
- return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
-#endif
+ int_overflow(mrb, "subtraction");
}
- return mrb_fixnum_value(c);
+ return mrb_int_value(mrb, c);
}
-#ifdef MRB_WITHOUT_FLOAT
- mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+ switch (mrb_type(y)) {
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ x = mrb_funcall_id(mrb, y, MRB_OPSYM(sub), 1, x);
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0);
+#endif
+ default:
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction");
#else
- return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a - mrb_as_float(mrb, y));
#endif
+ }
+}
+
+MRB_API mrb_value
+mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ if (mrb_integer_p(x)) {
+ return int_minus(mrb, x, y);
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(x)) {
+ return mrb_float_value(mrb, mrb_float(x) - mrb_as_float(mrb, y));
+ }
+#endif
+#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
+ switch (mrb_type(x)) {
+ case MRB_TT_RATIONAL:
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(sub), 1, y);
+ default:
+ break;
+ }
+#endif
+ mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction");
+ return mrb_nil_value(); /* not reached */
}
/* 15.2.8.3.2 */
@@ -1266,42 +1585,60 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
* result.
*/
static mrb_value
-fix_minus(mrb_state *mrb, mrb_value self)
+int_sub(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &other);
- return mrb_fixnum_minus(mrb, self, other);
+ return int_minus(mrb, self, other);
}
-
-MRB_API mrb_value
-mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+MRB_API char*
+mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base)
{
- char buf[MRB_INT_BIT+1];
- char *b = buf + sizeof buf;
- mrb_int val = mrb_fixnum(x);
+ char *bufend = buf + len;
+ char *b = bufend-1;
- if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
- }
+ if (base < 2 || 36 < base) return NULL;
+ if (len < 2) return NULL;
- if (val == 0) {
- *--b = '0';
+ if (n == 0) {
+ buf[0] = '0';
+ buf[1] = '\0';
+ return buf;
}
- else if (val < 0) {
+
+ *b = '\0';
+ if (n < 0) {
do {
- *--b = mrb_digitmap[-(val % base)];
- } while (val /= base);
- *--b = '-';
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[-(n % base)];
+ } while (n /= base);
+ if (b-- == buf) return NULL;
+ *b = '-';
}
else {
do {
- *--b = mrb_digitmap[(int)(val % base)];
- } while (val /= base);
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[(int)(n % base)];
+ } while (n /= base);
}
+ return b;
+}
- return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
+MRB_API mrb_value
+mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+{
+ char buf[MRB_INT_BIT+1];
+ mrb_int val = mrb_integer(x);
+
+ if (base < 2 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
+ }
+ const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base);
+ mrb_assert(p != NULL);
+ mrb_value str = mrb_str_new_cstr(mrb, p);
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
/* 15.2.8.3.25 */
@@ -1321,41 +1658,46 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
*
*/
static mrb_value
-fix_to_s(mrb_state *mrb, mrb_value self)
+int_to_s(mrb_state *mrb, mrb_value self)
{
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
- return mrb_fixnum_to_str(mrb, self, base);
+ return mrb_integer_to_str(mrb, self, base);
}
/* compare two numbers: (1:0:-1; -2 for error) */
static mrb_int
cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
-#ifdef MRB_WITHOUT_FLOAT
+#ifdef MRB_NO_FLOAT
mrb_int x, y;
#else
mrb_float x, y;
#endif
-#ifdef MRB_WITHOUT_FLOAT
- x = mrb_fixnum(v1);
+#ifdef MRB_NO_FLOAT
+ x = mrb_integer(v1);
#else
- x = mrb_to_flo(mrb, v1);
+ x = mrb_as_float(mrb, v1);
#endif
switch (mrb_type(v2)) {
- case MRB_TT_FIXNUM:
-#ifdef MRB_WITHOUT_FLOAT
- y = mrb_fixnum(v2);
+ case MRB_TT_INTEGER:
+#ifdef MRB_NO_FLOAT
+ y = mrb_integer(v2);
#else
- y = (mrb_float)mrb_fixnum(v2);
+ y = (mrb_float)mrb_integer(v2);
#endif
break;
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
y = mrb_float(v2);
break;
+#ifdef MRB_USE_RATIONAL
+ case MRB_TT_RATIONAL:
+ y = mrb_as_float(mrb, v2);
+ break;
+#endif
#endif
default:
return -2;
@@ -1372,41 +1714,38 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
/* 15.2.9.3.6 */
/*
* call-seq:
- * self.f <=> other.f => -1, 0, +1
+ * self.f <=> other.f => -1, 0, +1, or nil
* < => -1
* = => 0
* > => +1
* Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
* less than, equal to, or greater than <i>numeric</i>. This is the
- * basis for the tests in <code>Comparable</code>.
+ * basis for the tests in <code>Comparable</code>. When the operands are
+ * not comparable, it returns nil instead of raising an exception.
*/
static mrb_value
num_cmp(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
mrb_int n;
- mrb_get_args(mrb, "o", &other);
n = cmpnum(mrb, self, other);
if (n == -2) return mrb_nil_value();
return mrb_fixnum_value(n);
}
-static void
+static mrb_noreturn void
cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %S with %S failed",
- mrb_obj_value(mrb_class(mrb, v1)),
- mrb_obj_value(mrb_class(mrb, v2)));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
}
static mrb_value
num_lt(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
mrb_int n;
- mrb_get_args(mrb, "o", &other);
n = cmpnum(mrb, self, other);
if (n == -2) cmperr(mrb, self, other);
if (n < 0) return mrb_true_value();
@@ -1416,10 +1755,9 @@ num_lt(mrb_state *mrb, mrb_value self)
static mrb_value
num_le(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
mrb_int n;
- mrb_get_args(mrb, "o", &other);
n = cmpnum(mrb, self, other);
if (n == -2) cmperr(mrb, self, other);
if (n <= 0) return mrb_true_value();
@@ -1429,10 +1767,9 @@ num_le(mrb_state *mrb, mrb_value self)
static mrb_value
num_gt(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
mrb_int n;
- mrb_get_args(mrb, "o", &other);
n = cmpnum(mrb, self, other);
if (n == -2) cmperr(mrb, self, other);
if (n > 0) return mrb_true_value();
@@ -1442,131 +1779,135 @@ num_gt(mrb_state *mrb, mrb_value self)
static mrb_value
num_ge(mrb_state *mrb, mrb_value self)
{
- mrb_value other;
+ mrb_value other = mrb_get_arg1(mrb);
mrb_int n;
- mrb_get_args(mrb, "o", &other);
n = cmpnum(mrb, self, other);
if (n == -2) cmperr(mrb, self, other);
if (n >= 0) return mrb_true_value();
return mrb_false_value();
}
+MRB_API mrb_int
+mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
+{
+ mrb_value v;
+
+ switch (mrb_type(obj1)) {
+ case MRB_TT_INTEGER:
+ case MRB_TT_FLOAT:
+ return cmpnum(mrb, obj1, obj2);
+ case MRB_TT_STRING:
+ if (!mrb_string_p(obj2))
+ return -2;
+ return mrb_str_cmp(mrb, obj1, obj2);
+ default:
+ v = mrb_funcall_id(mrb, obj1, MRB_OPSYM(cmp), 1, obj2);
+ if (mrb_nil_p(v) || !mrb_integer_p(v))
+ return -2;
+ return mrb_integer(v);
+ }
+}
+
static mrb_value
num_finite_p(mrb_state *mrb, mrb_value self)
{
- mrb_get_args(mrb, "");
return mrb_true_value();
}
static mrb_value
num_infinite_p(mrb_state *mrb, mrb_value self)
{
- mrb_get_args(mrb, "");
return mrb_false_value();
}
-/* 15.2.9.3.1 */
-/*
- * call-seq:
- * float + other -> float
- *
- * Returns a new float which is the sum of <code>float</code>
- * and <code>other</code>.
- */
-#ifndef MRB_WITHOUT_FLOAT
-static mrb_value
-flo_plus(mrb_state *mrb, mrb_value x)
-{
- mrb_value y;
-
- mrb_get_args(mrb, "o", &y);
- return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
-}
-#endif
-
/* ------------------------------------------------------------------------*/
void
mrb_init_numeric(mrb_state *mrb)
{
- struct RClass *numeric, *integer, *fixnum;
-#ifndef MRB_WITHOUT_FLOAT
+ struct RClass *numeric, *integer;
+#ifndef MRB_NO_FLOAT
struct RClass *fl;
#endif
/* 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());
/* Integer Class */
- integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
- MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
+ mrb->integer_class = integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
+ MRB_SET_INSTANCE_TT(integer, MRB_TT_INTEGER);
mrb_undef_class_method(mrb, integer, "new");
+ mrb_define_method(mrb, integer, "**", int_pow, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, integer, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
+ mrb_define_method(mrb, integer, "<", num_lt, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, integer, "<=", num_le, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, integer, ">", num_gt, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, integer, ">=", num_ge, MRB_ARGS_REQ(1));
+
mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
-#ifndef MRB_WITHOUT_FLOAT
- mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */
- mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */
- mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 (x) */
- mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.15 (x) */
-#endif
- /* Fixnum Class */
- mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
- mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
- mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
- mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
- mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
- mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
- mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
- mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
- mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
- mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
- mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
- mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
- mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
-#ifndef MRB_WITHOUT_FLOAT
- mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
+ mrb_define_method(mrb, integer, "+", int_add, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
+ mrb_define_method(mrb, integer, "-", int_sub, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
+ mrb_define_method(mrb, integer, "*", int_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
+ mrb_define_method(mrb, integer, "%", int_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
+ mrb_define_method(mrb, integer, "/", int_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.6 */
+ mrb_define_method(mrb, integer, "quo", int_quo, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
+ mrb_define_method(mrb, integer, "div", int_idiv, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, integer, "==", int_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
+ mrb_define_method(mrb, integer, "~", int_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
+ mrb_define_method(mrb, integer, "&", int_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
+ mrb_define_method(mrb, integer, "|", int_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
+ mrb_define_method(mrb, integer, "^", int_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
+ mrb_define_method(mrb, integer, "<<", int_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
+ mrb_define_method(mrb, integer, ">>", int_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
+ mrb_define_method(mrb, integer, "eql?", int_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
+#ifndef MRB_NO_FLOAT
+ mrb_define_method(mrb, integer, "to_f", int_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
#endif
- mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
- mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
- mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
+ mrb_define_method(mrb, integer, "to_s", int_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
+ mrb_define_method(mrb, integer, "inspect", int_to_s, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, integer, "divmod", int_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
+ mrb_define_method(mrb, integer, "__coerce_step_counter", coerce_step_counter, MRB_ARGS_REQ(2));
+
+ /* Fixnum Class for compatibility */
+ mrb_define_const(mrb, mrb->object_class, "Fixnum", mrb_obj_value(integer));
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
/* Float Class */
mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
mrb_undef_class_method(mrb, fl, "new");
- mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
- mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
- mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
- mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
- mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
+ mrb_define_method(mrb, fl, "**", flo_pow, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "/", flo_div, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
+ mrb_define_method(mrb, fl, "quo", flo_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
+ mrb_define_method(mrb, fl, "div", flo_idiv, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "+", flo_add, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
+ mrb_define_method(mrb, fl, "-", flo_sub, MRB_ARGS_REQ(1)); /* 15.2.9.3.4 */
+ mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
+ mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
+ mrb_define_method(mrb, fl, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
+ mrb_define_method(mrb, fl, "<", num_lt, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "<=", num_le, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">", num_gt, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">=", num_ge, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
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, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
+ 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_OPT(1)); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
- mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
+ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */
mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
- mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
- mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
- mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
+ mrb_define_method(mrb, fl, "to_i", flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
+ mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */
mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
@@ -1575,11 +1916,10 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
#ifdef INFINITY
- mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
+ mrb_define_const_id(mrb, fl, MRB_SYM(INFINITY), mrb_float_value(mrb, INFINITY));
#endif
#ifdef NAN
- mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
+ mrb_define_const_id(mrb, fl, MRB_SYM(NAN), mrb_float_value(mrb, NAN));
#endif
#endif
- mrb_define_module(mrb, "Integral");
}
diff --git a/src/object.c b/src/object.c
index 8724c5416..8fe4688ac 100644
--- a/src/object.c
+++ b/src/object.c
@@ -9,6 +9,7 @@
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
+#include <mruby/presym.h>
MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
@@ -19,12 +20,12 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
return TRUE;
case MRB_TT_FALSE:
- case MRB_TT_FIXNUM:
- return (mrb_fixnum(v1) == mrb_fixnum(v2));
+ case MRB_TT_INTEGER:
+ return (mrb_integer(v1) == mrb_integer(v2));
case MRB_TT_SYMBOL:
return (mrb_symbol(v1) == mrb_symbol(v2));
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
return (mrb_float(v1) == mrb_float(v2));
#endif
@@ -47,7 +48,18 @@ mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
mrb_value result;
if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE;
- result = mrb_funcall(mrb, obj1, "==", 1, obj2);
+#ifndef MRB_NO_FLOAT
+ /* value mixing with integer and float */
+ if (mrb_integer_p(obj1)) {
+ if (mrb_float_p(obj2) && (mrb_float)mrb_integer(obj1) == mrb_float(obj2))
+ return TRUE;
+ }
+ else if (mrb_float_p(obj1)) {
+ if (mrb_integer_p(obj2) && mrb_float(obj1) == (mrb_float)mrb_integer(obj2))
+ return TRUE;
+ }
+#endif
+ result = mrb_funcall_id(mrb, obj1, MRB_OPSYM(eq), 1, obj2);
if (mrb_test(result)) return TRUE;
return FALSE;
}
@@ -83,13 +95,17 @@ mrb_true(mrb_state *mrb, mrb_value obj)
static mrb_value
nil_to_s(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new(mrb, 0, 0);
+ mrb_value str = mrb_str_new_frozen(mrb, NULL, 0);
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
static mrb_value
nil_inspect(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new_lit(mrb, "nil");
+ mrb_value str = mrb_str_new_lit_frozen(mrb, "nil");
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
/***********************************************************************
@@ -150,7 +166,9 @@ true_xor(mrb_state *mrb, mrb_value obj)
static mrb_value
true_to_s(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new_lit(mrb, "true");
+ mrb_value str = mrb_str_new_lit_frozen(mrb, "true");
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
/* 15.2.5.3.4 */
@@ -257,7 +275,9 @@ false_or(mrb_state *mrb, mrb_value obj)
static mrb_value
false_to_s(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new_lit(mrb, "false");
+ mrb_value str = mrb_str_new_lit_frozen(mrb, "false");
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
void
@@ -268,7 +288,7 @@ mrb_init_object(mrb_state *mrb)
struct RClass *f;
mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
- MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE);
+ MRB_SET_INSTANCE_TT(n, MRB_TT_FALSE);
mrb_undef_class_method(mrb, n, "new");
mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */
mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */
@@ -287,7 +307,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE());
mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class);
- MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE);
+ MRB_SET_INSTANCE_TT(f, MRB_TT_FALSE);
mrb_undef_class_method(mrb, f, "new");
mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */
mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */
@@ -296,136 +316,86 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE());
}
-static mrb_value
-inspect_type(mrb_state *mrb, mrb_value val)
+static const char*
+type_name(enum mrb_vtype t)
{
- if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) {
- return mrb_inspect(mrb, val);
- }
- else {
- return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val));
+ switch (t) {
+#define MRB_VTYPE_NAME(tt, type, name) case tt: return name;
+ MRB_VTYPE_FOREACH(MRB_VTYPE_NAME)
+#undef MRB_VTYPE_NAME
+ default: return NULL;
}
}
static mrb_value
-convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise)
+convert_type(mrb_state *mrb, mrb_value val, const char *tname, mrb_sym method, mrb_bool raise)
{
- mrb_sym m = 0;
-
- m = mrb_intern_cstr(mrb, method);
- if (!mrb_respond_to(mrb, val, m)) {
+ if (!mrb_respond_to(mrb, val, method)) {
if (raise) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname));
+ if (tname) mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into %s", val, tname);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y", val);
}
return mrb_nil_value();
}
- return mrb_funcall_argv(mrb, val, m, 0, 0);
+ return mrb_funcall_argv(mrb, val, method, 0, 0);
}
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_type_convert(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method)
{
mrb_value v;
+ const char *tname;
if (mrb_type(val) == type) return val;
+ tname = type_name(type);
v = convert_type(mrb, val, tname, method, TRUE);
if (mrb_type(v) != type) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val,
- mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method));
+ if (type == MRB_TT_STRING) return mrb_any_to_s(mrb, val);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%n", val, tname, method);
}
return v;
}
MRB_API mrb_value
-mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method)
+mrb_type_convert_check(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method)
{
mrb_value v;
if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val;
- v = convert_type(mrb, val, tname, method, FALSE);
+ v = convert_type(mrb, val, type_name(type), method, FALSE);
if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value();
return v;
}
-static const struct types {
- unsigned char type;
- const char *name;
-} builtin_types[] = {
-/* {MRB_TT_NIL, "nil"}, */
- {MRB_TT_FALSE, "false"},
- {MRB_TT_TRUE, "true"},
- {MRB_TT_FIXNUM, "Fixnum"},
- {MRB_TT_SYMBOL, "Symbol"}, /* :symbol */
- {MRB_TT_MODULE, "Module"},
- {MRB_TT_OBJECT, "Object"},
- {MRB_TT_CLASS, "Class"},
- {MRB_TT_ICLASS, "iClass"}, /* internal use: mixed-in module holder */
- {MRB_TT_SCLASS, "SClass"},
- {MRB_TT_PROC, "Proc"},
-#ifndef MRB_WITHOUT_FLOAT
- {MRB_TT_FLOAT, "Float"},
-#endif
- {MRB_TT_ARRAY, "Array"},
- {MRB_TT_HASH, "Hash"},
- {MRB_TT_STRING, "String"},
- {MRB_TT_RANGE, "Range"},
-/* {MRB_TT_BIGNUM, "Bignum"}, */
- {MRB_TT_FILE, "File"},
- {MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */
-/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */
-/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */
-/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */
- {MRB_TT_MAXDEFINE, 0}
-};
-
MRB_API void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
- const struct types *type = builtin_types;
- enum mrb_vtype xt;
-
- xt = mrb_type(x);
- if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) {
- while (type->type < MRB_TT_MAXDEFINE) {
- if (type->type == t) {
- const char *etype;
-
- if (mrb_nil_p(x)) {
- etype = "nil";
- }
- else if (mrb_fixnum_p(x)) {
- etype = "Fixnum";
- }
- else if (mrb_type(x) == MRB_TT_SYMBOL) {
- etype = "Symbol";
- }
- else if (mrb_immediate_p(x)) {
- etype = RSTRING_PTR(mrb_obj_as_string(mrb, x));
- }
- else {
- etype = mrb_obj_classname(mrb, x);
- }
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)",
- mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name));
- }
- type++;
- }
- mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)",
- mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x)));
+ enum mrb_vtype xt = mrb_type(x);
+ const char *tname, *ename;
+
+ if (t == xt) return;
+
+ tname = type_name(t);
+ if (mrb_nil_p(x)) {
+ ename = "nil";
+ }
+ else if (mrb_integer_p(x)) {
+ ename = "Integer";
+ }
+ else if (mrb_symbol_p(x)) {
+ ename = "Symbol";
}
+ else if (mrb_immediate_p(x)) {
+ ename = RSTRING_PTR(mrb_obj_as_string(mrb, x));
+ }
+ else {
+ ename = mrb_obj_classname(mrb, x);
+ }
+ if (tname) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)",
+ ename, tname);
+ }
+ mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %d (%s given)", t, ename);
}
/* 15.3.1.3.46 */
@@ -447,8 +417,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_cat_str(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj)));
+ }
mrb_str_cat_lit(mrb, str, ">");
return str;
@@ -505,25 +477,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_integer_p(val)) {
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(val)) {
+ return mrb_float_to_integer(mrb, val);
+ }
+#endif
+ if (mrb_string_p(val)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert String to Integer");
+ }
+ return mrb_type_convert(mrb, val, MRB_TT_INTEGER, MRB_SYM(to_i));
+ }
+ return val;
}
MRB_API mrb_value
@@ -533,22 +502,16 @@ 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
+#ifndef MRB_NO_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);
+ return mrb_float_to_integer(mrb, val);
#endif
- case MRB_TT_FIXNUM:
+ case MRB_TT_INTEGER:
if (base != 0) goto arg_error;
return val;
@@ -568,29 +531,20 @@ 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);
}
+#ifndef MRB_NO_FLOAT
MRB_API mrb_value
-mrb_Integer(mrb_state *mrb, mrb_value val)
-{
- return mrb_convert_to_integer(mrb, val, 0);
-}
-
-#ifndef MRB_WITHOUT_FLOAT
-MRB_API mrb_value
-mrb_Float(mrb_state *mrb, mrb_value val)
+mrb_to_float(mrb_state *mrb, mrb_value val)
{
if (mrb_nil_p(val)) {
mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Float");
}
switch (mrb_type(val)) {
- case MRB_TT_FIXNUM:
- return mrb_float_value(mrb, (mrb_float)mrb_fixnum(val));
+ case MRB_TT_INTEGER:
+ return mrb_float_value(mrb, (mrb_float)mrb_integer(val));
case MRB_TT_FLOAT:
return val;
@@ -599,20 +553,81 @@ mrb_Float(mrb_state *mrb, mrb_value val)
return mrb_float_value(mrb, mrb_str_to_dbl(mrb, val, TRUE));
default:
- return mrb_convert_type(mrb, val, MRB_TT_FLOAT, "Float", "to_f");
+ return mrb_type_convert(mrb, val, MRB_TT_FLOAT, MRB_SYM(to_f));
}
}
#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, "%Y cannot be converted to String", 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, "%Y cannot be converted to Array", 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, "%Y cannot be converted to Hash", 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));
+ return mrb_obj_as_string(mrb, mrb_funcall_id(mrb, obj, MRB_SYM(inspect), 0));
}
MRB_API mrb_bool
mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
{
if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE;
- return mrb_test(mrb_funcall(mrb, obj1, "eql?", 1, obj2));
+ return mrb_test(mrb_funcall_id(mrb, obj1, MRB_SYM_Q(eql), 1, obj2));
}
diff --git a/src/pool.c b/src/pool.c
index b87d2cfaa..ab30be1d8 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -4,8 +4,6 @@
** See Copyright Notice in mruby.h
*/
-#include <stddef.h>
-#include <stdint.h>
#include <string.h>
#include <mruby.h>
diff --git a/src/print.c b/src/print.c
index 03b5eadfa..4af871b43 100644
--- a/src/print.c
+++ b/src/print.c
@@ -7,41 +7,89 @@
#include <mruby.h>
#include <mruby/string.h>
#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/presym.h>
+#include <string.h>
+
+#ifndef MRB_NO_STDIO
+static void
+printcstr(const char *str, size_t len, FILE *stream)
+{
+ if (str) {
+ fwrite(str, len, 1, stream);
+ putc('\n', stream);
+ }
+}
-#ifndef MRB_DISABLE_STDIO
static void
printstr(mrb_value obj, FILE *stream)
{
if (mrb_string_p(obj)) {
- fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stream);
- putc('\n', stream);
+ printcstr(RSTRING_PTR(obj), RSTRING_LEN(obj), stream);
}
}
-#else
-# define printstr(obj, stream) (void)0
-#endif
+
+void
+mrb_core_init_printabort(void)
+{
+ static const char *str = "Failed mruby core initialization";
+ printcstr(str, strlen(str), stdout);
+}
MRB_API void
mrb_p(mrb_state *mrb, mrb_value obj)
{
- printstr(mrb_inspect(mrb, obj), stdout);
+ if (mrb_type(obj) == MRB_TT_EXCEPTION && mrb_obj_ptr(obj) == mrb->nomem_err) {
+ static const char *str = "Out of memory";
+ printcstr(str, strlen(str), stdout);
+ }
+ else {
+ printstr(mrb_inspect(mrb, obj), stdout);
+ }
}
+
MRB_API void
mrb_print_error(mrb_state *mrb)
{
mrb_print_backtrace(mrb);
- printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr);
}
MRB_API void
mrb_show_version(mrb_state *mrb)
{
- printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION")), stdout);
+ printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), MRB_SYM(MRUBY_DESCRIPTION)), stdout);
+}
+
+MRB_API void
+mrb_show_copyright(mrb_state *mrb)
+{
+ printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), MRB_SYM(MRUBY_COPYRIGHT)), stdout);
+}
+
+#else
+void
+mrb_core_init_printabort(void)
+{
+}
+
+MRB_API void
+mrb_p(mrb_state *mrb, mrb_value obj)
+{
+}
+
+MRB_API void
+mrb_print_error(mrb_state *mrb)
+{
+}
+
+MRB_API void
+mrb_show_version(mrb_state *mrb)
+{
}
MRB_API void
mrb_show_copyright(mrb_state *mrb)
{
- printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")), stdout);
}
+#endif
diff --git a/src/proc.c b/src/proc.c
index 05b897480..1d5a4aa76 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -8,52 +8,88 @@
#include <mruby/class.h>
#include <mruby/proc.h>
#include <mruby/opcode.h>
+#include <mruby/data.h>
+#include <mruby/presym.h>
+#include <mruby/array.h>
+#include <mruby/hash.h>
-static mrb_code call_iseq[] = {
+static const mrb_code call_iseq[] = {
OP_CALL,
};
+static const mrb_irep call_irep = {
+ 0, /* nlocals */
+ 2, /* nregs */
+ 0, /* clen */
+ MRB_ISEQ_NO_FREE | MRB_IREP_NO_FREE, /* flags */
+ call_iseq, /* iseq */
+ NULL, /* pool */
+ NULL, /* syms */
+ NULL, /* reps */
+ NULL, /* lv */
+ NULL, /* debug_info */
+ 1, /* ilen */
+ 0, /* plen */
+ 0, /* slen */
+ 1, /* rlen */
+ 0, /* refcnt */
+};
+
+static const struct RProc call_proc = {
+ NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT,
+ { &call_irep }, NULL, { NULL }
+};
+
struct RProc*
-mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
+mrb_proc_new(mrb_state *mrb, const mrb_irep *irep)
{
struct RProc *p;
mrb_callinfo *ci = mrb->c->ci;
- p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
if (ci) {
struct RClass *tc = NULL;
if (ci->proc) {
- tc = MRB_PROC_TARGET_CLASS(ci->proc);
+ if (ci->proc->color != MRB_GC_RED) {
+ tc = MRB_PROC_TARGET_CLASS(ci->proc);
+ }
+ else {
+ tc = mrb_vm_ci_target_class(ci);
+ if (tc && tc->tt == MRB_TT_ICLASS) {
+ tc = tc->c;
+ }
+ }
}
if (tc == NULL) {
- tc = ci->target_class;
+ tc = mrb_vm_ci_target_class(ci);
}
p->upper = ci->proc;
p->e.target_class = tc;
}
p->body.irep = irep;
- mrb_irep_incref(mrb, irep);
+ if (irep) {
+ mrb_irep_incref(mrb, (mrb_irep*)irep);
+ }
return p;
}
-static struct REnv*
-env_new(mrb_state *mrb, mrb_int nlocals)
+struct REnv*
+mrb_env_new(mrb_state *mrb, struct mrb_context *c, mrb_callinfo *ci, int nstacks, mrb_value *stack, struct RClass *tc)
{
struct REnv *e;
- mrb_callinfo *ci = mrb->c->ci;
- int bidx;
+ mrb_int bidx;
- e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL);
- MRB_ENV_SET_STACK_LEN(e, nlocals);
+ e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, tc);
+ MRB_ENV_SET_LEN(e, nstacks);
bidx = ci->argc;
- if (ci->argc < 0) bidx = 2;
+ if (bidx < 0) bidx = 2;
else bidx += 1;
MRB_ENV_SET_BIDX(e, bidx);
e->mid = ci->mid;
- e->stack = mrb->c->stack;
- e->cxt = mrb->c;
+ e->stack = stack;
+ e->cxt = c;
return e;
}
@@ -62,29 +98,30 @@ static void
closure_setup(mrb_state *mrb, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
- struct RProc *up = p->upper;
- struct REnv *e;
+ const struct RProc *up = p->upper;
+ struct REnv *e = NULL;
- if (ci->env) {
- e = ci->env;
+ if (ci && (e = mrb_vm_ci_env(ci)) != NULL) {
+ /* do nothing, because e is assigned already */
}
- else {
+ else if (up) {
struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
- e = env_new(mrb, up->body.irep->nlocals);
- ci->env = e;
- if (tc) {
- e->c = tc;
- mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc);
+ e = mrb_env_new(mrb, mrb->c, ci, up->body.irep->nlocals, ci->stack, tc);
+ ci->u.env = e;
+ if (MRB_PROC_ENV_P(up) && MRB_PROC_ENV(up)->cxt == NULL) {
+ e->mid = MRB_PROC_ENV(up)->mid;
}
}
- 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*
-mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
+mrb_closure_new(mrb_state *mrb, const mrb_irep *irep)
{
struct RProc *p = mrb_proc_new(mrb, irep);
@@ -97,7 +134,7 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
{
struct RProc *p;
- p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
p->body.func = func;
p->flags |= MRB_PROC_CFUNC_FL;
p->upper = 0;
@@ -113,11 +150,14 @@ mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const
struct REnv *e;
int i;
- p->e.env = e = env_new(mrb, argc);
+ p->e.env = e = mrb_env_new(mrb, mrb->c, mrb->c->ci, 0, NULL, NULL);
p->flags |= MRB_PROC_ENVSET;
mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
- MRB_ENV_UNSHARE_STACK(e);
+ MRB_ENV_CLOSE(e);
+
e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
+ MRB_ENV_SET_LEN(e, argc);
+
if (argv) {
for (i = 0; i < argc; ++i) {
e->stack[i] = argv[i];
@@ -140,19 +180,19 @@ mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
MRB_API mrb_value
mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
{
- struct RProc *p = mrb->c->ci->proc;
+ const struct RProc *p = mrb->c->ci->proc;
struct REnv *e;
if (!p || !MRB_PROC_CFUNC_P(p)) {
- mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
+ mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc");
}
e = MRB_PROC_ENV(p);
if (!e) {
- mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv.");
+ mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv");
}
- if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) {
- mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)",
- mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e)));
+ if (idx < 0 || MRB_ENV_LEN(e) <= idx) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %i (expected: 0 <= index < %i)",
+ idx, MRB_ENV_LEN(e));
}
return e->stack[idx];
@@ -168,7 +208,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
a->flags = b->flags;
a->body = b->body;
if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
- a->body.irep->refcnt++;
+ mrb_irep_incref(NULL, (mrb_irep*)a->body.irep);
}
a->upper = b->upper;
a->e.env = b->e.env;
@@ -182,17 +222,14 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
mrb_value proc;
struct RProc *p;
- mrb_get_args(mrb, "&", &blk);
- if (mrb_nil_p(blk)) {
- /* Calling Proc.new without a block is not implemented yet */
- mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
- }
- p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
+ /* Calling Proc.new without a block is not implemented yet */
+ mrb_get_args(mrb, "&!", &blk);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
mrb_proc_copy(p, mrb_proc_ptr(blk));
proc = mrb_obj_value(p);
- mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, proc);
+ mrb_funcall_with_block(mrb, proc, MRB_SYM(initialize), 0, NULL, proc);
if (!MRB_PROC_STRICT_P(p) &&
- mrb->c->ci > mrb->c->cibase && MRB_PROC_ENV(p) == mrb->c->ci[-1].env) {
+ mrb->c->ci > mrb->c->cibase && MRB_PROC_ENV(p) == mrb->c->ci[-1].u.env) {
p->flags |= MRB_PROC_ORPHAN;
}
return proc;
@@ -201,46 +238,76 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
static mrb_value
mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
{
- mrb_value proc;
+ mrb_value proc = mrb_get_arg1(mrb);
- mrb_get_args(mrb, "o", &proc);
- if (mrb_type(proc) != MRB_TT_PROC) {
+ if (!mrb_proc_p(proc)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
}
mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc));
return self;
}
-int
-mrb_proc_cfunc_p(struct RProc *p)
+/* 15.2.17.4.2 */
+static mrb_value
+proc_arity(mrb_state *mrb, mrb_value self)
{
- return MRB_PROC_CFUNC_P(p);
+ return mrb_int_value(mrb, mrb_proc_arity(mrb_proc_ptr(self)));
}
-/* 15.2.17.4.2 */
+/* 15.3.1.2.6 */
+/* 15.3.1.3.27 */
+/*
+ * call-seq:
+ * lambda { |...| block } -> a_proc
+ *
+ * Equivalent to <code>Proc.new</code>, except the resulting Proc objects
+ * check the number of parameters passed when called.
+ */
static mrb_value
-mrb_proc_arity(mrb_state *mrb, mrb_value self)
+proc_lambda(mrb_state *mrb, mrb_value self)
{
- struct RProc *p = mrb_proc_ptr(self);
- struct mrb_irep *irep;
- mrb_code *pc;
+ mrb_value blk;
+ struct RProc *p;
+
+ mrb_get_args(mrb, "&", &blk);
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
+ }
+ if (!mrb_proc_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
+ }
+ p = mrb_proc_ptr(blk);
+ if (!MRB_PROC_STRICT_P(p)) {
+ struct RProc *p2 = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, p->c);
+ mrb_proc_copy(p2, p);
+ p2->flags |= MRB_PROC_STRICT;
+ return mrb_obj_value(p2);
+ }
+ return blk;
+}
+
+mrb_int
+mrb_proc_arity(const struct RProc *p)
+{
+ const mrb_irep *irep;
+ const 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 mrb_fixnum_value(-1);
+ return -1;
}
irep = p->body.irep;
if (!irep) {
- return mrb_fixnum_value(0);
+ return 0;
}
pc = irep->iseq;
/* arity is depend on OP_ENTER */
if (*pc != OP_ENTER) {
- return mrb_fixnum_value(0);
+ return 0;
}
aspec = PEEK_W(pc+1);
@@ -250,64 +317,132 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
pa = MRB_ASPEC_POST(aspec);
arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
- return mrb_fixnum_value(arity);
+ return arity;
}
-/* 15.3.1.2.6 */
-/* 15.3.1.3.27 */
-/*
- * call-seq:
- * lambda { |...| block } -> a_proc
- *
- * Equivalent to <code>Proc.new</code>, except the resulting Proc objects
- * check the number of parameters passed when called.
- */
-static mrb_value
-proc_lambda(mrb_state *mrb, mrb_value self)
+mrb_value
+mrb_proc_local_variables(mrb_state *mrb, const struct RProc *proc)
{
- mrb_value blk;
- struct RProc *p;
+ const mrb_irep *irep;
+ mrb_value vars;
+ size_t i;
- mrb_get_args(mrb, "&", &blk);
- if (mrb_nil_p(blk)) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
+ if (proc == NULL || MRB_PROC_CFUNC_P(proc)) {
+ return mrb_ary_new(mrb);
}
- if (mrb_type(blk) != MRB_TT_PROC) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
+ vars = mrb_hash_new(mrb);
+ while (proc) {
+ if (MRB_PROC_CFUNC_P(proc)) break;
+ irep = proc->body.irep;
+ if (irep->lv) {
+ for (i = 0; i + 1 < irep->nlocals; ++i) {
+ if (irep->lv[i]) {
+ mrb_sym sym = irep->lv[i];
+ const char *name = mrb_sym_name(mrb, sym);
+ switch (name[0]) {
+ case '*': case '&':
+ break;
+ default:
+ mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value());
+ break;
+ }
+ }
+ }
+ }
+ if (MRB_PROC_SCOPE_P(proc)) break;
+ proc = proc->upper;
}
- p = mrb_proc_ptr(blk);
- if (!MRB_PROC_STRICT_P(p)) {
- struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c);
- mrb_proc_copy(p2, p);
- p2->flags |= MRB_PROC_STRICT;
- return mrb_obj_value(p2);
+
+ return mrb_hash_keys(mrb, vars);
+}
+
+const struct RProc *
+mrb_proc_get_caller(mrb_state *mrb, struct REnv **envp)
+{
+ struct mrb_context *c = mrb->c;
+ mrb_callinfo *ci = (c->ci > c->cibase) ? c->ci - 1 : c->cibase;
+ const struct RProc *proc = ci->proc;
+
+ if (!proc || MRB_PROC_CFUNC_P(proc)) {
+ if (envp) *envp = NULL;
}
- return blk;
+ else {
+ struct RClass *tc = MRB_PROC_TARGET_CLASS(proc);
+ struct REnv *e = mrb_vm_ci_env(ci);
+
+ if (e == NULL) {
+ int nstacks = proc->body.irep->nlocals;
+ e = mrb_env_new(mrb, c, ci, nstacks, ci->stack, tc);
+ ci->u.env = e;
+ }
+ else if (tc) {
+ e->c = tc;
+ mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc);
+ }
+ if (envp) *envp = e;
+ }
+
+ return proc;
+}
+
+#define IREP_LVAR_MERGE_DEFAULT 50
+#define IREP_LVAR_MERGE_MINIMUM 8
+#define IREP_LVAR_MERGE_MAXIMUM 240
+
+#ifdef MRB_IREP_LVAR_MERGE_LIMIT
+# define IREP_LVAR_MERGE_LIMIT \
+ ((MRB_IREP_LVAR_MERGE_LIMIT) < IREP_LVAR_MERGE_MINIMUM ? IREP_LVAR_MERGE_MINIMUM : \
+ (MRB_IREP_LVAR_MERGE_LIMIT) > IREP_LVAR_MERGE_MAXIMUM ? IREP_LVAR_MERGE_MAXIMUM : \
+ (MRB_IREP_LVAR_MERGE_LIMIT))
+#else
+# define IREP_LVAR_MERGE_LIMIT IREP_LVAR_MERGE_DEFAULT
+#endif
+
+void
+mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, const mrb_sym *lv, const mrb_value *stack)
+{
+ mrb_assert(!(irep->flags & MRB_IREP_NO_FREE));
+
+ if ((irep->nlocals + num) > IREP_LVAR_MERGE_LIMIT) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "too many local variables for binding (mruby limitation)");
+ }
+
+ if (!lv) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "unavailable local variable names");
+ }
+
+ irep->lv = (mrb_sym*)mrb_realloc(mrb, (mrb_sym*)irep->lv, sizeof(mrb_sym) * (irep->nlocals + num));
+ env->stack = (mrb_value*)mrb_realloc(mrb, env->stack, sizeof(mrb_value) * (irep->nlocals + 1 /* self */ + num));
+
+ mrb_sym *destlv = (mrb_sym*)irep->lv + irep->nlocals - 1 /* self */;
+ mrb_value *destst = env->stack + irep->nlocals;
+ memmove(destlv, lv, sizeof(mrb_sym) * num);
+ if (stack) {
+ memmove(destst, stack, sizeof(mrb_value) * num);
+ }
+ else {
+ for (int i = num; i > 0; i--, destst++) {
+ *destst = mrb_nil_value();
+ }
+ }
+ irep->nlocals += num;
+ irep->nregs = irep->nlocals;
+ MRB_ENV_SET_LEN(env, irep->nlocals);
}
void
mrb_init_proc(mrb_state *mrb)
{
- struct RProc *p;
mrb_method_t m;
- mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
- static const mrb_irep mrb_irep_zero = { 0 };
-
- *call_irep = mrb_irep_zero;
- call_irep->flags = MRB_ISEQ_NO_FREE;
- call_irep->iseq = call_iseq;
- 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_METHOD_FROM_PROC(m, &call_proc);
+ mrb_define_method_raw(mrb, mrb->proc_class, MRB_SYM(call), m);
+ mrb_define_method_raw(mrb, mrb->proc_class, MRB_OPSYM(aref), 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 e45308d35..477baa5e8 100644
--- a/src/range.c
+++ b/src/range.c
@@ -9,55 +9,102 @@
#include <mruby/range.h>
#include <mruby/string.h>
#include <mruby/array.h>
+#include <mruby/presym.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_FLAG 1
+#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_FLAG)
+#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_FLAG)
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;
enum mrb_vtype tb;
+ mrb_int n;
ta = mrb_type(a);
tb = mrb_type(b);
-#ifdef MRB_WITHOUT_FLOAT
- if (ta == MRB_TT_FIXNUM && tb == MRB_TT_FIXNUM ) {
+#ifdef MRB_NO_FLOAT
+ if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) return;
#else
- if ((ta == MRB_TT_FIXNUM || ta == MRB_TT_FLOAT) &&
- (tb == MRB_TT_FIXNUM || tb == MRB_TT_FLOAT)) {
-#endif
+ if ((ta == MRB_TT_INTEGER || ta == MRB_TT_FLOAT) &&
+ (tb == MRB_TT_INTEGER || tb == MRB_TT_FLOAT)) {
return;
}
+#endif
+
+ if (mrb_nil_p(a) || mrb_nil_p(b)) return;
- ans = mrb_funcall(mrb, a, "<=>", 1, b);
- if (mrb_nil_p(ans)) {
- /* can not be compared */
+ n = mrb_cmp(mrb, a, b);
+ if (n == -2) { /* can not be compared */
mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range");
}
}
-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_int n = mrb_cmp(mrb, a, b);
- range_check(mrb, beg, end);
- r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class);
+ if (n == 0 || n == -1) return TRUE;
+ return FALSE;
+}
+
+static mrb_bool
+r_gt(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ return mrb_cmp(mrb, a, b) == 1;
+}
+
+static mrb_bool
+r_ge(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ mrb_int n = mrb_cmp(mrb, a, b);
+
+ if (n == 0 || n == 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_SYM(initialize), "'initialize' called twice");
+ }
+ else {
+ range_ptr_alloc_edges(mrb, r);
+ }
+ }
+ else {
+ r = 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 +114,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 +130,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,28 +142,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;
- mrb_write_barrier(mrb, (struct RBasic*)r);
-}
/*
* call-seq:
* Range.new(start, end, exclusive=false) => range
@@ -130,25 +156,18 @@ 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);
+ mrb_obj_freeze(mrb, range);
return range;
}
+
/*
* call-seq:
* range == obj => true or false
@@ -161,17 +180,14 @@ 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;
- mrb_value obj, v1, v2;
-
- mrb_get_args(mrb, "o", &obj);
+ mrb_value obj = mrb_get_arg1(mrb);
+ mrb_bool v1, v2;
if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value();
if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */
@@ -180,108 +196,45 @@ 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_equal(mrb, RANGE_BEG(rr), RANGE_BEG(ro));
+ v2 = mrb_equal(mrb, RANGE_END(rr), RANGE_END(ro));
+ if (!v1 || !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;
+ mrb_value val = mrb_get_arg1(mrb);
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
- mrb_bool include_p;
-
- 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 */
-
- 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;
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
+ if (mrb_nil_p(beg)) {
+ if (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */
+ : r_ge(mrb, end, val)) { /* end >= val */
+ return mrb_true_value();
+ }
}
-
- if (trunc) {
- if (beg > len) return 2;
- if (end > len) end = len;
+ else if (r_le(mrb, beg, val)) { /* beg <= val */
+ if (mrb_nil_p(end)) {
+ return mrb_true_value();
+ }
+ if (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */
+ : r_ge(mrb, end, val)) { /* end >= val */
+ return mrb_true_value();
+ }
}
-
- 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;
+ return mrb_false_value();
}
/* 15.2.14.4.12(x) */
@@ -291,17 +244,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;
@@ -316,18 +268,24 @@ 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;
+ mrb_value str;
struct RRange *r = mrb_range_ptr(mrb, range);
- str = mrb_inspect(mrb, r->edges->beg);
- str2 = mrb_inspect(mrb, r->edges->end);
- str = mrb_str_dup(mrb, str);
- mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
- mrb_str_cat_str(mrb, str, str2);
+ if (!mrb_nil_p(RANGE_BEG(r))) {
+ str = mrb_inspect(mrb, RANGE_BEG(r));
+ str = mrb_str_dup(mrb, str);
+ mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2);
+ }
+ else {
+ str = mrb_str_new(mrb, "...", RANGE_EXCL(r) ? 3 : 2);
+ }
+ if (!mrb_nil_p(RANGE_END(r))) {
+ mrb_value str2 = mrb_inspect(mrb, RANGE_END(r));
+ mrb_str_cat_str(mrb, str, str2);
+ }
return str;
}
@@ -344,28 +302,22 @@ 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)
{
- mrb_value obj;
+ mrb_value obj = mrb_get_arg1(mrb);
struct RRange *r, *o;
- 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_type(obj) != MRB_TT_RANGE) return mrb_false_value();
+ if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value();
+ if (!mrb_range_p(obj)) 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();
@@ -375,22 +327,71 @@ range_eql(mrb_state *mrb, mrb_value range)
static mrb_value
range_initialize_copy(mrb_state *mrb, mrb_value copy)
{
- mrb_value src;
+ mrb_value src = mrb_get_arg1(mrb);
struct RRange *r;
- mrb_get_args(mrb, "o", &src);
-
if (mrb_obj_equal(mrb, copy, src)) return copy;
if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) {
mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
}
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));
+ mrb_obj_freeze(mrb, copy);
return copy;
}
+static mrb_value
+range_num_to_a(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+ mrb_value beg = RANGE_BEG(r);
+ mrb_value end = RANGE_END(r);
+ mrb_value ary;
+
+ if (mrb_nil_p(end)) {
+ mrb->c->ci->mid = 0;
+ mrb_raise(mrb, E_RANGE_ERROR, "cannot convert endless range to an array");
+ }
+ if (mrb_integer_p(beg)) {
+ if (mrb_integer_p(end)) {
+ mrb_int a = mrb_integer(beg);
+ mrb_int b = mrb_integer(end);
+ mrb_int len = b - a;
+
+ if (!RANGE_EXCL(r)) len++;
+ ary = mrb_ary_new_capa(mrb, len);
+ for (mrb_int i=0; i<len; i++) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, a+i));
+ }
+ return ary;
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(end)) {
+ mrb_float a = (mrb_float)mrb_integer(beg);
+ mrb_float b = mrb_float(end);
+
+ ary = mrb_ary_new_capa(mrb, (mrb_int)(b - a) + 1);
+ if (RANGE_EXCL(r)) {
+ while (a < b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a));
+ a += 1.0;
+ }
+ }
+ else {
+ while (a <= b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a));
+ a += 1.0;
+ }
+ }
+ return ary;
+ }
+#endif
+ }
+ return mrb_nil_value();
+}
+
mrb_value
mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int))
{
@@ -399,10 +400,10 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
result = mrb_ary_new(mrb);
for (i = 0; i < argc; ++i) {
- if (mrb_fixnum_p(argv[i])) {
- mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i])));
+ if (mrb_integer_p(argv[i])) {
+ mrb_ary_push(mrb, result, func(mrb, obj, mrb_integer(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));
@@ -413,7 +414,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
}
}
else {
- mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]);
+ mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %v", argv[i]);
}
}
@@ -421,6 +422,68 @@ 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;
+ mrb_bool excl;
+ struct RRange *r;
+
+ if (!mrb_range_p(range)) return MRB_RANGE_TYPE_MISMATCH;
+ r = mrb_range_ptr(mrb, range);
+
+ beg = mrb_nil_p(RANGE_BEG(r)) ? 0 : mrb_as_int(mrb, RANGE_BEG(r));
+ end = mrb_nil_p(RANGE_END(r)) ? -1 : mrb_as_int(mrb, RANGE_END(r));
+ excl = mrb_nil_p(RANGE_END(r)) ? 0 : RANGE_EXCL(r);
+
+ if (beg < 0) {
+ 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 (!excl && (!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;
@@ -429,19 +492,19 @@ 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) */
mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */
+ mrb_define_method(mrb, r, "__num_to_a", range_num_to_a, MRB_ARGS_NONE());
}
diff --git a/src/readflt.c b/src/readflt.c
new file mode 100644
index 000000000..19a8e8dc6
--- /dev/null
+++ b/src/readflt.c
@@ -0,0 +1,120 @@
+#include <mruby.h>
+
+#ifndef MRB_NO_FLOAT
+/*
+ * strtod implementation.
+ * author: Yasuhiro Matsumoto (@mattn)
+ * license: public domain
+ */
+
+/*
+The original code can be found in https://github.com/mattn/strtod
+
+I modified the routine for mruby:
+
+ * renamed the function `vim_strtod` -> `mrb_float_read`
+ * simplified the code
+
+My modifications in this file are also placed in the public domain.
+
+Matz (Yukihiro Matsumoto)
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+
+MRB_API double
+mrb_float_read(const char *str, char **end)
+{
+ double d = 0.0;
+ int sign;
+ int n = 0;
+ const char *p, *a;
+
+ a = p = str;
+ while (ISSPACE(*p))
+ ++p;
+
+ /* decimal part */
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ ++p;
+ } else if (*p == '+')
+ ++p;
+ if (ISDIGIT(*p)) {
+ d = (double)(*p++ - '0');
+ while (*p && ISDIGIT(*p)) {
+ d = d * 10.0 + (double)(*p - '0');
+ ++p;
+ ++n;
+ }
+ a = p;
+ } else if (*p != '.')
+ goto done;
+ d *= sign;
+
+ /* fraction part */
+ if (*p == '.') {
+ double f = 0.0;
+ double base = 0.1;
+ ++p;
+
+ if (ISDIGIT(*p))
+ {
+ while (*p && ISDIGIT(*p)) {
+ f += base * (*p - '0') ;
+ base /= 10.0;
+ ++p;
+ ++n;
+ }
+ }
+ d += f * sign;
+ a = p;
+ }
+
+ /* exponential part */
+ if ((*p == 'E') || (*p == 'e')) {
+ int e = 0;
+ ++p;
+
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ ++p;
+ } else if (*p == '+')
+ ++p;
+
+ if (ISDIGIT(*p)) {
+ while (*p == '0')
+ ++p;
+ if (*p == '\0') --p;
+ e = (int)(*p++ - '0');
+ for (; *p && ISDIGIT(*p); p++) {
+ if (e < 10000)
+ e = e * 10 + (*p - '0');
+ }
+ e *= sign;
+ }
+ else if (!ISDIGIT(*(a-1))) {
+ a = str;
+ goto done;
+ }
+ else if (*p == 0)
+ goto done;
+ d *= pow(10.0, (double) e);
+ a = p;
+ }
+ else if (p > str && !ISDIGIT(*(p-1))) {
+ a = str;
+ goto done;
+ }
+
+done:
+ if (end)
+ *end = (char*)a;
+ return d;
+}
+#endif
diff --git a/src/readint.c b/src/readint.c
new file mode 100644
index 000000000..5fae222c2
--- /dev/null
+++ b/src/readint.c
@@ -0,0 +1,30 @@
+#include <mruby.h>
+#include <mruby/numeric.h>
+#include <errno.h>
+
+/* mrb_int_read(): read mrb_int from a string (base 10 only) */
+/* const char *p - string to read */
+/* const char *e - end of string */
+/* char **endp - end of parsed integer */
+
+/* if integer overflows, errno will be set to ERANGE */
+/* also endp will be set to NULL on overflow */
+MRB_API mrb_int
+mrb_int_read(const char *p, const char *e, char **endp)
+{
+ mrb_int n = 0;
+ int ch;
+
+ while ((e == NULL || p < e) && ISDIGIT(*p)) {
+ ch = *p - '0';
+ if (mrb_int_mul_overflow(n, 10, &n) ||
+ mrb_int_add_overflow(n, ch, &n)) {
+ if (endp) *endp = NULL;
+ errno = ERANGE;
+ return MRB_INT_MAX;
+ }
+ p++;
+ }
+ if (endp) *endp = (char*)p;
+ return n;
+}
diff --git a/src/state.c b/src/state.c
index 18d104555..4dafc964a 100644
--- a/src/state.c
+++ b/src/state.c
@@ -19,13 +19,28 @@ void mrb_init_mrbgems(mrb_state*);
void mrb_gc_init(mrb_state*, mrb_gc *gc);
void mrb_gc_destroy(mrb_state*, mrb_gc *gc);
+int mrb_core_init_protect(mrb_state *mrb, void (*body)(mrb_state *, void *), void *opaque);
+
+static void
+init_gc_and_core(mrb_state *mrb, void *opaque)
+{
+ static const struct mrb_context mrb_context_zero = { 0 };
+
+ mrb_gc_init(mrb, &mrb->gc);
+ mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
+ *mrb->c = mrb_context_zero;
+ mrb->root_c = mrb->c;
+
+ mrb_init_core(mrb);
+}
+
MRB_API mrb_state*
mrb_open_core(mrb_allocf f, void *ud)
{
static const mrb_state mrb_state_zero = { 0 };
- 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;
@@ -34,12 +49,10 @@ mrb_open_core(mrb_allocf f, void *ud)
mrb->allocf = f;
mrb->atexit_stack_len = 0;
- mrb_gc_init(mrb, &mrb->gc);
- mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
- *mrb->c = mrb_context_zero;
- mrb->root_c = mrb->c;
-
- mrb_init_core(mrb);
+ if (mrb_core_init_protect(mrb, init_gc_and_core, NULL)) {
+ mrb_close(mrb);
+ return NULL;
+ }
return mrb;
}
@@ -56,38 +69,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)
{
@@ -96,6 +77,14 @@ mrb_open(void)
return mrb;
}
+#ifndef MRB_NO_GEMS
+static void
+init_mrbgems(mrb_state *mrb, void *opaque)
+{
+ mrb_init_mrbgems(mrb);
+}
+#endif
+
MRB_API mrb_state*
mrb_open_allocf(mrb_allocf f, void *ud)
{
@@ -105,8 +94,11 @@ mrb_open_allocf(mrb_allocf f, void *ud)
return NULL;
}
-#ifndef DISABLE_GEMS
- mrb_init_mrbgems(mrb);
+#ifndef MRB_NO_GEMS
+ if (mrb_core_init_protect(mrb, init_mrbgems, NULL)) {
+ mrb_close(mrb);
+ return NULL;
+ }
mrb_gc_arena_restore(mrb, 0);
#endif
return mrb;
@@ -117,12 +109,20 @@ void mrb_free_symtbl(mrb_state *mrb);
void
mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
{
+ if (irep->flags & MRB_IREP_NO_FREE) return;
+ if (irep->refcnt == UINT16_MAX) {
+ mrb_garbage_collect(mrb);
+ if (irep->refcnt == UINT16_MAX) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "too many irep references");
+ }
+ }
irep->refcnt++;
}
void
mrb_irep_decref(mrb_state *mrb, mrb_irep *irep)
{
+ if (irep->flags & MRB_IREP_NO_FREE) return;
irep->refcnt--;
if (irep->refcnt == 0) {
mrb_irep_free(mrb, irep);
@@ -132,12 +132,14 @@ mrb_irep_decref(mrb_state *mrb, mrb_irep *irep)
void
mrb_irep_cutref(mrb_state *mrb, mrb_irep *irep)
{
- mrb_irep *tmp;
+ mrb_irep **reps;
int i;
+ if (irep->flags & MRB_IREP_NO_FREE) return;
+ reps = (mrb_irep**)irep->reps;
for (i=0; i<irep->rlen; i++) {
- tmp = irep->reps[i];
- irep->reps[i] = NULL;
+ mrb_irep *tmp = reps[i];
+ reps[i] = NULL;
if (tmp) mrb_irep_decref(mrb, tmp);
}
}
@@ -147,120 +149,53 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
{
int i;
+ if (irep->flags & MRB_IREP_NO_FREE) return;
if (!(irep->flags & MRB_ISEQ_NO_FREE))
- mrb_free(mrb, irep->iseq);
- if (irep->pool) for (i=0; i<irep->plen; i++) {
- if (mrb_type(irep->pool[i]) == MRB_TT_STRING) {
- mrb_gc_free_str(mrb, RSTRING(irep->pool[i]));
- mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
- }
-#if defined(MRB_WORD_BOXING) && !defined(MRB_WITHOUT_FLOAT)
- else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) {
- mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
+ mrb_free(mrb, (void*)irep->iseq);
+ if (irep->pool) {
+ for (i=0; i<irep->plen; i++) {
+ if ((irep->pool[i].tt & 3) == IREP_TT_STR ||
+ irep->pool[i].tt == IREP_TT_BIGINT) {
+ mrb_free(mrb, (void*)irep->pool[i].u.str);
+ }
}
-#endif
- }
- mrb_free(mrb, irep->pool);
- mrb_free(mrb, irep->syms);
- for (i=0; i<irep->rlen; i++) {
- if (irep->reps[i])
- mrb_irep_decref(mrb, irep->reps[i]);
+ mrb_free(mrb, (void*)irep->pool);
}
- mrb_free(mrb, irep->reps);
- mrb_free(mrb, irep->lv);
- if (irep->own_filename) {
- mrb_free(mrb, (void *)irep->filename);
+ mrb_free(mrb, (void*)irep->syms);
+ if (irep->reps) {
+ for (i=0; i<irep->rlen; i++) {
+ if (irep->reps[i])
+ mrb_irep_decref(mrb, (mrb_irep*)irep->reps[i]);
+ }
+ mrb_free(mrb, (void*)irep->reps);
}
- mrb_free(mrb, irep->lines);
+ mrb_free(mrb, (void*)irep->lv);
mrb_debug_info_free(mrb, irep->debug_info);
mrb_free(mrb, irep);
}
-mrb_value
-mrb_str_pool(mrb_state *mrb, mrb_value str)
-{
- struct RString *s = mrb_str_ptr(str);
- struct RString *ns;
- char *ptr;
- mrb_int len;
-
- ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString));
- ns->tt = MRB_TT_STRING;
- ns->c = mrb->string_class;
-
- if (RSTR_NOFREE_P(s)) {
- ns->flags = MRB_STR_NOFREE;
- ns->as.heap.ptr = s->as.heap.ptr;
- ns->as.heap.len = s->as.heap.len;
- ns->as.heap.aux.capa = 0;
- }
- else {
- ns->flags = 0;
- if (RSTR_EMBED_P(s)) {
- ptr = s->as.ary;
- len = RSTR_EMBED_LEN(s);
- }
- else {
- ptr = s->as.heap.ptr;
- len = s->as.heap.len;
- }
-
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(ns);
- RSTR_SET_EMBED_LEN(ns, len);
- if (ptr) {
- memcpy(ns->as.ary, ptr, len);
- }
- ns->as.ary[len] = '\0';
- }
- else {
- ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- ns->as.heap.len = len;
- ns->as.heap.aux.capa = len;
- if (ptr) {
- memcpy(ns->as.heap.ptr, ptr, len);
- }
- ns->as.heap.ptr[len] = '\0';
- }
- }
- RSTR_SET_POOL_FLAG(ns);
- MRB_SET_FROZEN_FLAG(ns);
- return mrb_obj_value(ns);
-}
-
-void mrb_free_backtrace(mrb_state *mrb);
-
MRB_API void
mrb_free_context(mrb_state *mrb, struct mrb_context *c)
{
if (!c) return;
mrb_free(mrb, c->stbase);
mrb_free(mrb, c->cibase);
- mrb_free(mrb, c->rescue);
- mrb_free(mrb, c->ensure);
mrb_free(mrb, c);
}
-MRB_API void
+void mrb_protect_atexit(mrb_state *mrb);
+
+ MRB_API void
mrb_close(mrb_state *mrb)
{
if (!mrb) return;
- if (mrb->atexit_stack_len > 0) {
- mrb_int i;
- for (i = mrb->atexit_stack_len; i > 0; --i) {
- mrb->atexit_stack[i - 1](mrb);
- }
-#ifndef MRB_FIXED_STATE_ATEXIT_STACK
- mrb_free(mrb, mrb->atexit_stack);
-#endif
- }
+ mrb_protect_atexit(mrb);
/* free */
- mrb_gc_free_gv(mrb);
+ mrb_gc_destroy(mrb, &mrb->gc);
mrb_free_context(mrb, mrb->root_c);
+ mrb_gc_free_gv(mrb);
mrb_free_symtbl(mrb);
- mrb_alloca_free(mrb);
- mrb_gc_destroy(mrb, &mrb->gc);
mrb_free(mrb, mrb);
}
@@ -273,7 +208,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 b7abfb762..03d9c8a9c 100644
--- a/src/string.c
+++ b/src/string.c
@@ -8,8 +8,9 @@
# define _CRT_NONSTDC_NO_DEPRECATE
#endif
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
#include <float.h>
+#include <math.h>
#endif
#include <limits.h>
#include <stddef.h>
@@ -20,80 +21,124 @@
#include <mruby/class.h>
#include <mruby/range.h>
#include <mruby/string.h>
-#include <mruby/re.h>
+#include <mruby/numeric.h>
+#include <mruby/presym.h>
typedef struct mrb_shared_string {
- mrb_bool nofree : 1;
int refcnt;
+ mrb_ssize capa;
char *ptr;
- mrb_int len;
} mrb_shared_string;
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
+#define mrb_obj_alloc_string(mrb) MRB_OBJ_ALLOC((mrb), MRB_TT_STRING, (mrb)->string_class)
static struct RString*
-str_new_static(mrb_state *mrb, const char *p, size_t len)
+str_init_normal_capa(mrb_state *mrb, struct RString *s,
+ const char *p, size_t len, size_t capa)
+{
+ char *dst = (char *)mrb_malloc(mrb, capa + 1);
+ if (p) memcpy(dst, p, len);
+ dst[len] = '\0';
+ s->as.heap.ptr = dst;
+ s->as.heap.len = (mrb_ssize)len;
+ s->as.heap.aux.capa = (mrb_ssize)capa;
+ RSTR_UNSET_TYPE_FLAG(s);
+ return s;
+}
+
+static struct RString*
+str_init_normal(mrb_state *mrb, struct RString *s, const char *p, size_t len)
{
- struct RString *s;
+ return str_init_normal_capa(mrb, s, p, len, len);
+}
- if (len >= MRB_INT_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
- }
- s = mrb_obj_alloc_string(mrb);
- s->as.heap.len = (mrb_int)len;
- s->as.heap.aux.capa = 0; /* nofree */
+static struct RString*
+str_init_embed(struct RString *s, const char *p, size_t len)
+{
+ if (p) memcpy(RSTR_EMBED_PTR(s), p, len);
+ RSTR_EMBED_PTR(s)[len] = '\0';
+ RSTR_SET_TYPE_FLAG(s, EMBED);
+ RSTR_SET_EMBED_LEN(s, len);
+ return s;
+}
+
+static struct RString*
+str_init_nofree(struct RString *s, const char *p, size_t len)
+{
s->as.heap.ptr = (char *)p;
- s->flags = MRB_STR_NOFREE;
+ s->as.heap.len = (mrb_ssize)len;
+ s->as.heap.aux.capa = 0; /* nofree */
+ RSTR_SET_TYPE_FLAG(s, NOFREE);
+ return s;
+}
+static struct RString*
+str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, mrb_shared_string *shared)
+{
+ if (shared) {
+ shared->refcnt++;
+ }
+ else {
+ shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
+ shared->refcnt = 1;
+ shared->ptr = orig->as.heap.ptr;
+ shared->capa = orig->as.heap.aux.capa;
+ }
+ s->as.heap.ptr = orig->as.heap.ptr;
+ s->as.heap.len = orig->as.heap.len;
+ s->as.heap.aux.shared = shared;
+ RSTR_SET_TYPE_FLAG(s, SHARED);
return s;
}
static struct RString*
-str_new(mrb_state *mrb, const char *p, size_t len)
+str_init_fshared(const struct RString *orig, struct RString *s, struct RString *fshared)
{
- struct RString *s;
+ s->as.heap.ptr = orig->as.heap.ptr;
+ s->as.heap.len = orig->as.heap.len;
+ s->as.heap.aux.fshared = fshared;
+ RSTR_SET_TYPE_FLAG(s, FSHARED);
+ return s;
+}
- if (p && mrb_ro_data_p(p)) {
- return str_new_static(mrb, p, len);
- }
- s = mrb_obj_alloc_string(mrb);
- if (len <= RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- if (p) {
- memcpy(s->as.ary, p, len);
- }
+static struct RString*
+str_init_modifiable(mrb_state *mrb, struct RString *s, const char *p, size_t len)
+{
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(s, p, len);
}
else {
- if (len >= MRB_INT_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
- }
- s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1);
- s->as.heap.len = (mrb_int)len;
- s->as.heap.aux.capa = (mrb_int)len;
- if (p) {
- memcpy(s->as.heap.ptr, p, len);
- }
+ return str_init_normal(mrb, s, p, len);
}
- RSTR_PTR(s)[len] = '\0';
- return s;
}
-static inline void
-str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj)
+static struct RString*
+str_new_static(mrb_state *mrb, const char *p, size_t len)
{
- s->c = mrb_str_ptr(obj)->c;
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(mrb_obj_alloc_string(mrb), p, len);
+ }
+ if (len >= MRB_SSIZE_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ return str_init_nofree(mrb_obj_alloc_string(mrb), p, len);
}
-static mrb_value
-mrb_str_new_empty(mrb_state *mrb, mrb_value str)
+static struct RString*
+str_new(mrb_state *mrb, const char *p, size_t len)
{
- struct RString *s = str_new(mrb, 0, 0);
-
- str_with_class(mrb, s, str);
- return mrb_obj_value(s);
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(mrb_obj_alloc_string(mrb), p, len);
+ }
+ if (len >= MRB_SSIZE_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ if (p && mrb_ro_data_p(p)) {
+ return str_init_nofree(mrb_obj_alloc_string(mrb), p, len);
+ }
+ return str_init_normal(mrb, mrb_obj_alloc_string(mrb), p, len);
}
MRB_API mrb_value
@@ -101,52 +146,35 @@ mrb_str_new_capa(mrb_state *mrb, size_t capa)
{
struct RString *s;
- s = mrb_obj_alloc_string(mrb);
-
- if (capa >= MRB_INT_MAX) {
+ if (RSTR_EMBEDDABLE_P(capa)) {
+ s = str_init_embed(mrb_obj_alloc_string(mrb), NULL, 0);
+ }
+ else if (capa >= MRB_SSIZE_MAX) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big");
+ /* not reached */
+ s = NULL;
+ }
+ else {
+ s = str_init_normal_capa(mrb, mrb_obj_alloc_string(mrb), NULL, 0, capa);
}
- s->as.heap.len = 0;
- s->as.heap.aux.capa = (mrb_int)capa;
- s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1);
- RSTR_PTR(s)[0] = '\0';
return mrb_obj_value(s);
}
-#ifndef MRB_STR_BUF_MIN_SIZE
-# define MRB_STR_BUF_MIN_SIZE 128
-#endif
-
-MRB_API mrb_value
-mrb_str_buf_new(mrb_state *mrb, size_t capa)
-{
- if (capa < MRB_STR_BUF_MIN_SIZE) {
- capa = MRB_STR_BUF_MIN_SIZE;
- }
- return mrb_str_new_capa(mrb, capa);
-}
-
static void
resize_capa(mrb_state *mrb, struct RString *s, size_t capacity)
{
-#if SIZE_MAX > MRB_INT_MAX
- mrb_assert(capacity < MRB_INT_MAX);
+#if SIZE_MAX > MRB_SSIZE_MAX
+ mrb_assert(capacity < MRB_SSIZE_MAX);
#endif
if (RSTR_EMBED_P(s)) {
- if (RSTRING_EMBED_LEN_MAX < capacity) {
- char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
- const mrb_int len = RSTR_EMBED_LEN(s);
- memcpy(tmp, s->as.ary, len);
- RSTR_UNSET_EMBED_FLAG(s);
- s->as.heap.ptr = tmp;
- s->as.heap.len = len;
- s->as.heap.aux.capa = (mrb_int)capacity;
+ if (!RSTR_EMBEDDABLE_P(capacity)) {
+ str_init_normal_capa(mrb, s, RSTR_EMBED_PTR(s), RSTR_EMBED_LEN(s), capacity);
}
}
else {
s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
- s->as.heap.aux.capa = (mrb_int)capacity;
+ s->as.heap.aux.capa = (mrb_ssize)capacity;
}
}
@@ -156,13 +184,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)
{
@@ -193,13 +214,42 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared)
{
shared->refcnt--;
if (shared->refcnt == 0) {
- if (!shared->nofree) {
- mrb_free(mrb, shared->ptr);
- }
+ mrb_free(mrb, shared->ptr);
mrb_free(mrb, shared);
}
}
+static void
+str_modify_keep_ascii(mrb_state *mrb, struct RString *s)
+{
+ if (RSTR_SHARED_P(s)) {
+ mrb_shared_string *shared = s->as.heap.aux.shared;
+
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.aux.capa = shared->capa;
+ s->as.heap.ptr[s->as.heap.len] = '\0';
+ RSTR_UNSET_SHARED_FLAG(s);
+ mrb_free(mrb, shared);
+ }
+ else {
+ str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len);
+ str_decref(mrb, shared);
+ }
+ }
+ else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) {
+ str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len);
+ }
+}
+
+static void
+check_null_byte(mrb_state *mrb, mrb_value str)
+{
+ mrb_to_str(mrb, str);
+ 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)
{
@@ -220,104 +270,254 @@ static const char utf8len_codepage[256] =
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,
};
-static mrb_int
-utf8len(const char* p, const char* e)
+#define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80)
+
+mrb_int
+mrb_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)
+ if (utf8_islead(p[i]))
return 1;
return len;
}
-static mrb_int
-utf8_strlen(mrb_value str, mrb_int len)
+mrb_int
+mrb_utf8_strlen(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);
+ mrb_int len = 0;
+ const char *p = str;
+ const char *e = p + byte_len;
+
+ while (p < e) {
+ p += mrb_utf8len(p, e);
+ len++;
}
- e += len < 0 ? RSTRING_LEN(str) : len;
- while (p<e) {
- p += utf8len(p, e);
- total++;
+ return len;
+}
+
+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;
}
- if (RSTRING_LEN(str) == total) {
- RSTRING(str)->flags |= MRB_STR_NO_UTF;
+ else {
+ mrb_int utf8_len = mrb_utf8_strlen(RSTR_PTR(s), byte_len);
+ if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s);
+ return utf8_len;
}
- return total;
}
-#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1)
+#define RSTRING_CHAR_LEN(s) utf8_strlen(s)
/* map character index to byte offset index */
static mrb_int
chars2bytes(mrb_value s, mrb_int off, mrb_int idx)
{
- mrb_int i, b, n;
- const char *p = RSTRING_PTR(s) + off;
- const char *e = RSTRING_END(s);
+ if (RSTR_ASCII_P(mrb_str_ptr(s))) {
+ return idx;
+ }
+ else {
+ mrb_int i, b, n;
+ const char *p = RSTRING_PTR(s) + off;
+ const char *e = RSTRING_END(s);
- for (b=i=0; p<e && i<idx; i++) {
- n = utf8len(p, e);
- b += n;
- p += n;
+ for (b=i=0; p<e && i<idx; i++) {
+ n = mrb_utf8len(p, e);
+ b += n;
+ p += n;
+ }
+ return b;
}
- return b;
}
/* map byte offset to character index */
static mrb_int
-bytes2chars(char *p, mrb_int bi)
+bytes2chars(char *p, mrb_int len, mrb_int bi)
{
- mrb_int i, b, n;
+ const char *e = p + (size_t)len;
+ const char *pivot = p + bi;
+ mrb_int i;
- for (b=i=0; b<bi; i++) {
- n = utf8len_codepage[(unsigned char)*p];
- b += n;
- p += n;
+ for (i = 0; p < pivot; i ++) {
+ p += mrb_utf8len(p, e);
}
- if (b != bi) return -1;
+ if (p != pivot) return -1;
return i;
}
+static const char *
+char_adjust(const char *beg, const char *end, const char *ptr)
+{
+ if ((ptr > beg || ptr < end) && (*ptr & 0xc0) == 0x80) {
+ const int utf8_adjust_max = 3;
+ const char *p;
+
+ if (ptr - beg > utf8_adjust_max) {
+ beg = ptr - utf8_adjust_max;
+ }
+
+ p = ptr;
+ while (p > beg) {
+ p --;
+ if ((*p & 0xc0) != 0x80) {
+ int clen = mrb_utf8len(p, end);
+ if (clen > ptr - p) return p;
+ break;
+ }
+ }
+ }
+
+ return ptr;
+}
+
+static const char *
+char_backtrack(const char *ptr, const char *end)
+{
+ if (ptr < end) {
+ const int utf8_bytelen_max = 4;
+ const char *p;
+
+ if (end - ptr > utf8_bytelen_max) {
+ ptr = end - utf8_bytelen_max;
+ }
+
+ p = end;
+ while (p > ptr) {
+ p --;
+ if ((*p & 0xc0) != 0x80) {
+ int clen = utf8len_codepage[(unsigned char)*p];
+ if (clen == end - p) { return p; }
+ break;
+ }
+ }
+ }
+
+ return end - 1;
+}
+
+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 += mrb_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 += mrb_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 bytes2chars(p, end, bi) (bi)
+#define char_adjust(beg, end, ptr) (ptr)
+#define char_backtrack(ptr, end) ((end) - 1)
#define BYTES_ALIGN_CHECK(pos)
+#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos)
+#endif
+
+#ifndef MRB_QS_SHORT_STRING_LENGTH
+#define MRB_QS_SHORT_STRING_LENGTH 2048
#endif
static inline mrb_int
mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n)
{
- const unsigned char *x = xs, *xe = xs + m;
- const unsigned char *y = ys;
- int i;
- ptrdiff_t qstable[256];
+ if (n + m < MRB_QS_SHORT_STRING_LENGTH) {
+ const unsigned char *y = ys;
+ const unsigned char *ye = ys+n-m+1;
- /* Preprocessing */
- for (i = 0; i < 256; ++i)
- qstable[i] = m + 1;
- for (; x < xe; ++x)
- qstable[*x] = xe - x;
- /* Searching */
- for (; y + m <= ys + n; y += *(qstable + y[m])) {
- if (*xs == *y && memcmp(xs, y, m) == 0)
- return (mrb_int)(y - ys);
+ for (;;) {
+ y = (const unsigned char*)memchr(y, xs[0], (size_t)(ye-y));
+ if (y == NULL) return -1;
+ if (memcmp(xs, y, m) == 0) {
+ return (mrb_int)(y - ys);
+ }
+ y++;
+ }
+ return -1;
+ }
+ else {
+ const unsigned char *x = xs, *xe = xs + m;
+ const unsigned char *y = ys;
+ int i;
+ ptrdiff_t qstable[256];
+
+ /* Preprocessing */
+ for (i = 0; i < 256; ++i)
+ qstable[i] = m + 1;
+ for (; x < xe; ++x)
+ qstable[*x] = xe - x;
+ /* Searching */
+ for (; y + m <= ys + n; y += *(qstable + y[m])) {
+ if (*xs == *y && memcmp(xs, y, m) == 0)
+ return (mrb_int)(y - ys);
+ }
+ return -1;
}
- return -1;
}
static mrb_int
@@ -344,113 +544,87 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
}
static void
-str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s)
+str_share(mrb_state *mrb, struct RString *orig, struct RString *s)
{
- mrb_shared_string *shared;
- mrb_int len = RSTR_LEN(orig);
+ size_t len = (size_t)orig->as.heap.len;
mrb_assert(!RSTR_EMBED_P(orig));
- if (RSTR_SHARED_P(orig)) {
- shared = orig->as.heap.aux.shared;
- shared->refcnt++;
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.shared = shared;
- RSTR_SET_SHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ if (RSTR_NOFREE_P(orig)) {
+ str_init_nofree(s, orig->as.heap.ptr, len);
+ }
+ else if (RSTR_SHARED_P(orig)) {
+ str_init_shared(mrb, orig, s, orig->as.heap.aux.shared);
}
else if (RSTR_FSHARED_P(orig)) {
- struct RString *fs;
-
- fs = orig->as.heap.aux.fshared;
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.fshared = fs;
- RSTR_SET_FSHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
- }
- else if (MRB_FROZEN_P(orig) && !RSTR_POOL_P(orig)) {
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.fshared = orig;
- RSTR_SET_FSHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ str_init_fshared(orig, s, orig->as.heap.aux.fshared);
}
else {
- shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
- shared->refcnt = 2;
- shared->nofree = !!RSTR_NOFREE_P(orig);
- if (!shared->nofree && orig->as.heap.aux.capa > orig->as.heap.len) {
- shared->ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1);
- orig->as.heap.ptr = shared->ptr;
- }
- else {
- shared->ptr = orig->as.heap.ptr;
+ if (orig->as.heap.aux.capa > orig->as.heap.len) {
+ orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1);
+ orig->as.heap.aux.capa = (mrb_ssize)len;
}
- orig->as.heap.aux.shared = shared;
- RSTR_SET_SHARED_FLAG(orig);
- shared->len = len;
- s->as.heap.aux.shared = shared;
- s->as.heap.ptr = shared->ptr;
- s->as.heap.len = len;
- RSTR_SET_SHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ str_init_shared(mrb, orig, s, NULL);
+ str_init_shared(mrb, orig, orig, s->as.heap.aux.shared);
}
}
-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;
orig = mrb_str_ptr(str);
- if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || len <= RSTRING_EMBED_LEN_MAX) {
- s = str_new(mrb, RSTR_PTR(orig)+beg, len);
+ s = mrb_obj_alloc_string(mrb);
+ if (RSTR_EMBEDDABLE_P(len)) {
+ str_init_embed(s, RSTR_PTR(orig)+beg, len);
}
else {
- s = mrb_obj_alloc_string(mrb);
- str_make_shared(mrb, orig, s);
- s->as.heap.ptr += beg;
- s->as.heap.len = len;
+ str_share(mrb, orig, s);
+ s->as.heap.ptr += (mrb_ssize)beg;
+ s->as.heap.len = (mrb_ssize)len;
}
+ RSTR_COPY_ASCII_FLAG(s, orig);
return mrb_obj_value(s);
}
+
+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 (str_len < *begp || *lenp < 0) return FALSE;
+ if (*begp < 0) {
+ *begp += str_len;
+ if (*begp < 0) return FALSE;
}
- if (beg > clen) return mrb_nil_value();
- if (beg < 0) {
- beg += clen;
- if (beg < 0) return mrb_nil_value();
- }
- 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,44 +664,28 @@ 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;
+ size_t 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;
- len = RSTR_LEN(s2);
+ RSTR_COPY_ASCII_FLAG(s1, s2);
if (RSTR_SHARED_P(s1)) {
str_decref(mrb, s1->as.heap.aux.shared);
- RSTR_UNSET_SHARED_FLAG(s1);
}
else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1) && !RSTR_FSHARED_P(s1)
&& s1->as.heap.ptr) {
mrb_free(mrb, s1->as.heap.ptr);
}
- RSTR_UNSET_FSHARED_FLAG(s1);
- RSTR_UNSET_NOFREE_FLAG(s1);
- if (len <= RSTRING_EMBED_LEN_MAX) {
- RSTR_UNSET_SHARED_FLAG(s1);
- RSTR_UNSET_FSHARED_FLAG(s1);
- RSTR_SET_EMBED_FLAG(s1);
- memcpy(s1->as.ary, RSTR_PTR(s2), len);
- RSTR_SET_EMBED_LEN(s1, len);
+ len = (size_t)RSTR_LEN(s2);
+ if (RSTR_EMBEDDABLE_P(len)) {
+ str_init_embed(s1, RSTR_PTR(s2), len);
}
else {
- str_make_shared(mrb, s2, s1);
+ str_share(mrb, s2, s1);
}
return mrb_obj_value(s1);
@@ -536,7 +694,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
static mrb_int
str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
{
- char *s, *sbeg, *t;
+ const char *s, *sbeg, *t;
struct RString *ps = mrb_str_ptr(str);
mrb_int len = RSTRING_LEN(sub);
@@ -549,11 +707,12 @@ str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
s = RSTR_PTR(ps) + pos;
t = RSTRING_PTR(sub);
if (len) {
+ s = char_adjust(sbeg, sbeg + RSTR_LEN(ps), s);
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
return (mrb_int)(s - RSTR_PTR(ps));
}
- s--;
+ s = char_backtrack(sbeg, s);
}
return -1;
}
@@ -641,65 +800,17 @@ 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;
- if (RSTR_SHARED_P(s)) {
- mrb_shared_string *shared = s->as.heap.aux.shared;
+ mrb_check_frozen(mrb, s);
+ str_modify_keep_ascii(mrb, s);
+}
- if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
- s->as.heap.ptr = shared->ptr;
- s->as.heap.aux.capa = shared->len;
- RSTR_PTR(s)[s->as.heap.len] = '\0';
- mrb_free(mrb, shared);
- }
- else {
- char *ptr, *p;
- mrb_int len;
-
- p = RSTR_PTR(s);
- len = s->as.heap.len;
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- ptr = RSTR_PTR(s);
- }
- else {
- ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
- s->as.heap.ptr = ptr;
- s->as.heap.aux.capa = len;
- }
- if (p) {
- memcpy(ptr, p, len);
- }
- ptr[len] = '\0';
- str_decref(mrb, shared);
- }
- RSTR_UNSET_SHARED_FLAG(s);
- return;
- }
- if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) {
- char *p = s->as.heap.ptr;
- mrb_int len = s->as.heap.len;
-
- RSTR_UNSET_FSHARED_FLAG(s);
- RSTR_UNSET_NOFREE_FLAG(s);
- RSTR_UNSET_FSHARED_FLAG(s);
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- }
- else {
- s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- s->as.heap.aux.capa = len;
- }
- if (p) {
- memcpy(RSTR_PTR(s), p, len);
- }
- RSTR_PTR(s)[len] = '\0';
- return;
- }
+MRB_API void
+mrb_str_modify(mrb_state *mrb, struct RString *s)
+{
+ mrb_str_modify_keep_ascii(mrb, s);
+ RSTR_UNSET_ASCII_FLAG(s);
}
MRB_API mrb_value
@@ -728,38 +839,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_obj_as_string(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)
{
@@ -777,10 +868,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)
@@ -834,13 +928,12 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
if (times < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
}
- if (times && MRB_INT_MAX / times < RSTRING_LEN(self)) {
+ if (times && MRB_SSIZE_MAX / times < RSTRING_LEN(self)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "argument too big");
}
len = RSTRING_LEN(self)*times;
str2 = str_new(mrb, 0, len);
- str_with_class(mrb, str2, self);
p = RSTR_PTR(str2);
if (len > 0) {
n = RSTRING_LEN(self);
@@ -852,6 +945,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);
}
@@ -915,26 +1009,11 @@ mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
static mrb_value
mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
{
- mrb_value str2;
+ mrb_value str2 = mrb_get_arg1(mrb);
mrb_int result;
- mrb_get_args(mrb, "o", &str2);
if (!mrb_string_p(str2)) {
- if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_s"))) {
- return mrb_nil_value();
- }
- else if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "<=>"))) {
- return mrb_nil_value();
- }
- else {
- mrb_value tmp = mrb_funcall(mrb, str2, "<=>", 1, str1);
-
- if (mrb_nil_p(tmp)) return mrb_nil_value();
- if (!mrb_fixnum_p(tmp)) {
- return mrb_funcall(mrb, mrb_fixnum_value(0), "-", 1, tmp);
- }
- result = -mrb_fixnum(tmp);
- }
+ return mrb_nil_value();
}
else {
result = mrb_str_cmp(mrb, str1, str2);
@@ -956,15 +1035,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);
}
@@ -982,54 +1053,26 @@ mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2)
static mrb_value
mrb_str_equal_m(mrb_state *mrb, mrb_value str1)
{
- mrb_value str2;
-
- mrb_get_args(mrb, "o", &str2);
+ mrb_value str2 = mrb_get_arg1(mrb);
return mrb_bool_value(mrb_str_equal(mrb, str1, str2));
}
/* ---------------------------------- */
-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;
- }
- return str;
-}
+/* obslete: use RSTRING_PTR() */
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_obj_as_string(mrb, str);
return RSTRING_PTR(str);
}
+/* obslete: use RSTRING_LEN() */
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
@@ -1038,56 +1081,94 @@ 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);
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
+};
+
+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_as_int(mrb, indx);
+ *len = mrb_as_int(mrb, alen);
+ return STR_CHAR_RANGE;
+ }
+ else {
+ switch (mrb_type(indx)) {
+ case MRB_TT_INTEGER:
+ *beg = mrb_integer(indx);
+ *len = 1;
+ return STR_CHAR_RANGE;
- case MRB_TT_RANGE:
- goto range_arg;
+ 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;
- 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_RANGE:
+ goto range_arg;
+
+ default:
+ indx = mrb_to_int(mrb, indx);
+ if (mrb_integer_p(indx)) {
+ *beg = mrb_integer(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");
+
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Integer");
+ }
+ }
+ 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);
}
- idx = mrb_fixnum(indx);
- goto num_index;
+ else {
+ return mrb_str_byte_subseq(mrb, str, beg, len);
+ }
+ case STR_OUT_OF_RANGE:
+ default:
+ return mrb_nil_value();
}
- return mrb_nil_value(); /* not reached */
}
/* 15.2.10.5.6 */
@@ -1097,16 +1178,14 @@ num_index:
* str[fixnum] => fixnum or nil
* str[fixnum, fixnum] => new_str or nil
* str[range] => new_str or nil
- * str[regexp] => new_str or nil
- * str[regexp, fixnum] => new_str or nil
* str[other_str] => new_str or nil
* str.slice(fixnum) => fixnum or nil
* str.slice(fixnum, fixnum) => new_str or nil
* str.slice(range) => new_str or nil
* str.slice(other_str) => new_str or nil
*
- * Element Reference---If passed a single <code>Fixnum</code>, returns the code
- * of the character at that position. If passed two <code>Fixnum</code>
+ * Element Reference---If passed a single <code>Integer</code>, returns the code
+ * of the character at that position. If passed two <code>Integer</code>
* objects, returns a substring starting at the offset given by the first, and
* a length given by the second. If given a range, a substring containing
* characters at offsets given by the range is returned. In all three cases, if
@@ -1134,20 +1213,198 @@ 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 %v out of string", index);
+}
- mrb_regexp_check(mrb, a1);
- mrb_get_args(mrb, "ii", &n1, &n2);
- return str_substr(mrb, str, n1, n2);
+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));
+
+ if (newlen >= MRB_SSIZE_MAX || newlen < replen /* overflowed */) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big");
+ }
+
+ 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)) {
+ memmove(strp + pos, RSTRING_PTR(rep), replen);
}
- if (argc != 1) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
+ RSTR_SET_LEN(str, newlen);
+ strp[newlen] = '\0';
+
+ if (len - newlen >= shrink_threshold) {
+ resize_capa(mrb, str, newlen);
}
- return mrb_str_aref(mrb, str, a1);
+
+ return src;
+}
+
+#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
+
+static mrb_value
+str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect)
+{
+ const char *p, *pend;
+ char buf[4]; /* `\x??` or UTF-8 character */
+ mrb_value result = mrb_str_new_lit(mrb, "\"");
+#ifdef MRB_UTF8_STRING
+ uint32_t ascii_flag = MRB_STR_ASCII;
+#endif
+
+ p = RSTRING_PTR(str); pend = RSTRING_END(str);
+ for (;p < pend; p++) {
+ unsigned char c, cc;
+#ifdef MRB_UTF8_STRING
+ if (inspect) {
+ mrb_int clen = mrb_utf8len(p, pend);
+ if (clen > 1) {
+ mrb_int i;
+
+ for (i=0; i<clen; i++) {
+ buf[i] = p[i];
+ }
+ mrb_str_cat(mrb, result, buf, clen);
+ p += clen-1;
+ ascii_flag = 0;
+ continue;
+ }
+ }
+#endif
+ c = *p;
+ if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) {
+ buf[0] = '\\'; buf[1] = c;
+ mrb_str_cat(mrb, result, buf, 2);
+ continue;
+ }
+ if (ISPRINT(c)) {
+ buf[0] = c;
+ mrb_str_cat(mrb, result, buf, 1);
+ continue;
+ }
+ switch (c) {
+ case '\n': cc = 'n'; break;
+ case '\r': cc = 'r'; break;
+ case '\t': cc = 't'; break;
+ case '\f': cc = 'f'; break;
+ case '\013': cc = 'v'; break;
+ case '\010': cc = 'b'; break;
+ case '\007': cc = 'a'; break;
+ case 033: cc = 'e'; break;
+ default: cc = 0; break;
+ }
+ if (cc) {
+ buf[0] = '\\';
+ buf[1] = (char)cc;
+ mrb_str_cat(mrb, result, buf, 2);
+ continue;
+ }
+ else {
+ buf[0] = '\\';
+ buf[1] = 'x';
+ buf[3] = mrb_digitmap[c % 16]; c /= 16;
+ buf[2] = mrb_digitmap[c % 16];
+ mrb_str_cat(mrb, result, buf, 4);
+ continue;
+ }
+ }
+ mrb_str_cat_lit(mrb, result, "\"");
+#ifdef MRB_UTF8_STRING
+ if (inspect) {
+ mrb_str_ptr(str)->flags |= ascii_flag;
+ mrb_str_ptr(result)->flags |= ascii_flag;
+ }
+ else {
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(result));
+ }
+#endif
+
+ return result;
+}
+
+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;
+
+ 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 %v", 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[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;
+ }
+ mrb_str_aset(mrb, str, indx, alen, replace);
+ return str;
}
/* 15.2.10.5.8 */
@@ -1170,7 +1427,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)) {
@@ -1229,7 +1486,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();
@@ -1291,9 +1548,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
* str.chomp(separator="\n") => new_str
*
* Returns a new <code>String</code> with the given record separator removed
- * from the end of <i>str</i> (if present). If <code>$/</code> has not been
- * changed from the default Ruby record separator, then <code>chomp</code> also
- * removes carriage return characters (that is it will remove <code>\n</code>,
+ * from the end of <i>str</i> (if present). <code>chomp</code> also removes
+ * carriage return characters (that is it will remove <code>\n</code>,
* <code>\r</code>, and <code>\r\n</code>).
*
* "hello".chomp #=> "hello"
@@ -1328,14 +1584,14 @@ 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
const char* t = RSTR_PTR(s), *p = t;
const char* e = p + RSTR_LEN(s);
while (p<e) {
- mrb_int clen = utf8len(p, e);
+ mrb_int clen = mrb_utf8len(p, e);
if (p + clen>=e) break;
p += clen;
}
@@ -1397,7 +1653,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) {
@@ -1461,11 +1717,10 @@ mrb_str_empty_p(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_eql(mrb_state *mrb, mrb_value self)
{
- mrb_value str2;
+ mrb_value str2 = mrb_get_arg1(mrb);
mrb_bool eql_p;
- mrb_get_args(mrb, "o", &str2);
- eql_p = (mrb_type(str2) == MRB_TT_STRING) && str_eql(mrb, self, str2);
+ eql_p = (mrb_string_p(str2)) && str_eql(mrb, self, str2);
return mrb_bool_value(eql_p);
}
@@ -1483,13 +1738,17 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_int len = RSTR_LEN(s);
char *p = RSTR_PTR(s);
- uint64_t key = 0;
+ uint32_t hash = 0;
- while (len--) {
- key = key*65599 + *p;
- p++;
+ for(int i = 0; i < len; ++i) {
+ hash += p[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
}
- return (uint32_t)(key + (key>>5));
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
}
/* 15.2.10.5.20 */
@@ -1534,77 +1793,40 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
/*
* call-seq:
* str.index(substring [, offset]) => fixnum or nil
- * str.index(fixnum [, offset]) => fixnum or nil
- * str.index(regexp [, offset]) => fixnum or nil
*
* Returns the index of the first occurrence of the given
- * <i>substring</i>,
- * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>.
- * Returns
- * <code>nil</code> if not found.
+ * <i>substring</i>. Returns <code>nil</code> if not found.
* If the second parameter is present, it
* specifies the position in the string to begin the search.
*
- * "hello".index('e') #=> 1
+ * "hello".index('l') #=> 2
* "hello".index('lo') #=> 3
* "hello".index('a') #=> nil
- * "hello".index(101) #=> 1(101=0x65='e')
- * "hello".index(/[aeiou]/, -3) #=> 4
+ * "hello".index('l', -2) #=> 3
*/
static mrb_value
mrb_str_index_m(mrb_state *mrb, mrb_value str)
{
- mrb_value *argv;
- mrb_int argc;
mrb_value sub;
- mrb_int pos, clen;
+ mrb_int pos;
- mrb_get_args(mrb, "*!", &argv, &argc);
- if (argc == 2) {
- mrb_get_args(mrb, "oi", &sub, &pos);
- }
- else {
+ if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) {
pos = 0;
- if (argc > 0)
- sub = argv[0];
- else
- sub = mrb_nil_value();
}
- mrb_regexp_check(mrb, sub);
- clen = RSTRING_CHAR_LEN(str);
- if (pos < 0) {
+ else if (pos < 0) {
+ mrb_int 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: {
- mrb_value tmp;
-
- tmp = mrb_check_string_type(mrb, sub);
- if (mrb_nil_p(tmp)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub);
- }
- sub = tmp;
- }
- /* fall through */
- case MRB_TT_STRING:
- pos = str_index_str(mrb, str, sub, pos);
- break;
- }
+ pos = str_index_str_by_char(mrb, str, sub, pos);
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 */
/*
@@ -1651,7 +1873,7 @@ mrb_str_init(mrb_state *mrb, mrb_value self)
* str.to_sym => symbol
*
* Returns the <code>Symbol</code> corresponding to <i>str</i>, creating the
- * symbol if it did not previously exist. See <code>Symbol#id2name</code>.
+ * symbol if it did not previously exist.
*
* "Koala".intern #=> :Koala
* s = 'cat'.to_sym #=> :cat
@@ -1673,15 +1895,20 @@ mrb_str_intern(mrb_state *mrb, mrb_value self)
MRB_API mrb_value
mrb_obj_as_string(mrb_state *mrb, mrb_value obj)
{
- mrb_value str;
-
- if (mrb_string_p(obj)) {
+ switch (mrb_type(obj)) {
+ case MRB_TT_STRING:
return obj;
+ case MRB_TT_SYMBOL:
+ return mrb_sym_str(mrb, mrb_symbol(obj));
+ case MRB_TT_INTEGER:
+ return mrb_integer_to_str(mrb, obj, 10);
+ case MRB_TT_SCLASS:
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ return mrb_mod_to_s(mrb, obj);
+ default:
+ return mrb_type_convert(mrb, obj, MRB_TT_STRING, MRB_SYM(to_s));
}
- str = mrb_funcall(mrb, obj, "to_s", 0);
- if (!mrb_string_p(str))
- return mrb_any_to_s(mrb, obj);
- return str;
}
MRB_API mrb_value
@@ -1714,16 +1941,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 */
@@ -1736,53 +1963,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);
+ mrb_int clen = mrb_utf8len(p, e);
+ 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;
}
/* ---------------------------------- */
@@ -1806,73 +2018,43 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
/* 15.2.10.5.31 */
/*
* call-seq:
- * str.rindex(substring [, fixnum]) => fixnum or nil
- * str.rindex(fixnum [, fixnum]) => fixnum or nil
- * str.rindex(regexp [, fixnum]) => fixnum or nil
+ * str.rindex(substring [, offset]) => fixnum or nil
*
- * Returns the index of the last occurrence of the given <i>substring</i>,
- * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns
- * <code>nil</code> if not found. If the second parameter is present, it
- * specifies the position in the string to end the search---characters beyond
- * this point will not be considered.
+ * Returns the index of the last occurrence of the given <i>substring</i>.
+ * Returns <code>nil</code> if not found. If the second parameter is
+ * present, it specifies the position in the string to end the
+ * search---characters beyond this point will not be considered.
*
* "hello".rindex('e') #=> 1
* "hello".rindex('l') #=> 3
* "hello".rindex('a') #=> nil
- * "hello".rindex(101) #=> 1
- * "hello".rindex(/[aeiou]/, -2) #=> 1
+ * "hello".rindex('l', 2) #=> 2
*/
static mrb_value
mrb_str_rindex(mrb_state *mrb, mrb_value str)
{
- mrb_value *argv;
- mrb_int argc;
mrb_value sub;
mrb_int pos, len = RSTRING_CHAR_LEN(str);
- mrb_get_args(mrb, "*!", &argv, &argc);
- if (argc == 2) {
- mrb_get_args(mrb, "oi", &sub, &pos);
+ if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) {
+ pos = len;
+ }
+ else {
if (pos < 0) {
pos += len;
if (pos < 0) {
- mrb_regexp_check(mrb, sub);
return mrb_nil_value();
}
}
if (pos > len) pos = len;
}
- else {
- pos = len;
- if (argc > 0)
- sub = argv[0];
- else
- sub = mrb_nil_value();
- }
pos = chars2bytes(str, 0, pos);
- mrb_regexp_check(mrb, sub);
-
- switch (mrb_type(sub)) {
- default: {
- mrb_value tmp;
-
- tmp = mrb_check_string_type(mrb, sub);
- if (mrb_nil_p(tmp)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub);
- }
- sub = tmp;
- }
- /* fall through */
- case MRB_TT_STRING:
- pos = str_rindex(mrb, str, sub, pos);
- if (pos >= 0) {
- pos = bytes2chars(RSTRING_PTR(str), pos);
- BYTES_ALIGN_CHECK(pos);
- return mrb_fixnum_value(pos);
- }
- break;
-
- } /* end of switch (TYPE(sub)) */
+ pos = str_rindex(mrb, str, sub, pos);
+ if (pos >= 0) {
+ pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos);
+ BYTES_ALIGN_CHECK(pos);
+ return mrb_fixnum_value(pos);
+ }
return mrb_nil_value();
}
@@ -1880,23 +2062,18 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
/*
* call-seq:
- * str.split(pattern="\n", [limit]) => anArray
+ * str.split(separator=nil, [limit]) => anArray
*
* Divides <i>str</i> into substrings based on a delimiter, returning an array
* of these substrings.
*
- * If <i>pattern</i> is a <code>String</code>, then its contents are used as
- * the delimiter when splitting <i>str</i>. If <i>pattern</i> is a single
+ * If <i>separator</i> is a <code>String</code>, then its contents are used as
+ * the delimiter when splitting <i>str</i>. If <i>separator</i> is a single
* space, <i>str</i> is split on whitespace, with leading whitespace and runs
* of contiguous whitespace characters ignored.
*
- * If <i>pattern</i> is a <code>Regexp</code>, <i>str</i> is divided where the
- * pattern matches. Whenever the pattern matches a zero-length string,
- * <i>str</i> is split into individual characters.
- *
- * If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If
- * <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is
- * split on whitespace as if ' ' were specified.
+ * If <i>separator</i> is omitted or <code>nil</code> (which is the default),
+ * <i>str</i> is split on whitespace as if ' ' were specified.
*
* If the <i>limit</i> parameter is omitted, trailing null fields are
* suppressed. If <i>limit</i> is a positive number, at most that number of
@@ -1907,9 +2084,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
*
* " now's the time".split #=> ["now's", "the", "time"]
* " now's the time".split(' ') #=> ["now's", "the", "time"]
- * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"]
- * "hello".split(//) #=> ["h", "e", "l", "l", "o"]
- * "hello".split(//, 3) #=> ["h", "e", "llo"]
*
* "mellow yellow".split("ello") #=> ["m", "w y", "w"]
* "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"]
@@ -1922,7 +2096,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
{
mrb_int argc;
mrb_value spat = mrb_nil_value();
- enum {awk, string, regexp} split_type = string;
+ enum {awk, string} split_type = string;
mrb_int i = 0;
mrb_int beg;
mrb_int end;
@@ -1944,16 +2118,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);
@@ -1979,7 +2148,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;
@@ -1990,7 +2159,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;
@@ -2004,22 +2173,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);
+ tmp = mrb_str_new(mrb, 0, 0);
}
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);
}
@@ -2033,14 +2199,14 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
-MRB_API mrb_value
-mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck)
+static mrb_value
+mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck)
{
const char *p = str;
const char *pend = str + len;
char sign = 1;
int c;
- uint64_t n = 0;
+ mrb_int n = 0;
mrb_int val;
#define conv_digit(c) \
@@ -2117,7 +2283,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
break;
default:
if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base);
}
break;
} /* end of switch (base) { */
@@ -2144,7 +2310,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
if (*(p - 1) == '0')
p--;
}
- if (p == pend) {
+ if (p == pend || *p == '_') {
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
@@ -2167,62 +2333,65 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
if (c < 0 || c >= base) {
break;
}
- n *= base;
- n += c;
- if (n > (uint64_t)MRB_INT_MAX + (sign ? 0 : 1)) {
-#ifndef MRB_WITHOUT_FLOAT
- if (base == 10) {
- return mrb_float_value(mrb, mrb_str_to_dbl(mrb, mrb_str_new(mrb, str, len), badcheck));
- }
- else
-#endif
- {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer",
- mrb_str_new(mrb, str, pend-str));
+ if (mrb_int_mul_overflow(n, base, &n)) goto overflow;
+ if (MRB_INT_MAX - c < n) {
+ if (sign == 0 && MRB_INT_MAX - n == c - 1) {
+ n = MRB_INT_MIN;
+ sign = 1;
+ break;
}
+ overflow:
+ mrb_raisef(mrb, E_RANGE_ERROR, "string (%l) too big for integer", str, pend-str);
}
+ n += c;
}
val = (mrb_int)n;
if (badcheck) {
- if (p == str) goto bad; /* no number */
+ if (p == str) goto bad; /* no number */
+ if (*(p - 1) == '_') goto bad; /* trailing '_' */
while (p<pend && ISSPACE(*p)) p++;
- if (p<pend) goto bad; /* trailing garbage */
+ if (p<pend) goto bad; /* trailing garbage */
}
- return mrb_fixnum_value(sign ? val : -val);
+ return mrb_int_value(mrb, sign ? val : -val);
nullbyte:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
/* not reached */
bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)",
- mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str)));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%!l)", str, pend-str);
/* not reached */
return mrb_fixnum_value(0);
}
-MRB_API mrb_value
-mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
-{
- return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck);
-}
-
+/* obslete: use RSTRING_CSTR() or mrb_string_cstr() */
MRB_API const char*
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
- 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') {
- if (MRB_FROZEN_P(ps)) {
- *ptr = str = mrb_str_dup(mrb, str);
- ps = mrb_str_ptr(str);
- }
- mrb_str_modify(mrb, ps);
- return RSTR_PTR(ps);
+ check_null_byte(mrb, *ptr);
+ ps = mrb_str_ptr(*ptr);
+ p = RSTR_PTR(ps);
+ len = RSTR_LEN(ps);
+ if (p[len] == '\0') {
+ return p;
}
- return p;
+
+ /*
+ * Even after str_modify_keep_ascii(), NULL termination is not ensured if
+ * RSTR_SET_LEN() is used explicitly (e.g. String#delete_suffix!).
+ */
+ str_modify_keep_ascii(mrb, ps);
+ RSTR_PTR(ps)[len] = '\0';
+ return RSTR_PTR(ps);
+}
+
+MRB_API const char*
+mrb_string_cstr(mrb_state *mrb, mrb_value str)
+{
+ return mrb_string_value_cstr(mrb, &str);
}
MRB_API mrb_value
@@ -2231,7 +2400,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
const char *s;
mrb_int len;
- s = mrb_string_value_ptr(mrb, str);
+ mrb_to_str(mrb, str);
+ s = RSTRING_PTR(str);
len = RSTRING_LEN(str);
return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
}
@@ -2263,72 +2433,98 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
- if (base < 0) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
+ if (base < 0 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base);
}
return mrb_str_to_inum(mrb, self, base, FALSE);
}
-#ifndef MRB_WITHOUT_FLOAT
-MRB_API double
-mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
+#ifndef MRB_NO_FLOAT
+static double
+mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
{
+ char buf[DBL_DIG * 4 + 20];
+ const char *p = s, *p2;
+ const char *pend = p + len;
char *end;
- char buf[DBL_DIG * 4 + 10];
+ char *n;
+ char prev = 0;
double d;
-
- enum {max_width = 20};
+ mrb_bool dot = FALSE;
if (!p) return 0.0;
- while (ISSPACE(*p)) p++;
-
- if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
- return 0.0;
+ while (p<pend && ISSPACE(*p)) p++;
+ p2 = p;
+
+ if (pend - p > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ mrb_value x;
+
+ if (!badcheck) return 0.0;
+ x = mrb_str_len_to_inum(mrb, p, pend-p, 0, badcheck);
+ if (mrb_integer_p(x))
+ d = (double)mrb_integer(x);
+ else /* if (mrb_float_p(x)) */
+ d = mrb_float(x);
+ return d;
+ }
+ while (p < pend) {
+ if (!*p) {
+ if (badcheck) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte");
+ /* not reached */
+ }
+ pend = p;
+ p = p2;
+ goto nocopy;
+ }
+ if (!badcheck && *p == ' ') {
+ pend = p;
+ p = p2;
+ goto nocopy;
+ }
+ if (*p == '_') break;
+ p++;
}
+ p = p2;
+ n = buf;
+ while (p < pend) {
+ char c = *p++;
+ if (c == '.') dot = TRUE;
+ if (c == '_') {
+ /* remove an underscore between digits */
+ if (n == buf || !ISDIGIT(prev) || p == pend) {
+ if (badcheck) goto bad;
+ break;
+ }
+ }
+ else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad;
+ else {
+ const char *bend = buf+sizeof(buf)-1;
+ if (n==bend) { /* buffer overflow */
+ if (dot) break; /* cut off remaining fractions */
+ return INFINITY;
+ }
+ *n++ = c;
+ }
+ prev = c;
+ }
+ *n = '\0';
+ p = buf;
+ pend = n;
+nocopy:
d = mrb_float_read(p, &end);
if (p == end) {
if (badcheck) {
bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%!s)", s);
/* not reached */
}
return d;
}
- if (*end) {
- char *n = buf;
- char *e = buf + sizeof(buf) - 1;
- char prev = 0;
-
- while (p < end && n < e) prev = *n++ = *p++;
- while (*p) {
- if (*p == '_') {
- /* remove underscores between digits */
- if (badcheck) {
- if (n == buf || !ISDIGIT(prev)) goto bad;
- ++p;
- if (!ISDIGIT(*p)) goto bad;
- }
- else {
- while (*++p == '_');
- continue;
- }
- }
- prev = *p++;
- if (n < e) *n++ = prev;
- }
- *n = '\0';
- p = buf;
-
- if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
- return 0.0;
- }
-
- d = mrb_float_read(p, &end);
- if (badcheck) {
- if (!end || p == end) goto bad;
- while (*end && ISSPACE(*end)) end++;
- if (*end) goto bad;
- }
+ if (badcheck) {
+ if (!end || p == end) goto bad;
+ while (end<pend && ISSPACE(*end)) end++;
+ if (end<pend) goto bad;
}
return d;
}
@@ -2336,22 +2532,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_str_len_to_dbl(mrb, RSTRING_PTR(str), RSTRING_LEN(str), badcheck);
}
/* 15.2.10.5.39 */
@@ -2360,7 +2541,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
* str.to_f => float
*
* Returns the result of interpreting leading characters in <i>str</i> as a
- * floating point number. Extraneous characters past the end of a valid number
+ * floating-point number. Extraneous characters past the end of a valid number
* are ignored. If there is not a valid number at the start of <i>str</i>,
* <code>0.0</code> is returned. This method never raises an exception.
*
@@ -2379,7 +2560,6 @@ mrb_str_to_f(mrb_state *mrb, mrb_value self)
/*
* call-seq:
* str.to_s => str
- * str.to_str => str
*
* Returns the receiver.
*/
@@ -2407,7 +2587,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) {
@@ -2443,8 +2623,6 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self)
return str;
}
-#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
-
/*
* call-seq:
* str.dump -> new_str
@@ -2455,113 +2633,7 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self)
mrb_value
mrb_str_dump(mrb_state *mrb, mrb_value str)
{
- mrb_int len;
- const char *p, *pend;
- char *q;
- struct RString *result;
-
- len = 2; /* "" */
- p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
- while (p < pend) {
- unsigned char c = *p++;
- switch (c) {
- case '"': case '\\':
- case '\n': case '\r':
- case '\t': case '\f':
- case '\013': case '\010': case '\007': case '\033':
- len += 2;
- break;
-
- case '#':
- len += IS_EVSTR(p, pend) ? 2 : 1;
- break;
-
- default:
- if (ISPRINT(c)) {
- len++;
- }
- else {
- len += 4; /* \NNN */
- }
- break;
- }
- }
-
- result = str_new(mrb, 0, len);
- str_with_class(mrb, result, str);
- p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
- q = RSTR_PTR(result);
- *q++ = '"';
- while (p < pend) {
- unsigned char c = *p++;
-
- switch (c) {
- case '"':
- case '\\':
- *q++ = '\\';
- *q++ = c;
- break;
-
- case '\n':
- *q++ = '\\';
- *q++ = 'n';
- break;
-
- case '\r':
- *q++ = '\\';
- *q++ = 'r';
- break;
-
- case '\t':
- *q++ = '\\';
- *q++ = 't';
- break;
-
- case '\f':
- *q++ = '\\';
- *q++ = 'f';
- break;
-
- case '\013':
- *q++ = '\\';
- *q++ = 'v';
- break;
-
- case '\010':
- *q++ = '\\';
- *q++ = 'b';
- break;
-
- case '\007':
- *q++ = '\\';
- *q++ = 'a';
- break;
-
- case '\033':
- *q++ = '\\';
- *q++ = 'e';
- break;
-
- case '#':
- if (IS_EVSTR(p, pend)) *q++ = '\\';
- *q++ = '#';
- break;
-
- default:
- if (ISPRINT(c)) {
- *q++ = c;
- }
- else {
- *q++ = '\\';
- *q++ = 'x';
- q[1] = mrb_digitmap[c % 16]; c /= 16;
- q[0] = mrb_digitmap[c % 16];
- q += 2;
- }
- }
- }
- *q = '"';
- return mrb_obj_value(result);
+ return str_escape(mrb, str, FALSE);
}
MRB_API mrb_value
@@ -2580,21 +2652,21 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
capa = RSTR_CAPA(s);
total = RSTR_LEN(s)+len;
- if (total >= MRB_INT_MAX) {
+ if (total >= MRB_SSIZE_MAX) {
size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
if (capa <= total) {
if (capa == 0) capa = 1;
while (capa <= total) {
- if (capa <= MRB_INT_MAX / 2) {
+ if (capa <= MRB_SSIZE_MAX / 2) {
capa *= 2;
}
else {
capa = total+1;
}
}
- if (capa <= total || capa > MRB_INT_MAX) {
+ if (capa <= total || capa > MRB_SSIZE_MAX) {
goto size_error;
}
resize_capa(mrb, s, capa);
@@ -2603,7 +2675,7 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
ptr = RSTR_PTR(s) + off;
}
memcpy(RSTR_PTR(s) + RSTR_LEN(s), ptr, len);
- mrb_assert_int_fit(size_t, total, mrb_int, MRB_INT_MAX);
+ mrb_assert_int_fit(size_t, total, mrb_ssize, MRB_SSIZE_MAX);
RSTR_SET_LEN(s, total);
RSTR_PTR(s)[total] = '\0'; /* sentinel */
return str;
@@ -2612,7 +2684,7 @@ mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
MRB_API mrb_value
mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr)
{
- return mrb_str_cat(mrb, str, ptr, strlen(ptr));
+ return mrb_str_cat(mrb, str, ptr, ptr ? strlen(ptr) : 0);
}
MRB_API mrb_value
@@ -2627,12 +2699,10 @@ 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);
}
-#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
-
/*
* call-seq:
* str.inspect -> string
@@ -2647,68 +2717,7 @@ mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2)
mrb_value
mrb_str_inspect(mrb_state *mrb, mrb_value str)
{
- const char *p, *pend;
- char buf[CHAR_ESC_LEN + 1];
- mrb_value result = mrb_str_new_lit(mrb, "\"");
-
- p = RSTRING_PTR(str); pend = RSTRING_END(str);
- for (;p < pend; p++) {
- unsigned char c, cc;
-#ifdef MRB_UTF8_STRING
- mrb_int clen;
-
- clen = utf8len(p, pend);
- if (clen > 1) {
- mrb_int i;
-
- for (i=0; i<clen; i++) {
- buf[i] = p[i];
- }
- mrb_str_cat(mrb, result, buf, clen);
- p += clen-1;
- continue;
- }
-#endif
- c = *p;
- if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) {
- buf[0] = '\\'; buf[1] = c;
- mrb_str_cat(mrb, result, buf, 2);
- continue;
- }
- if (ISPRINT(c)) {
- buf[0] = c;
- mrb_str_cat(mrb, result, buf, 1);
- continue;
- }
- switch (c) {
- case '\n': cc = 'n'; break;
- case '\r': cc = 'r'; break;
- case '\t': cc = 't'; break;
- case '\f': cc = 'f'; break;
- case '\013': cc = 'v'; break;
- case '\010': cc = 'b'; break;
- case '\007': cc = 'a'; break;
- case 033: cc = 'e'; break;
- default: cc = 0; break;
- }
- if (cc) {
- buf[0] = '\\';
- buf[1] = (char)cc;
- mrb_str_cat(mrb, result, buf, 2);
- continue;
- }
- else {
- buf[0] = '\\';
- buf[1] = 'x';
- buf[3] = mrb_digitmap[c % 16]; c /= 16;
- buf[2] = mrb_digitmap[c % 16];
- mrb_str_cat(mrb, result, buf, 4);
- continue;
- }
- }
- mrb_str_cat_lit(mrb, result, "\"");
-
- return result;
+ return str_escape(mrb, str, TRUE);
}
/*
@@ -2734,13 +2743,119 @@ mrb_str_bytes(mrb_state *mrb, mrb_value str)
return a;
}
+/*
+ * call-seq:
+ * str.getbyte(index) -> 0 .. 255
+ *
+ * returns the <i>index</i>th byte as an integer.
+ */
+static mrb_value
+mrb_str_getbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos;
+ mrb_get_args(mrb, "i", &pos);
+
+ if (pos < 0)
+ pos += RSTRING_LEN(str);
+ if (pos < 0 || RSTRING_LEN(str) <= pos)
+ return mrb_nil_value();
+
+ return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]);
+}
+
+/*
+ * call-seq:
+ * str.setbyte(index, integer) -> integer
+ *
+ * modifies the <i>index</i>th byte as <i>integer</i>.
+ */
+static mrb_value
+mrb_str_setbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos, byte;
+ mrb_int len;
+
+ mrb_get_args(mrb, "ii", &pos, &byte);
+
+ len = RSTRING_LEN(str);
+ if (pos < -len || len <= pos)
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of string", pos);
+ if (pos < 0)
+ pos += len;
+
+ mrb_str_modify(mrb, mrb_str_ptr(str));
+ byte &= 0xff;
+ RSTRING_PTR(str)[pos] = (unsigned char)byte;
+ return mrb_fixnum_value((unsigned char)byte);
+}
+
+/*
+ * call-seq:
+ * str.byteslice(integer) -> new_str or nil
+ * str.byteslice(integer, integer) -> new_str or nil
+ * str.byteslice(range) -> new_str or nil
+ *
+ * Byte Reference---If passed a single Integer, returns a
+ * substring of one byte at that position. If passed two Integer
+ * objects, returns a substring starting at the offset given by the first, and
+ * a length given by the second. If given a Range, a substring containing
+ * bytes at offsets given by the range is returned. In all three cases, if
+ * an offset is negative, it is counted from the end of <i>str</i>. Returns
+ * <code>nil</code> if the initial offset falls outside the string, the length
+ * is negative, or the beginning of the range is greater than the end.
+ * The encoding of the resulted string keeps original encoding.
+ *
+ * "hello".byteslice(1) #=> "e"
+ * "hello".byteslice(-1) #=> "o"
+ * "hello".byteslice(1, 2) #=> "el"
+ * "\x80\u3042".byteslice(1, 3) #=> "\u3042"
+ * "\x03\u3042\xff".byteslice(1..3) #=> "\u3042"
+ */
+static mrb_value
+mrb_str_byteslice(mrb_state *mrb, mrb_value str)
+{
+ mrb_value a1;
+ mrb_int str_len = RSTRING_LEN(str), beg, len;
+ mrb_bool empty = TRUE;
+
+ len = mrb_get_argc(mrb);
+ switch (len) {
+ case 2:
+ mrb_get_args(mrb, "ii", &beg, &len);
+ break;
+ case 1:
+ a1 = mrb_get_arg1(mrb);
+ if (mrb_range_p(a1)) {
+ if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) != MRB_RANGE_OK) {
+ return mrb_nil_value();
+ }
+ }
+ else {
+ beg = mrb_integer(mrb_to_int(mrb, a1));
+ len = 1;
+ empty = FALSE;
+ }
+ break;
+ default:
+ mrb_argnum_error(mrb, len, 1, 2);
+ break;
+ }
+ if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) {
+ return mrb_str_byte_subseq(mrb, str, beg, len);
+ }
+ else {
+ return mrb_nil_value();
+ }
+}
+
/* ---------------------------*/
void
mrb_init_string(mrb_state *mrb)
{
struct RClass *s;
- mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string");
+ mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << MRB_STR_EMBED_LEN_BIT),
+ "pointer size too big for embedded string");
mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
@@ -2752,6 +2867,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 */
@@ -2765,7 +2881,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */
mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */
- mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
+ mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ARG(1,1)); /* 15.2.10.5.22 */
mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */
mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */
mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */
@@ -2778,7 +2894,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.34 */
mrb_define_method(mrb, s, "split", mrb_str_split_m, MRB_ARGS_ANY()); /* 15.2.10.5.35 */
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.38 */
#endif
mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */
@@ -2789,251 +2905,8 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */
mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
-}
-
-#ifndef MRB_WITHOUT_FLOAT
-/*
- * Source code for the "strtod" library procedure.
- *
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * Copyright (c) 1994 Sun Microsystems, Inc.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $
- */
-
-#include <ctype.h>
-#include <errno.h>
-
-static const int maxExponent = 511; /* Largest possible base 10 exponent. Any
- * exponent larger than this will already
- * produce underflow or overflow, so there's
- * no need to worry about additional digits.
- */
-static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */
- 10., /* is 10^2^i. Used to convert decimal */
- 100., /* exponents into floating-point numbers. */
- 1.0e4,
- 1.0e8,
- 1.0e16,
- 1.0e32,
- 1.0e64,
- 1.0e128,
- 1.0e256
-};
-
-MRB_API double
-mrb_float_read(const char *string, char **endPtr)
-/* const char *string; A decimal ASCII floating-point number,
- * optionally preceded by white space.
- * Must have form "-I.FE-X", where I is the
- * integer part of the mantissa, F is the
- * fractional part of the mantissa, and X
- * is the exponent. Either of the signs
- * may be "+", "-", or omitted. Either I
- * or F may be omitted, or both. The decimal
- * point isn't necessary unless F is present.
- * The "E" may actually be an "e". E and X
- * may both be omitted (but not just one).
- */
-/* char **endPtr; If non-NULL, store terminating character's
- * address here. */
-{
- int sign, expSign = FALSE;
- double fraction, dblExp;
- const double *d;
- const char *p;
- int c;
- int exp = 0; /* Exponent read from "EX" field. */
- int fracExp = 0; /* Exponent that derives from the fractional
- * part. Under normal circumstatnces, it is
- * the negative of the number of digits in F.
- * However, if I is very long, the last digits
- * of I get dropped (otherwise a long I with a
- * large negative exponent could cause an
- * unnecessary overflow on I alone). In this
- * case, fracExp is incremented one for each
- * dropped digit. */
- int mantSize; /* Number of digits in mantissa. */
- int decPt; /* Number of mantissa digits BEFORE decimal
- * point. */
- const char *pExp; /* Temporarily holds location of exponent
- * in string. */
-
- /*
- * Strip off leading blanks and check for a sign.
- */
-
- p = string;
- while (isspace(*p)) {
- p += 1;
- }
- if (*p == '-') {
- sign = TRUE;
- p += 1;
- }
- else {
- if (*p == '+') {
- p += 1;
- }
- sign = FALSE;
- }
-
- /*
- * Count the number of digits in the mantissa (including the decimal
- * point), and also locate the decimal point.
- */
-
- decPt = -1;
- for (mantSize = 0; ; mantSize += 1)
- {
- c = *p;
- if (!isdigit(c)) {
- if ((c != '.') || (decPt >= 0)) {
- break;
- }
- decPt = mantSize;
- }
- p += 1;
- }
-
- /*
- * Now suck up the digits in the mantissa. Use two integers to
- * collect 9 digits each (this is faster than using floating-point).
- * If the mantissa has more than 18 digits, ignore the extras, since
- * they can't affect the value anyway.
- */
-
- pExp = p;
- p -= mantSize;
- if (decPt < 0) {
- decPt = mantSize;
- }
- else {
- mantSize -= 1; /* One of the digits was the point. */
- }
- if (mantSize > 18) {
- if (decPt - 18 > 29999) {
- fracExp = 29999;
- }
- else {
- fracExp = decPt - 18;
- }
- mantSize = 18;
- }
- else {
- fracExp = decPt - mantSize;
- }
- if (mantSize == 0) {
- fraction = 0.0;
- p = string;
- goto done;
- }
- else {
- int frac1, frac2;
- frac1 = 0;
- for ( ; mantSize > 9; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac1 = 10*frac1 + (c - '0');
- }
- frac2 = 0;
- for (; mantSize > 0; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac2 = 10*frac2 + (c - '0');
- }
- fraction = (1.0e9 * frac1) + frac2;
- }
-
- /*
- * Skim off the exponent.
- */
-
- p = pExp;
- if ((*p == 'E') || (*p == 'e')) {
- p += 1;
- if (*p == '-') {
- expSign = TRUE;
- p += 1;
- }
- else {
- if (*p == '+') {
- p += 1;
- }
- expSign = FALSE;
- }
- while (isdigit(*p)) {
- exp = exp * 10 + (*p - '0');
- if (exp > 19999) {
- exp = 19999;
- }
- p += 1;
- }
- }
- if (expSign) {
- exp = fracExp - exp;
- }
- else {
- exp = fracExp + exp;
- }
-
- /*
- * Generate a floating-point number that represents the exponent.
- * Do this by processing the exponent one bit at a time to combine
- * many powers of 2 of 10. Then combine the exponent with the
- * fraction.
- */
-
- if (exp < 0) {
- expSign = TRUE;
- exp = -exp;
- }
- else {
- expSign = FALSE;
- }
- if (exp > maxExponent) {
- exp = maxExponent;
- errno = ERANGE;
- }
- dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
- if (exp & 01) {
- dblExp *= *d;
- }
- }
- if (expSign) {
- fraction /= dblExp;
- }
- else {
- fraction *= dblExp;
- }
-
-done:
- if (endPtr != NULL) {
- *endPtr = (char *) p;
- }
- if (sign) {
- return -fraction;
- }
- return fraction;
+ mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1));
}
-#endif
diff --git a/src/symbol.c b/src/symbol.c
index 6b4c7200c..007b8c885 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -11,65 +11,195 @@
#include <mruby/string.h>
#include <mruby/dump.h>
#include <mruby/class.h>
+#include <mruby/presym.h>
+
+#ifndef MRB_NO_PRESYM
+
+#ifndef MRB_PRESYM_SCANNING
+/* const uint16_t presym_length_table[] */
+/* const char * const presym_name_table[] */
+# include <mruby/presym/table.h>
+#endif
+
+static mrb_sym
+presym_find(const char *name, size_t len)
+{
+ if (presym_length_table[MRB_PRESYM_MAX-1] < len) return 0;
+
+ mrb_sym start, idx, presym_size = MRB_PRESYM_MAX;
+ int cmp;
+ for (start = 0; presym_size != 0; presym_size/=2) {
+ idx = start+presym_size/2;
+ cmp = (int)len-(int)presym_length_table[idx];
+ if (cmp == 0) {
+ cmp = memcmp(name, presym_name_table[idx], len);
+ if (cmp == 0) return idx+1;
+ }
+ if (0 < cmp) {
+ start = ++idx;
+ --presym_size;
+ }
+ }
+ return 0;
+}
+
+static const char*
+presym_sym2name(mrb_sym sym, mrb_int *lenp)
+{
+ if (sym > MRB_PRESYM_MAX) return NULL;
+ if (lenp) *lenp = presym_length_table[sym-1];
+ return presym_name_table[sym-1];
+}
+
+#endif /* MRB_NO_PRESYM */
/* ------------------------------------------------------ */
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)
+static void
+sym_validate_len(mrb_state *mrb, size_t len)
+{
+ if (len >= UINT16_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
+}
+
+#ifdef MRB_USE_ALL_SYMBOLS
+# define SYMBOL_INLINE_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) >= (1<<24))
+
+static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+static mrb_sym
+sym_inline_pack(const char *name, size_t len)
{
- khint_t h = 0;
- size_t i, len = mrb->symtbl[s].len;
- const char *p = mrb->symtbl[s].name;
+ const size_t pack_length_max = 5;
+
+ char c;
+ const char *p;
+ size_t i;
+ mrb_sym sym = 0;
+ if (len > pack_length_max) return 0; /* too long */
+ if (len == 0) return 0; /* empty string */
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;
+ sym |= bits<<(24-i*6);
}
- return h;
+ mrb_assert(SYMBOL_INLINE_P(sym));
+ return sym;
}
-#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 i;
+
+ mrb_assert(SYMBOL_INLINE_P(sym));
+
+ for (i=0; i<5; i++) {
+ uint32_t bits = sym>>(24-i*6) & 0x3f;
+ 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, size_t len, uint8_t *hashp)
+{
+ mrb_sym i;
+ symbol_name *sname;
+ uint8_t hash;
+
+#ifndef MRB_NO_PRESYM
+ /* presym */
+ i = presym_find(name, len);
+ if (i > 0) return i;
+#endif
+
+ /* inline symbol */
+ i = sym_inline_pack(name, len);
+ if (i > 0) return i;
+
+ hash = symhash(name, len);
+ if (hashp) *hashp = hash;
+
+ 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+MRB_PRESYM_MAX);
+ }
+ 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)+MRB_PRESYM_MAX);
+ }
+ 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);
- }
+ sym = find_symbol(mrb, name, len, &hash);
+ if (sym > 0) return sym;
/* registering a new symbol */
- sym = ++mrb->symidx;
+ sym = mrb->symidx + 1;
if (mrb->symcapa < sym) {
- if (mrb->symcapa == 0) mrb->symcapa = 100;
- else mrb->symcapa = (size_t)(mrb->symcapa * 6 / 5);
- mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1));
+ size_t symcapa = mrb->symcapa;
+ if (symcapa == 0) symcapa = 100;
+ else symcapa = (size_t)(symcapa * 6 / 5);
+ mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(symcapa+1));
+ mrb->symcapa = symcapa;
}
sname = &mrb->symtbl[sym];
sname->len = (uint16_t)len;
@@ -78,15 +208,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] = mrb->symidx = sym;
- return sym;
+ return (sym+MRB_PRESYM_MAX);
}
MRB_API mrb_sym
@@ -113,41 +253,69 @@ mrb_intern_str(mrb_state *mrb, mrb_value str)
return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
-MRB_API mrb_value
-mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
+MRB_API mrb_sym
+mrb_intern_check(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;
+ sym = find_symbol(mrb, name, len, NULL);
+ if (sym > 0) return sym;
+ return 0;
+}
- k = kh_get(n2s, mrb, h, 0);
- if (k != kh_end(h)) {
- return mrb_symbol_value(kh_key(h, k));
- }
- return mrb_nil_value();
+MRB_API mrb_value
+mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
+{
+ mrb_sym sym = mrb_intern_check(mrb, name, len);
+ if (sym == 0) return mrb_nil_value();
+ return mrb_symbol_value(sym);
+}
+
+MRB_API mrb_sym
+mrb_intern_check_cstr(mrb_state *mrb, const char *name)
+{
+ return mrb_intern_check(mrb, name, strlen(name));
}
MRB_API mrb_value
mrb_check_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
+ mrb_sym sym = mrb_intern_check_cstr(mrb, name);
+ if (sym == 0) return mrb_nil_value();
+ return mrb_symbol_value(sym);
+}
+
+MRB_API mrb_sym
+mrb_intern_check_str(mrb_state *mrb, mrb_value str)
+{
+ return mrb_intern_check(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
MRB_API mrb_value
mrb_check_intern_str(mrb_state *mrb, mrb_value str)
{
- return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
+ mrb_sym sym = mrb_intern_check_str(mrb, str);
+ if (sym == 0) return mrb_nil_value();
+ return mrb_symbol_value(sym);
}
-/* 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 (sym == 0 || mrb->symidx < sym) {
+ if (sym == 0) goto outofsym;
+ if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp);
+
+#ifndef MRB_NO_PRESYM
+ {
+ const char *name = presym_sym2name(sym, lenp);
+ if (name) return name;
+ }
+#endif
+ sym -= MRB_PRESYM_MAX;
+
+ if (mrb->symidx < sym) {
+ outofsym:
if (lenp) *lenp = 0;
return NULL;
}
@@ -156,6 +324,16 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
return mrb->symtbl[sym].name;
}
+MRB_API const char*
+mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
+{
+#ifdef MRB_USE_ALL_SYMBOLS
+ return sym2name_len(mrb, sym, NULL, lenp);
+#else
+ return sym2name_len(mrb, sym, mrb->symbuf, lenp);
+#endif
+}
+
void
mrb_free_symtbl(mrb_state *mrb)
{
@@ -167,13 +345,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,46 +385,44 @@ mrb_init_symtbl(mrb_state *mrb)
*
*/
-
-/* 15.2.11.3.1 */
+/* 15.2.11.3.2 */
+/* 15.2.11.3.3 */
/*
* call-seq:
- * sym == obj -> true or false
+ * sym.to_s -> string
*
- * Equality---If <i>sym</i> and <i>obj</i> are exactly the same
- * symbol, returns <code>true</code>.
+ * Returns the name or string corresponding to <i>sym</i>.
+ *
+ * :fred.to_s #=> "fred"
*/
-
static mrb_value
-sym_equal(mrb_state *mrb, mrb_value sym1)
+sym_to_s(mrb_state *mrb, mrb_value sym)
{
- mrb_value sym2;
-
- mrb_get_args(mrb, "o", &sym2);
-
- return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2));
+ return mrb_sym_str(mrb, mrb_symbol(sym));
}
-/* 15.2.11.3.2 */
-/* 15.2.11.3.3 */
/*
* call-seq:
- * sym.id2name -> string
- * sym.to_s -> string
+ * sym.name -> string
*
- * Returns the name or string corresponding to <i>sym</i>.
+ * Returns the name or string corresponding to <i>sym</i>. Unlike #to_s, the
+ * returned string is frozen.
*
- * :fred.id2name #=> "fred"
+ * :fred.name #=> "fred"
+ * :fred.name.frozen? #=> true
*/
static mrb_value
-mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
+sym_name(mrb_state *mrb, mrb_value vsym)
{
- mrb_sym id = mrb_symbol(sym);
- const char *p;
+ mrb_sym sym = mrb_symbol(vsym);
mrb_int len;
+ const char *name = mrb_sym_name_len(mrb, sym, &len);
- p = mrb_sym2name_len(mrb, id, &len);
- return mrb_str_new_static(mrb, p, len);
+ mrb_assert(name != NULL);
+ if (SYMBOL_INLINE_P(sym)) {
+ return mrb_str_new_frozen(mrb, name, len);
+ }
+ return mrb_str_new_static_frozen(mrb, name, len);
}
/* 15.2.11.3.4 */
@@ -403,57 +577,77 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
mrb_sym id = mrb_symbol(sym);
char *sp;
- name = mrb_sym2name_len(mrb, id, &len);
- str = mrb_str_new(mrb, 0, len+1);
+ name = mrb_sym_name_len(mrb, id, &len);
+ str = mrb_str_new(mrb, NULL, 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) {
- str = mrb_str_dump(mrb, str);
+ str = mrb_str_inspect(mrb, str);
sp = RSTRING_PTR(str);
sp[0] = ':';
sp[1] = '"';
}
+#ifdef MRB_UTF8_STRING
+ if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+#endif
return str;
}
MRB_API mrb_value
-mrb_sym2str(mrb_state *mrb, mrb_sym sym)
+mrb_sym_str(mrb_state *mrb, mrb_sym sym)
{
mrb_int len;
- const char *name = mrb_sym2name_len(mrb, sym, &len);
+ const char *name = mrb_sym_name_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);
}
-MRB_API const char*
-mrb_sym2name(mrb_state *mrb, mrb_sym sym)
+static const char*
+sym_cstr(mrb_state *mrb, mrb_sym sym, mrb_bool dump)
{
mrb_int len;
- const char *name = mrb_sym2name_len(mrb, sym, &len);
+ const char *name = mrb_sym_name_len(mrb, sym, &len);
if (!name) return NULL;
- if (symname_p(name) && strlen(name) == (size_t)len) {
+ if (strlen(name) == (size_t)len && (!dump || symname_p(name))) {
return name;
}
else {
- mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
+ mrb_value str = mrb_str_new_static(mrb, name, len);
+ str = mrb_str_dump(mrb, str);
return RSTRING_PTR(str);
}
}
+MRB_API const char*
+mrb_sym_name(mrb_state *mrb, mrb_sym sym)
+{
+ return sym_cstr(mrb, sym, FALSE);
+}
+
+MRB_API const char*
+mrb_sym_dump(mrb_state *mrb, mrb_sym sym)
+{
+ return sym_cstr(mrb, sym, TRUE);
+}
+
#define lesser(a,b) (((a)>(b))?(b):(a))
static mrb_value
sym_cmp(mrb_state *mrb, mrb_value s1)
{
- mrb_value s2;
+ mrb_value s2 = mrb_get_arg1(mrb);
mrb_sym sym1, sym2;
- mrb_get_args(mrb, "o", &s2);
- if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value();
+ if (!mrb_symbol_p(s2)) return mrb_nil_value();
sym1 = mrb_symbol(s1);
sym2 = mrb_symbol(s2);
if (sym1 == sym2) return mrb_fixnum_value(0);
@@ -461,9 +655,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 +676,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, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */
+ mrb_define_method(mrb, sym, "name", sym_name, MRB_ARGS_NONE());
+ mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
+ mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
+ mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1));
}
diff --git a/src/value_array.h b/src/value_array.h
index bc5f28b06..6089b8aa0 100644
--- a/src/value_array.h
+++ b/src/value_array.h
@@ -6,6 +6,7 @@
static inline void
value_move(mrb_value *s1, const mrb_value *s2, size_t n)
{
+ if (n == 0) return;
if (s1 > s2 && s1 < s2 + n)
{
s1 += n;
diff --git a/src/variable.c b/src/variable.c
index 72c13aa1f..d89295229 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -9,24 +9,19 @@
#include <mruby/class.h>
#include <mruby/proc.h>
#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/presym.h>
-typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
-
-#ifndef MRB_IV_SEGMENT_SIZE
-#define MRB_IV_SEGMENT_SIZE 4
-#endif
-
-typedef struct segment {
- mrb_sym key[MRB_IV_SEGMENT_SIZE];
- mrb_value val[MRB_IV_SEGMENT_SIZE];
- struct segment *next;
-} segment;
+struct iv_elem {
+ mrb_sym key;
+ mrb_value val;
+};
/* Instance variable table structure */
typedef struct iv_tbl {
- segment *rootseg;
size_t size;
- size_t last_len;
+ size_t alloc;
+ struct iv_elem *table;
} iv_tbl;
/* Creates the instance variable table. */
@@ -37,67 +32,82 @@ iv_new(mrb_state *mrb)
t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl));
t->size = 0;
- t->rootseg = NULL;
- t->last_len = 0;
+ t->alloc = 0;
+ t->table = NULL;
return t;
}
+static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val);
+
+static void
+iv_rehash(mrb_state *mrb, iv_tbl *t)
+{
+ size_t old_alloc = t->alloc;
+ size_t new_alloc = old_alloc+1;
+ struct iv_elem *old_table = t->table;
+
+ khash_power2(new_alloc);
+ if (old_alloc == new_alloc) return;
+
+ t->alloc = new_alloc;
+ t->size = 0;
+ t->table = (struct iv_elem*)mrb_calloc(mrb, sizeof(struct iv_elem), new_alloc);
+
+ for (size_t i = 0; i < old_alloc; i++) {
+ struct iv_elem *slot = &old_table[i];
+
+ /* key = 0 means empty; val = undef means deleted */
+ if (slot->key != 0 && !mrb_undef_p(slot->val)) {
+ iv_put(mrb, t, slot->key, slot->val);
+ }
+ }
+ mrb_free(mrb, old_table);
+}
+
+#define slot_empty_p(slot) ((slot)->key == 0 && !mrb_undef_p((slot)->val))
+
/* 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)
{
- segment *seg;
- segment *prev = NULL;
- segment *matched_seg = NULL;
- size_t matched_idx = 0;
- size_t i;
+ size_t hash, pos, start;
+ struct iv_elem *dslot = NULL;
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;
+ if (t->alloc == 0) {
+ iv_rehash(mrb, t);
+ }
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct iv_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ slot->val = val;
+ return;
+ }
+ else if (slot_empty_p(slot)) {
+ t->size++;
+ slot->key = sym;
+ slot->val = val;
+ return;
+ }
+ else if (!dslot && mrb_undef_p(slot->val)) { /* deleted */
+ dslot = slot;
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ if (dslot) {
t->size++;
+ dslot->key = sym;
+ dslot->val = val;
return;
}
- if (!matched_seg && key == 0) {
- matched_seg = seg;
- matched_idx = i;
- }
- else if (key == sym) {
- seg->val[i] = val;
- return;
- }
+ /* no room */
+ iv_rehash(mrb, t);
+ start = pos = hash & (t->alloc-1);
}
- prev = seg;
- seg = seg->next;
- }
-
- /* Not found */
- t->size++;
- if (matched_seg) {
- matched_seg->key[matched_idx] = sym;
- matched_seg->val[matched_idx] = val;
- return;
- }
-
- seg = (segment*)mrb_malloc(mrb, sizeof(segment));
- if (!seg) return;
- seg->next = NULL;
- seg->key[0] = sym;
- seg->val[0] = val;
- t->last_len = 1;
- if (prev) {
- prev->next = seg;
- }
- else {
- t->rootseg = seg;
}
}
@@ -105,133 +115,111 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
static mrb_bool
iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
{
- segment *seg;
- size_t i;
+ size_t hash, pos, start;
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 (t->alloc == 0) return FALSE;
+ if (t->size == 0) return FALSE;
- if (!seg->next && i >= t->last_len) {
- return FALSE;
- }
- if (key == sym) {
- if (vp) *vp = seg->val[i];
- return TRUE;
- }
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct iv_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ if (vp) *vp = slot->val;
+ return TRUE;
+ }
+ else if (slot_empty_p(slot)) {
+ return FALSE;
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ return FALSE;
}
- seg = seg->next;
}
- return FALSE;
}
/* 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;
+ size_t hash, pos, start;
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 (t->alloc == 0) return FALSE;
+ if (t->size == 0) return FALSE;
- 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;
- }
+ hash = kh_int_hash_func(mrb, sym);
+ start = pos = hash & (t->alloc-1);
+ for (;;) {
+ struct iv_elem *slot = &t->table[pos];
+
+ if (slot->key == sym) {
+ if (vp) *vp = slot->val;
+ t->size--;
+ slot->key = 0;
+ slot->val = mrb_undef_value();
+ return TRUE;
+ }
+ else if (slot_empty_p(slot)) {
+ return FALSE;
+ }
+ pos = (pos+1) & (t->alloc-1);
+ if (pos == start) { /* not found */
+ return FALSE;
}
- seg = seg->next;
}
- return FALSE;
}
/* Iterates over the instance variable table. */
-static mrb_bool
-iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
+static void
+iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p)
{
- segment *seg;
size_t i;
- int n;
- if (t == NULL) return TRUE;
- seg = t->rootseg;
- while (seg) {
- for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
- mrb_sym key = seg->key[i];
+ if (t == NULL) return;
+ if (t->alloc == 0) return;
+ if (t->size == 0) return;
- /* no value in last segment after last_len */
- if (!seg->next && i >= t->last_len) {
- return FALSE;
- }
- if (key != 0) {
- n =(*func)(mrb, key, seg->val[i], p);
- if (n > 0) return FALSE;
- if (n < 0) {
- t->size--;
- seg->key[i] = 0;
- }
+ for (i=0; i<t->alloc; i++) {
+ struct iv_elem *slot = &t->table[i];
+
+ if (slot->key && !mrb_undef_p(slot->val)) {
+ if ((*func)(mrb, slot->key, slot->val, 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)
{
- 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;
+ return t->size;
}
/* Copy the instance variable table. */
static iv_tbl*
iv_copy(mrb_state *mrb, iv_tbl *t)
{
- segment *seg;
iv_tbl *t2;
-
size_t i;
- seg = t->rootseg;
- t2 = iv_new(mrb);
+ if (t == NULL) return NULL;
+ if (t->alloc == 0) return NULL;
+ if (t->size == 0) return NULL;
- while (seg != NULL) {
- for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
- mrb_sym key = seg->key[i];
- mrb_value val = seg->val[i];
+ t2 = iv_new(mrb);
+ for (i=0; i<t->alloc; i++) {
+ struct iv_elem *slot = &t->table[i];
- if ((seg->next == NULL) && (i >= t->last_len)) {
- return t2;
- }
- iv_put(mrb, t2, key, val);
+ if (slot->key && !mrb_undef_p(slot->val)) {
+ iv_put(mrb, t2, slot->key, slot->val);
}
- seg = seg->next;
}
return t2;
}
@@ -240,14 +228,7 @@ iv_copy(mrb_state *mrb, iv_tbl *t)
static void
iv_free(mrb_state *mrb, iv_tbl *t)
{
- segment *seg;
-
- seg = t->rootseg;
- while (seg) {
- segment *p = seg;
- seg = seg->next;
- mrb_free(mrb, p);
- }
+ mrb_free(mrb, t->table);
mrb_free(mrb, t);
}
@@ -346,21 +327,30 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
-MRB_API void
-mrb_obj_iv_set(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)
{
- iv_tbl *t;
-
- if (MRB_FROZEN_P(obj)) {
- mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
- }
assign_class_name(mrb, obj, sym, v);
if (!obj->iv) {
obj->iv = iv_new(mrb);
}
- t = obj->iv;
- iv_put(mrb, t, sym, v);
- mrb_write_barrier(mrb, (struct RBasic*)obj);
+ iv_put(mrb, obj->iv, sym, v);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)obj, v);
+}
+
+MRB_API void
+mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
+{
+ mrb_check_frozen(mrb, obj);
+ mrb_obj_iv_set_force(mrb, obj, sym, v);
+}
+
+/* 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
@@ -374,20 +364,20 @@ 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__");
+ if (obj != c && ISUPPER(mrb_sym_name_len(mrb, sym, NULL)[0])) {
+ mrb_sym id_classname = MRB_SYM(__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__");
+ mrb_sym id_outer = MRB_SYM(__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(mrb, c, id_classname, mrb_symbol_value(sym));
+ mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym));
}
else {
- mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj));
+ mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj));
}
}
}
@@ -425,29 +415,24 @@ 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_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);
+ s = mrb_sym_name_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_name_sym_check(mrb_state *mrb, mrb_sym 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));
+ mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name);
}
}
@@ -484,10 +469,10 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
else {
mrb_str_cat_lit(mrb, str, ", ");
}
- s = mrb_sym2name_len(mrb, sym, &len);
+ s = mrb_sym_name_len(mrb, sym, &len);
mrb_str_cat(mrb, str, s, len);
mrb_str_cat_lit(mrb, str, "=");
- if (mrb_type(v) == MRB_TT_OBJECT) {
+ if (mrb_object_p(v)) {
ins = mrb_any_to_s(mrb, v);
}
else {
@@ -510,7 +495,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
mrb_str_cat_lit(mrb, str, "-<");
mrb_str_cat_cstr(mrb, str, cn);
mrb_str_cat_lit(mrb, str, ":");
- mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));
+ mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, obj));
iv_foreach(mrb, t, inspect_i, &str);
mrb_str_cat_lit(mrb, str, ">");
@@ -526,6 +511,7 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
iv_tbl *t = mrb_obj_ptr(obj)->iv;
mrb_value val;
+ mrb_check_frozen(mrb, mrb_obj_ptr(obj));
if (iv_del(mrb, t, sym, &val)) {
return val;
}
@@ -541,7 +527,7 @@ iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
mrb_int len;
ary = *(mrb_value*)p;
- s = mrb_sym2name_len(mrb, sym, &len);
+ s = mrb_sym_name_len(mrb, sym, &len);
if (len > 1 && s[0] == '@' && s[1] != '@') {
mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
}
@@ -585,7 +571,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
mrb_int len;
ary = *(mrb_value*)p;
- s = mrb_sym2name_len(mrb, sym, &len);
+ s = mrb_sym_name_len(mrb, sym, &len);
if (len > 2 && s[0] == '@' && s[1] == '@') {
mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
}
@@ -595,7 +581,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
/* 15.2.2.4.19 */
/*
* call-seq:
- * mod.class_variables -> array
+ * mod.class_variables(inherit=true) -> array
*
* Returns an array of the names of class variables in <i>mod</i>.
*
@@ -613,17 +599,20 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
{
mrb_value ary;
struct RClass *c;
+ mrb_bool inherit = TRUE;
+ mrb_get_args(mrb, "|b", &inherit);
ary = mrb_ary_new(mrb);
c = mrb_class_ptr(mod);
while (c) {
iv_foreach(mrb, c->iv, cv_i, &ary);
+ if (!inherit) break;
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;
@@ -640,8 +629,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
if (cls && cls->tt == MRB_TT_SCLASS) {
mrb_value klass;
- klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
- mrb_intern_lit(mrb, "__attached__"));
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)cls, MRB_SYM(__attached__));
c = mrb_class_ptr(klass);
if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) {
given = FALSE;
@@ -654,8 +642,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
if (given) return v;
}
}
- mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
- mrb_sym2str(mrb, sym), mrb_obj_value(cls));
+ mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls);
/* not reached */
return mrb_nil_value();
}
@@ -675,8 +662,9 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
iv_tbl *t = c->iv;
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);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v);
return;
}
c = c->super;
@@ -685,8 +673,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
if (cls && cls->tt == MRB_TT_SCLASS) {
mrb_value klass;
- klass = mrb_obj_iv_get(mrb, (struct RObject*)cls,
- mrb_intern_lit(mrb, "__attached__"));
+ klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, MRB_SYM(__attached__));
switch (mrb_type(klass)) {
case MRB_TT_CLASS:
case MRB_TT_MODULE:
@@ -702,12 +689,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);
}
iv_put(mrb, c->iv, sym, v);
- mrb_write_barrier(mrb, (struct RBasic*)c);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v);
}
MRB_API void
@@ -716,7 +704,7 @@ 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) {
@@ -739,7 +727,13 @@ mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
{
struct RClass *c;
- c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ const struct RProc *p = mrb->c->ci->proc;
+
+ for (;;) {
+ c = MRB_PROC_TARGET_CLASS(p);
+ if (c && c->tt != MRB_TT_SCLASS) break;
+ p = p->upper;
+ }
return mrb_mod_cv_get(mrb, c, sym);
}
@@ -747,8 +741,13 @@ void
mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
{
struct RClass *c;
+ const struct RProc *p = mrb->c->ci->proc;
- c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ for (;;) {
+ c = MRB_PROC_TARGET_CLASS(p);
+ if (c && c->tt != MRB_TT_SCLASS) break;
+ p = p->upper;
+ }
mrb_mod_cv_set(mrb, c, sym, v);
}
@@ -767,16 +766,17 @@ mod_const_check(mrb_state *mrb, mrb_value mod)
}
static mrb_value
-const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
+const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip)
{
struct RClass *c = base;
mrb_value v;
mrb_bool retry = FALSE;
mrb_value name;
+ if (skip) c = c->super;
L_RETRY:
while (c) {
- if (c->iv) {
+ if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && c->iv) {
if (iv_get(mrb, c->iv, sym, &v))
return v;
}
@@ -788,14 +788,14 @@ L_RETRY:
goto L_RETRY;
}
name = mrb_symbol_value(sym);
- return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name);
+ return mrb_funcall_argv(mrb, mrb_obj_value(base), MRB_SYM(const_missing), 1, &name);
}
MRB_API mrb_value
mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
mod_const_check(mrb, mod);
- return const_get(mrb, mrb_class_ptr(mod), sym);
+ return const_get(mrb, mrb_class_ptr(mod), sym, FALSE);
}
mrb_value
@@ -804,9 +804,10 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
struct RClass *c;
struct RClass *c2;
mrb_value v;
- struct RProc *proc;
+ const struct RProc *proc = mrb->c->ci->proc;
- c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ c = MRB_PROC_TARGET_CLASS(proc);
+ if (!c) c = mrb->object_class;
if (iv_get(mrb, c->iv, sym, &v)) {
return v;
}
@@ -814,15 +815,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
while (c2 && c2->tt == MRB_TT_SCLASS) {
mrb_value klass;
- if (!iv_get(mrb, c2->iv, mrb_intern_lit(mrb, "__attached__"), &klass)) {
+ if (!iv_get(mrb, c2->iv, MRB_SYM(__attached__), &klass)) {
c2 = NULL;
break;
}
c2 = mrb_class_ptr(klass);
}
if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2;
- mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc));
- proc = mrb->c->ci->proc;
+ proc = proc->upper;
while (proc) {
c2 = MRB_PROC_TARGET_CLASS(proc);
if (c2 && iv_get(mrb, c2->iv, sym, &v)) {
@@ -830,7 +830,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
}
proc = proc->upper;
}
- return const_get(mrb, c, sym);
+ return const_get(mrb, c, sym, TRUE);
}
MRB_API void
@@ -849,6 +849,7 @@ mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
struct RClass *c;
c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ if (!c) c = mrb->object_class;
mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
}
@@ -860,6 +861,12 @@ mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
}
MRB_API void
+mrb_define_const_id(mrb_state *mrb, struct RClass *mod, mrb_sym name, mrb_value v)
+{
+ mrb_obj_iv_set(mrb, (struct RObject*)mod, name, v);
+}
+
+MRB_API void
mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
{
mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v);
@@ -879,9 +886,17 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
mrb_int len;
ary = *(mrb_value*)p;
- s = mrb_sym2name_len(mrb, sym, &len);
+ s = mrb_sym_name_len(mrb, sym, &len);
if (len >= 1 && ISUPPER(s[0])) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ mrb_int i, alen = RARRAY_LEN(ary);
+
+ for (i=0; i<alen; i++) {
+ if (mrb_symbol(RARRAY_PTR(ary)[i]) == sym)
+ break;
+ }
+ if (i==alen) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ }
}
return 0;
}
@@ -891,7 +906,7 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
* call-seq:
* mod.constants -> array
*
- * Returns an array of all names of contants defined in the receiver.
+ * Returns an array of all names of constants defined in the receiver.
*/
mrb_value
mrb_mod_constants(mrb_state *mrb, mrb_value mod)
@@ -964,16 +979,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];
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)));
- }
return ary;
}
@@ -1055,7 +1062,7 @@ outer_class(mrb_state *mrb, struct RClass *c)
{
mrb_value ov;
- ov = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
+ ov = mrb_obj_iv_get(mrb, (struct RObject*)c, MRB_SYM(__outer__));
if (mrb_nil_p(ov)) return NULL;
switch (mrb_type(ov)) {
case MRB_TT_CLASS:
@@ -1102,12 +1109,34 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c)
mrb_str_cat_cstr(mrb, path, str);
mrb_str_cat_cstr(mrb, path, "::");
- str = mrb_sym2name_len(mrb, name, &len);
+ str = mrb_sym_name_len(mrb, name, &len);
mrb_str_cat(mrb, path, str, len);
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);
+ iv_del(mrb, c->iv, MRB_SYM(__outer__), NULL);
+ iv_put(mrb, c->iv, MRB_SYM(__classname__), path);
mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
+ path = mrb_str_dup(mrb, path);
}
return path;
}
+
+size_t
+mrb_obj_iv_tbl_memsize(mrb_value obj)
+{
+ iv_tbl *t = mrb_obj_ptr(obj)->iv;
+ if (t == NULL) return 0;
+ return sizeof(iv_tbl) + t->alloc*sizeof(struct iv_elem);
+}
+
+#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;
+}
diff --git a/src/vm.c b/src/vm.c
index 9eeb388fc..cd70faf11 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -6,7 +6,9 @@
#include <stddef.h>
#include <stdarg.h>
+#ifndef MRB_NO_FLOAT
#include <math.h>
+#endif
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
@@ -21,8 +23,10 @@
#include <mruby/opcode.h>
#include "value_array.h"
#include <mruby/throw.h>
+#include <mruby/dump.h>
+#include <mruby/presym.h>
-#ifdef MRB_DISABLE_STDIO
+#ifdef MRB_NO_STDIO
#if defined(__cplusplus)
extern "C" {
#endif
@@ -35,14 +39,6 @@ void abort(void);
#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32
-#ifndef ENSURE_STACK_INIT_SIZE
-#define ENSURE_STACK_INIT_SIZE 16
-#endif
-
-#ifndef RESCUE_STACK_INIT_SIZE
-#define RESCUE_STACK_INIT_SIZE 16
-#endif
-
/* Define amount of linear stack growth. */
#ifndef MRB_STACK_GROWTH
#define MRB_STACK_GROWTH 128
@@ -53,11 +49,6 @@ void abort(void);
#define MRB_FUNCALL_DEPTH_MAX 512
#endif
-/* Maximum depth of ecall() recursion. */
-#ifndef MRB_ECALL_DEPTH_MAX
-#define MRB_ECALL_DEPTH_MAX 32
-#endif
-
/* Maximum stack depth. Should be set lower on memory constrained systems.
The value below allows about 60000 recursive calls in the simplest case. */
#ifndef MRB_STACK_MAX
@@ -100,26 +91,20 @@ void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value
static inline void
stack_clear(mrb_value *from, size_t count)
{
-#ifndef MRB_NAN_BOXING
- const mrb_value mrb_value_zero = { 0 };
-
- while (count-- > 0) {
- *from++ = mrb_value_zero;
- }
-#else
+#ifdef MRB_NAN_BOXING
while (count-- > 0) {
SET_NIL_VALUE(*from);
from++;
}
+#else
+ memset(from, 0, sizeof(mrb_value)*count);
#endif
}
static inline void
stack_copy(mrb_value *dst, const mrb_value *src, size_t size)
{
- while (size-- > 0) {
- *dst++ = *src++;
- }
+ memcpy(dst, src, sizeof(mrb_value)*size);
}
static void
@@ -130,14 +115,13 @@ stack_init(mrb_state *mrb)
/* mrb_assert(mrb->stack == NULL); */
c->stbase = (mrb_value *)mrb_calloc(mrb, STACK_INIT_SIZE, sizeof(mrb_value));
c->stend = c->stbase + STACK_INIT_SIZE;
- c->stack = c->stbase;
/* mrb_assert(ci == NULL); */
c->cibase = (mrb_callinfo *)mrb_calloc(mrb, CALLINFO_INIT_SIZE, sizeof(mrb_callinfo));
c->ciend = c->cibase + CALLINFO_INIT_SIZE;
c->ci = c->cibase;
- c->ci->target_class = mrb->object_class;
- c->ci->stackent = c->stack;
+ c->ci->u.target_class = mrb->object_class;
+ c->ci->stack = c->stbase;
}
static inline void
@@ -147,20 +131,20 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize
if (newbase == oldbase) return;
while (ci <= mrb->c->ci) {
- struct REnv *e = ci->env;
+ struct REnv *e = mrb_vm_ci_env(ci);
mrb_value *st;
- if (e && MRB_ENV_STACK_SHARED_P(e) &&
+ if (e && MRB_ENV_ONSTACK_P(e) &&
(st = e->stack) && oldbase <= st && st < oldbase+oldsize) {
ptrdiff_t off = e->stack - oldbase;
e->stack = newbase + off;
}
- if (ci->proc && MRB_PROC_ENV_P(ci->proc) && ci->env != MRB_PROC_ENV(ci->proc)) {
+ if (ci->proc && MRB_PROC_ENV_P(ci->proc) && e != MRB_PROC_ENV(ci->proc)) {
e = MRB_PROC_ENV(ci->proc);
- if (e && MRB_ENV_STACK_SHARED_P(e) &&
+ if (e && MRB_ENV_ONSTACK_P(e) &&
(st = e->stack) && oldbase <= st && st < oldbase+oldsize) {
ptrdiff_t off = e->stack - oldbase;
@@ -168,7 +152,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize
}
}
- ci->stackent = newbase + (ci->stackent - oldbase);
+ ci->stack = newbase + (ci->stack - oldbase);
ci++;
}
}
@@ -182,11 +166,11 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room)
mrb_value *newstack;
size_t oldsize = mrb->c->stend - mrb->c->stbase;
size_t size = oldsize;
- size_t off = mrb->c->stack - mrb->c->stbase;
+ size_t off = mrb->c->ci->stack ? mrb->c->stend - mrb->c->ci->stack : 0;
if (off > size) size = off;
#ifdef MRB_STACK_EXTEND_DOUBLING
- if (room <= (size_t)size)
+ if ((size_t)room <= size)
size *= 2;
else
size += room;
@@ -200,14 +184,13 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room)
size += room;
#endif
- newstack = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+ newstack = (mrb_value *)mrb_realloc_simple(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
if (newstack == NULL) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
stack_clear(&(newstack[oldsize]), size - oldsize);
envadjust(mrb, oldbase, newstack, oldsize);
mrb->c->stbase = newstack;
- mrb->c->stack = mrb->c->stbase + off;
mrb->c->stend = mrb->c->stbase + size;
/* Raise an exception if the new stack size will be too large,
@@ -220,15 +203,15 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room)
MRB_API void
mrb_stack_extend(mrb_state *mrb, mrb_int room)
{
- if (mrb->c->stack + room >= mrb->c->stend) {
+ if (!mrb->c->ci->stack || mrb->c->ci->stack + room >= mrb->c->stend) {
stack_extend_alloc(mrb, room);
}
}
static inline struct REnv*
-uvenv(mrb_state *mrb, int up)
+uvenv(mrb_state *mrb, mrb_int up)
{
- struct RProc *proc = mrb->c->ci->proc;
+ const struct RProc *proc = mrb->c->ci->proc;
struct REnv *e;
while (up--) {
@@ -243,7 +226,7 @@ uvenv(mrb_state *mrb, int up)
while (cb <= ci) {
if (ci->proc == proc) {
- return ci->env;
+ return mrb_vm_ci_env(ci);
}
ci--;
}
@@ -251,8 +234,8 @@ uvenv(mrb_state *mrb, int up)
return NULL;
}
-static inline struct RProc*
-top_proc(mrb_state *mrb, struct RProc *proc)
+static inline const struct RProc*
+top_proc(mrb_state *mrb, const struct RProc *proc)
{
while (proc->upper) {
if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc))
@@ -267,14 +250,12 @@ top_proc(mrb_state *mrb, struct RProc *proc)
#define CI_ACC_RESUMED -3
static inline mrb_callinfo*
-cipush(mrb_state *mrb)
+cipush(mrb_state *mrb, mrb_int push_stacks, mrb_int acc,
+ struct RClass *target_class, const struct RProc *proc, mrb_sym mid, mrb_int argc)
{
struct mrb_context *c = mrb->c;
- static const mrb_callinfo ci_zero = { 0 };
mrb_callinfo *ci = c->ci;
- int ridx = ci->ridx;
-
if (ci + 1 == c->ciend) {
ptrdiff_t size = ci - c->cibase;
@@ -283,9 +264,12 @@ cipush(mrb_state *mrb)
c->ciend = c->cibase + size * 2;
}
ci = ++c->ci;
- *ci = ci_zero;
- ci->epos = mrb->c->eidx;
- ci->ridx = ridx;
+ ci->mid = mid;
+ mrb_vm_ci_proc_set(ci, proc);
+ ci->stack = ci[-1].stack + push_stacks;
+ ci->argc = (int16_t)argc;
+ ci->acc = (int16_t)acc;
+ ci->u.target_class = target_class;
return ci;
}
@@ -295,82 +279,79 @@ mrb_env_unshare(mrb_state *mrb, struct REnv *e)
{
if (e == NULL) return;
else {
- size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+ size_t len = (size_t)MRB_ENV_LEN(e);
mrb_value *p;
- if (!MRB_ENV_STACK_SHARED_P(e)) return;
+ if (!MRB_ENV_ONSTACK_P(e)) return;
if (e->cxt != mrb->c) return;
- if (e == mrb->c->cibase->env) return; /* for mirb */
+ if (e == mrb_vm_ci_env(mrb->c->cibase)) return; /* for mirb */
p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
if (len > 0) {
stack_copy(p, e->stack, len);
}
e->stack = p;
- MRB_ENV_UNSHARE_STACK(e);
+ MRB_ENV_CLOSE(e);
mrb_write_barrier(mrb, (struct RBasic *)e);
}
}
-static inline void
+static inline mrb_callinfo*
cipop(mrb_state *mrb)
{
struct mrb_context *c = mrb->c;
- struct REnv *env = c->ci->env;
+ struct REnv *env = mrb_vm_ci_env(c->ci);
c->ci--;
if (env) mrb_env_unshare(mrb, env);
+ return c->ci;
}
-void mrb_exc_set(mrb_state *mrb, mrb_value exc);
-
-static void
-ecall(mrb_state *mrb)
+MRB_API mrb_value
+mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, mrb_bool *error)
{
- struct RProc *p;
- struct mrb_context *c = mrb->c;
- mrb_callinfo *ci = c->ci;
- struct RObject *exc;
- struct REnv *env;
- ptrdiff_t cioff;
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+ mrb_value result = mrb_nil_value();
int ai = mrb_gc_arena_save(mrb);
- uint16_t i = --c->eidx;
- int nregs;
+ const struct mrb_context *c = mrb->c;
+ int ci_index = c->ci - c->cibase;
- if (i<0) return;
- if (ci - c->cibase > MRB_ECALL_DEPTH_MAX) {
- mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+ if (error) { *error = FALSE; }
+
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ result = body(mrb, userdata);
+ mrb->jmp = prev_jmp;
}
- p = c->ensure[i];
- if (!p) return;
- mrb_assert(!MRB_PROC_CFUNC_P(p));
- c->ensure[i] = NULL;
- nregs = p->upper->body.irep->nregs;
- if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc) &&
- ci->proc->body.irep->nregs > nregs) {
- nregs = ci->proc->body.irep->nregs;
- }
- cioff = ci - c->cibase;
- ci = cipush(mrb);
- ci->stackent = mrb->c->stack;
- ci->mid = ci[-1].mid;
- ci->acc = CI_ACC_SKIP;
- ci->argc = 0;
- ci->proc = p;
- ci->target_class = MRB_PROC_TARGET_CLASS(p);
- env = MRB_PROC_ENV(p);
- mrb_assert(env);
- c->stack += nregs;
- exc = mrb->exc; mrb->exc = 0;
- if (exc) {
- mrb_gc_protect(mrb, mrb_obj_value(exc));
- }
- mrb_run(mrb, p, env->stack[0]);
- mrb->c = c;
- c->ci = c->cibase + cioff;
- if (!mrb->exc) mrb->exc = exc;
+ MRB_CATCH(&c_jmp) {
+ mrb->jmp = prev_jmp;
+ result = mrb_obj_value(mrb->exc);
+ mrb->exc = NULL;
+ if (error) { *error = TRUE; }
+ if (mrb->c == c) {
+ while (c->ci - c->cibase > ci_index) {
+ cipop(mrb);
+ }
+ }
+ else {
+ // It was probably switched by mrb_fiber_resume().
+ // Simply destroy all successive CI_ACC_DIRECTs once the fiber has been switched.
+ c = mrb->c;
+ while (c->ci > c->cibase && c->ci->acc == CI_ACC_DIRECT) {
+ cipop(mrb);
+ }
+ }
+ }
+ MRB_END_EXC(&c_jmp);
+
mrb_gc_arena_restore(mrb, ai);
+ mrb_gc_protect(mrb, result);
+ return result;
}
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+static mrb_value mrb_run(mrb_state *mrb, const struct RProc* proc, mrb_value self);
+
#ifndef MRB_FUNCALL_ARGC_MAX
#define MRB_FUNCALL_ARGC_MAX 16
#endif
@@ -395,11 +376,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
+MRB_API mrb_value
+mrb_funcall_id(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, ...)
+{
+ mrb_value argv[MRB_FUNCALL_ARGC_MAX];
+ va_list ap;
+ mrb_int i;
+
+ if (argc > MRB_FUNCALL_ARGC_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")");
+ }
+
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++) {
+ argv[i] = va_arg(ap, mrb_value);
+ }
+ va_end(ap);
+ return mrb_funcall_argv(mrb, self, mid, argc, argv);
+}
+
+static mrb_int
ci_nregs(mrb_callinfo *ci)
{
- struct RProc *p;
- int n = 0;
+ const struct RProc *p;
+ mrb_int n = 0;
if (!ci) return 3;
p = ci->proc;
@@ -423,6 +423,7 @@ MRB_API mrb_value
mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk)
{
mrb_value val;
+ int ai = mrb_gc_arena_save(mrb);
if (!mrb->jmp) {
struct mrb_jmpbuf c_jmp;
@@ -436,7 +437,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
}
MRB_CATCH(&c_jmp) { /* error */
while (nth_ci < (mrb->c->ci - mrb->c->cibase)) {
- mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
mrb->jmp = 0;
@@ -449,19 +449,19 @@ 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 = ci_nregs(mrb->c->ci);
+ mrb_int n = ci_nregs(mrb->c->ci);
ptrdiff_t voff = -1;
- if (!mrb->c->stack) {
+ if (!mrb->c->stbase) {
stack_init(mrb);
}
if (argc < 0) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%i)", argc);
}
c = mrb_class(mrb, self);
m = mrb_method_search_vm(mrb, &c, mid);
if (MRB_METHOD_UNDEF_P(m)) {
- mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ mrb_sym missing = MRB_SYM(method_missing);
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
m = mrb_method_search_vm(mrb, &c, missing);
if (MRB_METHOD_UNDEF_P(m)) {
@@ -469,65 +469,53 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
}
mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
mrb_stack_extend(mrb, n+2);
- mrb->c->stack[n+1] = args;
+ mrb->c->ci->stack[n+1] = args;
argc = -1;
}
if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
- ci = cipush(mrb);
- ci->mid = mid;
- ci->stackent = mrb->c->stack;
- ci->argc = (int)argc;
- ci->target_class = c;
- mrb->c->stack = mrb->c->stack + n;
+ ci = cipush(mrb, n, 0, c, NULL, mid, argc);
+ 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)) {
- mrb_stack_extend(mrb, argc + 2);
- }
- else if (argc >= CALL_MAXARGS) {
+ if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
- mrb_stack_extend(mrb, 3);
- mrb->c->stack[1] = args;
+ mrb->c->ci->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;
- mrb_stack_extend(mrb, p->body.irep->nregs + argc);
+ mrb_vm_ci_proc_set(ci, p);
+ if (!MRB_PROC_CFUNC_P(p)) {
+ mrb_stack_extend(mrb, p->body.irep->nregs + argc);
+ }
}
if (voff >= 0) {
argv = mrb->c->stbase + voff;
}
- mrb->c->stack[0] = self;
+ mrb->c->ci->stack[0] = self;
if (ci->argc > 0) {
- stack_copy(mrb->c->stack+1, argv, argc);
+ stack_copy(mrb->c->ci->stack+1, argv, argc);
}
- mrb->c->stack[argc+1] = blk;
+ mrb->c->ci->stack[argc+1] = blk;
if (MRB_METHOD_CFUNC_P(m)) {
- 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);
- mrb_gc_arena_restore(mrb, ai);
}
else {
ci->acc = CI_ACC_SKIP;
val = mrb_run(mrb, MRB_METHOD_PROC(m), self);
}
}
+ mrb_gc_arena_restore(mrb, ai);
mrb_gc_protect(mrb, val);
return val;
}
@@ -538,14 +526,14 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
-mrb_value
-mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
+static mrb_value
+exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
int keep, nregs;
- mrb->c->stack[0] = self;
- ci->proc = p;
+ ci->stack[0] = self;
+ mrb_vm_ci_proc_set(ci, p);
if (MRB_PROC_CFUNC_P(p)) {
return MRB_PROC_CFUNC(p)(mrb, self);
}
@@ -557,18 +545,39 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
}
else {
mrb_stack_extend(mrb, nregs);
- stack_clear(mrb->c->stack+keep, nregs-keep);
+ stack_clear(ci->stack+keep, nregs-keep);
}
- ci = cipush(mrb);
- ci->target_class = 0;
- ci->pc = p->body.irep->iseq;
- ci->stackent = mrb->c->stack;
- ci->acc = 0;
+ cipush(mrb, 0, 0, NULL, NULL, 0, 0);
return self;
}
+mrb_value
+mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
+{
+ mrb_callinfo *ci = mrb->c->ci;
+ if (ci->acc >= 0) {
+ return exec_irep(mrb, self, p);
+ }
+ else {
+ mrb_value ret;
+ if (MRB_PROC_CFUNC_P(p)) {
+ cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc);
+ ret = MRB_PROC_CFUNC(p)(mrb, self);
+ cipop(mrb);
+ }
+ else {
+ int keep = (ci->argc < 0 ? 1 : ci->argc) + 2 /* receiver + block */;
+ ret = mrb_top_run(mrb, p, self, keep);
+ }
+ if (mrb->exc && mrb->jmp) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
+ }
+ return ret;
+ }
+}
+
/* 15.3.1.3.4 */
/* 15.3.1.3.44 */
/*
@@ -588,11 +597,12 @@ 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;
- mrb_value block, *argv, *regs;
+ mrb_value block, *regs;
+ const mrb_value *argv;
mrb_int argc, i, len;
mrb_method_t m;
struct RClass *c;
@@ -612,8 +622,8 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
}
ci->mid = name;
- ci->target_class = c;
- regs = mrb->c->stack+1;
+ ci->u.target_class = c;
+ regs = mrb->c->ci->stack+1;
/* remove first symbol from arguments */
if (ci->argc >= 0) {
for (i=0,len=ci->argc; i<len; i++) {
@@ -622,16 +632,16 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
ci->argc--;
}
else { /* variable length arguments */
- mrb_ary_shift(mrb, regs[0]);
+ regs[0] = mrb_ary_subseq(mrb, regs[0], 1, RARRAY_LEN(regs[0]) - 1);
}
if (MRB_METHOD_CFUNC_P(m)) {
if (MRB_METHOD_PROC_P(m)) {
- ci->proc = MRB_METHOD_PROC(m);
+ mrb_vm_ci_proc_set(ci, MRB_METHOD_PROC(m));
}
return MRB_METHOD_CFUNC(m)(mrb, self);
}
- return mrb_exec_irep(mrb, self, MRB_METHOD_PROC(m));
+ return exec_irep(mrb, self, MRB_METHOD_PROC(m));
}
static mrb_value
@@ -646,31 +656,27 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
}
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
- ci->target_class = c;
- return mrb_yield_cont(mrb, blk, self, 1, &self);
+ return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
}
- ci->target_class = c;
+ ci->u.target_class = c;
p = mrb_proc_ptr(blk);
- ci->proc = p;
+ mrb_vm_ci_proc_set(ci, p);
ci->argc = 1;
ci->mid = ci[-1].mid;
if (MRB_PROC_CFUNC_P(p)) {
mrb_stack_extend(mrb, 3);
- mrb->c->stack[0] = self;
- mrb->c->stack[1] = self;
- mrb->c->stack[2] = mrb_nil_value();
+ mrb->c->ci->stack[0] = self;
+ mrb->c->ci->stack[1] = self;
+ mrb->c->ci->stack[2] = mrb_nil_value();
return MRB_PROC_CFUNC(p)(mrb, self);
}
nregs = p->body.irep->nregs;
- mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs);
- mrb->c->stack[0] = self;
- mrb->c->stack[1] = self;
- mrb->c->stack[2] = mrb_nil_value();
- ci = cipush(mrb);
- ci->target_class = 0;
- ci->pc = p->body.irep->iseq;
- ci->stackent = mrb->c->stack;
- ci->acc = 0;
+ if (nregs < 3) nregs = 3;
+ mrb_stack_extend(mrb, nregs);
+ mrb->c->ci->stack[0] = self;
+ mrb->c->ci->stack[1] = self;
+ stack_clear(mrb->c->ci->stack+2, nregs-2);
+ ci = cipush(mrb, 0, 0, NULL, NULL, 0, 0);
return self;
}
@@ -721,26 +727,11 @@ mrb_value
mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
{
mrb_value a, b;
- mrb_value cv;
- struct RClass *c;
if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
}
- switch (mrb_type(self)) {
- case MRB_TT_SYMBOL:
- case MRB_TT_FIXNUM:
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#endif
- c = 0;
- break;
- default:
- cv = mrb_singleton_class(mrb, self);
- c = mrb_class_ptr(cv);
- break;
- }
- return eval_under(mrb, self, b, c);
+ return eval_under(mrb, self, b, mrb_singleton_class_ptr(mrb, self));
}
MRB_API mrb_value
@@ -750,7 +741,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
mrb_sym mid = mrb->c->ci->mid;
mrb_callinfo *ci;
mrb_value val;
- int n;
+ mrb_int n;
if (mrb_nil_p(b)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
@@ -761,26 +752,29 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
p = mrb_proc_ptr(b);
- ci = cipush(mrb);
- ci->mid = mid;
- ci->proc = p;
- ci->stackent = mrb->c->stack;
- 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 = cipush(mrb, n, CI_ACC_SKIP, c, p, mid, 0 /* dummy */);
+ if (argc >= CALL_MAXARGS) {
+ ci->argc = -1;
+ n = 3;
+ }
+ else {
+ ci->argc = (int)argc;
+ n = argc + 2;
+ }
mrb_stack_extend(mrb, n);
-
- mrb->c->stack[0] = self;
- if (argc > 0) {
- stack_copy(mrb->c->stack+1, argv, argc);
+ mrb->c->ci->stack[0] = self;
+ if (ci->argc < 0) {
+ mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
+ argc = 1;
+ }
+ else if (argc > 0) {
+ stack_copy(mrb->c->ci->stack+1, argv, argc);
}
- mrb->c->stack[argc+1] = mrb_nil_value();
+ mrb->c->ci->stack[argc+1] = mrb_nil_value();
if (MRB_PROC_CFUNC_P(p)) {
+ ci->acc = CI_ACC_DIRECT;
val = MRB_PROC_CFUNC(p)(mrb, self);
- mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
else {
@@ -814,7 +808,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
if (mrb_nil_p(b)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
- if (mrb_type(b) != MRB_TT_PROC) {
+ if (!mrb_proc_p(b)) {
mrb_raise(mrb, E_TYPE_ERROR, "not a block");
}
@@ -822,47 +816,61 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
ci = mrb->c->ci;
mrb_stack_extend(mrb, 3);
- mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
- mrb->c->stack[2] = mrb_nil_value();
+ mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
+ mrb->c->ci->stack[2] = mrb_nil_value();
ci->argc = -1;
- return mrb_exec_irep(mrb, self, p);
+ return exec_irep(mrb, self, p);
}
-mrb_value
-mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
+static struct RBreak*
+break_new(mrb_state *mrb, uint32_t tag, const struct RProc *p, mrb_value val)
{
- struct RProc *proc;
- mrb_value ary;
- struct RClass *c = NULL;
+ struct RBreak *brk;
- 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);
+ brk = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL);
+ mrb_break_proc_set(brk, p);
+ mrb_break_value_set(brk, val);
+ mrb_break_tag_set(brk, tag);
- if (c2 != c) {
- c = c2;
- mrb_ary_push(mrb, ary, mrb_obj_value(c));
- }
- }
- proc = proc->upper;
- }
- return ary;
+ return brk;
}
-static struct RBreak*
-break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
+#define MRB_CATCH_FILTER_RESCUE (UINT32_C(1) << MRB_CATCH_RESCUE)
+#define MRB_CATCH_FILTER_ENSURE (UINT32_C(1) << MRB_CATCH_ENSURE)
+#define MRB_CATCH_FILTER_ALL (MRB_CATCH_FILTER_RESCUE | MRB_CATCH_FILTER_ENSURE)
+
+static const struct mrb_irep_catch_handler *
+catch_handler_find(mrb_state *mrb, mrb_callinfo *ci, const mrb_code *pc, uint32_t filter)
{
- struct RBreak *brk;
+ const mrb_irep *irep;
+ ptrdiff_t xpc;
+ size_t cnt;
+ const struct mrb_irep_catch_handler *e;
+
+/* The comparison operators use `>` and `<=` because pc already points to the next instruction */
+#define catch_cover_p(pc, beg, end) ((pc) > (ptrdiff_t)(beg) && (pc) <= (ptrdiff_t)(end))
+
+ if (ci->proc == NULL || MRB_PROC_CFUNC_P(ci->proc)) return NULL;
+ irep = ci->proc->body.irep;
+ if (irep->clen < 1) return NULL;
+ xpc = pc - irep->iseq;
+ /* If it retry at the top level, pc will be 0, so check with -1 as the start position */
+ mrb_assert(catch_cover_p(xpc, -1, irep->ilen));
+ if (!catch_cover_p(xpc, -1, irep->ilen)) return NULL;
+
+ /* Currently uses a simple linear search to avoid processing complexity. */
+ cnt = irep->clen;
+ e = mrb_irep_catch_handler_table(irep) + cnt - 1;
+ for (; cnt > 0; cnt --, e --) {
+ if (((UINT32_C(1) << e->type) & filter) &&
+ catch_cover_p(xpc, mrb_irep_catch_handler_unpack(e->begin), mrb_irep_catch_handler_unpack(e->end))) {
+ return e;
+ }
+ }
- brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
- brk->proc = p;
- brk->val = val;
+#undef catch_cover_p
- return brk;
+ return NULL;
}
typedef enum {
@@ -895,27 +903,87 @@ argnum_error(mrb_state *mrb, mrb_int num)
mrb_int argc = mrb->c->ci->argc;
if (argc < 0) {
- mrb_value args = mrb->c->stack[1];
+ mrb_value args = mrb->c->ci->stack[1];
if (mrb_array_p(args)) {
argc = RARRAY_LEN(args);
}
}
if (mrb->c->ci->mid) {
- str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
- mrb_sym2str(mrb, mrb->c->ci->mid),
- mrb_fixnum_value(argc), mrb_fixnum_value(num));
+ str = mrb_format(mrb, "'%n': wrong number of arguments (%i for %i)",
+ mrb->c->ci->mid, argc, num);
}
else {
- str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
- mrb_fixnum_value(argc), mrb_fixnum_value(num));
+ str = mrb_format(mrb, "wrong number of arguments (%i for %i)", argc, num);
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
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;
-#ifdef MRB_ENABLE_DEBUG_HOOK
+static mrb_bool
+break_tag_p(struct RBreak *brk, uint32_t tag)
+{
+ return (brk != NULL && brk->tt == MRB_TT_BREAK) ? TRUE : FALSE;
+}
+
+static void
+prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb_value val)
+{
+ if (break_tag_p((struct RBreak*)mrb->exc, tag)) {
+ mrb_break_tag_set((struct RBreak*)mrb->exc, tag);
+ }
+ else {
+ mrb->exc = (struct RObject*)break_new(mrb, tag, proc, val);
+ }
+}
+
+#define THROW_TAGGED_BREAK(mrb, tag, proc, val) \
+ do { \
+ prepare_tagged_break(mrb, tag, proc, val); \
+ goto L_CATCH_TAGGED_BREAK; \
+ } while (0)
+
+#define UNWIND_ENSURE(mrb, ci, pc, tag, proc, val) \
+ do { \
+ ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ENSURE); \
+ if (ch) { \
+ THROW_TAGGED_BREAK(mrb, tag, proc, val); \
+ } \
+ } while (0)
+
+/*
+ * CHECKPOINT_RESTORE(tag) {
+ * This part is executed when jumping by the same "tag" of RBreak (it is not executed the first time).
+ * Write the code required (initialization of variables, etc.) for the subsequent processing.
+ * }
+ * CHECKPOINT_MAIN(tag) {
+ * This part is always executed.
+ * }
+ * CHECKPOINT_END(tag);
+ *
+ * ...
+ *
+ * // Jump to CHECKPOINT_RESTORE with the same "tag".
+ * goto CHECKPOINT_LABEL_MAKE(tag);
+ */
+
+#define CHECKPOINT_LABEL_MAKE(tag) L_CHECKPOINT_ ## tag
+
+#define CHECKPOINT_RESTORE(tag) \
+ do { \
+ if (FALSE) { \
+ CHECKPOINT_LABEL_MAKE(tag): \
+ do {
+
+#define CHECKPOINT_MAIN(tag) \
+ } while (0); \
+ } \
+ do {
+
+#define CHECKPOINT_END(tag) \
+ } while (0); \
+ } while (0)
+
+#ifdef MRB_USE_DEBUG_HOOK
#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
#else
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
@@ -927,24 +995,24 @@ argnum_error(mrb_state *mrb, mrb_int num)
#define BYTECODE_DECODER(x) (x)
#endif
-#ifndef MRB_DISABLE_DIRECT_THREADING
+#ifndef MRB_NO_DIRECT_THREADING
#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
#define DIRECT_THREADED
#endif
-#endif /* ifndef MRB_DISABLE_DIRECT_THREADING */
+#endif /* ifndef MRB_NO_DIRECT_THREADING */
#ifndef DIRECT_THREADED
-#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) {
-#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY:
-#define NEXT break
+#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) {
+#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY:
+#define NEXT goto L_END_DISPATCH
#define JUMP NEXT
-#define END_DISPATCH }}
+#define END_DISPATCH L_END_DISPATCH:;}}
#else
#define INIT_DISPATCH JUMP; return mrb_nil_value();
-#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY:
+#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY:
#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn]
#define JUMP NEXT
@@ -953,65 +1021,89 @@ argnum_error(mrb_state *mrb, mrb_int num)
#endif
MRB_API mrb_value
-mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+mrb_vm_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int stack_keep)
{
- mrb_irep *irep = proc->body.irep;
+ const mrb_irep *irep = proc->body.irep;
mrb_value result;
struct mrb_context *c = mrb->c;
ptrdiff_t cioff = c->ci - c->cibase;
- unsigned int nregs = irep->nregs;
+ mrb_int nregs = irep->nregs;
- if (!c->stack) {
+ if (!c->stbase) {
stack_init(mrb);
}
if (stack_keep > nregs)
nregs = stack_keep;
mrb_stack_extend(mrb, nregs);
- stack_clear(c->stack + stack_keep, nregs - stack_keep);
- c->stack[0] = self;
+ stack_clear(c->ci->stack + stack_keep, nregs - stack_keep);
+ c->ci->stack[0] = self;
result = mrb_vm_exec(mrb, proc, irep->iseq);
- if (c->ci - c->cibase > cioff) {
- 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;
+ }
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");
+ if (!mrb_vm_ci_target_class(mrb->c->ci)) {
+ mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR, "no target class or module");
mrb_exc_set(mrb, exc);
return FALSE;
}
return TRUE;
}
+mrb_value
+get_send_args(mrb_state *mrb, mrb_int argc, mrb_value *regs)
+{
+ if (argc < 0) return regs[0];
+ return mrb_ary_new_from_values(mrb, argc, regs);
+}
+
+static void
+proc_adjust_upper(struct RProc *p)
+{
+ /* skip upper procs while unnamed blocks and method closures */
+ while (p->upper) {
+ if (MRB_FLAG_TEST(p->upper, MRB_PROC_SCOPE) &&
+ !MRB_FLAG_TEST(p->upper, MRB_PROC_STRICT)) {
+ break;
+ }
+ p->upper = p->upper->upper;
+ }
+}
+
+mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod);
void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
+void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid);
MRB_API mrb_value
-mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
+mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *pc)
{
- /* mrb_assert(mrb_proc_cfunc_p(proc)) */
- mrb_irep *irep = proc->body.irep;
- mrb_value *pool = irep->pool;
- mrb_sym *syms = irep->syms;
+ /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */
+ const mrb_irep *irep = proc->body.irep;
+ const mrb_pool_value *pool = irep->pool;
+ const mrb_sym *syms = irep->syms;
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;
+ uint16_t c;
+ mrb_sym mid;
+ const struct mrb_irep_catch_handler *ch;
#ifdef DIRECT_THREADED
- static void *optable[] = {
+ static const void * const optable[] = {
#define OPCODE(x,_) &&L_OP_ ## x,
#include "mruby/ops.h"
#undef OPCODE
@@ -1031,9 +1123,9 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
mrb->jmp = &c_jmp;
- mrb->c->ci->proc = proc;
+ mrb_vm_ci_proc_set(mrb->c->ci, proc);
-#define regs (mrb->c->stack)
+#define regs (mrb->c->ci->stack)
INIT_DISPATCH {
CASE(OP_NOP, Z) {
/* do nothing */
@@ -1046,27 +1138,45 @@ RETRY_TRY_BLOCK:
}
CASE(OP_LOADL, BB) {
-#ifdef MRB_WORD_BOXING
- mrb_value val = pool[b];
-#ifndef MRB_WITHOUT_FLOAT
- if (mrb_float_p(val)) {
- val = mrb_float_value(mrb, mrb_float(val));
- }
-#endif
- regs[a] = val;
+ switch (pool[b].tt) { /* number */
+ case IREP_TT_INT32:
+ regs[a] = mrb_int_value(mrb, (mrb_int)pool[b].u.i32);
+ break;
+ case IREP_TT_INT64:
+#if defined(MRB_INT64)
+ regs[a] = mrb_int_value(mrb, (mrb_int)pool[b].u.i64);
+ break;
#else
- regs[a] = pool[b];
+#if defined(MRB_64BIT)
+ if (INT32_MIN <= pool[b].u.i64 && pool[b].u.i64 <= INT32_MAX) {
+ regs[a] = mrb_int_value(mrb, (mrb_int)pool[b].u.i64);
+ break;
+ }
#endif
+ goto L_INT_OVERFLOW;
+#endif
+ case IREP_TT_BIGINT:
+ goto L_INT_OVERFLOW;
+#ifndef MRB_NO_FLOAT
+ case IREP_TT_FLOAT:
+ regs[a] = mrb_float_value(mrb, pool[b].u.f);
+ break;
+#endif
+ default:
+ /* should not happen (tt:string) */
+ regs[a] = mrb_nil_value();
+ break;
+ }
NEXT;
}
CASE(OP_LOADI, BB) {
- SET_INT_VALUE(regs[a], b);
+ SET_FIXNUM_VALUE(regs[a], b);
NEXT;
}
CASE(OP_LOADINEG, BB) {
- SET_INT_VALUE(regs[a], -b);
+ SET_FIXNUM_VALUE(regs[a], -b);
NEXT;
}
@@ -1080,7 +1190,17 @@ RETRY_TRY_BLOCK:
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);
+ SET_FIXNUM_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0);
+ NEXT;
+ }
+
+ CASE(OP_LOADI16, BS) {
+ SET_FIXNUM_VALUE(regs[a], (mrb_int)(int16_t)b);
+ NEXT;
+ }
+
+ CASE(OP_LOADI32, BSS) {
+ SET_INT_VALUE(mrb, regs[a], (int32_t)(((uint32_t)b<<16)+c));
NEXT;
}
@@ -1121,13 +1241,13 @@ RETRY_TRY_BLOCK:
}
CASE(OP_GETSV, BB) {
- mrb_value val = mrb_vm_special_get(mrb, b);
+ mrb_value val = mrb_vm_special_get(mrb, syms[b]);
regs[a] = val;
NEXT;
}
CASE(OP_SETSV, BB) {
- mrb_vm_special_set(mrb, b, regs[a]);
+ mrb_vm_special_set(mrb, syms[b], regs[a]);
NEXT;
}
@@ -1143,9 +1263,7 @@ RETRY_TRY_BLOCK:
CASE(OP_GETCV, BB) {
mrb_value val;
- ERR_PC_SET(mrb, pc);
val = mrb_vm_cv_get(mrb, syms[b]);
- ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
}
@@ -1159,9 +1277,7 @@ RETRY_TRY_BLOCK:
mrb_value val;
mrb_sym sym = syms[b];
- ERR_PC_SET(mrb, pc);
val = mrb_vm_const_get(mrb, sym);
- ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
}
@@ -1174,9 +1290,7 @@ RETRY_TRY_BLOCK:
CASE(OP_GETMCNST, BB) {
mrb_value val;
- ERR_PC_SET(mrb, pc);
val = mrb_const_get(mrb, regs[a], syms[b]);
- ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
}
@@ -1190,7 +1304,7 @@ RETRY_TRY_BLOCK:
mrb_value *regs_a = regs + a;
struct REnv *e = uvenv(mrb, c);
- if (e && b < MRB_ENV_STACK_LEN(e)) {
+ if (e && b < MRB_ENV_LEN(e)) {
*regs_a = e->stack[b];
}
else {
@@ -1205,7 +1319,7 @@ RETRY_TRY_BLOCK:
if (e) {
mrb_value *regs_a = regs + a;
- if (b < MRB_ENV_STACK_LEN(e)) {
+ if (b < MRB_ENV_LEN(e)) {
e->stack[b] = *regs_a;
mrb_write_barrier(mrb, (struct RBasic*)e);
}
@@ -1214,57 +1328,75 @@ RETRY_TRY_BLOCK:
}
CASE(OP_JMP, S) {
- pc = irep->iseq+a;
+ pc += (int16_t)a;
JUMP;
}
CASE(OP_JMPIF, BS) {
if (mrb_test(regs[a])) {
- pc = irep->iseq+b;
+ pc += (int16_t)b;
JUMP;
}
NEXT;
}
CASE(OP_JMPNOT, BS) {
if (!mrb_test(regs[a])) {
- pc = irep->iseq+b;
+ pc += (int16_t)b;
JUMP;
}
NEXT;
}
CASE(OP_JMPNIL, BS) {
if (mrb_nil_p(regs[a])) {
- pc = irep->iseq+b;
+ pc += (int16_t)b;
JUMP;
}
NEXT;
}
- 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;
+ CASE(OP_JMPUW, S) {
+ a = (uint32_t)((pc - irep->iseq) + (int16_t)a);
+ CHECKPOINT_RESTORE(RBREAK_TAG_JUMP) {
+ struct RBreak *brk = (struct RBreak*)mrb->exc;
+ mrb_value target = mrb_break_value_get(brk);
+ mrb_assert(mrb_integer_p(target));
+ a = (uint32_t)mrb_integer(target);
+ mrb_assert(a >= 0 && a < irep->ilen);
}
- /* 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;
- if (mrb->c->rsize <= mrb->c->ci->ridx) {
- mrb->c->rsize = UINT16_MAX;
+ CHECKPOINT_MAIN(RBREAK_TAG_JUMP) {
+ ch = catch_handler_find(mrb, mrb->c->ci, pc, MRB_CATCH_FILTER_ENSURE);
+ if (ch) {
+ /* avoiding a jump from a catch handler into the same handler */
+ if (a < mrb_irep_catch_handler_unpack(ch->begin) || a >= mrb_irep_catch_handler_unpack(ch->end)) {
+ THROW_TAGGED_BREAK(mrb, RBREAK_TAG_JUMP, proc, mrb_fixnum_value(a));
}
}
- mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t)*mrb->c->rsize);
}
- /* push rescue stack */
- mrb->c->rescue[mrb->c->ci->ridx++] = a;
- NEXT;
+ CHECKPOINT_END(RBREAK_TAG_JUMP);
+
+ mrb->exc = NULL; /* clear break object */
+ pc = irep->iseq + a;
+ JUMP;
}
CASE(OP_EXCEPT, B) {
- mrb_value exc = mrb_obj_value(mrb->exc);
- mrb->exc = 0;
+ mrb_value exc;
+
+ if (mrb->exc == NULL) {
+ exc = mrb_nil_value();
+ }
+ else {
+ switch (mrb->exc->tt) {
+ case MRB_TT_BREAK:
+ case MRB_TT_EXCEPTION:
+ exc = mrb_obj_value(mrb->exc);
+ break;
+ default:
+ mrb_assert(!"bad mrb_type");
+ exc = mrb_nil_value();
+ break;
+ }
+ mrb->exc = NULL;
+ }
regs[a] = exc;
NEXT;
}
@@ -1281,7 +1413,7 @@ RETRY_TRY_BLOCK:
{
mrb_value exc;
- exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR,
"class or module required for rescue clause");
mrb_exc_set(mrb, exc);
goto L_RAISE;
@@ -1292,82 +1424,19 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_POPERR, B) {
- mrb->c->ci->ridx -= a;
- NEXT;
- }
-
- CASE(OP_RAISE, B) {
- mrb_exc_set(mrb, regs[a]);
- goto L_RAISE;
- }
-
- CASE(OP_EPUSH, B) {
- struct RProc *p;
-
- 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;
+ CASE(OP_RAISEIF, B) {
+ mrb_value exc = regs[a];
+ if (mrb_break_p(exc)) {
+ mrb->exc = mrb_obj_ptr(exc);
+ goto L_BREAK;
}
- /* 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;
- 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);
+ mrb_exc_set(mrb, exc);
+ if (mrb->exc) {
+ goto L_RAISE;
}
- /* 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, B) {
- mrb_callinfo *ci = mrb->c->ci;
- unsigned int n, epos = ci->epos;
- mrb_value self = regs[0];
- struct RClass *target_class = ci->target_class;
-
- if (mrb->c->eidx <= epos) {
- NEXT;
- }
-
- if (a > (int)mrb->c->eidx - epos)
- a = mrb->c->eidx - epos;
- 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;
- irep = proc->body.irep;
- ci = cipush(mrb);
- ci->mid = ci[-1].mid;
- ci->argc = 0;
- ci->proc = proc;
- ci->stackent = mrb->c->stack;
- ci->target_class = target_class;
- ci->pc = pc;
- ci->acc = nregs;
- mrb->c->stack += ci->acc;
- mrb_stack_extend(mrb, irep->nregs);
- regs[0] = self;
- pc = irep->iseq;
- }
- pool = irep->pool;
- syms = irep->syms;
- mrb->c->eidx = epos;
- JUMP;
- }
-
CASE(OP_SENDV, BB) {
c = CALL_MAXARGS;
goto L_SEND;
@@ -1386,38 +1455,52 @@ RETRY_TRY_BLOCK:
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;
+ };
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_int argc = (c == CALL_MAXARGS) ? -1 : c;
+ mrb_int bidx = (argc < 0) ? a+2 : a+c+1;
mrb_method_t m;
struct RClass *cls;
mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
- mrb_sym mid = syms[b];
mrb_assert(bidx < irep->nregs);
recv = regs[a];
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(),
+ if (!mrb_nil_p(blk) && !mrb_proc_p(blk)) {
+ blk = mrb_type_convert(mrb, blk, MRB_TT_PROC, MRB_SYM(to_proc));
+ /* The stack might have been reallocated during mrb_type_convert(),
see #3622 */
regs[bidx] = blk;
}
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, &cls, missing);
- if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1);
- ERR_PC_SET(mrb, pc);
+ mrb_sym missing = MRB_SYM(method_missing);
+ mrb_value args;
+
+ if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
+ method_missing:
+ args = get_send_args(mrb, argc, regs+a+1);
mrb_method_missing(mrb, mid, recv, args);
}
+ if (mid != missing) {
+ cls = mrb_class(mrb, recv);
+ }
+ m = mrb_method_search_vm(mrb, &cls, missing);
+ if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */
if (argc >= 0) {
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
@@ -1431,25 +1514,20 @@ RETRY_TRY_BLOCK:
}
/* push callinfo */
- ci = cipush(mrb);
- ci->mid = mid;
- ci->stackent = mrb->c->stack;
- ci->target_class = cls;
- ci->argc = argc;
-
- ci->pc = pc;
- ci->acc = a;
-
- /* prepare stack */
- mrb->c->stack += a;
+ ci = cipush(mrb, a, a, cls, NULL, mid, argc);
if (MRB_METHOD_CFUNC_P(m)) {
if (MRB_METHOD_PROC_P(m)) {
struct RProc *p = MRB_METHOD_PROC(m);
- ci->proc = p;
+ mrb_vm_ci_proc_set(ci, p);
recv = p->body.func(mrb, recv);
}
+ else if (MRB_METHOD_NOARG_P(m) &&
+ (argc > 0 || (argc == -1 && RARRAY_LEN(regs[1]) != 0))) {
+ argnum_error(mrb, 0);
+ goto L_RAISE;
+ }
else {
recv = MRB_METHOD_FUNC(m)(mrb, recv);
}
@@ -1457,13 +1535,13 @@ RETRY_TRY_BLOCK:
mrb_gc_arena_shrink(mrb, ai);
if (mrb->exc) goto L_RAISE;
ci = mrb->c->ci;
- if (mrb_type(blk) == MRB_TT_PROC) {
+ if (mrb_proc_p(blk)) {
struct RProc *p = mrb_proc_ptr(blk);
- if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) {
+ if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == mrb_vm_ci_env(&ci[-1])) {
p->flags |= MRB_PROC_ORPHAN;
}
}
- if (!ci->target_class) { /* return from context modifying method (resume/yield) */
+ if (!ci->u.target_class) { /* return from context modifying method (resume/yield) */
if (ci->acc == CI_ACC_RESUMED) {
mrb->jmp = prev_jmp;
return recv;
@@ -1476,43 +1554,34 @@ RETRY_TRY_BLOCK:
syms = irep->syms;
}
}
- mrb->c->stack[0] = recv;
+ mrb->c->ci->stack[0] = recv;
/* pop stackpos */
- mrb->c->stack = ci->stackent;
+ ci = cipop(mrb);
pc = ci->pc;
- cipop(mrb);
- JUMP;
}
else {
/* setup environment for calling method */
- proc = ci->proc = MRB_METHOD_PROC(m);
+ mrb_vm_ci_proc_set(ci, (proc = MRB_METHOD_PROC(m)));
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs);
pc = irep->iseq;
- JUMP;
}
}
+ JUMP;
CASE(OP_CALL, Z) {
mrb_callinfo *ci;
- mrb_value recv = mrb->c->stack[0];
+ mrb_value recv = mrb->c->ci->stack[0];
struct RProc *m = mrb_proc_ptr(recv);
/* replace callinfo */
ci = mrb->c->ci;
- ci->target_class = MRB_PROC_TARGET_CLASS(m);
- ci->proc = m;
+ ci->u.target_class = MRB_PROC_TARGET_CLASS(m);
+ mrb_vm_ci_proc_set(ci, m);
if (MRB_PROC_ENV_P(m)) {
- mrb_sym mid;
- struct REnv *e = MRB_PROC_ENV(m);
-
- mid = e->mid;
- if (mid) ci->mid = mid;
- if (!e->stack) {
- e->stack = mrb->c->stack;
- }
+ ci->mid = MRB_PROC_ENV(m)->mid;
}
/* prepare stack */
@@ -1522,11 +1591,9 @@ RETRY_TRY_BLOCK:
mrb_gc_arena_shrink(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
- ci = mrb->c->ci;
- mrb->c->stack = ci->stackent;
- regs[ci->acc] = recv;
+ ci = cipop(mrb);
pc = ci->pc;
- cipop(mrb);
+ regs[ci[1].acc] = recv;
irep = mrb->c->ci->proc->body.irep;
pool = irep->pool;
syms = irep->syms;
@@ -1537,7 +1604,7 @@ RETRY_TRY_BLOCK:
proc = m;
irep = m->body.irep;
if (!irep) {
- mrb->c->stack[0] = mrb_nil_value();
+ mrb->c->ci->stack[0] = mrb_nil_value();
a = 0;
c = OP_R_NORMAL;
goto L_OP_RETURN_BODY;
@@ -1562,60 +1629,67 @@ RETRY_TRY_BLOCK:
}
CASE(OP_SUPER, BB) {
- int argc = (b == CALL_MAXARGS) ? -1 : b;
+ mrb_int argc = (b == CALL_MAXARGS) ? -1 : b;
int bidx = (argc < 0) ? a+2 : a+b+1;
mrb_method_t m;
struct RClass *cls;
mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
+ const struct RProc *p = ci->proc;
mrb_sym mid = ci->mid;
- struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc);
+ struct RClass* target_class = MRB_PROC_TARGET_CLASS(p);
+ if (MRB_PROC_ENV_P(p) && p->e.env->mid && p->e.env->mid != mid) { /* alias support */
+ mid = p->e.env->mid; /* restore old mid */
+ }
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");
+ mrb_value exc = mrb_exc_new_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
- if (target_class->tt == MRB_TT_MODULE) {
- target_class = ci->target_class;
+ if (target_class->flags & MRB_FL_CLASS_IS_PREPENDED) {
+ target_class = mrb_vm_ci_target_class(ci);
+ }
+ else if (target_class->tt == MRB_TT_MODULE) {
+ target_class = mrb_vm_ci_target_class(ci);
if (target_class->tt != MRB_TT_ICLASS) {
- mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "superclass info lost [mruby limitations]");
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
+ goto super_typeerror;
}
}
recv = regs[0];
if (!mrb_obj_is_kind_of(mrb, recv, target_class)) {
- mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ super_typeerror: ;
+ mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR,
"self has wrong type to call super in this context");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
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");
+ if (!mrb_nil_p(blk) && !mrb_proc_p(blk)) {
+ blk = mrb_type_convert(mrb, blk, MRB_TT_PROC, MRB_SYM(to_proc));
/* The stack or ci stack might have been reallocated during
- mrb_convert_type(), see #3622 and #3784 */
+ mrb_type_convert(), see #3622 and #3784 */
regs[bidx] = blk;
ci = mrb->c->ci;
}
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");
+ mrb_sym missing = MRB_SYM(method_missing);
+ mrb_value args;
+ if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
+ super_missing:
+ args = get_send_args(mrb, argc, regs+a+1);
+ mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid);
+ }
if (mid != missing) {
cls = mrb_class(mrb, recv);
}
m = mrb_method_search_vm(mrb, &cls, missing);
- if (MRB_METHOD_UNDEF_P(m)) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1);
- ERR_PC_SET(mrb, pc);
- mrb_method_missing(mrb, mid, recv, args);
- }
- mid = missing;
+ if (MRB_METHOD_UNDEF_P(m)) goto super_missing; /* just in case */
if (argc >= 0) {
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
@@ -1624,32 +1698,28 @@ RETRY_TRY_BLOCK:
regs[a+2] = blk;
argc = -1;
}
- mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
+ mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid));
+ mid = missing;
}
/* push callinfo */
- ci = cipush(mrb);
- ci->mid = mid;
- ci->stackent = mrb->c->stack;
- ci->target_class = cls;
- ci->pc = pc;
- ci->argc = argc;
+ ci = cipush(mrb, a, 0, cls, NULL, mid, argc);
/* prepare stack */
- mrb->c->stack += a;
- mrb->c->stack[0] = recv;
+ mrb->c->ci->stack[0] = recv;
if (MRB_METHOD_CFUNC_P(m)) {
mrb_value v;
if (MRB_METHOD_PROC_P(m)) {
- ci->proc = MRB_METHOD_PROC(m);
+ mrb_vm_ci_proc_set(ci, MRB_METHOD_PROC(m));
}
v = MRB_METHOD_CFUNC(m)(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
ci = mrb->c->ci;
- if (!ci->target_class) { /* return from context modifying method (resume/yield) */
+ mrb_assert(!mrb_break_p(v));
+ if (!mrb_vm_ci_target_class(ci)) { /* return from context modifying method (resume/yield) */
if (ci->acc == CI_ACC_RESUMED) {
mrb->jmp = prev_jmp;
return v;
@@ -1662,11 +1732,9 @@ RETRY_TRY_BLOCK:
syms = irep->syms;
}
}
- mrb->c->stack[0] = v;
- /* pop stackpos */
- mrb->c->stack = ci->stackent;
+ mrb->c->ci->stack[0] = v;
+ ci = cipop(mrb);
pc = ci->pc;
- cipop(mrb);
JUMP;
}
else {
@@ -1674,7 +1742,7 @@ RETRY_TRY_BLOCK:
ci->acc = a;
/* setup environment for calling method */
- proc = ci->proc = MRB_METHOD_PROC(m);
+ mrb_vm_ci_proc_set(ci, (proc = MRB_METHOD_PROC(m)));
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
@@ -1685,18 +1753,18 @@ RETRY_TRY_BLOCK:
}
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_int m1 = (b>>11)&0x3f;
+ mrb_int r = (b>>10)&0x1;
+ mrb_int m2 = (b>>5)&0x1f;
+ mrb_int kd = (b>>4)&0x1;
+ mrb_int lv = (b>>0)&0xf;
mrb_value *stack;
- if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) {
+ if (mrb->c->ci->mid == 0 || mrb_vm_ci_target_class(mrb->c->ci) == NULL) {
mrb_value exc;
L_NOSUPER:
- exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+ exc = mrb_exc_new_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
@@ -1704,7 +1772,7 @@ 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+kd+1)
+ if (MRB_ENV_LEN(e) <= m1+r+m2+kd+1)
goto L_NOSUPER;
stack = e->stack + 1;
}
@@ -1714,13 +1782,13 @@ RETRY_TRY_BLOCK:
else {
mrb_value *pp = NULL;
struct RArray *rest;
- int len = 0;
+ mrb_int len = 0;
if (mrb_array_p(stack[m1])) {
struct RArray *ary = mrb_ary_ptr(stack[m1]);
pp = ARY_PTR(ary);
- len = (int)ARY_LEN(ary);
+ len = ARY_LEN(ary);
}
regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd);
rest = mrb_ary_ptr(regs[a]);
@@ -1744,22 +1812,22 @@ RETRY_TRY_BLOCK:
}
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;
+ mrb_int m1 = MRB_ASPEC_REQ(a);
+ mrb_int o = MRB_ASPEC_OPT(a);
+ mrb_int r = MRB_ASPEC_REST(a);
+ mrb_int m2 = MRB_ASPEC_POST(a);
+ mrb_int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0;
/* unused
int b = MRB_ASPEC_BLOCK(a);
*/
- int argc = mrb->c->ci->argc;
+ mrb_int argc = mrb->c->ci->argc;
mrb_value *argv = regs+1;
mrb_value * const argv0 = argv;
- int const len = m1 + o + r + m2;
- int const blk_pos = len + kd + 1;
+ mrb_int const len = m1 + o + r + m2;
+ mrb_int const blk_pos = len + kd + 1;
mrb_value *blk = &argv[argc < 0 ? 1 : argc];
- mrb_value kdict;
- int kargs = kd;
+ mrb_value kdict = mrb_nil_value();
+ mrb_int kargs = kd;
/* arguments is passed with Array */
if (argc < 0) {
@@ -1771,11 +1839,9 @@ RETRY_TRY_BLOCK:
/* strict argument check */
if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
- if (argc >= 0 && !(argc <= 1 && kd)) {
- if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) {
- 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 */
@@ -1796,13 +1862,13 @@ RETRY_TRY_BLOCK:
kdict = argv[argc-1];
mrb_hash_check_kdict(mrb, kdict);
}
- else if (r) {
+ 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 {
- mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments");
- mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
+ argnum_error(mrb, m1+m2);
goto L_RAISE;
}
if (MRB_ASPEC_KEY(a) > 0) {
@@ -1813,7 +1879,7 @@ RETRY_TRY_BLOCK:
/* no rest arguments */
if (argc-kargs < len) {
- int mlen = m2;
+ mrb_int mlen = m2;
if (argc < m1+m2) {
mlen = m1 < argc ? argc - m1 : 0;
}
@@ -1821,7 +1887,7 @@ RETRY_TRY_BLOCK:
if (kd) regs[len + 1] = kdict;
/* copy mandatory and optional arguments */
- if (argv0 != argv) {
+ if (argv0 != argv && argv) {
value_move(&regs[1], argv, argc-mlen); /* m1 + o */
}
if (argc < m1) {
@@ -1834,16 +1900,16 @@ RETRY_TRY_BLOCK:
if (mlen < m2) {
stack_clear(&regs[len-m2+mlen+1], m2-mlen);
}
- /* initalize rest arguments with empty Array */
+ /* initialize rest arguments with empty Array */
if (r) {
regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
}
- /* skip initailizer of passed arguments */
+ /* skip initializer of passed arguments */
if (o > 0 && argc-kargs > m1+m2)
pc += (argc - kargs - m1 - m2)*3;
}
else {
- int rnum = 0;
+ mrb_int rnum = 0;
if (argv0 != argv) {
regs[blk_pos] = *blk; /* move block */
if (kd) regs[len + 1] = kdict;
@@ -1869,7 +1935,7 @@ RETRY_TRY_BLOCK:
}
/* format arguments for generated code */
- mrb->c->ci->argc = len + kd;
+ mrb->c->ci->argc = (int16_t)(len + kd);
/* clear local (but non-argument) variables */
if (irep->nlocals-blk_pos-1 > 0) {
@@ -1882,8 +1948,8 @@ RETRY_TRY_BLOCK:
mrb_value k = mrb_symbol_value(syms[b]);
mrb_value kdict = regs[mrb->c->ci->argc];
- if (!mrb_hash_key_p(mrb, kdict, k)) {
- mrb_value str = mrb_format(mrb, "missing keyword: %S", k);
+ if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) {
+ mrb_value str = mrb_format(mrb, "missing keyword: %v", k);
mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
goto L_RAISE;
}
@@ -1895,8 +1961,11 @@ RETRY_TRY_BLOCK:
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 = mrb_hash_key_p(mrb, kdict, k);
+ 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;
}
@@ -1907,7 +1976,7 @@ RETRY_TRY_BLOCK:
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_value str = mrb_format(mrb, "unknown keyword: %v", key1);
mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
goto L_RAISE;
}
@@ -1926,13 +1995,7 @@ RETRY_TRY_BLOCK:
c = OP_R_NORMAL;
L_RETURN:
{
- mrb_callinfo *ci;
-
-#define ecall_adjust() do {\
- ptrdiff_t cioff = ci - mrb->c->cibase;\
- ecall(mrb);\
- ci = mrb->c->cibase + cioff;\
-} while (0)
+ mrb_callinfo *ci;
ci = mrb->c->ci;
if (ci->mid) {
@@ -1944,50 +2007,43 @@ RETRY_TRY_BLOCK:
else {
blk = regs[ci->argc+1];
}
- if (mrb_type(blk) == MRB_TT_PROC) {
+ if (mrb_proc_p(blk)) {
struct RProc *p = mrb_proc_ptr(blk);
if (!MRB_PROC_STRICT_P(p) &&
- ci > mrb->c->cibase && MRB_PROC_ENV(p) == ci[-1].env) {
+ ci > mrb->c->cibase && MRB_PROC_ENV(p) == mrb_vm_ci_env(&ci[-1])) {
p->flags |= MRB_PROC_ORPHAN;
}
}
}
if (mrb->exc) {
- mrb_callinfo *ci0;
-
L_RAISE:
- ci0 = ci = mrb->c->ci;
+ ci = mrb->c->ci;
if (ci == mrb->c->cibase) {
- if (ci->ridx == 0) goto L_FTOP;
- goto L_RESCUE;
+ ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL);
+ if (ch == NULL) goto L_FTOP;
+ goto L_CATCH;
}
- while (ci[0].ridx == ci[-1].ridx) {
- cipop(mrb);
- mrb->c->stack = ci->stackent;
- if (ci->acc == CI_ACC_SKIP && prev_jmp) {
+ while ((ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL)) == NULL) {
+ ci = cipop(mrb);
+ if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
mrb->jmp = prev_jmp;
MRB_THROW(prev_jmp);
}
- ci = mrb->c->ci;
+ pc = ci[0].pc;
if (ci == mrb->c->cibase) {
- if (ci->ridx == 0) {
+ ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL);
+ if (ch == NULL) {
L_FTOP: /* fiber top */
if (mrb->c == mrb->root_c) {
- mrb->c->stack = mrb->c->stbase;
+ mrb->c->ci->stack = mrb->c->stbase;
goto L_STOP;
}
else {
struct mrb_context *c = mrb->c;
- while (c->eidx > ci->epos) {
- ecall_adjust();
- }
- if (c->fib) {
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
- }
- mrb->c->status = MRB_FIBER_TERMINATED;
+ c->status = MRB_FIBER_TERMINATED;
mrb->c = c->prev;
c->prev = NULL;
goto L_RAISE;
@@ -1995,29 +2051,23 @@ RETRY_TRY_BLOCK:
}
break;
}
- /* call ensure only when we skip this callinfo */
- if (ci[0].ridx == ci[-1].ridx) {
- while (mrb->c->eidx > ci->epos) {
- ecall_adjust();
- }
- }
}
- L_RESCUE:
- if (ci->ridx == 0) goto L_STOP;
+ L_CATCH:
+ if (ch == NULL) goto L_STOP;
+ if (FALSE) {
+ L_CATCH_TAGGED_BREAK: /* from THROW_TAGGED_BREAK() or UNWIND_ENSURE() */
+ ci = mrb->c->ci;
+ }
proc = ci->proc;
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- if (ci < ci0) {
- mrb->c->stack = ci[1].stackent;
- }
mrb_stack_extend(mrb, irep->nregs);
- pc = irep->iseq+mrb->c->rescue[--ci->ridx];
+ pc = irep->iseq + mrb_irep_catch_handler_unpack(ch->target);
}
else {
- int acc;
+ mrb_int acc;
mrb_value v;
- struct RProc *dst;
ci = mrb->c->ci;
v = regs[a];
@@ -2026,55 +2076,92 @@ RETRY_TRY_BLOCK:
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)) {
- mrb_callinfo *cibase = mrb->c->cibase;
+ const struct RProc *dst;
+ mrb_callinfo *cibase;
+ cibase = mrb->c->cibase;
dst = top_proc(mrb, proc);
if (MRB_PROC_ENV_P(dst)) {
struct REnv *e = MRB_PROC_ENV(dst);
- if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt != mrb->c) {
+ if (!MRB_ENV_ONSTACK_P(e) || (e->cxt && e->cxt != mrb->c)) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
}
+ /* check jump destination */
while (cibase <= ci && ci->proc != dst) {
- if (ci->acc < 0) {
+ if (ci->acc < 0) { /* jump cross C boundary */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ci--;
}
- if (ci <= cibase) {
+ if (ci <= cibase) { /* no jump destination */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
+ ci = mrb->c->ci;
+ while (cibase <= ci && ci->proc != dst) {
+ CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_BLOCK) {
+ cibase = mrb->c->cibase;
+ dst = top_proc(mrb, proc);
+ }
+ CHECKPOINT_MAIN(RBREAK_TAG_RETURN_BLOCK) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN_BLOCK, proc, v);
+ }
+ CHECKPOINT_END(RBREAK_TAG_RETURN_BLOCK);
+ ci = cipop(mrb);
+ pc = ci->pc;
+ }
+ proc = ci->proc;
+ mrb->exc = NULL; /* clear break object */
break;
}
/* fallthrough */
case OP_R_NORMAL:
NORMAL_RETURN:
if (ci == mrb->c->cibase) {
- struct mrb_context *c = mrb->c;
+ struct mrb_context *c;
+ c = mrb->c;
if (!c->prev) { /* toplevel return */
regs[irep->nlocals] = v;
- goto L_STOP;
+ goto CHECKPOINT_LABEL_MAKE(RBREAK_TAG_STOP);
}
- if (c->prev->ci == c->prev->cibase) {
- mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
+ if (!c->vmexec && c->prev->ci == c->prev->cibase) {
+ mrb_value exc = mrb_exc_new_lit(mrb, E_FIBER_ERROR, "double resume");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
- while (c->eidx > 0) {
- ecall(mrb);
+ CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_TOPLEVEL) {
+ c = mrb->c;
}
+ CHECKPOINT_MAIN(RBREAK_TAG_RETURN_TOPLEVEL) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN_TOPLEVEL, proc, v);
+ }
+ CHECKPOINT_END(RBREAK_TAG_RETURN_TOPLEVEL);
/* automatic yield at the end */
c->status = MRB_FIBER_TERMINATED;
mrb->c = c->prev;
- c->prev = NULL;
mrb->c->status = MRB_FIBER_RUNNING;
+ c->prev = NULL;
+ if (c->vmexec) {
+ mrb_gc_arena_restore(mrb, ai);
+ c->vmexec = FALSE;
+ mrb->jmp = prev_jmp;
+ return v;
+ }
ci = mrb->c->ci;
}
+ CHECKPOINT_RESTORE(RBREAK_TAG_RETURN) {
+ /* do nothing */
+ }
+ CHECKPOINT_MAIN(RBREAK_TAG_RETURN) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN, proc, v);
+ }
+ CHECKPOINT_END(RBREAK_TAG_RETURN);
+ mrb->exc = NULL; /* clear break object */
break;
case OP_R_BREAK:
if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
@@ -2082,12 +2169,12 @@ RETRY_TRY_BLOCK:
mrb_value exc;
L_BREAK_ERROR:
- exc = mrb_exc_new_str_lit(mrb, E_LOCALJUMP_ERROR,
+ exc = mrb_exc_new_lit(mrb, E_LOCALJUMP_ERROR,
"break from proc-closure");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
- if (!MRB_PROC_ENV_P(proc) || !MRB_ENV_STACK_SHARED_P(MRB_PROC_ENV(proc))) {
+ if (!MRB_PROC_ENV_P(proc) || !MRB_ENV_ONSTACK_P(MRB_PROC_ENV(proc))) {
goto L_BREAK_ERROR;
}
else {
@@ -2097,9 +2184,13 @@ RETRY_TRY_BLOCK:
goto L_BREAK_ERROR;
}
}
- while (mrb->c->eidx > mrb->c->ci->epos) {
- ecall_adjust();
+ CHECKPOINT_RESTORE(RBREAK_TAG_BREAK) {
+ /* do nothing */
+ }
+ CHECKPOINT_MAIN(RBREAK_TAG_BREAK) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK, proc, v);
}
+ CHECKPOINT_END(RBREAK_TAG_BREAK);
/* break from fiber block */
if (ci == mrb->c->cibase && ci->pc) {
struct mrb_context *c = mrb->c;
@@ -2109,62 +2200,78 @@ RETRY_TRY_BLOCK:
ci = mrb->c->ci;
}
if (ci->acc < 0) {
+ ci = cipop(mrb);
mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
- mrb->exc = (struct RObject*)break_new(mrb, proc, v);
+ mrb->exc = (struct RObject*)break_new(mrb, RBREAK_TAG_BREAK, proc, v);
mrb->jmp = prev_jmp;
MRB_THROW(prev_jmp);
}
if (FALSE) {
+ struct RBreak *brk;
+
L_BREAK:
- v = ((struct RBreak*)mrb->exc)->val;
- proc = ((struct RBreak*)mrb->exc)->proc;
- mrb->exc = NULL;
+ brk = (struct RBreak*)mrb->exc;
+ proc = mrb_break_proc_get(brk);
+ v = mrb_break_value_get(brk);
ci = mrb->c->ci;
+
+ switch (mrb_break_tag_get(brk)) {
+#define DISPATCH_CHECKPOINTS(n, i) case n: goto CHECKPOINT_LABEL_MAKE(n);
+ RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS)
+#undef DISPATCH_CHECKPOINTS
+ default:
+ mrb_assert(!"wrong break tag");
+ }
}
- mrb->c->stack = ci->stackent;
- proc = proc->upper;
- while (mrb->c->cibase < ci && ci[-1].proc != proc) {
+ while (mrb->c->cibase < ci && ci[-1].proc != proc->upper) {
if (ci[-1].acc == CI_ACC_SKIP) {
- while (ci < mrb->c->ci) {
- cipop(mrb);
- }
goto L_BREAK_ERROR;
}
- ci--;
+ CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_UPPER) {
+ /* do nothing */
+ }
+ CHECKPOINT_MAIN(RBREAK_TAG_BREAK_UPPER) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK_UPPER, proc, v);
+ }
+ CHECKPOINT_END(RBREAK_TAG_BREAK_UPPER);
+ ci = cipop(mrb);
+ pc = ci->pc;
}
+ CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_INTARGET) {
+ /* do nothing */
+ }
+ CHECKPOINT_MAIN(RBREAK_TAG_BREAK_INTARGET) {
+ UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK_INTARGET, proc, v);
+ }
+ CHECKPOINT_END(RBREAK_TAG_BREAK_INTARGET);
if (ci == mrb->c->cibase) {
goto L_BREAK_ERROR;
}
+ mrb->exc = NULL; /* clear break object */
break;
default:
/* cannot happen */
break;
}
- while (ci < mrb->c->ci) {
- cipop(mrb);
- }
- ci[0].ridx = ci[-1].ridx;
- while (mrb->c->eidx > ci->epos) {
- ecall_adjust();
- }
- if (mrb->c->vmexec && !ci->target_class) {
+ mrb_assert(ci == mrb->c->ci);
+ mrb_assert(mrb->exc == NULL);
+
+ if (mrb->c->vmexec && !mrb_vm_ci_target_class(ci)) {
mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
mrb->jmp = prev_jmp;
return v;
}
acc = ci->acc;
- mrb->c->stack = ci->stackent;
- cipop(mrb);
+ ci = cipop(mrb);
if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
mrb_gc_arena_restore(mrb, ai);
mrb->jmp = prev_jmp;
return v;
}
- pc = ci->pc;
- ci = mrb->c->ci;
- DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid)));
+ pc = ci[0].pc;
+ DEBUG(fprintf(stderr, "from :%s\n", mrb_sym_name(mrb, ci->mid)));
proc = mrb->c->ci->proc;
irep = proc->body.irep;
pool = irep->pool;
@@ -2187,8 +2294,8 @@ RETRY_TRY_BLOCK:
if (lv == 0) stack = regs + 1;
else {
struct REnv *e = uvenv(mrb, lv-1);
- if (!e || (!MRB_ENV_STACK_SHARED_P(e) && e->mid == 0) ||
- MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) {
+ if (!e || (!MRB_ENV_ONSTACK_P(e) && e->mid == 0) ||
+ MRB_ENV_LEN(e) <= m1+r+m2+1) {
localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
goto L_RAISE;
}
@@ -2202,210 +2309,98 @@ RETRY_TRY_BLOCK:
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, BB) {
- /* 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);
- }
-#else
- OP_MATH_BODY(+,mrb_float,mrb_float);
-#endif
- break;
-#endif
- case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
- regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
- break;
- default:
- c = 1;
- goto L_SEND;
- }
- mrb_gc_arena_restore(mrb, ai);
- NEXT;
+ L_INT_OVERFLOW:
+ {
+ mrb_value exc = mrb_exc_new_lit(mrb, E_RANGE_ERROR, "integer overflow");
+ mrb_exc_set(mrb, exc);
}
+ goto L_RAISE;
- CASE(OP_SUB, BB) {
- /* 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;
-
- 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);
- }
+#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
+#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_INTEGER(op_name); \
+ OP_MATH_CASE_FLOAT(op_name, integer, float); \
+ OP_MATH_CASE_FLOAT(op_name, float, integer); \
+ OP_MATH_CASE_FLOAT(op_name, float, float); \
+ OP_MATH_CASE_STRING_##op_name(); \
+ default: \
+ c = 1; \
+ mid = MRB_OPSYM(op_name); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATH_CASE_INTEGER(op_name) \
+ case TYPES2(MRB_TT_INTEGER, MRB_TT_INTEGER): \
+ { \
+ mrb_int x = mrb_integer(regs[a]), y = mrb_integer(regs[a+1]), z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(); \
+ else \
+ SET_INT_VALUE(mrb,regs[a], z); \
+ } \
+ break
+#ifdef MRB_NO_FLOAT
+#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0
#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
#endif
- break;
-#endif
- default:
- c = 1;
- goto L_SEND;
- }
- NEXT;
+#define OP_MATH_OVERFLOW_INT() goto L_INT_OVERFLOW
+#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_integer MRB_TT_INTEGER
+#define OP_MATH_TT_float MRB_TT_FLOAT
+
+ CASE(OP_ADD, B) {
+ OP_MATH(add);
}
- CASE(OP_MUL, BB) {
- /* 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:
- c = 1;
- goto L_SEND;
- }
- NEXT;
+ CASE(OP_MUL, B) {
+ OP_MATH(mul);
}
- CASE(OP_DIV, BB) {
-#ifndef MRB_WITHOUT_FLOAT
- double x, y, f;
+ CASE(OP_DIV, B) {
+#ifndef MRB_NO_FLOAT
+ mrb_float x, y, f;
#endif
/* 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):
-#ifdef MRB_WITHOUT_FLOAT
+ case TYPES2(MRB_TT_INTEGER,MRB_TT_INTEGER):
{
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_INT_VALUE(regs[a], y ? x / y : 0);
+ mrb_int x = mrb_integer(regs[a]);
+ mrb_int y = mrb_integer(regs[a+1]);
+ mrb_int div = mrb_div_int(mrb, x, y);
+ SET_INT_VALUE(mrb, regs[a], div);
}
- break;
-#else
- x = (mrb_float)mrb_fixnum(regs[a]);
- y = (mrb_float)mrb_fixnum(regs[a+1]);
- break;
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- x = (mrb_float)mrb_fixnum(regs[a]);
+ NEXT;
+#ifndef MRB_NO_FLOAT
+ case TYPES2(MRB_TT_INTEGER,MRB_TT_FLOAT):
+ x = (mrb_float)mrb_integer(regs[a]);
y = mrb_float(regs[a+1]);
break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
+ case TYPES2(MRB_TT_FLOAT,MRB_TT_INTEGER):
x = mrb_float(regs[a]);
- y = (mrb_float)mrb_fixnum(regs[a+1]);
+ y = (mrb_float)mrb_integer(regs[a+1]);
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
x = mrb_float(regs[a]);
@@ -2414,114 +2409,73 @@ RETRY_TRY_BLOCK:
#endif
default:
c = 1;
- goto L_SEND;
+ mid = MRB_OPSYM(div);
+ goto L_SEND_SYM;
}
-#ifndef MRB_WITHOUT_FLOAT
- if (y == 0) {
- if (x > 0) f = INFINITY;
- else if (x < 0) f = -INFINITY;
- else /* if (x == 0) */ f = NAN;
- }
- else {
- f = x / y;
- }
+#ifndef MRB_NO_FLOAT
+ f = mrb_div_float(x, y);
SET_FLOAT_VALUE(mrb, regs[a], f);
#endif
NEXT;
}
- CASE(OP_ADDI, BBB) {
- /* 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 = (mrb_int)c;
- 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 + c);
- }
+#define OP_MATHI(op_name) \
+ /* need to check if op is overridden */ \
+ switch (mrb_type(regs[a])) { \
+ OP_MATHI_CASE_INTEGER(op_name); \
+ OP_MATHI_CASE_FLOAT(op_name); \
+ default: \
+ SET_INT_VALUE(mrb,regs[a+1], b); \
+ c = 1; \
+ mid = MRB_OPSYM(op_name); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATHI_CASE_INTEGER(op_name) \
+ case MRB_TT_INTEGER: \
+ { \
+ mrb_int x = mrb_integer(regs[a]), y = (mrb_int)b, z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(); \
+ else \
+ SET_INT_VALUE(mrb,regs[a], z); \
+ } \
+ break
+#ifdef MRB_NO_FLOAT
+#define OP_MATHI_CASE_FLOAT(op_name) (void)0
#else
- mrb_float(regs[a]) += c;
+#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
- break;
-#endif
- default:
- SET_INT_VALUE(regs[a+1], c);
- c = 1;
- goto L_SEND;
- }
- NEXT;
- }
- CASE(OP_SUBI, BBB) {
- 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 = (mrb_int)c;
- 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], (mrb_float)x - (mrb_float)c);
- }
-#else
- mrb_float(regs_a[0]) -= c;
-#endif
- break;
-#endif
- default:
- SET_INT_VALUE(regs_a[1], c);
- c = 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]))
-#ifdef MRB_WITHOUT_FLOAT
-#define OP_CMP(op) do {\
+#ifdef MRB_NO_FLOAT
+#define OP_CMP(op,sym) do {\
int result;\
/* need to check if - is overridden */\
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
+ case TYPES2(MRB_TT_INTEGER,MRB_TT_INTEGER):\
result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
break;\
default:\
c = 1;\
- goto L_SEND;\
+ mid = MRB_OPSYM(sym);\
+ goto L_SEND_SYM;\
}\
if (result) {\
SET_TRUE_VALUE(regs[a]);\
@@ -2531,17 +2485,17 @@ RETRY_TRY_BLOCK:
}\
} while(0)
#else
-#define OP_CMP(op) do {\
+#define OP_CMP(op, sym) do {\
int result;\
/* need to check if - is overridden */\
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
+ case TYPES2(MRB_TT_INTEGER,MRB_TT_INTEGER):\
result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
break;\
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
+ case TYPES2(MRB_TT_INTEGER,MRB_TT_FLOAT):\
result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\
break;\
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
+ case TYPES2(MRB_TT_FLOAT,MRB_TT_INTEGER):\
result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\
break;\
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
@@ -2549,7 +2503,8 @@ RETRY_TRY_BLOCK:
break;\
default:\
c = 1;\
- goto L_SEND;\
+ mid = MRB_OPSYM(sym);\
+ goto L_SEND_SYM;\
}\
if (result) {\
SET_TRUE_VALUE(regs[a]);\
@@ -2560,33 +2515,33 @@ RETRY_TRY_BLOCK:
} while(0)
#endif
- CASE(OP_EQ, BB) {
+ CASE(OP_EQ, B) {
if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
SET_TRUE_VALUE(regs[a]);
}
else {
- OP_CMP(==);
+ OP_CMP(==,eq);
}
NEXT;
}
- CASE(OP_LT, BB) {
- OP_CMP(<);
+ CASE(OP_LT, B) {
+ OP_CMP(<,lt);
NEXT;
}
- CASE(OP_LE, BB) {
- OP_CMP(<=);
+ CASE(OP_LE, B) {
+ OP_CMP(<=,le);
NEXT;
}
- CASE(OP_GT, BB) {
- OP_CMP(>);
+ CASE(OP_GT, B) {
+ OP_CMP(>,gt);
NEXT;
}
- CASE(OP_GE, BB) {
- OP_CMP(>=);
+ CASE(OP_GE, B) {
+ OP_CMP(>=,ge);
NEXT;
}
@@ -2605,7 +2560,12 @@ RETRY_TRY_BLOCK:
CASE(OP_ARYCAT, B) {
mrb_value splat = mrb_ary_splat(mrb, regs[a+1]);
- mrb_ary_concat(mrb, regs[a], splat);
+ if (mrb_nil_p(regs[a])) {
+ regs[a] = splat;
+ }
+ else {
+ mrb_ary_concat(mrb, regs[a], splat);
+ }
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2693,9 +2653,15 @@ RETRY_TRY_BLOCK:
}
CASE(OP_STRING, BB) {
- mrb_value str = mrb_str_dup(mrb, pool[b]);
+ size_t len;
- regs[a] = str;
+ len = pool[b].tt >> 2;
+ if (pool[b].tt & IREP_TT_SFLAG) {
+ regs[a] = mrb_str_new_static(mrb, pool[b].u.str, len);
+ }
+ else {
+ regs[a] = mrb_str_new(mrb, pool[b].u.str, len);
+ }
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2743,7 +2709,7 @@ RETRY_TRY_BLOCK:
L_MAKE_LAMBDA:
{
struct RProc *p;
- mrb_irep *nirep = irep->reps[b];
+ const mrb_irep *nirep = irep->reps[b];
if (c & OP_L_CAPTURE) {
p = mrb_closure_new(mrb, nirep);
@@ -2753,6 +2719,7 @@ RETRY_TRY_BLOCK:
p->flags |= MRB_PROC_SCOPE;
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
+ if (c == OP_L_METHOD) proc_adjust_upper(p);
regs[a] = mrb_obj_value(p);
mrb_gc_arena_restore(mrb, ai);
NEXT;
@@ -2794,6 +2761,7 @@ RETRY_TRY_BLOCK:
super = regs[a+1];
if (mrb_nil_p(base)) {
baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ if (!baseclass) baseclass = mrb->object_class;
base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_class(mrb, base, super, id);
@@ -2810,6 +2778,7 @@ RETRY_TRY_BLOCK:
base = regs[a];
if (mrb_nil_p(base)) {
baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ if (!baseclass) baseclass = mrb->object_class;
base = mrb_obj_value(baseclass);
}
cls = mrb_vm_define_module(mrb, base, id);
@@ -2818,11 +2787,11 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_EXEC, BB) {
- mrb_callinfo *ci;
+ CASE(OP_EXEC, BB)
+ {
mrb_value recv = regs[a];
struct RProc *p;
- mrb_irep *nirep = irep->reps[b];
+ const mrb_irep *nirep = irep->reps[b];
/* prepare closure */
p = mrb_proc_new(mrb, nirep);
@@ -2830,21 +2799,10 @@ RETRY_TRY_BLOCK:
mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)proc);
MRB_PROC_SET_TARGET_CLASS(p, mrb_class_ptr(recv));
p->flags |= MRB_PROC_SCOPE;
+ proc_adjust_upper(p);
/* prepare call stack */
- ci = cipush(mrb);
- ci->pc = pc;
- ci->acc = a;
- ci->mid = 0;
- ci->stackent = mrb->c->stack;
- ci->argc = 0;
- ci->target_class = mrb_class_ptr(recv);
-
- /* prepare stack */
- mrb->c->stack += a;
-
- /* setup block to call */
- ci->proc = p;
+ cipush(mrb, a, a, mrb_class_ptr(recv), p, 0, 0);
irep = p->body.irep;
pool = irep->pool;
@@ -2859,10 +2817,13 @@ RETRY_TRY_BLOCK:
struct RClass *target = mrb_class_ptr(regs[a]);
struct RProc *p = mrb_proc_ptr(regs[a+1]);
mrb_method_t m;
+ mrb_sym mid = syms[b];
MRB_METHOD_FROM_PROC(m, p);
- mrb_define_method_raw(mrb, target, syms[b], m);
+ mrb_define_method_raw(mrb, target, mid, m);
+ mrb_method_added(mrb, target, mid);
mrb_gc_arena_restore(mrb, ai);
+ regs[a] = mrb_symbol_value(mid);
NEXT;
}
@@ -2874,7 +2835,7 @@ RETRY_TRY_BLOCK:
CASE(OP_TCLASS, B) {
if (!check_target_class(mrb)) goto L_RAISE;
- regs[a] = mrb_obj_value(mrb->c->ci->target_class);
+ regs[a] = mrb_obj_value(mrb_vm_ci_target_class(mrb->c->ci));
NEXT;
}
@@ -2882,25 +2843,26 @@ RETRY_TRY_BLOCK:
struct RClass *target;
if (!check_target_class(mrb)) goto L_RAISE;
- target = mrb->c->ci->target_class;
+ target = mrb_vm_ci_target_class(mrb->c->ci);
mrb_alias_method(mrb, target, syms[a], syms[b]);
- NEXT;
+ mrb_method_added(mrb, target, syms[a]);
+ NEXT;
}
CASE(OP_UNDEF, B) {
struct RClass *target;
if (!check_target_class(mrb)) goto L_RAISE;
- target = mrb->c->ci->target_class;
+ target = mrb_vm_ci_target_class(mrb->c->ci);
mrb_undef_method_id(mrb, target, syms[a]);
NEXT;
}
CASE(OP_DEBUG, Z) {
FETCH_BBB();
-#ifdef MRB_ENABLE_DEBUG_HOOK
+#ifdef MRB_USE_DEBUG_HOOK
mrb->debug_op_hook(mrb, irep, pc, regs);
#else
-#ifndef MRB_DISABLE_STDIO
+#ifndef MRB_NO_STDIO
printf("OP_DEBUG %d %d %d\n", a, b, c);
#else
abort();
@@ -2910,19 +2872,23 @@ RETRY_TRY_BLOCK:
}
CASE(OP_ERR, B) {
- mrb_value msg = mrb_str_dup(mrb, pool[a]);
+ size_t len = pool[a].tt >> 2;
mrb_value exc;
- exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
- ERR_PC_SET(mrb, pc);
+ mrb_assert((pool[a].tt&IREP_TT_NFLAG)==0);
+ exc = mrb_exc_new(mrb, E_LOCALJUMP_ERROR, pool[a].u.str, len);
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
+ CASE(OP_SENDVK, BB) { /* not yet implemented */
+ NEXT;
+ }
+
CASE(OP_EXT1, Z) {
insn = READ_B();
switch (insn) {
-#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); goto L_OP_ ## insn ## _BODY;
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
#include "mruby/ops.h"
#undef OPCODE
}
@@ -2932,7 +2898,7 @@ RETRY_TRY_BLOCK:
CASE(OP_EXT2, Z) {
insn = READ_B();
switch (insn) {
-#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); goto L_OP_ ## insn ## _BODY;
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
#include "mruby/ops.h"
#undef OPCODE
}
@@ -2942,7 +2908,7 @@ RETRY_TRY_BLOCK:
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;
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
#include "mruby/ops.h"
#undef OPCODE
}
@@ -2952,14 +2918,17 @@ RETRY_TRY_BLOCK:
CASE(OP_STOP, Z) {
/* stop VM */
- L_STOP:
- while (mrb->c->eidx > 0) {
- ecall(mrb);
+ CHECKPOINT_RESTORE(RBREAK_TAG_STOP) {
+ /* do nothing */
}
- mrb->c->cibase->ridx = 0;
- ERR_PC_CLR(mrb);
+ CHECKPOINT_MAIN(RBREAK_TAG_STOP) {
+ UNWIND_ENSURE(mrb, mrb->c->ci, pc, RBREAK_TAG_STOP, proc, mrb_nil_value());
+ }
+ CHECKPOINT_END(RBREAK_TAG_STOP);
+ L_STOP:
mrb->jmp = prev_jmp;
if (mrb->exc) {
+ mrb_assert(mrb->exc->tt == MRB_TT_EXCEPTION);
return mrb_obj_value(mrb->exc);
}
return regs[irep->nlocals];
@@ -2969,14 +2938,19 @@ RETRY_TRY_BLOCK:
#undef regs
}
MRB_CATCH(&c_jmp) {
+ mrb_callinfo *ci = mrb->c->ci;
+ while (ci > mrb->c->cibase && ci->acc == CI_ACC_DIRECT) {
+ ci = cipop(mrb);
+ }
exc_catched = TRUE;
+ pc = ci->pc;
goto RETRY_TRY_BLOCK;
}
MRB_END_EXC(&c_jmp);
}
-MRB_API mrb_value
-mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
+static mrb_value
+mrb_run(mrb_state *mrb, const struct RProc *proc, mrb_value self)
{
if (mrb->c->ci->argc < 0) {
return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */
@@ -2987,33 +2961,29 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
MRB_API mrb_value
-mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+mrb_top_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int stack_keep)
{
- mrb_callinfo *ci;
mrb_value v;
if (!mrb->c->cibase) {
return mrb_vm_run(mrb, proc, self, stack_keep);
}
if (mrb->c->ci == mrb->c->cibase) {
+ mrb_vm_ci_env_set(mrb->c->ci, NULL);
return mrb_vm_run(mrb, proc, self, stack_keep);
}
- ci = cipush(mrb);
- ci->mid = 0;
- ci->acc = CI_ACC_SKIP;
- ci->target_class = mrb->object_class;
+ cipush(mrb, 0, CI_ACC_SKIP, mrb->object_class, NULL, 0, 0);
v = mrb_vm_run(mrb, proc, self, stack_keep);
- cipop(mrb);
return v;
}
-#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
-# if !defined(MRB_ENABLE_CXX_ABI)
+#if defined(MRB_USE_CXX_EXCEPTION) && defined(__cplusplus)
+# if !defined(MRB_USE_CXX_ABI)
} /* end of extern "C" */
# endif
mrb_int mrb_jmpbuf::jmpbuf_id = 0;
-# if !defined(MRB_ENABLE_CXX_ABI)
+# if !defined(MRB_USE_CXX_ABI)
extern "C" {
# endif
#endif