summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/deps/mruby/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:57:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:57:58 +0000
commitbe1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 (patch)
tree9754ff1ca740f6346cf8483ec915d4054bc5da2d /web/server/h2o/libh2o/deps/mruby/src
parentInitial commit. (diff)
downloadnetdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.tar.xz
netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.zip
Adding upstream version 1.44.3.upstream/1.44.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/server/h2o/libh2o/deps/mruby/src')
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/array.c1249
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/backtrace.c281
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/class.c2474
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/codedump.c474
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/compar.c13
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/crc.c39
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/debug.c217
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/dump.c1100
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/enum.c14
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/error.c503
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/error.h3
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/etc.c234
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep0
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c372
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/gc.c1824
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/hash.c905
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/init.c51
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/kernel.c1238
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/load.c704
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake19
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/numeric.c1355
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/object.c610
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/opcode.h2
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/pool.c198
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/print.c47
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/proc.c294
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/range.c442
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/state.c303
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/string.c3013
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/symbol.c494
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/value_array.h27
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/variable.c987
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/version.c17
-rw-r--r--web/server/h2o/libh2o/deps/mruby/src/vm.c2909
34 files changed, 22412 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/mruby/src/array.c b/web/server/h2o/libh2o/deps/mruby/src/array.c
new file mode 100644
index 00000000..8f33defe
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/array.c
@@ -0,0 +1,1249 @@
+/*
+** array.c - Array class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/range.h>
+#include "value_array.h"
+
+#define ARY_DEFAULT_LEN 4
+#define ARY_SHRINK_RATIO 5 /* must be larger than 2 */
+#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
+#define ARY_MAX_SIZE ((mrb_int)((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? ARY_C_MAX_SIZE : MRB_INT_MAX-1))
+
+static struct RArray*
+ary_new_capa(mrb_state *mrb, mrb_int capa)
+{
+ struct RArray *a;
+ size_t blen;
+
+ if (capa > ARY_MAX_SIZE) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ blen = capa * sizeof(mrb_value);
+
+ a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+ if (capa <= MRB_ARY_EMBED_LEN_MAX) {
+ ARY_SET_EMBED_LEN(a, 0);
+ }
+ else {
+ a->as.heap.ptr = (mrb_value *)mrb_malloc(mrb, blen);
+ a->as.heap.aux.capa = capa;
+ a->as.heap.len = 0;
+ }
+
+ return a;
+}
+
+MRB_API mrb_value
+mrb_ary_new_capa(mrb_state *mrb, mrb_int capa)
+{
+ struct RArray *a = ary_new_capa(mrb, capa);
+ return mrb_obj_value(a);
+}
+
+MRB_API mrb_value
+mrb_ary_new(mrb_state *mrb)
+{
+ return mrb_ary_new_capa(mrb, 0);
+}
+
+/*
+ * 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
+ * * gcc on MIPS also fail
+ * http://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
+ *
+ */
+static inline void
+array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
+{
+ mrb_int i;
+
+ for (i = 0; i < size; i++) {
+ dst[i] = src[i];
+ }
+}
+
+MRB_API mrb_value
+mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
+{
+ struct RArray *a = ary_new_capa(mrb, size);
+
+ array_copy(ARY_PTR(a), vals, size);
+ ARY_SET_LEN(a, size);
+
+ return mrb_obj_value(a);
+}
+
+MRB_API mrb_value
+mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
+{
+ struct RArray *a;
+
+ a = ary_new_capa(mrb, 2);
+ ARY_PTR(a)[0] = car;
+ ARY_PTR(a)[1] = cdr;
+ ARY_SET_LEN(a, 2);
+ return mrb_obj_value(a);
+}
+
+static void
+ary_fill_with_nil(mrb_value *ptr, mrb_int size)
+{
+ mrb_value nil = mrb_nil_value();
+
+ while (size--) {
+ *ptr++ = nil;
+ }
+}
+
+static void
+ary_modify_check(mrb_state *mrb, struct RArray *a)
+{
+ if (MRB_FROZEN_P(a)) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
+ }
+}
+
+static void
+ary_modify(mrb_state *mrb, struct RArray *a)
+{
+ ary_modify_check(mrb, a);
+
+ if (ARY_SHARED_P(a)) {
+ mrb_shared_array *shared = a->as.heap.aux.shared;
+
+ if (shared->refcnt == 1 && a->as.heap.ptr == shared->ptr) {
+ a->as.heap.ptr = shared->ptr;
+ a->as.heap.aux.capa = a->as.heap.len;
+ mrb_free(mrb, shared);
+ }
+ else {
+ mrb_value *ptr, *p;
+ mrb_int len;
+
+ p = a->as.heap.ptr;
+ len = a->as.heap.len * sizeof(mrb_value);
+ ptr = (mrb_value *)mrb_malloc(mrb, len);
+ if (p) {
+ array_copy(ptr, p, a->as.heap.len);
+ }
+ a->as.heap.ptr = ptr;
+ a->as.heap.aux.capa = a->as.heap.len;
+ mrb_ary_decref(mrb, shared);
+ }
+ ARY_UNSET_SHARED_FLAG(a);
+ }
+}
+
+MRB_API void
+mrb_ary_modify(mrb_state *mrb, struct RArray* a)
+{
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ ary_modify(mrb, a);
+}
+
+static void
+ary_make_shared(mrb_state *mrb, struct RArray *a)
+{
+ if (!ARY_SHARED_P(a) && !ARY_EMBED_P(a)) {
+ mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array));
+ mrb_value *ptr = a->as.heap.ptr;
+ mrb_int len = a->as.heap.len;
+
+ shared->refcnt = 1;
+ if (a->as.heap.aux.capa > len) {
+ a->as.heap.ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, ptr, sizeof(mrb_value)*len+1);
+ }
+ else {
+ shared->ptr = ptr;
+ }
+ shared->len = len;
+ a->as.heap.aux.shared = shared;
+ ARY_SET_SHARED_FLAG(a);
+ }
+}
+
+static void
+ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
+{
+ mrb_int capa = ARY_CAPA(a);
+
+ if (len > ARY_MAX_SIZE || len < 0) {
+ size_error:
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+
+ if (capa < ARY_DEFAULT_LEN) {
+ capa = ARY_DEFAULT_LEN;
+ }
+ while (capa < len) {
+ if (capa <= ARY_MAX_SIZE / 2) {
+ capa *= 2;
+ }
+ else {
+ capa = len;
+ }
+ }
+ if (capa < len || capa > ARY_MAX_SIZE) {
+ goto size_error;
+ }
+
+ if (ARY_EMBED_P(a)) {
+ mrb_value *ptr = ARY_EMBED_PTR(a);
+ mrb_int len = ARY_EMBED_LEN(a);
+ mrb_value *expanded_ptr = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*capa);
+
+ ARY_UNSET_EMBED_FLAG(a);
+ array_copy(expanded_ptr, ptr, len);
+ a->as.heap.len = len;
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = expanded_ptr;
+ }
+ else if (capa > a->as.heap.aux.capa) {
+ mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
+
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = expanded_ptr;
+ }
+}
+
+static void
+ary_shrink_capa(mrb_state *mrb, struct RArray *a)
+{
+
+ mrb_int capa;
+
+ if (ARY_EMBED_P(a)) return;
+
+ capa = a->as.heap.aux.capa;
+ if (capa < ARY_DEFAULT_LEN * 2) return;
+ if (capa <= a->as.heap.len * ARY_SHRINK_RATIO) return;
+
+ do {
+ capa /= 2;
+ if (capa < ARY_DEFAULT_LEN) {
+ capa = ARY_DEFAULT_LEN;
+ break;
+ }
+ } while (capa > a->as.heap.len * ARY_SHRINK_RATIO);
+
+ if (capa > a->as.heap.len && capa < a->as.heap.aux.capa) {
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
+ }
+}
+
+MRB_API mrb_value
+mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
+{
+ mrb_int old_len;
+ struct RArray *a = mrb_ary_ptr(ary);
+
+ ary_modify(mrb, a);
+ old_len = RARRAY_LEN(ary);
+ if (old_len != new_len) {
+ ARY_SET_LEN(a, new_len);
+ if (new_len < old_len) {
+ ary_shrink_capa(mrb, a);
+ }
+ else {
+ ary_expand_capa(mrb, a, new_len);
+ ary_fill_with_nil(ARY_PTR(a) + old_len, new_len - old_len);
+ }
+ }
+
+ return ary;
+}
+
+static mrb_value
+mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value ary;
+ mrb_value *vals;
+ mrb_int len;
+ struct RArray *a;
+
+ mrb_get_args(mrb, "*!", &vals, &len);
+ ary = mrb_ary_new_from_values(mrb, len, vals);
+ a = mrb_ary_ptr(ary);
+ a->c = mrb_class_ptr(klass);
+
+ return ary;
+}
+
+static void
+ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
+{
+ mrb_int len;
+
+ if (ARY_LEN(a2) > ARY_MAX_SIZE - ARY_LEN(a)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ len = ARY_LEN(a) + ARY_LEN(a2);
+
+ ary_modify(mrb, a);
+ if (ARY_CAPA(a) < len) {
+ ary_expand_capa(mrb, a, len);
+ }
+ array_copy(ARY_PTR(a)+ARY_LEN(a), ARY_PTR(a2), ARY_LEN(a2));
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ ARY_SET_LEN(a, len);
+}
+
+MRB_API void
+mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
+{
+ struct RArray *a2 = mrb_ary_ptr(other);
+
+ ary_concat(mrb, mrb_ary_ptr(self), a2);
+}
+
+static mrb_value
+mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value ary;
+
+ mrb_get_args(mrb, "A", &ary);
+ mrb_ary_concat(mrb, self, ary);
+ return self;
+}
+
+static mrb_value
+mrb_ary_plus(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a1 = mrb_ary_ptr(self);
+ struct RArray *a2;
+ mrb_value *ptr;
+ mrb_int blen, len1;
+
+ mrb_get_args(mrb, "a", &ptr, &blen);
+ if (ARY_MAX_SIZE - blen < ARY_LEN(a1)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ len1 = ARY_LEN(a1);
+ a2 = ary_new_capa(mrb, len1 + blen);
+ array_copy(ARY_PTR(a2), ARY_PTR(a1), len1);
+ array_copy(ARY_PTR(a2) + len1, ptr, blen);
+ ARY_SET_LEN(a2, len1+blen);
+
+ return mrb_obj_value(a2);
+}
+
+static void
+ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
+{
+ ary_modify(mrb, a);
+ if (ARY_CAPA(a) < len)
+ ary_expand_capa(mrb, a, len);
+ array_copy(ARY_PTR(a), argv, len);
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ ARY_SET_LEN(a, len);
+}
+
+MRB_API void
+mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
+{
+ struct RArray *a1 = mrb_ary_ptr(self);
+ struct RArray *a2 = mrb_ary_ptr(other);
+
+ if (a1 != a2) {
+ ary_replace(mrb, a1, ARY_PTR(a2), ARY_LEN(a2));
+ }
+}
+
+static mrb_value
+mrb_ary_replace_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value other;
+
+ mrb_get_args(mrb, "A", &other);
+ mrb_ary_replace(mrb, self, other);
+
+ return self;
+}
+
+static mrb_value
+mrb_ary_times(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a1 = mrb_ary_ptr(self);
+ struct RArray *a2;
+ mrb_value *ptr;
+ mrb_int times, len1;
+
+ mrb_get_args(mrb, "i", &times);
+ if (times < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
+ }
+ if (times == 0) return mrb_ary_new(mrb);
+ if (ARY_MAX_SIZE / times < ARY_LEN(a1)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ len1 = ARY_LEN(a1);
+ a2 = ary_new_capa(mrb, len1 * times);
+ ARY_SET_LEN(a2, len1 * times);
+ ptr = ARY_PTR(a2);
+ while (times--) {
+ array_copy(ptr, ARY_PTR(a1), len1);
+ ptr += len1;
+ }
+
+ return mrb_obj_value(a2);
+}
+
+static mrb_value
+mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
+
+ if (len > 1) {
+ mrb_value *p1, *p2;
+
+ ary_modify(mrb, a);
+ p1 = ARY_PTR(a);
+ p2 = p1 + len - 1;
+
+ while (p1 < p2) {
+ mrb_value tmp = *p1;
+ *p1++ = *p2;
+ *p2-- = tmp;
+ }
+ }
+ return self;
+}
+
+static mrb_value
+mrb_ary_reverse(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, ARY_LEN(a));
+ mrb_int len = ARY_LEN(a);
+
+ if (len > 0) {
+ mrb_value *p1, *p2, *e;
+
+ p1 = ARY_PTR(a);
+ e = p1 + len;
+ p2 = ARY_PTR(b) + len - 1;
+ while (p1 < e) {
+ *p2-- = *p1++;
+ }
+ ARY_SET_LEN(b, len);
+ }
+ return mrb_obj_value(b);
+}
+
+MRB_API void
+mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
+{
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
+
+ ary_modify(mrb, a);
+ if (len == ARY_CAPA(a))
+ ary_expand_capa(mrb, a, len + 1);
+ ARY_PTR(a)[len] = elem;
+ ARY_SET_LEN(a, len+1);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem);
+}
+
+static mrb_value
+mrb_ary_push_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value *argv;
+ mrb_int len, len2, alen;
+ struct RArray *a;
+
+ mrb_get_args(mrb, "*!", &argv, &alen);
+ a = mrb_ary_ptr(self);
+ ary_modify(mrb, a);
+ len = ARY_LEN(a);
+ len2 = len + alen;
+ if (ARY_CAPA(a) < len2) {
+ ary_expand_capa(mrb, a, len2);
+ }
+ array_copy(ARY_PTR(a)+len, argv, alen);
+ ARY_SET_LEN(a, len2);
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+
+ return self;
+}
+
+MRB_API mrb_value
+mrb_ary_pop(mrb_state *mrb, mrb_value ary)
+{
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
+
+ ary_modify_check(mrb, a);
+ if (len == 0) return mrb_nil_value();
+ ARY_SET_LEN(a, len-1);
+ return ARY_PTR(a)[len-1];
+}
+
+#define ARY_SHIFT_SHARED_MIN 10
+
+MRB_API mrb_value
+mrb_ary_shift(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
+ mrb_value val;
+
+ ary_modify_check(mrb, a);
+ if (len == 0) return mrb_nil_value();
+ if (ARY_SHARED_P(a)) {
+ L_SHIFT:
+ val = a->as.heap.ptr[0];
+ a->as.heap.ptr++;
+ a->as.heap.len--;
+ return val;
+ }
+ if (len > ARY_SHIFT_SHARED_MIN) {
+ ary_make_shared(mrb, a);
+ goto L_SHIFT;
+ }
+ else {
+ mrb_value *ptr = ARY_PTR(a);
+ mrb_int size = len;
+
+ val = *ptr;
+ while (--size) {
+ *ptr = *(ptr+1);
+ ++ptr;
+ }
+ ARY_SET_LEN(a, len-1);
+ }
+ return val;
+}
+
+/* self = [1,2,3]
+ item = 0
+ self.unshift item
+ p self #=> [0, 1, 2, 3] */
+MRB_API mrb_value
+mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
+
+ if (ARY_SHARED_P(a)
+ && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+ && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= 1) /* there's room for unshifted item */ {
+ a->as.heap.ptr--;
+ a->as.heap.ptr[0] = item;
+ }
+ else {
+ mrb_value *ptr;
+
+ ary_modify(mrb, a);
+ if (ARY_CAPA(a) < len + 1)
+ ary_expand_capa(mrb, a, len + 1);
+ ptr = ARY_PTR(a);
+ value_move(ptr + 1, ptr, len);
+ ptr[0] = item;
+ }
+ ARY_SET_LEN(a, len+1);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item);
+
+ return self;
+}
+
+static mrb_value
+mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_value *vals, *ptr;
+ mrb_int alen, len;
+
+ mrb_get_args(mrb, "*!", &vals, &alen);
+ if (alen == 0) {
+ ary_modify_check(mrb, a);
+ return self;
+ }
+ len = ARY_LEN(a);
+ if (alen > ARY_MAX_SIZE - len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ if (ARY_SHARED_P(a)
+ && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+ && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= alen) /* there's room for unshifted item */ {
+ ary_modify_check(mrb, a);
+ a->as.heap.ptr -= alen;
+ ptr = a->as.heap.ptr;
+ }
+ else {
+ 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);
+ }
+ array_copy(ptr, vals, alen);
+ ARY_SET_LEN(a, len+alen);
+ while (alen--) {
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[alen]);
+ }
+
+ 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)
+{
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
+
+ ary_modify(mrb, a);
+ /* range check */
+ if (n < 0) {
+ n += len;
+ if (n < 0) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len));
+ }
+ }
+ if (len <= n) {
+ if (ARY_CAPA(a) <= n)
+ ary_expand_capa(mrb, a, n + 1);
+ ary_fill_with_nil(ARY_PTR(a) + len, n + 1 - len);
+ ARY_SET_LEN(a, n+1);
+ }
+
+ ARY_PTR(a)[n] = val;
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
+}
+
+static struct RArray*
+ary_dup(mrb_state *mrb, struct RArray *a)
+{
+ mrb_int len = ARY_LEN(a);
+ struct RArray *d = ary_new_capa(mrb, len);
+
+ ary_replace(mrb, d, ARY_PTR(a), len);
+ return d;
+}
+
+MRB_API mrb_value
+mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
+{
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int alen = ARY_LEN(a);
+ const mrb_value *argv;
+ mrb_int argc;
+ mrb_int tail;
+
+ ary_modify(mrb, a);
+
+ /* len check */
+ if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len));
+
+ /* range check */
+ if (head < 0) {
+ head += alen;
+ if (head < 0) {
+ mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
+ }
+ }
+ tail = head + len;
+ if (alen < len || alen < tail) {
+ len = alen - head;
+ }
+
+ /* size check */
+ if (mrb_array_p(rpl)) {
+ argc = RARRAY_LEN(rpl);
+ argv = RARRAY_PTR(rpl);
+ if (argv == ARY_PTR(a)) {
+ struct RArray *r;
+
+ if (argc > 32767) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "too big recursive splice");
+ }
+ r = ary_dup(mrb, a);
+ argv = ARY_PTR(r);
+ }
+ }
+ 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));
+ }
+ len = head + argc;
+ if (len > ARY_CAPA(a)) {
+ ary_expand_capa(mrb, a, head + argc);
+ }
+ ary_fill_with_nil(ARY_PTR(a) + alen, head - alen);
+ if (argc > 0) {
+ array_copy(ARY_PTR(a) + head, argv, argc);
+ }
+ ARY_SET_LEN(a, len);
+ }
+ else {
+ 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));
+ }
+ newlen = alen + argc - len;
+ if (newlen > ARY_CAPA(a)) {
+ ary_expand_capa(mrb, a, newlen);
+ }
+
+ if (len != argc) {
+ mrb_value *ptr = ARY_PTR(a);
+ tail = head + len;
+ value_move(ptr + head + argc, ptr + tail, alen - tail);
+ ARY_SET_LEN(a, newlen);
+ }
+ if (argc > 0) {
+ value_move(ARY_PTR(a) + head, argv, argc);
+ }
+ }
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ return ary;
+}
+
+void
+mrb_ary_decref(mrb_state *mrb, mrb_shared_array *shared)
+{
+ shared->refcnt--;
+ if (shared->refcnt == 0) {
+ mrb_free(mrb, shared->ptr);
+ mrb_free(mrb, shared);
+ }
+}
+
+static mrb_value
+ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
+{
+ struct RArray *b;
+
+ if (!ARY_SHARED_P(a) && len <= ARY_SHIFT_SHARED_MIN) {
+ 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->as.heap.ptr = a->as.heap.ptr + beg;
+ b->as.heap.len = len;
+ b->as.heap.aux.shared = a->as.heap.aux.shared;
+ b->as.heap.aux.shared->refcnt++;
+ ARY_SET_SHARED_FLAG(b);
+
+ return mrb_obj_value(b);
+}
+
+static mrb_int
+aget_index(mrb_state *mrb, mrb_value index)
+{
+ if (mrb_fixnum_p(index)) {
+ return mrb_fixnum(index);
+ }
+ else if (mrb_float_p(index)) {
+ return (mrb_int)mrb_float(index);
+ }
+ else {
+ mrb_int i, argc;
+ mrb_value *argv;
+
+ mrb_get_args(mrb, "i*!", &i, &argv, &argc);
+ return i;
+ }
+}
+
+/*
+ * call-seq:
+ * ary[index] -> obj or nil
+ * ary[start, length] -> new_ary or nil
+ * ary[range] -> new_ary or nil
+ * ary.slice(index) -> obj or nil
+ * ary.slice(start, length) -> new_ary or nil
+ * ary.slice(range) -> new_ary or nil
+ *
+ * Element Reference --- Returns the element at +index+, or returns a
+ * subarray starting at the +start+ index and continuing for +length+
+ * elements, or returns a subarray specified by +range+ of indices.
+ *
+ * Negative indices count backward from the end of the array (-1 is the last
+ * element). For +start+ and +range+ cases the starting index is just before
+ * an element. Additionally, an empty array is returned when the starting
+ * index for an element range is at the end of the array.
+ *
+ * Returns +nil+ if the index (or starting index) are out of range.
+ *
+ * a = [ "a", "b", "c", "d", "e" ]
+ * a[1] => "b"
+ * a[1,2] => ["b", "c"]
+ * a[1..-2] => ["b", "c", "d"]
+ *
+ */
+
+static mrb_value
+mrb_ary_aget(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int i, len, alen = ARY_LEN(a);
+ mrb_value index;
+
+ if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
+ switch (mrb_type(index)) {
+ /* a[n..m] */
+ case MRB_TT_RANGE:
+ if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) {
+ 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));
+ default:
+ return mrb_ary_ref(mrb, self, aget_index(mrb, index));
+ }
+ }
+
+ i = aget_index(mrb, index);
+ if (i < 0) i += alen;
+ if (i < 0 || alen < i) return mrb_nil_value();
+ if (len < 0) return mrb_nil_value();
+ if (alen == i) return mrb_ary_new(mrb);
+ if (len > alen - i) len = alen - i;
+
+ return ary_subseq(mrb, a, i, len);
+}
+
+/*
+ * call-seq:
+ * ary[index] = obj -> obj
+ * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil
+ * ary[range] = obj or other_ary or nil -> obj or other_ary or nil
+ *
+ * Element Assignment --- Sets the element at +index+, or replaces a subarray
+ * from the +start+ index for +length+ elements, or replaces a subarray
+ * specified by the +range+ of indices.
+ *
+ * If indices are greater than the current capacity of the array, the array
+ * grows automatically. Elements are inserted into the array at +start+ if
+ * +length+ is zero.
+ *
+ * Negative indices will count backward from the end of the array. For
+ * +start+ and +range+ cases the starting index is just before an element.
+ *
+ * An IndexError is raised if a negative index points past the beginning of
+ * the array.
+ *
+ * See also Array#push, and Array#unshift.
+ *
+ * a = Array.new
+ * a[4] = "4"; #=> [nil, nil, nil, nil, "4"]
+ * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
+ * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"]
+ * a[0, 2] = "?" #=> ["?", 2, nil, "4"]
+ * a[0..2] = "A" #=> ["A", "4"]
+ * a[-1] = "Z" #=> ["A", "Z"]
+ * a[1..-1] = nil #=> ["A", nil]
+ * a[1..-1] = [] #=> ["A"]
+ * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"]
+ * a[3, 0] = "B" #=> [1, 2, "A", "B"]
+ */
+
+static mrb_value
+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) {
+ /* a[n..m] = v */
+ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) {
+ case 0: /* not range */
+ mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
+ break;
+ case 1: /* range */
+ 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);
+ break;
+ }
+ return v2;
+ }
+
+ /* a[n,m] = v */
+ mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3);
+ return v3;
+}
+
+static mrb_value
+mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int index;
+ mrb_value val;
+ mrb_value *ptr;
+ mrb_int len, alen = ARY_LEN(a);
+
+ mrb_get_args(mrb, "i", &index);
+ if (index < 0) index += alen;
+ if (index < 0 || alen <= index) return mrb_nil_value();
+
+ ary_modify(mrb, a);
+ ptr = ARY_PTR(a);
+ val = ptr[index];
+
+ ptr += index;
+ len = alen - index;
+ while (--len) {
+ *ptr = *(ptr+1);
+ ++ptr;
+ }
+ ARY_SET_LEN(a, alen-1);
+
+ ary_shrink_capa(mrb, a);
+
+ return val;
+}
+
+static mrb_value
+mrb_ary_first(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int size, alen = ARY_LEN(a);
+
+ if (mrb->c->ci->argc == 0) {
+ return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value();
+ }
+ mrb_get_args(mrb, "|i", &size);
+ if (size < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
+ }
+
+ if (size > alen) size = alen;
+ if (ARY_SHARED_P(a)) {
+ return ary_subseq(mrb, a, 0, size);
+ }
+ return mrb_ary_new_from_values(mrb, size, ARY_PTR(a));
+}
+
+static mrb_value
+mrb_ary_last(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int size, alen = ARY_LEN(a);
+
+ if (mrb_get_args(mrb, "|i", &size) == 0)
+ return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value();
+
+ if (size < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
+ }
+ if (size > alen) size = alen;
+ if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) {
+ return ary_subseq(mrb, a, alen - size, size);
+ }
+ return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size);
+}
+
+static mrb_value
+mrb_ary_index_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value obj;
+ 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);
+ }
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value obj;
+ 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);
+ }
+ if (i > (len = RARRAY_LEN(self))) {
+ i = len;
+ }
+ }
+ return mrb_nil_value();
+}
+
+MRB_API mrb_value
+mrb_ary_splat(mrb_state *mrb, mrb_value v)
+{
+ mrb_value a, recv_class;
+
+ if (mrb_array_p(v)) {
+ return v;
+ }
+
+ if (!mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "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)) {
+ 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();
+ }
+}
+
+static mrb_value
+mrb_ary_size(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+
+ return mrb_fixnum_value(ARY_LEN(a));
+}
+
+MRB_API mrb_value
+mrb_ary_clear(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+
+ ary_modify(mrb, a);
+ if (ARY_SHARED_P(a)) {
+ mrb_ary_decref(mrb, a->as.heap.aux.shared);
+ ARY_UNSET_SHARED_FLAG(a);
+ }
+ else if (!ARY_EMBED_P(a)){
+ mrb_free(mrb, a->as.heap.ptr);
+ }
+ ARY_SET_EMBED_LEN(a, 0);
+
+ return self;
+}
+
+static mrb_value
+mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+
+ return mrb_bool_value(ARY_LEN(a) == 0);
+}
+
+MRB_API mrb_value
+mrb_check_array_type(mrb_state *mrb, mrb_value ary)
+{
+ return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
+}
+
+MRB_API mrb_value
+mrb_ary_entry(mrb_value ary, mrb_int offset)
+{
+ if (offset < 0) {
+ offset += RARRAY_LEN(ary);
+ }
+ if (offset < 0 || RARRAY_LEN(ary) <= offset) {
+ return mrb_nil_value();
+ }
+ return RARRAY_PTR(ary)[offset];
+}
+
+static mrb_value
+join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
+{
+ mrb_int i;
+ mrb_value result, val, tmp;
+
+ /* check recursive */
+ for (i=0; i<RARRAY_LEN(list); i++) {
+ if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join");
+ }
+ }
+
+ mrb_ary_push(mrb, list, ary);
+
+ result = mrb_str_new_capa(mrb, 64);
+
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ if (i > 0 && !mrb_nil_p(sep)) {
+ mrb_str_cat_str(mrb, result, sep);
+ }
+
+ val = RARRAY_PTR(ary)[i];
+ switch (mrb_type(val)) {
+ case MRB_TT_ARRAY:
+ ary_join:
+ val = join_ary(mrb, val, sep, list);
+ /* fall through */
+
+ case MRB_TT_STRING:
+ str_join:
+ mrb_str_cat_str(mrb, result, val);
+ break;
+
+ default:
+ if (!mrb_immediate_p(val)) {
+ tmp = mrb_check_string_type(mrb, val);
+ if (!mrb_nil_p(tmp)) {
+ val = tmp;
+ goto str_join;
+ }
+ tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
+ if (!mrb_nil_p(tmp)) {
+ val = tmp;
+ goto ary_join;
+ }
+ }
+ val = mrb_obj_as_string(mrb, val);
+ goto str_join;
+ }
+ }
+
+ mrb_ary_pop(mrb, list);
+
+ return result;
+}
+
+MRB_API mrb_value
+mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
+{
+ if (!mrb_nil_p(sep)) {
+ sep = mrb_obj_as_string(mrb, sep);
+ }
+ return join_ary(mrb, ary, sep, mrb_ary_new(mrb));
+}
+
+/*
+ * call-seq:
+ * ary.join(sep="") -> str
+ *
+ * Returns a string created by converting each element of the array to
+ * a string, separated by <i>sep</i>.
+ *
+ * [ "a", "b", "c" ].join #=> "abc"
+ * [ "a", "b", "c" ].join("-") #=> "a-b-c"
+ */
+
+static mrb_value
+mrb_ary_join_m(mrb_state *mrb, mrb_value ary)
+{
+ mrb_value sep = mrb_nil_value();
+
+ mrb_get_args(mrb, "|S!", &sep);
+ return mrb_ary_join(mrb, ary, sep);
+}
+
+static mrb_value
+mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
+{
+ mrb_value ary2;
+
+ mrb_get_args(mrb, "o", &ary2);
+ if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
+ if (!mrb_array_p(ary2)) {
+ return mrb_false_value();
+ }
+ if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value();
+
+ return ary2;
+}
+
+static mrb_value
+mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
+{
+ mrb_value ary2;
+
+ mrb_get_args(mrb, "o", &ary2);
+ if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0);
+ if (!mrb_array_p(ary2)) {
+ return mrb_nil_value();
+ }
+
+ return ary2;
+}
+
+void
+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_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_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 */
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/backtrace.c b/web/server/h2o/libh2o/deps/mruby/src/backtrace.c
new file mode 100644
index 00000000..3e4e1a43
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/backtrace.c
@@ -0,0 +1,281 @@
+/*
+** backtrace.c -
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/variable.h>
+#include <mruby/proc.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+#include <mruby/debug.h>
+#include <mruby/error.h>
+#include <mruby/numeric.h>
+#include <mruby/data.h>
+
+struct backtrace_location {
+ int lineno;
+ const char *filename;
+ mrb_sym method_id;
+};
+
+typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*);
+
+static const mrb_data_type bt_type = { "Backtrace", mrb_free };
+
+static void
+each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
+{
+ ptrdiff_t i, j;
+
+ if (ciidx >= mrb->c->ciend - mrb->c->cibase)
+ ciidx = 10; /* ciidx is broken... */
+
+ for (i=ciidx, j=0; i >= 0; i--,j++) {
+ struct backtrace_location loc;
+ mrb_callinfo *ci;
+ mrb_irep *irep;
+ mrb_code *pc;
+
+ 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) {
+ pc = mrb->c->cibase[i+1].pc - 1;
+ }
+ else {
+ pc = pc0;
+ }
+ 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;
+
+ if (!loc.filename) {
+ loc.filename = "(unknown)";
+ }
+
+ loc.method_id = ci->mid;
+ func(mrb, &loc, data);
+ }
+}
+
+#ifndef MRB_DISABLE_STDIO
+
+static void
+print_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+ int i, n;
+ FILE *stream = stderr;
+
+ if (!mrb_array_p(backtrace)) return;
+
+ n = RARRAY_LEN(backtrace) - 1;
+ if (n == 0) return;
+
+ fprintf(stream, "trace:\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));
+ }
+ }
+}
+
+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:\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);
+ }
+ fprintf(stream, "\n");
+ }
+}
+
+/* mrb_print_backtrace
+
+ function to retrieve backtrace information from the last exception.
+*/
+
+MRB_API void
+mrb_print_backtrace(mrb_state *mrb)
+{
+ mrb_value backtrace;
+
+ if (!mrb->exc) {
+ return;
+ }
+
+ backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+ if (mrb_nil_p(backtrace)) return;
+ if (mrb_array_p(backtrace)) {
+ print_backtrace(mrb, backtrace);
+ }
+ else {
+ print_packed_backtrace(mrb, backtrace);
+ }
+}
+#else
+
+MRB_API void
+mrb_print_backtrace(mrb_state *mrb)
+{
+}
+
+#endif
+
+static void
+count_backtrace_i(mrb_state *mrb,
+ 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,
+ 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;
+}
+
+static mrb_value
+packed_backtrace(mrb_state *mrb)
+{
+ struct RData *backtrace;
+ ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase;
+ int len = 0;
+ int size;
+ void *ptr;
+
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len);
+ size = len * sizeof(struct backtrace_location);
+ ptr = mrb_malloc(mrb, size);
+ if (ptr) memset(ptr, 0, size);
+ backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type);
+ backtrace->flags = (unsigned int)len;
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr);
+ return mrb_obj_value(backtrace);
+}
+
+void
+mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
+{
+ mrb_value backtrace;
+ int ai = mrb_gc_arena_save(mrb);
+
+ backtrace = packed_backtrace(mrb);
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+ mrb_gc_arena_restore(mrb, ai);
+}
+
+mrb_value
+mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+ struct backtrace_location *bt;
+ mrb_int n, i;
+ int ai;
+
+ if (mrb_nil_p(backtrace)) {
+ empty_backtrace:
+ return mrb_ary_new_capa(mrb, 0);
+ }
+ if (mrb_array_p(backtrace)) return 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;
+ 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];
+ 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->method_id != 0) {
+ mrb_str_cat_lit(mrb, btline, ":in ");
+ mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id));
+ }
+ mrb_ary_push(mrb, backtrace, btline);
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return backtrace;
+}
+
+MRB_API 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);
+ if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) {
+ return backtrace;
+ }
+ backtrace = mrb_unpack_backtrace(mrb, backtrace);
+ mrb_iv_set(mrb, exc, attr_name, backtrace);
+ return backtrace;
+}
+
+MRB_API mrb_value
+mrb_get_backtrace(mrb_state *mrb)
+{
+ return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/class.c b/web/server/h2o/libh2o/deps/mruby/src/class.c
new file mode 100644
index 00000000..e3888001
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/class.c
@@ -0,0 +1,2474 @@
+/*
+** class.c - Class class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <stdarg.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/data.h>
+#include <mruby/istruct.h>
+
+KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
+
+void
+mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
+{
+ khiter_t k;
+ khash_t(mt) *h = c->mt;
+
+ if (!h) return;
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ struct RProc *m = kh_value(h, k);
+ if (m) {
+ mrb_gc_mark(mrb, (struct RBasic*)m);
+ }
+ }
+ }
+}
+
+size_t
+mrb_gc_mark_mt_size(mrb_state *mrb, struct RClass *c)
+{
+ khash_t(mt) *h = c->mt;
+
+ if (!h) return 0;
+ return kh_size(h);
+}
+
+void
+mrb_gc_free_mt(mrb_state *mrb, struct RClass *c)
+{
+ kh_destroy(mt, 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__");
+
+ if (mrb_obj_iv_defined(mrb, (struct RObject*)c, nsym)) return;
+ if (outer == NULL || outer == mrb->object_class) {
+ name = mrb_symbol_value(id);
+ }
+ else {
+ name = mrb_class_path(mrb, outer);
+ if (mrb_nil_p(name)) { /* unnamed outer class */
+ if (outer != mrb->object_class) {
+ mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
+ mrb_obj_value(outer));
+ }
+ return;
+ }
+ mrb_str_cat_cstr(mrb, name, "::");
+ mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id));
+ }
+ mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name);
+}
+
+static void
+setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
+{
+ mrb_class_name_class(mrb, outer, c, id);
+ mrb_obj_iv_set(mrb, (struct RObject*)outer, id, mrb_obj_value(c));
+}
+
+#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))
+
+static void
+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->flags |= MRB_FLAG_IS_INHERITED;
+ sc->mt = kh_init(mt, mrb);
+ sc->iv = 0;
+ if (o->tt == MRB_TT_CLASS) {
+ c = (struct RClass*)o;
+ if (!c->super) {
+ sc->super = mrb->class_class;
+ }
+ else {
+ sc->super = c->super->c;
+ }
+ }
+ else if (o->tt == MRB_TT_SCLASS) {
+ c = (struct RClass*)o;
+ while (c->super->tt == MRB_TT_ICLASS)
+ c = c->super;
+ make_metaclass(mrb, c->super);
+ sc->super = c->super->c;
+ }
+ else {
+ sc->super = o->c;
+ prepare_singleton_class(mrb, (struct RBasic*)sc);
+ }
+ 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));
+}
+
+static struct RClass*
+class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
+{
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
+
+ mrb_check_type(mrb, c, MRB_TT_CLASS);
+ return mrb_class_ptr(c);
+}
+
+static struct RClass*
+module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
+{
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
+
+ mrb_check_type(mrb, c, MRB_TT_MODULE);
+ return mrb_class_ptr(c);
+}
+
+static mrb_bool
+class_ptr_p(mrb_value obj)
+{
+ switch (mrb_type(obj)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+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));
+ }
+}
+
+static struct RClass*
+define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer)
+{
+ struct RClass *m;
+
+ if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
+ return module_from_sym(mrb, outer, name);
+ }
+ m = mrb_module_new(mrb);
+ setup_class(mrb, outer, m, name);
+
+ return m;
+}
+
+MRB_API struct RClass*
+mrb_define_module_id(mrb_state *mrb, mrb_sym name)
+{
+ return define_module(mrb, name, mrb->object_class);
+}
+
+MRB_API struct RClass*
+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*
+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));
+ }
+ return mrb_class_ptr(old);
+ }
+ return define_module(mrb, id, mrb_class_ptr(outer));
+}
+
+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);
+ struct RClass * c = define_module(mrb, id, outer);
+
+ setup_class(mrb, outer, c, id);
+ return c;
+}
+
+static struct RClass*
+find_origin(struct RClass *c)
+{
+ MRB_CLASS_ORIGIN(c);
+ return c;
+}
+
+static struct RClass*
+define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer)
+{
+ struct RClass * c;
+
+ if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
+ 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));
+ }
+ return c;
+ }
+
+ c = mrb_class_new(mrb, super);
+ setup_class(mrb, outer, c, name);
+
+ return c;
+}
+
+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));
+ }
+ return define_class(mrb, name, super, mrb->object_class);
+}
+
+MRB_API struct RClass*
+mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
+{
+ return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
+}
+
+static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value);
+#ifdef MRB_METHOD_CACHE
+static void mc_clear_all(mrb_state *mrb);
+static void mc_clear_by_class(mrb_state *mrb, struct RClass*);
+static void mc_clear_by_id(mrb_state *mrb, struct RClass*, mrb_sym);
+#else
+#define mc_clear_all(mrb)
+#define mc_clear_by_class(mrb,c)
+#define mc_clear_by_id(mrb,c,s)
+#endif
+
+static void
+mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
+{
+ mrb_value s;
+ mrb_sym mid;
+
+ if (!super)
+ super = mrb->object_class;
+ super->flags |= MRB_FLAG_IS_INHERITED;
+ s = mrb_obj_value(super);
+ mc_clear_by_class(mrb, klass);
+ mid = mrb_intern_lit(mrb, "inherited");
+ if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
+ mrb_value c = mrb_obj_value(klass);
+ mrb_funcall_argv(mrb, s, mid, 1, &c);
+ }
+}
+
+MRB_API 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));
+ }
+ s = mrb_class_ptr(super);
+ }
+ else {
+ s = 0;
+ }
+ 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_CLASS) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, 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);
+ }
+ }
+ return c;
+ }
+ c = define_class(mrb, id, s, mrb_class_ptr(outer));
+ mrb_class_inherited(mrb, mrb_class_real(c->super), c);
+
+ return c;
+}
+
+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_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_API struct RClass*
+mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
+{
+ return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, 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)
+{
+ struct RClass *exc, *e;
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class),
+ mrb_intern_cstr(mrb, name));
+
+ if (mrb_type(c) != MRB_TT_CLASS) {
+ mrb_raise(mrb, mrb->eException_class, "exception corrupted");
+ }
+ exc = e = mrb_class_ptr(c);
+
+ while (e) {
+ if (e == mrb->eException_class)
+ return exc;
+ e = e->super;
+ }
+ return mrb->eException_class;
+}
+
+MRB_API struct RClass*
+mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
+{
+ return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
+}
+
+MRB_API struct RClass*
+mrb_module_get(mrb_state *mrb, const char *name)
+{
+ return mrb_module_get_under(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 super a class from which the new class will derive.
+ * NULL means \c Object class.
+ * \return the created class
+ * \throw TypeError if the constant name \a name is already taken but
+ * the constant is not a \c Class.
+ * \throw NameError if the class is already defined but the class can not
+ * be reopened because its superclass is not \a super.
+ * \post top-level constant named \a name refers the returned class.
+ *
+ * \note if a class named \a name is already defined and its superclass is
+ * \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_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));
+ }
+#endif
+ c = define_class(mrb, id, super, outer);
+ setup_class(mrb, outer, c, id);
+ return c;
+}
+
+MRB_API void
+mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p)
+{
+ khash_t(mt) *h;
+ khiter_t k;
+ MRB_CLASS_ORIGIN(c);
+ h = c->mt;
+
+ if (MRB_FROZEN_P(c)) {
+ if (c->tt == MRB_TT_MODULE)
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module");
+ else
+ mrb_raise(mrb, E_RUNTIME_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) = p;
+ if (p) {
+ p->c = NULL;
+ mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
+ }
+ mc_clear_by_id(mrb, c, mid);
+}
+
+MRB_API void
+mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec)
+{
+ struct RProc *p;
+ int ai = mrb_gc_arena_save(mrb);
+
+ p = mrb_proc_new_cfunc(mrb, func);
+ p->target_class = c;
+ mrb_define_method_raw(mrb, c, mid, p);
+ mrb_gc_arena_restore(mrb, ai);
+}
+
+MRB_API void
+mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
+{
+ mrb_define_method_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec);
+}
+
+/* a function to raise NotImplementedError with current method name */
+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));
+ }
+}
+
+/* a function to be replacement of unimplemented method */
+MRB_API mrb_value
+mrb_notimplement_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_notimplement(mrb);
+ /* not reached */
+ return mrb_nil_value();
+}
+
+static mrb_value
+check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m)
+{
+ mrb_value tmp;
+
+ tmp = mrb_check_convert_type(mrb, val, t, c, m);
+ if (mrb_nil_p(tmp)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c));
+ }
+ return tmp;
+}
+
+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");
+}
+
+static mrb_value
+to_hash(mrb_state *mrb, mrb_value val)
+{
+ return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash");
+}
+
+static mrb_sym
+to_sym(mrb_state *mrb, mrb_value ss)
+{
+ if (mrb_type(ss) == MRB_TT_SYMBOL) {
+ return mrb_symbol(ss);
+ }
+ else if (mrb_string_p(ss)) {
+ return mrb_intern_str(mrb, to_str(mrb, ss));
+ }
+ else {
+ mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
+ /* not reached */
+ return 0;
+ }
+}
+
+/*
+ retrieve arguments from mrb_state.
+
+ mrb_get_args(mrb, format, ...)
+
+ returns number of arguments parsed.
+
+ format specifiers:
+
+ string mruby type C type note
+ ----------------------------------------------------------------------------------------------
+ o: Object [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]
+ *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
+ |: optional Following arguments are optional
+ ?: optional given [mrb_bool] true if preceding argument (optional) is given
+ */
+MRB_API mrb_int
+mrb_get_args(mrb_state *mrb, const char *format, ...)
+{
+ const char *fmt = format;
+ char c;
+ int i = 0;
+ va_list ap;
+ int argc = mrb->c->ci->argc;
+ int arg_i = 0;
+ mrb_value *array_argv;
+ mrb_bool opt = FALSE;
+ mrb_bool opt_skip = TRUE;
+ mrb_bool given = TRUE;
+
+ va_start(ap, format);
+ if (argc < 0) {
+ struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
+
+ argc = ARY_LEN(a);
+ array_argv = ARY_PTR(a);
+ }
+ else {
+ array_argv = NULL;
+ }
+
+#define ARGV \
+ (array_argv ? array_argv : (mrb->c->stack + 1))
+
+ while ((c = *fmt++)) {
+ switch (c) {
+ case '|':
+ opt = TRUE;
+ break;
+ case '*':
+ opt_skip = FALSE;
+ goto check_exit;
+ case '!':
+ break;
+ case '&': case '?':
+ if (opt) opt_skip = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ check_exit:
+ opt = FALSE;
+ i = 0;
+ while ((c = *format++)) {
+ switch (c) {
+ case '|': case '*': case '&': case '?':
+ break;
+ default:
+ if (argc <= i) {
+ if (opt) {
+ given = FALSE;
+ }
+ else {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ }
+ }
+ break;
+ }
+
+ switch (c) {
+ case 'o':
+ {
+ mrb_value *p;
+
+ p = va_arg(ap, mrb_value*);
+ if (i < argc) {
+ *p = ARGV[arg_i++];
+ i++;
+ }
+ }
+ break;
+ case 'C':
+ {
+ mrb_value *p;
+
+ p = va_arg(ap, mrb_value*);
+ if (i < argc) {
+ mrb_value ss;
+
+ ss = ARGV[arg_i++];
+ if (!class_ptr_p(ss)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+ }
+ *p = ss;
+ i++;
+ }
+ }
+ break;
+ case 'S':
+ {
+ 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++;
+ }
+ }
+ break;
+ case 'A':
+ {
+ 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++;
+ }
+ }
+ break;
+ case 'H':
+ {
+ 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++;
+ }
+ }
+ break;
+ case 's':
+ {
+ mrb_value ss;
+ char **ps = 0;
+ mrb_int *pl = 0;
+
+ ps = va_arg(ap, char**);
+ pl = va_arg(ap, mrb_int*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *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++;
+ }
+ }
+ break;
+ case 'z':
+ {
+ mrb_value ss;
+ const char **ps;
+
+ ps = va_arg(ap, const char**);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *ps = NULL;
+ i++; arg_i++;
+ break;
+ }
+ }
+ if (i < argc) {
+ ss = to_str(mrb, ARGV[arg_i++]);
+ *ps = mrb_string_value_cstr(mrb, &ss);
+ i++;
+ }
+ }
+ break;
+ case 'a':
+ {
+ mrb_value aa;
+ struct RArray *a;
+ mrb_value **pb;
+ mrb_int *pl;
+
+ pb = va_arg(ap, mrb_value**);
+ pl = va_arg(ap, mrb_int*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *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++;
+ }
+ }
+ break;
+ case 'I':
+ {
+ void* *p;
+ mrb_value ss;
+
+ p = va_arg(ap, void**);
+ if (i < argc) {
+ ss = ARGV[arg_i];
+ if (mrb_type(ss) != MRB_TT_ISTRUCT)
+ {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+ }
+ *p = mrb_istruct_ptr(ss);
+ arg_i++;
+ i++;
+ }
+ }
+ break;
+ 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++;
+ }
+ }
+ break;
+ case 'i':
+ {
+ mrb_int *p;
+
+ 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;
+ 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;
+ 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++;
+ }
+ }
+ break;
+ case 'b':
+ {
+ mrb_bool *boolp = va_arg(ap, mrb_bool*);
+
+ if (i < argc) {
+ mrb_value b = ARGV[arg_i++];
+ *boolp = mrb_test(b);
+ i++;
+ }
+ }
+ break;
+ case 'n':
+ {
+ mrb_sym *symp;
+
+ symp = va_arg(ap, mrb_sym*);
+ if (i < argc) {
+ mrb_value ss;
+
+ ss = ARGV[arg_i++];
+ *symp = to_sym(mrb, ss);
+ i++;
+ }
+ }
+ break;
+ case 'd':
+ {
+ void** datap;
+ struct mrb_data_type const* type;
+
+ 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])) {
+ *datap = 0;
+ i++; arg_i++;
+ break;
+ }
+ }
+ if (i < argc) {
+ *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type);
+ ++i;
+ }
+ }
+ break;
+
+ case '&':
+ {
+ mrb_value *p, *bp;
+
+ p = va_arg(ap, mrb_value*);
+ if (mrb->c->ci->argc < 0) {
+ bp = mrb->c->stack + 2;
+ }
+ else {
+ bp = mrb->c->stack + mrb->c->ci->argc + 1;
+ }
+ *p = *bp;
+ }
+ break;
+ case '|':
+ if (opt_skip && i == argc) return argc;
+ opt = TRUE;
+ break;
+ case '?':
+ {
+ mrb_bool *p;
+
+ p = va_arg(ap, mrb_bool*);
+ *p = given;
+ }
+ break;
+
+ case '*':
+ {
+ mrb_value **var;
+ mrb_int *pl;
+ mrb_bool nocopy = array_argv ? TRUE : FALSE;
+
+ if (*format == '!') {
+ format++;
+ nocopy = TRUE;
+ }
+ var = va_arg(ap, mrb_value**);
+ pl = va_arg(ap, mrb_int*);
+ if (argc > i) {
+ *pl = argc-i;
+ if (*pl > 0) {
+ if (nocopy) {
+ *var = ARGV+arg_i;
+ }
+ else {
+ mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i);
+ RARRAY(args)->c = NULL;
+ *var = RARRAY_PTR(args);
+ }
+ }
+ i = argc;
+ arg_i += *pl;
+ }
+ else {
+ *pl = 0;
+ *var = NULL;
+ }
+ }
+ break;
+ default:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1));
+ break;
+ }
+ }
+
+#undef ARGV
+
+ if (!c && argc > i) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ }
+ va_end(ap);
+ return i;
+}
+
+static struct RClass*
+boot_defclass(mrb_state *mrb, struct RClass *super)
+{
+ struct RClass *c;
+
+ c = (struct RClass*)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);
+ }
+ else {
+ c->super = mrb->object_class;
+ }
+ c->mt = kh_init(mt, mrb);
+ return c;
+}
+
+static void
+boot_initmod(mrb_state *mrb, struct RClass *mod)
+{
+ if (!mod->mt) {
+ mod->mt = kh_init(mt, 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);
+ if (m->tt == MRB_TT_ICLASS) {
+ m = m->c;
+ }
+ MRB_CLASS_ORIGIN(m);
+ ic->iv = m->iv;
+ ic->mt = m->mt;
+ ic->super = super;
+ if (m->tt == MRB_TT_ICLASS) {
+ ic->c = m->c;
+ }
+ else {
+ ic->c = m;
+ }
+ return ic;
+}
+
+static int
+include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super)
+{
+ struct RClass *p, *ic;
+ void *klass_mt = find_origin(c)->mt;
+
+ while (m) {
+ int superclass_seen = 0;
+
+ if (m->flags & MRB_FLAG_IS_PREPENDED)
+ goto skip;
+
+ if (klass_mt && klass_mt == m->mt)
+ return -1;
+
+ p = c->super;
+ while (p) {
+ if (p->tt == MRB_TT_ICLASS) {
+ if (p->mt == m->mt) {
+ if (!superclass_seen) {
+ ins_pos = p; /* move insert point */
+ }
+ goto skip;
+ }
+ } else if (p->tt == MRB_TT_CLASS) {
+ if (!search_super) break;
+ superclass_seen = 1;
+ }
+ p = p->super;
+ }
+
+ ic = include_class_new(mrb, m, ins_pos->super);
+ m->flags |= MRB_FLAG_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);
+ return 0;
+}
+
+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_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
+ }
+}
+
+MRB_API void
+mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+{
+ struct RClass *origin;
+ int changed = 0;
+
+ if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
+ origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
+ origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED;
+ origin->super = c->super;
+ c->super = origin;
+ origin->mt = c->mt;
+ c->mt = kh_init(mt, mrb);
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin);
+ c->flags |= MRB_FLAG_IS_PREPENDED;
+ }
+ changed = include_module_at(mrb, c, c, m, 0);
+ if (changed < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected");
+ }
+}
+
+static mrb_value
+mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value klass;
+
+ 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));
+ return mod;
+}
+
+static mrb_value
+mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value klass;
+
+ 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));
+ return mod;
+}
+
+/* 15.2.2.4.28 */
+/*
+ * call-seq:
+ * mod.include?(module) -> true or false
+ *
+ * Returns <code>true</code> if <i>module</i> is included in
+ * <i>mod</i> or one of <i>mod</i>'s ancestors.
+ *
+ * module A
+ * end
+ * class B
+ * include A
+ * end
+ * class C < B
+ * end
+ * B.include?(A) #=> true
+ * C.include?(A) #=> true
+ * A.include?(A) #=> false
+ */
+static mrb_value
+mrb_mod_include_p(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value mod2;
+ struct RClass *c = mrb_class_ptr(mod);
+
+ mrb_get_args(mrb, "C", &mod2);
+ mrb_check_type(mrb, mod2, MRB_TT_MODULE);
+
+ while (c) {
+ if (c->tt == MRB_TT_ICLASS) {
+ if (c->c == mrb_class_ptr(mod2)) return mrb_true_value();
+ }
+ c = c->super;
+ }
+ return mrb_false_value();
+}
+
+static mrb_value
+mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ struct RClass *c = mrb_class_ptr(self);
+ result = mrb_ary_new(mrb);
+ while (c) {
+ if (c->tt == MRB_TT_ICLASS) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ }
+ else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c));
+ }
+ c = c->super;
+ }
+
+ return result;
+}
+
+static mrb_value
+mrb_mod_extend_object(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value obj;
+
+ 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;
+}
+
+static mrb_value
+mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ struct RClass *c = mrb_class_ptr(self);
+ struct RClass *origin = c;
+
+ MRB_CLASS_ORIGIN(origin);
+ result = mrb_ary_new(mrb);
+ while (c) {
+ if (c != origin && c->tt == MRB_TT_ICLASS) {
+ if (c->c->tt == MRB_TT_MODULE) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ }
+ }
+ c = c->super;
+ }
+
+ return result;
+}
+
+static mrb_value
+mrb_mod_initialize(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value b;
+ struct RClass *m = mrb_class_ptr(mod);
+ boot_initmod(mrb, m); /* bootstrap a newly initialized module */
+ mrb_get_args(mrb, "|&", &b);
+ if (!mrb_nil_p(b)) {
+ mrb_yield_with_class(mrb, b, 1, &mod, mod, m);
+ }
+ return mod;
+}
+
+mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
+
+/* 15.2.2.4.33 */
+/*
+ * call-seq:
+ * mod.instance_methods(include_super=true) -> array
+ *
+ * Returns an array containing the names of the public and protected instance
+ * methods in the receiver. For a module, these are the public and protected methods;
+ * for a class, they are the instance (not singleton) methods. With no
+ * argument, or with an argument that is <code>false</code>, the
+ * instance methods in <i>mod</i> are returned, otherwise the methods
+ * in <i>mod</i> and <i>mod</i>'s superclasses are returned.
+ *
+ * module A
+ * def method1() end
+ * end
+ * class B
+ * def method2() end
+ * end
+ * class C < B
+ * def method3() end
+ * end
+ *
+ * A.instance_methods #=> [:method1]
+ * B.instance_methods(false) #=> [:method2]
+ * C.instance_methods(false) #=> [:method3]
+ * C.instance_methods(true).length #=> 43
+ */
+
+static mrb_value
+mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_class_instance_method_list(mrb, recur, c, 0);
+}
+
+/* implementation of module_eval/class_eval */
+mrb_value mrb_mod_module_eval(mrb_state*, mrb_value);
+
+static mrb_value
+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)
+{
+ 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);
+ case MRB_TT_TRUE:
+ return mrb_obj_value(mrb->true_class);
+ case MRB_TT_CPTR:
+ return mrb_obj_value(mrb->object_class);
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_FLOAT:
+ mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
+ return mrb_nil_value(); /* not reached */
+ default:
+ break;
+ }
+ obj = mrb_basic_ptr(v);
+ prepare_singleton_class(mrb, obj);
+ return mrb_obj_value(obj->c);
+}
+
+MRB_API void
+mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, mrb_aspec aspec)
+{
+ prepare_singleton_class(mrb, (struct RBasic*)o);
+ mrb_define_method_id(mrb, o->c, mrb_intern_cstr(mrb, 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(mrb, c, name, func, aspec);
+ mrb_define_method(mrb, c, name, func, aspec);
+}
+
+#ifdef MRB_METHOD_CACHE
+static void
+mc_clear_all(mrb_state *mrb)
+{
+ struct mrb_cache_entry *mc = mrb->cache;
+ int i;
+
+ for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+ mc[i].c = 0;
+ }
+}
+
+static void
+mc_clear_by_class(mrb_state *mrb, struct RClass *c)
+{
+ struct mrb_cache_entry *mc = mrb->cache;
+ int i;
+
+ if (c->flags & MRB_FLAG_IS_INHERITED) {
+ mc_clear_all(mrb);
+ c->flags &= ~MRB_FLAG_IS_INHERITED;
+ return;
+ }
+ for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+ if (mc[i].c == c) mc[i].c = 0;
+ }
+}
+
+static void
+mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+{
+ struct mrb_cache_entry *mc = mrb->cache;
+ int i;
+
+ if (c->flags & MRB_FLAG_IS_INHERITED) {
+ mc_clear_all(mrb);
+ c->flags &= ~MRB_FLAG_IS_INHERITED;
+ return;
+ }
+ for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+ if (mc[i].c == c || mc[i].mid == mid)
+ mc[i].c = 0;
+ }
+}
+#endif
+
+MRB_API struct RProc*
+mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
+{
+ khiter_t k;
+ struct RProc *m;
+ struct RClass *c = *cp;
+#ifdef MRB_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];
+
+ if (mc->c == c && mc->mid == mid) {
+ return mc->m;
+ }
+#endif
+
+ while (c) {
+ khash_t(mt) *h = c->mt;
+
+ if (h) {
+ k = kh_get(mt, mrb, h, mid);
+ if (k != kh_end(h)) {
+ m = kh_value(h, k);
+ if (!m) break;
+ *cp = c;
+#ifdef MRB_METHOD_CACHE
+ mc->c = oc;
+ mc->mid = mid;
+ mc->m = m;
+#endif
+ return m;
+ }
+ }
+ c = c->super;
+ }
+ return NULL; /* no method */
+}
+
+MRB_API struct RProc*
+mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
+{
+ struct RProc *m;
+
+ m = mrb_method_search_vm(mrb, &c, mid);
+ if (!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);
+ }
+ return m;
+}
+
+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)
+{
+ 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;
+ mrb_sym method, sym;
+
+ 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_check(mrb, sym);
+ name = mrb_symbol_value(sym);
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return mrb_nil_value();
+}
+
+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_get_args(mrb, "o", &val);
+ mrb_iv_set(mrb, obj, to_sym(mrb, name), val);
+ return val;
+}
+
+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;
+
+ 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_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);
+
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
+{
+ struct RClass *c = mrb_class_ptr(cv);
+ struct RObject *o;
+ enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
+
+ if (c->tt == MRB_TT_SCLASS)
+ mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
+
+ 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);
+ }
+ o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
+ return mrb_obj_value(o);
+}
+
+/*
+ * call-seq:
+ * class.new(args, ...) -> obj
+ *
+ * Creates a new object of <i>class</i>'s class, then
+ * invokes that object's <code>initialize</code> method,
+ * passing it <i>args</i>. This is the method that ends
+ * up getting called whenever an object is constructed using
+ * `.new`.
+ *
+ */
+
+MRB_API mrb_value
+mrb_instance_new(mrb_state *mrb, mrb_value cv)
+{
+ mrb_value obj, blk;
+ mrb_value *argv;
+ mrb_int argc;
+ mrb_sym init;
+
+ mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+ obj = mrb_instance_alloc(mrb, cv);
+ init = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
+ mrb_funcall_with_block(mrb, obj, init, argc, argv, blk);
+ }
+
+ return obj;
+}
+
+MRB_API mrb_value
+mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
+{
+ mrb_value obj;
+ mrb_sym mid;
+
+ obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
+ mid = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) {
+ mrb_funcall_argv(mrb, obj, mid, argc, argv);
+ }
+ return obj;
+}
+
+static mrb_value
+mrb_class_initialize(mrb_state *mrb, mrb_value c)
+{
+ mrb_value a, b;
+
+ mrb_get_args(mrb, "|C&", &a, &b);
+ if (!mrb_nil_p(b)) {
+ mrb_yield_with_class(mrb, b, 1, &c, c, mrb_class_ptr(c));
+ }
+ return c;
+}
+
+static mrb_value
+mrb_class_new_class(mrb_state *mrb, mrb_value cv)
+{
+ mrb_int n;
+ mrb_value super, blk;
+ mrb_value new_class;
+ mrb_sym mid;
+
+ n = mrb_get_args(mrb, "|C&", &super, &blk);
+ if (n == 0) {
+ 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)) {
+ mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
+ }
+ mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
+ return new_class;
+}
+
+static mrb_value
+mrb_class_superclass(mrb_state *mrb, mrb_value klass)
+{
+ struct RClass *c;
+
+ c = mrb_class_ptr(klass);
+ c = find_origin(c)->super;
+ while (c && c->tt == MRB_TT_ICLASS) {
+ c = find_origin(c)->super;
+ }
+ if (!c) return mrb_nil_value();
+ return mrb_obj_value(c);
+}
+
+static mrb_value
+mrb_bob_init(mrb_state *mrb, mrb_value cv)
+{
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_bob_not(mrb_state *mrb, mrb_value cv)
+{
+ return mrb_bool_value(!mrb_test(cv));
+}
+
+/* 15.3.1.3.1 */
+/* 15.3.1.3.10 */
+/* 15.3.1.3.11 */
+/*
+ * call-seq:
+ * obj == other -> true or false
+ * obj.equal?(other) -> true or false
+ * obj.eql?(other) -> true or false
+ *
+ * Equality---At the <code>Object</code> level, <code>==</code> returns
+ * <code>true</code> only if <i>obj</i> and <i>other</i> are the
+ * same object. Typically, this method is overridden in descendant
+ * classes to provide class-specific meaning.
+ *
+ * Unlike <code>==</code>, the <code>equal?</code> method should never be
+ * overridden by subclasses: it is used to determine object identity
+ * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
+ * object as <code>b</code>).
+ *
+ * The <code>eql?</code> method returns <code>true</code> if
+ * <i>obj</i> and <i>anObject</i> have the same value. Used by
+ * <code>Hash</code> to test members for equality. For objects of
+ * class <code>Object</code>, <code>eql?</code> is synonymous with
+ * <code>==</code>. Subclasses normally continue this tradition, but
+ * there are exceptions. <code>Numeric</code> types, for example,
+ * perform type conversion across <code>==</code>, but not across
+ * <code>eql?</code>, so:
+ *
+ * 1 == 1.0 #=> true
+ * 1.eql? 1.0 #=> false
+ */
+mrb_value
+mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value arg;
+
+ 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)
+{
+ struct RProc *m;
+
+ m = mrb_method_search_vm(mrb, &c, mid);
+ if (!m) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+MRB_API mrb_bool
+mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid)
+{
+ return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid);
+}
+
+MRB_API mrb_value
+mrb_class_path(mrb_state *mrb, struct RClass *c)
+{
+ mrb_value path;
+ mrb_sym nsym = mrb_intern_lit(mrb, "__classname__");
+
+ path = mrb_obj_iv_get(mrb, (struct RObject*)c, nsym);
+ if (mrb_nil_p(path)) {
+ /* no name (yet) */
+ return mrb_class_find_path(mrb, c);
+ }
+ else if (mrb_symbol_p(path)) {
+ /* topleve 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_str_dup(mrb, path);
+}
+
+MRB_API struct RClass*
+mrb_class_real(struct RClass* cl)
+{
+ if (cl == 0)
+ return NULL;
+ while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) {
+ cl = cl->super;
+ }
+ return cl;
+}
+
+MRB_API const char*
+mrb_class_name(mrb_state *mrb, struct RClass* c)
+{
+ mrb_value path = mrb_class_path(mrb, c);
+ if (mrb_nil_p(path)) {
+ path = mrb_str_new_lit(mrb, "#<Class:");
+ mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
+ mrb_str_cat_lit(mrb, path, ">");
+ }
+ return RSTRING_PTR(path);
+}
+
+MRB_API const char*
+mrb_obj_classname(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_class_name(mrb, mrb_obj_class(mrb, obj));
+}
+
+/*!
+ * Ensures a class can be derived from super.
+ *
+ * \param super a reference to an object.
+ * \exception TypeError if \a super is not a Class or \a super is a singleton class.
+ */
+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));
+ }
+ if (super->tt == MRB_TT_SCLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class");
+ }
+ if (super == mrb->class_class) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of Class");
+ }
+}
+
+/*!
+ * Creates a new class.
+ * \param super a class from which the new class derives.
+ * \exception TypeError \a super is not inheritable.
+ * \exception TypeError \a super is the Class class.
+ */
+MRB_API struct RClass*
+mrb_class_new(mrb_state *mrb, struct RClass *super)
+{
+ struct RClass *c;
+
+ if (super) {
+ mrb_check_inheritable(mrb, super);
+ }
+ c = boot_defclass(mrb, super);
+ if (super) {
+ MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super));
+ }
+ make_metaclass(mrb, c);
+
+ return c;
+}
+
+/*!
+ * Creates a new module.
+ */
+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);
+ boot_initmod(mrb, m);
+ return m;
+}
+
+/*
+ * call-seq:
+ * obj.class => class
+ *
+ * Returns the class of <i>obj</i>, now preferred over
+ * <code>Object#type</code>, as an object's type in Ruby is only
+ * loosely tied to that object's class. This method must always be
+ * called with an explicit receiver, as <code>class</code> is also a
+ * reserved word in Ruby.
+ *
+ * 1.class #=> Fixnum
+ * self.class #=> Object
+ */
+
+MRB_API struct RClass*
+mrb_obj_class(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_class_real(mrb_class(mrb, obj));
+}
+
+MRB_API void
+mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
+{
+ struct RProc *m = mrb_method_search(mrb, c, b);
+
+ mrb_define_method_raw(mrb, c, a, m);
+}
+
+/*!
+ * Defines an alias of a method.
+ * \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
+ */
+MRB_API void
+mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2)
+{
+ mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2));
+}
+
+/*
+ * call-seq:
+ * mod.to_s -> string
+ *
+ * Return a string representing this module or class. For basic
+ * classes and modules, this is the name. For singletons, we
+ * show information on the thing we're attached to as well.
+ */
+
+static 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 (class_ptr_p(v)) {
+ mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
+ }
+ else {
+ mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v));
+ }
+ 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;
+ }
+ }
+}
+
+static mrb_value
+mrb_mod_alias(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_sym new_name, old_name;
+
+ mrb_get_args(mrb, "nn", &new_name, &old_name);
+ mrb_alias_method(mrb, c, new_name, old_name);
+ return mrb_nil_value();
+}
+
+static void
+undef_method(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_define_method_raw(mrb, c, a, NULL);
+ }
+}
+
+MRB_API void
+mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
+{
+ undef_method(mrb, c, mrb_intern_cstr(mrb, name));
+}
+
+MRB_API void
+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);
+}
+
+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;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ while (argc--) {
+ undef_method(mrb, c, to_sym(mrb, *argv));
+ argv++;
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
+mod_define_method(mrb_state *mrb, mrb_value self)
+{
+ struct RClass *c = mrb_class_ptr(self);
+ struct RProc *p;
+ mrb_sym mid;
+ mrb_value proc = mrb_undef_value();
+ mrb_value blk;
+
+ mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
+ switch (mrb_type(proc)) {
+ case MRB_TT_PROC:
+ blk = proc;
+ break;
+ case MRB_TT_UNDEF:
+ /* ignored */
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
+ break;
+ }
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ mrb_proc_copy(p, mrb_proc_ptr(blk));
+ p->flags |= MRB_PROC_STRICT;
+ mrb_define_method_raw(mrb, c, mid, p);
+ return mrb_symbol_value(mid);
+}
+
+static void
+check_cv_name_str(mrb_state *mrb, mrb_value str)
+{
+ const char *s = RSTRING_PTR(str);
+ mrb_int len = RSTRING_LEN(str);
+
+ if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
+ mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str);
+ }
+}
+
+static void
+check_cv_name_sym(mrb_state *mrb, mrb_sym id)
+{
+ check_cv_name_str(mrb, mrb_sym2str(mrb, id));
+}
+
+/* 15.2.2.4.16 */
+/*
+ * call-seq:
+ * obj.class_variable_defined?(symbol) -> true or false
+ *
+ * Returns <code>true</code> if the given class variable is defined
+ * in <i>obj</i>.
+ *
+ * class Fred
+ * @@foo = 99
+ * end
+ * Fred.class_variable_defined?(:@@foo) #=> true
+ * Fred.class_variable_defined?(:@@bar) #=> false
+ */
+
+static mrb_value
+mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+
+ mrb_get_args(mrb, "n", &id);
+ check_cv_name_sym(mrb, id);
+ return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
+}
+
+/* 15.2.2.4.17 */
+/*
+ * call-seq:
+ * mod.class_variable_get(symbol) -> obj
+ *
+ * Returns the value of the given class variable (or throws a
+ * <code>NameError</code> exception). The <code>@@</code> part of the
+ * variable name should be included for regular class variables
+ *
+ * class Fred
+ * @@foo = 99
+ * end
+ * Fred.class_variable_get(:@@foo) #=> 99
+ */
+
+static mrb_value
+mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+
+ mrb_get_args(mrb, "n", &id);
+ check_cv_name_sym(mrb, id);
+ return mrb_cv_get(mrb, mod, id);
+}
+
+/* 15.2.2.4.18 */
+/*
+ * call-seq:
+ * obj.class_variable_set(symbol, obj) -> obj
+ *
+ * Sets the class variable names by <i>symbol</i> to
+ * <i>object</i>.
+ *
+ * class Fred
+ * @@foo = 99
+ * def foo
+ * @@foo
+ * end
+ * end
+ * Fred.class_variable_set(:@@foo, 101) #=> 101
+ * Fred.new.foo #=> 101
+ */
+
+static mrb_value
+mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value value;
+ mrb_sym id;
+
+ mrb_get_args(mrb, "no", &id, &value);
+ check_cv_name_sym(mrb, id);
+ mrb_cv_set(mrb, mod, id, value);
+ return value;
+}
+
+/* 15.2.2.4.39 */
+/*
+ * call-seq:
+ * remove_class_variable(sym) -> obj
+ *
+ * Removes the definition of the <i>sym</i>, returning that
+ * constant's value.
+ *
+ * class Dummy
+ * @@var = 99
+ * puts @@var
+ * p class_variables
+ * remove_class_variable(:@@var)
+ * p class_variables
+ * end
+ *
+ * <em>produces:</em>
+ *
+ * 99
+ * [:@@var]
+ * []
+ */
+
+static mrb_value
+mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value val;
+ mrb_sym id;
+
+ mrb_get_args(mrb, "n", &id);
+ check_cv_name_sym(mrb, id);
+
+ val = mrb_iv_remove(mrb, mod, id);
+ if (!mrb_undef_p(val)) return val;
+
+ if (mrb_cv_defined(mrb, mod, id)) {
+ mrb_name_error(mrb, id, "cannot remove %S for %S",
+ mrb_sym2str(mrb, id), mod);
+ }
+
+ mrb_name_error(mrb, id, "class variable %S not defined for %S",
+ mrb_sym2str(mrb, id), mod);
+
+ /* not reached */
+ return mrb_nil_value();
+}
+
+/* 15.2.2.4.34 */
+/*
+ * call-seq:
+ * mod.method_defined?(symbol) -> true or false
+ *
+ * Returns +true+ if the named method is defined by
+ * _mod_ (or its included modules and, if _mod_ is a class,
+ * its ancestors). Public and protected methods are matched.
+ *
+ * module A
+ * def method1() end
+ * end
+ * class B
+ * def method2() end
+ * end
+ * class C < B
+ * include A
+ * def method3() end
+ * end
+ *
+ * A.method_defined? :method1 #=> true
+ * C.method_defined? "method1" #=> true
+ * C.method_defined? "method2" #=> true
+ * C.method_defined? "method3" #=> true
+ * C.method_defined? "method4" #=> false
+ */
+
+static mrb_value
+mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+
+ mrb_get_args(mrb, "n", &id);
+ return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id));
+}
+
+static void
+remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ khash_t(mt) *h = find_origin(c)->mt;
+ khiter_t k;
+
+ if (h) {
+ k = kh_get(mt, mrb, h, mid);
+ if (k != kh_end(h)) {
+ kh_del(mt, mrb, h, k);
+ mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid));
+ return;
+ }
+ }
+
+ mrb_name_error(mrb, mid, "method '%S' not defined in %S",
+ mrb_sym2str(mrb, mid), mod);
+}
+
+/* 15.2.2.4.41 */
+/*
+ * call-seq:
+ * remove_method(symbol) -> self
+ *
+ * Removes the method identified by _symbol_ from the current
+ * class. For an example, see <code>Module.undef_method</code>.
+ */
+
+static mrb_value
+mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
+{
+ mrb_int argc;
+ mrb_value *argv;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ while (argc--) {
+ remove_method(mrb, mod, to_sym(mrb, *argv));
+ argv++;
+ }
+ return mod;
+}
+
+
+
+static void
+check_const_name_str(mrb_state *mrb, mrb_value str)
+{
+ if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) {
+ mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str);
+ }
+}
+
+static void
+check_const_name_sym(mrb_state *mrb, mrb_sym id)
+{
+ check_const_name_str(mrb, mrb_sym2str(mrb, id));
+}
+
+static mrb_value
+const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit)
+{
+ if (inherit) {
+ return mrb_bool_value(mrb_const_defined(mrb, mod, id));
+ }
+ return mrb_bool_value(mrb_const_defined_at(mrb, mod, id));
+}
+
+static mrb_value
+mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+ mrb_bool inherit = TRUE;
+
+ mrb_get_args(mrb, "n|b", &id, &inherit);
+ check_const_name_sym(mrb, id);
+ return const_defined(mrb, mod, id, inherit);
+}
+
+static mrb_value
+mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+ check_const_name_sym(mrb, id);
+ return mrb_const_get(mrb, mod, id);
+}
+
+static mrb_value
+mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value path;
+ 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);
+ return mrb_const_get_sym(mrb, mod, id);
+ }
+
+ /* const get with class path string */
+ path = mrb_string_type(mrb, path);
+ ptr = RSTRING_PTR(path);
+ len = RSTRING_LEN(path);
+ off = 0;
+
+ while (off < len) {
+ end = mrb_str_index_lit(mrb, path, "::", off);
+ end = (end == -1) ? len : end;
+ id = mrb_intern(mrb, ptr+off, end-off);
+ mod = mrb_const_get_sym(mrb, mod, id);
+ off = (end == len) ? end : end+2;
+ }
+
+ return mod;
+}
+
+static mrb_value
+mrb_mod_const_set(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+ mrb_value value;
+
+ mrb_get_args(mrb, "no", &id, &value);
+ check_const_name_sym(mrb, id);
+ mrb_const_set(mrb, mod, id, value);
+ return value;
+}
+
+static mrb_value
+mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+ mrb_value val;
+
+ mrb_get_args(mrb, "n", &id);
+ 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));
+ }
+ return val;
+}
+
+static mrb_value
+mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym sym;
+
+ 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));
+ }
+ else {
+ mrb_name_error(mrb, sym, "uninitialized constant %S",
+ mrb_sym2str(mrb, sym));
+ }
+ /* not reached */
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
+{
+ mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented");
+ return mrb_nil_value(); /* not reached */
+}
+
+static mrb_value
+mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value obj;
+ 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
+mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value *argv;
+ mrb_int argc, i;
+ mrb_sym mid;
+ struct RProc *method_rproc;
+ struct RClass *rclass;
+ int ai;
+
+ mrb_check_type(mrb, mod, MRB_TT_MODULE);
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ if (argc == 0) {
+ /* set MODFUNC SCOPE if implemented */
+ return mod;
+ }
+
+ /* set PRIVATE method visibility if implemented */
+ /* mrb_mod_dummy_visibility(mrb, mod); */
+
+ for (i=0; i<argc; i++) {
+ mrb_check_type(mrb, argv[i], MRB_TT_SYMBOL);
+
+ mid = mrb_symbol(argv[i]);
+ rclass = mrb_class_ptr(mod);
+ method_rproc = mrb_method_search(mrb, rclass, mid);
+
+ prepare_singleton_class(mrb, (struct RBasic*)rclass);
+ ai = mrb_gc_arena_save(mrb);
+ mrb_define_method_raw(mrb, rclass->c, mid, method_rproc);
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return mod;
+}
+
+/* implementation of __id__ */
+mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
+/* implementation of instance_eval */
+mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
+/* implementation of Module.nesting */
+mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value);
+
+void
+mrb_init_class(mrb_state *mrb)
+{
+ struct RClass *bob; /* BasicObject */
+ struct RClass *obj; /* Object */
+ struct RClass *mod; /* Module */
+ struct RClass *cls; /* Class */
+
+ /* boot class hierarchy */
+ bob = boot_defclass(mrb, 0);
+ obj = boot_defclass(mrb, bob); mrb->object_class = obj;
+ mod = boot_defclass(mrb, obj); mrb->module_class = mod;/* obj -> mod */
+ cls = boot_defclass(mrb, mod); mrb->class_class = cls; /* obj -> cls */
+ /* fix-up loose ends */
+ bob->c = obj->c = mod->c = cls->c = cls;
+ make_metaclass(mrb, bob);
+ make_metaclass(mrb, obj);
+ make_metaclass(mrb, mod);
+ 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));
+
+ /* 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->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class); /* 15.2.17 */
+ MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC);
+
+ MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
+ 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.3 */
+ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
+ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
+
+ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
+ 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));
+
+ MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
+ mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */
+ mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */
+ mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
+ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
+ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
+ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */
+ mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */
+ mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */
+ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */
+ mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
+ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */
+ mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */
+ mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
+ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */
+ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY());
+ mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */
+ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */
+ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */
+ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
+ mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
+ mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */
+ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */
+ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, MRB_ARGS_ANY()); /* 15.2.2.4.8 */
+ mrb_define_method(mrb, mod, "ancestors", mrb_mod_ancestors, MRB_ARGS_NONE()); /* 15.2.2.4.9 */
+ mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
+ mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */
+ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */
+ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */
+ mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
+ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
+ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1));
+ mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
+ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
+ mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */
+
+ mrb_undef_method(mrb, cls, "append_features");
+ mrb_undef_method(mrb, cls, "extend_object");
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/codedump.c b/web/server/h2o/libh2o/deps/mruby/src/codedump.c
new file mode 100644
index 00000000..e3a33419
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/codedump.c
@@ -0,0 +1,474 @@
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+#include <mruby/opcode.h>
+#include <mruby/string.h>
+#include <mruby/proc.h>
+
+#ifndef MRB_DISABLE_STDIO
+static int
+print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
+{
+ size_t i;
+
+ if (n == 0) return 0;
+
+ for (i=0; i+1<irep->nlocals; i++) {
+ if (irep->lv[i].r == n) {
+ mrb_sym sym = irep->lv[i].name;
+ if (pre) printf(" ");
+ printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define RA 1
+#define RB 2
+#define RAB 3
+
+static void
+print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r)
+{
+ int pre = 0;
+
+ if (!irep->lv
+ || ((!(r & RA) || GETARG_A(c) >= irep->nlocals)
+ && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) {
+ printf("\n");
+ return;
+ }
+ printf("\t; ");
+ if (r & RA) {
+ pre = print_r(mrb, irep, GETARG_A(c), 0);
+ }
+ if (r & RB) {
+ print_r(mrb, irep, GETARG_B(c), pre);
+ }
+ printf("\n");
+}
+#endif
+
+static void
+codedump(mrb_state *mrb, mrb_irep *irep)
+{
+#ifndef MRB_DISABLE_STDIO
+ int i;
+ int ai;
+ mrb_code c;
+ const char *file = NULL, *next_file;
+ int32_t line;
+
+ if (!irep) return;
+ printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep,
+ irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
+
+ for (i = 0; i < (int)irep->ilen; i++) {
+ ai = mrb_gc_arena_save(mrb);
+
+ next_file = mrb_debug_get_filename(irep, i);
+ if (next_file && file != next_file) {
+ printf("file: %s\n", next_file);
+ file = next_file;
+ }
+ line = mrb_debug_get_line(irep, i);
+ if (line < 0) {
+ printf(" ");
+ }
+ else {
+ printf("%5d ", line);
+ }
+
+ printf("%03d ", i);
+ c = irep->iseq[i];
+ switch (GET_OPCODE(c)) {
+ case OP_NOP:
+ printf("OP_NOP\n");
+ break;
+ case OP_MOVE:
+ printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_LOADL:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_inspect(mrb, v);
+ printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADI:
+ printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADSYM:
+ printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADNIL:
+ printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADSELF:
+ printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADT:
+ printf("OP_LOADT\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADF:
+ printf("OP_LOADF\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETGLOBAL:
+ printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETGLOBAL:
+ printf("OP_SETGLOBAL\t:%s\tR%d\t",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETCONST:
+ printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETCONST:
+ printf("OP_SETCONST\t:%s\tR%d\t",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETMCNST:
+ printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_SETMCNST:
+ printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1,
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETIV:
+ printf("OP_GETIV\tR%d\t%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETIV:
+ printf("OP_SETIV\t%s\tR%d",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETUPVAR:
+ printf("OP_GETUPVAR\tR%d\t%d\t%d",
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETUPVAR:
+ printf("OP_SETUPVAR\tR%d\t%d\t%d",
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETCV:
+ printf("OP_GETCV\tR%d\t%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETCV:
+ printf("OP_SETCV\t%s\tR%d",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_JMP:
+ printf("OP_JMP\t%03d\n", i+GETARG_sBx(c));
+ break;
+ case OP_JMPIF:
+ printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
+ break;
+ case OP_JMPNOT:
+ printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
+ break;
+ case OP_SEND:
+ printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SENDB:
+ printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_TAILCALL:
+ printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUPER:
+ printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c),
+ GETARG_C(c));
+ break;
+ case OP_ARGARY:
+ printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c),
+ (GETARG_Bx(c)>>10)&0x3f,
+ (GETARG_Bx(c)>>9)&0x1,
+ (GETARG_Bx(c)>>4)&0x1f,
+ (GETARG_Bx(c)>>0)&0xf);
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_ENTER:
+ printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
+ (GETARG_Ax(c)>>18)&0x1f,
+ (GETARG_Ax(c)>>13)&0x1f,
+ (GETARG_Ax(c)>>12)&0x1,
+ (GETARG_Ax(c)>>7)&0x1f,
+ (GETARG_Ax(c)>>2)&0x1f,
+ (GETARG_Ax(c)>>1)&0x1,
+ GETARG_Ax(c) & 0x1);
+ break;
+ case OP_RETURN:
+ printf("OP_RETURN\tR%d", GETARG_A(c));
+ switch (GETARG_B(c)) {
+ case OP_R_NORMAL:
+ printf("\tnormal\t"); break;
+ case OP_R_RETURN:
+ printf("\treturn\t"); break;
+ case OP_R_BREAK:
+ printf("\tbreak\t"); break;
+ default:
+ printf("\tbroken\t"); break;
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_BLKPUSH:
+ printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c),
+ (GETARG_Bx(c)>>10)&0x3f,
+ (GETARG_Bx(c)>>9)&0x1,
+ (GETARG_Bx(c)>>4)&0x1f,
+ (GETARG_Bx(c)>>0)&0xf);
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_LAMBDA:
+ printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1);
+ switch (GETARG_c(c)) {
+ case OP_L_METHOD:
+ printf("method"); break;
+ case OP_L_BLOCK:
+ printf("block"); break;
+ case OP_L_LAMBDA:
+ printf("lambda"); break;
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_RANGE:
+ printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_METHOD:
+ printf("OP_METHOD\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_ADD:
+ printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_ADDI:
+ printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUB:
+ printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUBI:
+ printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_MUL:
+ printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_DIV:
+ printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_LT:
+ printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_LE:
+ printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_GT:
+ printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_GE:
+ printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_EQ:
+ printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+
+ case OP_STOP:
+ printf("OP_STOP\n");
+ break;
+
+ case OP_ARRAY:
+ printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_ARYCAT:
+ printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_ARYPUSH:
+ printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_AREF:
+ printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_APOST:
+ printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_STRING:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+ printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_STRCAT:
+ printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_HASH:
+ printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+
+ case OP_OCLASS:
+ printf("OP_OCLASS\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_CLASS:
+ printf("OP_CLASS\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_MODULE:
+ printf("OP_MODULE\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_EXEC:
+ printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1);
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SCLASS:
+ printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_TCLASS:
+ printf("OP_TCLASS\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_ERR:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+ printf("OP_ERR\t%s\n", RSTRING_PTR(s));
+ }
+ break;
+ case OP_EPUSH:
+ printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
+ break;
+ case OP_ONERR:
+ printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
+ break;
+ case OP_RESCUE:
+ {
+ int a = GETARG_A(c);
+ int b = GETARG_B(c);
+ int cnt = GETARG_C(c);
+
+ if (b == 0) {
+ printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : "");
+ print_lv(mrb, irep, c, RA);
+ break;
+ }
+ else {
+ printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : "");
+ print_lv(mrb, irep, c, RAB);
+ break;
+ }
+ }
+ break;
+ case OP_RAISE:
+ printf("OP_RAISE\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_POPERR:
+ printf("OP_POPERR\t%d\t\t\n", GETARG_A(c));
+ break;
+ case OP_EPOP:
+ printf("OP_EPOP\t%d\n", GETARG_A(c));
+ break;
+
+ default:
+ printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c),
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ break;
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ printf("\n");
+#endif
+}
+
+static void
+codedump_recur(mrb_state *mrb, mrb_irep *irep)
+{
+ int i;
+
+ codedump(mrb, irep);
+ for (i=0; i<irep->rlen; i++) {
+ codedump_recur(mrb, irep->reps[i]);
+ }
+}
+
+void
+mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
+{
+ codedump_recur(mrb, proc->body.irep);
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/compar.c b/web/server/h2o/libh2o/deps/mruby/src/compar.c
new file mode 100644
index 00000000..0032fc85
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/compar.c
@@ -0,0 +1,13 @@
+/*
+** compar.c - Comparable module
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+
+void
+mrb_init_comparable(mrb_state *mrb)
+{
+ mrb_define_module(mrb, "Comparable"); /* 15.3.3 */
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/crc.c b/web/server/h2o/libh2o/deps/mruby/src/crc.c
new file mode 100644
index 00000000..290b2ca0
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/crc.c
@@ -0,0 +1,39 @@
+/*
+** 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/web/server/h2o/libh2o/deps/mruby/src/debug.c b/web/server/h2o/libh2o/deps/mruby/src/debug.c
new file mode 100644
index 00000000..e55f11d4
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/debug.c
@@ -0,0 +1,217 @@
+#include <string.h>
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+
+static mrb_irep_debug_info_file*
+get_file(mrb_irep_debug_info *info, uint32_t pc)
+{
+ mrb_irep_debug_info_file **ret;
+ int32_t count;
+
+ if (pc >= info->pc_count) { return NULL; }
+ /* get upper bound */
+ ret = info->files;
+ count = info->flen;
+ while (count > 0) {
+ int32_t step = count / 2;
+ mrb_irep_debug_info_file **it = ret + step;
+ if (!(pc < (*it)->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ }
+ else { count = step; }
+ }
+
+ --ret;
+
+ /* check returning file exists inside debug info */
+ mrb_assert(info->files <= ret && ret < (info->files + info->flen));
+ /* check pc is within the range of returning file */
+ mrb_assert((*ret)->start_pos <= pc &&
+ pc < (((ret + 1 - info->files) < info->flen)
+ ? (*(ret+1))->start_pos : info->pc_count));
+
+ return *ret;
+}
+
+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 i;
+ for (i = 0; i < lines_len; ++i) {
+ if (lines[i] != prev_line) {
+ ++line_count;
+ }
+ }
+ return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count)
+ ? mrb_debug_line_ary : mrb_debug_line_flat_map;
+}
+
+MRB_API char const*
+mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc)
+{
+ if (irep && pc >= 0 && pc < irep->ilen) {
+ mrb_irep_debug_info_file* f = NULL;
+ if (!irep->debug_info) { return irep->filename; }
+ else if ((f = get_file(irep->debug_info, (uint32_t)pc))) {
+ return f->filename;
+ }
+ }
+ return NULL;
+}
+
+MRB_API int32_t
+mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc)
+{
+ if (irep && pc >= 0 && pc < irep->ilen) {
+ mrb_irep_debug_info_file* f = NULL;
+ if (!irep->debug_info) {
+ return irep->lines? irep->lines[pc] : -1;
+ }
+ else if ((f = get_file(irep->debug_info, (uint32_t)pc))) {
+ switch (f->line_type) {
+ case mrb_debug_line_ary:
+ mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count));
+ return f->lines.ary[pc - f->start_pos];
+
+ case mrb_debug_line_flat_map: {
+ /* get upper bound */
+ mrb_irep_debug_info_line *ret = f->lines.flat_map;
+ uint32_t count = f->line_entry_count;
+ while (count > 0) {
+ int32_t step = count / 2;
+ mrb_irep_debug_info_line *it = ret + step;
+ if (!(pc < it->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ }
+ else { count = step; }
+ }
+
+ --ret;
+
+ /* check line entry pointer range */
+ mrb_assert(f->lines.flat_map <= ret && ret < (f->lines.flat_map + f->line_entry_count));
+ /* check pc range */
+ mrb_assert(ret->start_pos <= pc &&
+ pc < (((uint32_t)(ret + 1 - f->lines.flat_map) < f->line_entry_count)
+ ? (ret+1)->start_pos : irep->debug_info->pc_count));
+
+ return ret->line;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+MRB_API mrb_irep_debug_info*
+mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep)
+{
+ static const mrb_irep_debug_info initial = { 0, 0, NULL };
+ mrb_irep_debug_info *ret;
+
+ mrb_assert(!irep->debug_info);
+ ret = (mrb_irep_debug_info *)mrb_malloc(mrb, sizeof(*ret));
+ *ret = initial;
+ irep->debug_info = ret;
+ return ret;
+}
+
+MRB_API mrb_irep_debug_info_file*
+mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
+ uint32_t start_pos, uint32_t end_pos)
+{
+ mrb_irep_debug_info *info;
+ mrb_irep_debug_info_file *ret;
+ 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);
+
+ info = irep->debug_info;
+
+ if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 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))
+ : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*)));
+ info->files[info->flen++] = ret;
+
+ file_pc_count = end_pos - start_pos;
+
+ ret->start_pos = start_pos;
+ info->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);
+
+ ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos);
+ ret->lines.ptr = NULL;
+
+ switch (ret->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);
+ for (i = 0; i < file_pc_count; ++i) {
+ ret->lines.ary[i] = irep->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;
+ for (i = 0; i < file_pc_count; ++i) {
+ if (irep->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;
+
+ /* update */
+ ++ret->line_entry_count;
+ prev_line = irep->lines[start_pos + i];
+ }
+ } break;
+
+ default: mrb_assert(0); break;
+ }
+
+ return ret;
+}
+
+MRB_API void
+mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
+{
+ uint32_t i;
+
+ 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]);
+ }
+ mrb_free(mrb, d->files);
+ mrb_free(mrb, d);
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/dump.c b/web/server/h2o/libh2o/deps/mruby/src/dump.c
new file mode 100644
index 00000000..d479a1a4
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/dump.c
@@ -0,0 +1,1100 @@
+/*
+** dump.c - mruby binary dumper (mrbc binary format)
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <string.h>
+#include <limits.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
+
+#ifdef MRB_USE_FLOAT
+#define MRB_FLOAT_FMT "%.8e"
+#else
+#define MRB_FLOAT_FMT "%.16e"
+#endif
+
+static size_t get_irep_record_size_1(mrb_state *mrb, 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;
+
+ size += sizeof(uint32_t) * 1;
+ size += sizeof(uint16_t) * 3;
+
+ return size;
+}
+
+static ptrdiff_t
+write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+{
+ uint8_t *cur = buf;
+
+ cur += uint32_to_bin((uint32_t)get_irep_record_size_1(mrb, irep), cur); /* record size */
+ cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */
+ cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
+ cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */
+
+ return cur - buf;
+}
+
+
+static size_t
+get_iseq_block_size(mrb_state *mrb, 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) */
+
+ return size;
+}
+
+static ptrdiff_t
+write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
+{
+ uint8_t *cur = buf;
+ int iseq_no;
+
+ cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
+ cur += write_padding(cur);
+ switch (flags & DUMP_ENDIAN_NAT) {
+ case DUMP_ENDIAN_BIG:
+ if (bigendian_p()) goto native;
+ for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
+ cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
+ }
+ break;
+ case DUMP_ENDIAN_LIL:
+ if (!bigendian_p()) goto native;
+ for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
+ cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */
+ }
+ break;
+
+ native:
+ case DUMP_ENDIAN_NAT:
+ memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
+ cur += irep->ilen * sizeof(mrb_code);
+ break;
+ }
+
+ return cur - buf;
+}
+
+
+static size_t
+get_pool_block_size(mrb_state *mrb, 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) */
+
+ 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);
+ {
+ mrb_int len = RSTRING_LEN(str);
+ mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
+ size += (size_t)len;
+ }
+ break;
+
+ case MRB_TT_FLOAT:
+ str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
+ {
+ mrb_int len = RSTRING_LEN(str);
+ mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
+ size += (size_t)len;
+ }
+ break;
+
+ case MRB_TT_STRING:
+ {
+ mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
+ mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
+ size += (size_t)len;
+ }
+ break;
+
+ default:
+ break;
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return size;
+}
+
+static ptrdiff_t
+write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+{
+ int pool_no;
+ uint8_t *cur = buf;
+ uint16_t len;
+ mrb_value str;
+ const char *char_ptr;
+
+ cur += uint32_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;
+
+ 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);
+ break;
+
+ case MRB_TT_STRING:
+ cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
+ str = irep->pool[pool_no];
+ break;
+
+ default:
+ continue;
+ }
+
+ 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;
+ }
+
+ 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)
+{
+ size_t size = 0;
+ int sym_no;
+ mrb_int len;
+
+ size += sizeof(uint32_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);
+ size += len + 1; /* sn(n) + null char */
+ }
+ }
+
+ return size;
+}
+
+static ptrdiff_t
+write_syms_block(mrb_state *mrb, 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 */
+
+ 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);
+
+ mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
+ memcpy(cur, name, len); /* symbol name */
+ cur += (uint16_t)len;
+ *cur++ = '\0';
+ }
+ else {
+ cur += uint16_to_bin(MRB_DUMP_NULL_SYM_LEN, cur); /* length of symbol name */
+ }
+ }
+
+ return cur - buf;
+}
+
+static size_t
+get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t size = 0;
+
+ size += get_irep_header_size(mrb);
+ size += get_iseq_block_size(mrb, irep);
+ size += get_pool_block_size(mrb, irep);
+ size += get_syms_block_size(mrb, irep);
+ return size;
+}
+
+static size_t
+get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t size = 0;
+ int irep_no;
+
+ size = get_irep_record_size_1(mrb, irep);
+ for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
+ size += get_irep_record_size(mrb, irep->reps[irep_no]);
+ }
+ return size;
+}
+
+static int
+write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
+{
+ int i;
+ uint8_t *src = bin;
+
+ if (irep == NULL) {
+ 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);
+ bin += write_syms_block(mrb, irep, bin);
+
+ for (i = 0; i < irep->rlen; i++) {
+ int result;
+ size_t rsize;
+
+ result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags);
+ if (result != MRB_DUMP_OK) {
+ return result;
+ }
+ bin += rsize;
+ }
+ *irep_record_size = bin - src;
+ return MRB_DUMP_OK;
+}
+
+static uint32_t
+write_footer(mrb_state *mrb, uint8_t *bin)
+{
+ struct rite_binary_footer footer;
+
+ memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident));
+ uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
+ memcpy(bin, &footer, sizeof(struct rite_binary_footer));
+
+ return sizeof(struct rite_binary_footer);
+}
+
+
+static int
+write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
+{
+ struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
+
+ memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident));
+
+ mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
+ memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
+
+ return MRB_DUMP_OK;
+}
+
+static int
+write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
+{
+ int result;
+ size_t rsize = 0;
+ uint8_t *cur = bin;
+
+ if (mrb == NULL || bin == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+
+ cur += sizeof(struct rite_section_irep_header);
+
+ result = write_irep_record(mrb, irep, cur, &rsize, flags);
+ if (result != MRB_DUMP_OK) {
+ return result;
+ }
+ *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)
+{
+ size_t ret = 0;
+ uint16_t f_idx;
+ int i;
+
+ ret += sizeof(uint32_t); /* record size */
+ ret += sizeof(uint16_t); /* file count */
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
+
+ ret += sizeof(uint32_t); /* position */
+ ret += sizeof(uint16_t); /* filename index */
+
+ /* lines */
+ ret += sizeof(uint32_t); /* entry count */
+ ret += sizeof(uint8_t); /* line type */
+ switch (file->line_type) {
+ case mrb_debug_line_ary:
+ ret += sizeof(uint16_t) * (size_t)(file->line_entry_count);
+ break;
+
+ case mrb_debug_line_flat_map:
+ ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
+ break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+ for (i=0; i<irep->rlen; i++) {
+ ret += get_debug_record_size(mrb, irep->reps[i]);
+ }
+
+ return ret;
+}
+
+static int
+find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s)
+{
+ int i;
+
+ for (i = 0; i < ary_len; ++i) {
+ if (ary[i] == s) { return i; }
+ }
+ return -1;
+}
+
+static size_t
+get_filename_table_size(mrb_state *mrb, 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;
+ int i;
+
+ mrb_assert(lp);
+ for (i = 0; i < di->flen; ++i) {
+ mrb_irep_debug_info_file *file;
+ mrb_int filename_len;
+
+ file = di->files[i];
+ if (find_filename_index(filenames, *lp, file->filename_sym) == -1) {
+ /* register filename */
+ *lp += 1;
+ *fp = filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
+ filenames[*lp - 1] = file->filename_sym;
+
+ /* filename */
+ mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
+ size += sizeof(uint16_t) + (size_t)filename_len;
+ }
+ }
+ for (i=0; i<irep->rlen; i++) {
+ size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
+ }
+ return size;
+}
+
+static size_t
+write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+{
+ uint8_t *cur;
+ uint16_t f_idx;
+ ptrdiff_t ret;
+
+ cur = bin + sizeof(uint32_t); /* skip record size */
+ cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ int filename_idx;
+ const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx];
+
+ /* position */
+ cur += uint32_to_bin(file->start_pos, cur);
+
+ /* filename index */
+ filename_idx = find_filename_index(filenames, filenames_len,
+ file->filename_sym);
+ mrb_assert_int_fit(int, filename_idx, uint16_t, UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)filename_idx, cur);
+
+ /* lines */
+ cur += uint32_to_bin(file->line_entry_count, cur);
+ cur += uint8_to_bin(file->line_type, cur);
+ switch (file->line_type) {
+ case mrb_debug_line_ary: {
+ uint32_t l;
+ for (l = 0; l < file->line_entry_count; ++l) {
+ cur += uint16_to_bin(file->lines.ary[l], cur);
+ }
+ } break;
+
+ case mrb_debug_line_flat_map: {
+ uint32_t line;
+ for (line = 0; line < file->line_entry_count; ++line) {
+ cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur);
+ cur += uint16_to_bin(file->lines.flat_map[line].line, cur);
+ }
+ } break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+
+ ret = cur - bin;
+ mrb_assert_int_fit(ptrdiff_t, ret, uint32_t, UINT32_MAX);
+ uint32_to_bin((uint32_t)ret, bin);
+
+ mrb_assert_int_fit(ptrdiff_t, ret, size_t, SIZE_MAX);
+ return (size_t)ret;
+}
+
+static size_t
+write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+{
+ size_t size, len;
+ int irep_no;
+
+ size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len);
+ bin += len;
+ for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
+ len = write_debug_record(mrb, irep->reps[irep_no], bin, filenames, filenames_len);
+ bin += len;
+ size += len;
+ }
+
+ mrb_assert(size == get_debug_record_size(mrb, irep));
+ return size;
+}
+
+static int
+write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
+{
+ size_t section_size = 0;
+ const uint8_t *bin = cur;
+ struct rite_section_debug_header *header;
+ size_t dlen;
+ uint16_t i;
+ char const *sym; mrb_int sym_len;
+
+ if (mrb == NULL || cur == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+
+ header = (struct rite_section_debug_header *)bin;
+ cur += sizeof(struct rite_section_debug_header);
+ section_size += sizeof(struct rite_section_debug_header);
+
+ /* filename table */
+ 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);
+ mrb_assert(sym);
+ cur += uint16_to_bin(sym_len, cur);
+ memcpy(cur, sym, sym_len);
+ cur += sym_len;
+ section_size += sizeof(uint16_t) + sym_len;
+ }
+
+ /* debug records */
+ dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
+ section_size += dlen;
+
+ memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident));
+ mrb_assert(section_size <= INT32_MAX);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
+
+ return MRB_DUMP_OK;
+}
+
+static void
+create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32_t *syms_len)
+{
+ int i;
+
+ if (*syms == NULL) {
+ *syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * 1);
+ }
+
+ for (i = 0; i + 1 < irep->nlocals; ++i) {
+ mrb_sym const name = irep->lv[i].name;
+ if (name == 0) continue;
+ if (find_filename_index(*syms, *syms_len, name) != -1) continue;
+
+ ++(*syms_len);
+ *syms = (mrb_sym*)mrb_realloc(mrb, *syms, sizeof(mrb_sym) * (*syms_len));
+ (*syms)[*syms_len - 1] = name;
+ }
+
+ for (i = 0; i < irep->rlen; ++i) {
+ create_lv_sym_table(mrb, irep->reps[i], syms, syms_len);
+ }
+}
+
+static int
+write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
+{
+ uint8_t *cur = *start;
+ uint32_t i;
+ const char *str;
+ mrb_int str_len;
+
+ cur += uint32_to_bin(syms_len, cur);
+
+ for (i = 0; i < syms_len; ++i) {
+ str = mrb_sym2name_len(mrb, syms[i], &str_len);
+ cur += uint16_to_bin(str_len, cur);
+ memcpy(cur, str, str_len);
+ cur += str_len;
+ }
+
+ *start = cur;
+
+ return MRB_DUMP_OK;
+}
+
+static int
+write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
+{
+ uint8_t *cur = *start;
+ int i;
+
+ for (i = 0; i + 1 < irep->nlocals; ++i) {
+ if (irep->lv[i].name == 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);
+ 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);
+ }
+ }
+
+ for (i = 0; i < irep->rlen; ++i) {
+ write_lv_record(mrb, irep->reps[i], &cur, syms, syms_len);
+ }
+
+ *start = cur;
+
+ return MRB_DUMP_OK;
+}
+
+static size_t
+get_lv_record_size(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t ret = 0;
+ int i;
+
+ ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1);
+
+ for (i = 0; i < irep->rlen; ++i) {
+ ret += get_lv_record_size(mrb, irep->reps[i]);
+ }
+
+ return ret;
+}
+
+static size_t
+get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len)
+{
+ size_t ret = 0, i;
+
+ ret += sizeof(uint32_t); /* syms_len */
+ 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);
+ ret += str_len;
+ }
+
+ ret += get_lv_record_size(mrb, irep);
+
+ return ret;
+}
+
+static int
+write_section_lv(mrb_state *mrb, 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;
+ ptrdiff_t diff;
+ int result = MRB_DUMP_OK;
+
+ if (mrb == NULL || cur == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+
+ header = (struct rite_section_lv_header*)cur;
+ cur += sizeof(struct rite_section_lv_header);
+
+ result = write_lv_sym_table(mrb, &cur, syms, syms_len);
+ if (result != MRB_DUMP_OK) {
+ goto lv_section_exit;
+ }
+
+ result = write_lv_record(mrb, irep, &cur, syms, syms_len);
+ if (result != MRB_DUMP_OK) {
+ goto lv_section_exit;
+ }
+
+ memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident));
+
+ diff = cur - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+ uint32_to_bin((uint32_t)diff, header->section_size);
+
+lv_section_exit:
+ return result;
+}
+
+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->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)
+{
+ 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;
+ }
+ return TRUE;
+}
+
+static mrb_bool
+is_lv_defined(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; }
+ }
+
+ 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)
+{
+ 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_sym *lv_syms = NULL; uint32_t lv_syms_len = 0;
+ mrb_sym *filenames = NULL; uint16_t filenames_len = 0;
+
+ if (mrb == NULL) {
+ *bin = NULL;
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ section_irep_size = sizeof(struct rite_section_irep_header);
+ section_irep_size += get_irep_record_size(mrb, irep);
+
+ /* DEBUG section size */
+ if (flags & DUMP_DEBUG_INFO) {
+ if (debug_info_defined) {
+ section_lineno_size += sizeof(struct rite_section_debug_header);
+ /* filename table */
+ filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1);
+
+ /* filename table size */
+ section_lineno_size += sizeof(uint16_t);
+ section_lineno_size += get_filename_table_size(mrb, irep, &filenames, &filenames_len);
+
+ 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) {
+ section_lv_size += sizeof(struct rite_section_lv_header);
+ create_lv_sym_table(mrb, irep, &lv_syms, &lv_syms_len);
+ section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len);
+ }
+
+ malloc_size = sizeof(struct rite_binary_header) +
+ section_irep_size + section_lineno_size + section_lv_size +
+ sizeof(struct rite_binary_footer);
+ cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size);
+ cur += sizeof(struct rite_binary_header);
+
+ result = write_section_irep(mrb, irep, cur, &section_irep_size, flags);
+ if (result != MRB_DUMP_OK) {
+ goto error_exit;
+ }
+ cur += section_irep_size;
+ *bin_size = sizeof(struct rite_binary_header) +
+ section_irep_size + section_lineno_size + section_lv_size +
+ sizeof(struct rite_binary_footer);
+
+ /* write DEBUG section */
+ if (flags & DUMP_DEBUG_INFO) {
+ if (debug_info_defined) {
+ result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
+ }
+ else {
+ result = write_section_lineno(mrb, irep, cur);
+ }
+ if (result != MRB_DUMP_OK) {
+ goto error_exit;
+ }
+ cur += section_lineno_size;
+ }
+
+ if (lv_defined) {
+ result = write_section_lv(mrb, irep, cur, lv_syms, lv_syms_len);
+ if (result != MRB_DUMP_OK) {
+ goto error_exit;
+ }
+ cur += section_lv_size;
+ }
+
+ write_footer(mrb, cur);
+ write_rite_binary_header(mrb, *bin_size, *bin, flags);
+
+error_exit:
+ if (result != MRB_DUMP_OK) {
+ mrb_free(mrb, *bin);
+ *bin = NULL;
+ }
+ mrb_free(mrb, lv_syms);
+ mrb_free(mrb, filenames);
+ return result;
+}
+
+int
+mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
+{
+ return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size);
+}
+
+#ifndef MRB_DISABLE_STDIO
+
+int
+mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
+{
+ uint8_t *bin = NULL;
+ size_t bin_size = 0;
+ int result;
+
+ if (fp == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+
+ result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size);
+ if (result == MRB_DUMP_OK) {
+ if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
+ result = MRB_DUMP_WRITE_FAULT;
+ }
+ }
+
+ mrb_free(mrb, bin);
+ 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)
+{
+ uint8_t *bin = NULL;
+ size_t bin_size = 0, bin_idx = 0;
+ int result;
+
+ 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) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ while (bin_idx < bin_size) {
+ if (bin_idx % 16 == 0) {
+ if (fputs("\n", fp) == EOF) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ if (fputs("\n};\n", fp) == EOF) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+
+ mrb_free(mrb, bin);
+ return result;
+}
+
+#endif /* MRB_DISABLE_STDIO */
diff --git a/web/server/h2o/libh2o/deps/mruby/src/enum.c b/web/server/h2o/libh2o/deps/mruby/src/enum.c
new file mode 100644
index 00000000..adb815bf
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/enum.c
@@ -0,0 +1,14 @@
+/*
+** enum.c - Enumerable module
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+
+void
+mrb_init_enumerable(mrb_state *mrb)
+{
+ mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */
+}
+
diff --git a/web/server/h2o/libh2o/deps/mruby/src/error.c b/web/server/h2o/libh2o/deps/mruby/src/error.c
new file mode 100644
index 00000000..2c4fd1a4
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/error.c
@@ -0,0 +1,503 @@
+/*
+** error.c - Exception class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/irep.h>
+#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>
+
+MRB_API mrb_value
+mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
+{
+ mrb_value arg = mrb_str_new(mrb, ptr, len);
+ return mrb_obj_new(mrb, c, 1, &arg);
+}
+
+MRB_API mrb_value
+mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
+{
+ str = mrb_str_to_str(mrb, str);
+ return mrb_obj_new(mrb, c, 1, &str);
+}
+
+/*
+ * call-seq:
+ * Exception.new(msg = nil) -> exception
+ *
+ * Construct a new Exception object, optionally passing in
+ * a message.
+ */
+
+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);
+ }
+ return exc;
+}
+
+/*
+ * Document-method: exception
+ *
+ * call-seq:
+ * exc.exception(string) -> an_exception or exc
+ *
+ * With no argument, or if the argument is the same as the receiver,
+ * return the receiver. Otherwise, create a new
+ * exception object of the same class as the receiver, but with a
+ * message equal to <code>string</code>.
+ *
+ */
+
+static mrb_value
+exc_exception(mrb_state *mrb, mrb_value self)
+{
+ mrb_value exc;
+ mrb_value a;
+ int argc;
+
+ argc = mrb_get_args(mrb, "|o", &a);
+ 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);
+
+ return exc;
+}
+
+/*
+ * call-seq:
+ * exception.to_s -> string
+ *
+ * Returns exception's message (or the name of the exception if
+ * no message is set).
+ */
+
+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"));
+ struct RObject *p;
+
+ if (!mrb_string_p(mesg)) {
+ return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
+ }
+ p = mrb_obj_ptr(mesg);
+ if (!p->c) {
+ p->c = mrb->string_class;
+ }
+ return mesg;
+}
+
+/*
+ * call-seq:
+ * exception.message -> string
+ *
+ * Returns the result of invoking <code>exception.to_s</code>.
+ * Normally this returns the exception's message or name.
+ */
+
+static mrb_value
+exc_message(mrb_state *mrb, mrb_value exc)
+{
+ return mrb_funcall(mrb, exc, "to_s", 0);
+}
+
+/*
+ * call-seq:
+ * exception.inspect -> string
+ *
+ * Returns this exception's file name, line number,
+ * message and class name.
+ * If file name or line number is not set,
+ * returns message and class name.
+ */
+
+static mrb_value
+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;
+}
+
+void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
+
+static void
+set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
+{
+ if (!mrb_array_p(backtrace)) {
+ type_err:
+ mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
+ }
+ else {
+ const mrb_value *p = RARRAY_PTR(backtrace);
+ const mrb_value *pend = p + RARRAY_LEN(backtrace);
+
+ while (p < pend) {
+ if (!mrb_string_p(*p)) goto type_err;
+ p++;
+ }
+ }
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+}
+
+static mrb_value
+exc_set_backtrace(mrb_state *mrb, mrb_value exc)
+{
+ mrb_value backtrace;
+
+ 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;
+
+ 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)
+{
+ if (mrb_nil_p(exc)) {
+ mrb->exc = 0;
+ }
+ else {
+ mrb->exc = mrb_obj_ptr(exc);
+ if (!mrb->gc.out_of_memory) {
+ exc_debug_info(mrb, mrb->exc);
+ mrb_keep_backtrace(mrb, exc);
+ }
+ }
+}
+
+MRB_API mrb_noreturn void
+mrb_exc_raise(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();
+ }
+ MRB_THROW(mrb->jmp);
+}
+
+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)));
+}
+
+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;
+ mrb_value ary = mrb_ary_new_capa(mrb, 4);
+ int ai = mrb_gc_arena_save(mrb);
+
+ while (*p) {
+ const char c = *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;
+ }
+ else {
+ break;
+ }
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ if (b == format) {
+ return mrb_str_new_cstr(mrb, format);
+ }
+ else {
+ size = p - b;
+ if (size > 0) {
+ mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return mrb_ary_join(mrb, ary, mrb_nil_value());
+ }
+}
+
+MRB_API mrb_value
+mrb_format(mrb_state *mrb, const char *format, ...)
+{
+ va_list ap;
+ mrb_value str;
+
+ va_start(ap, format);
+ str = mrb_vformat(mrb, format, ap);
+ va_end(ap);
+
+ return str;
+}
+
+static mrb_noreturn void
+raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv)
+{
+ mrb_value mesg;
+
+ mesg = mrb_vformat(mrb, fmt, ap);
+ if (argv == NULL) {
+ argv = &mesg;
+ }
+ else {
+ argv[0] = mesg;
+ }
+ mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv));
+}
+
+MRB_API mrb_noreturn void
+mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ raise_va(mrb, c, fmt, args, 0, NULL);
+ va_end(args);
+}
+
+MRB_API mrb_noreturn void
+mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
+{
+ mrb_value argv[2];
+ va_list args;
+
+ va_start(args, fmt);
+ argv[1] = mrb_symbol_value(id);
+ raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv);
+ va_end(args);
+}
+
+MRB_API void
+mrb_warn(mrb_state *mrb, const char *fmt, ...)
+{
+#ifndef MRB_DISABLE_STDIO
+ va_list ap;
+ mrb_value str;
+
+ va_start(ap, fmt);
+ str = mrb_vformat(mrb, fmt, ap);
+ fputs("warning: ", stderr);
+ fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
+ va_end(ap);
+#endif
+}
+
+MRB_API mrb_noreturn void
+mrb_bug(mrb_state *mrb, const char *fmt, ...)
+{
+#ifndef MRB_DISABLE_STDIO
+ va_list ap;
+ mrb_value str;
+
+ va_start(ap, fmt);
+ str = mrb_vformat(mrb, fmt, ap);
+ fputs("bug: ", stderr);
+ fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
+ va_end(ap);
+#endif
+ exit(EXIT_FAILURE);
+}
+
+MRB_API mrb_value
+mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
+{
+ mrb_value mesg;
+ int n;
+
+ mesg = mrb_nil_value();
+ switch (argc) {
+ case 0:
+ break;
+ case 1:
+ if (mrb_nil_p(argv[0]))
+ break;
+ if (mrb_string_p(argv[0])) {
+ mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, argv[0]);
+ break;
+ }
+ n = 0;
+ goto exception_call;
+
+ case 2:
+ case 3:
+ n = 1;
+exception_call:
+ {
+ mrb_sym exc = mrb_intern_lit(mrb, "exception");
+ if (mrb_respond_to(mrb, argv[0], exc)) {
+ mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
+ }
+ else {
+ /* undef */
+ mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
+ }
+ }
+
+ break;
+ default:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
+ break;
+ }
+ if (argc > 0) {
+ if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
+ mrb_raise(mrb, mrb->eException_class, "exception object expected");
+ if (argc > 2)
+ set_backtrace(mrb, mesg, argv[2]);
+ }
+
+ return mesg;
+}
+
+MRB_API void
+mrb_sys_fail(mrb_state *mrb, const char *mesg)
+{
+ struct RClass *sce;
+ mrb_int no;
+
+ no = (mrb_int)errno;
+ if (mrb_class_defined(mrb, "SystemCallError")) {
+ sce = mrb_class_get(mrb, "SystemCallError");
+ if (mesg != NULL) {
+ mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
+ }
+ else {
+ mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
+ }
+ }
+ else {
+ mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
+ }
+}
+
+MRB_API mrb_noreturn void
+mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
+{
+ mrb_value exc;
+ mrb_value argv[3];
+ va_list ap;
+
+ va_start(ap, fmt);
+ argv[0] = mrb_vformat(mrb, fmt, ap);
+ argv[1] = mrb_symbol_value(id);
+ argv[2] = args;
+ va_end(ap);
+ exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv);
+ mrb_exc_raise(mrb, exc);
+}
+
+void
+mrb_init_exception(mrb_state *mrb)
+{
+ struct RClass *exception, *script_error, *stack_error, *nomem_error;
+
+ 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_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, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
+ mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1));
+
+ mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
+ mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
+ 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"));
+
+ 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"));
+#ifdef MRB_GC_FIXED_ARENA
+ mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error"));
+#endif
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/error.h b/web/server/h2o/libh2o/deps/mruby/src/error.h
new file mode 100644
index 00000000..eb755ec7
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/error.h
@@ -0,0 +1,3 @@
+/* this header file is to be removed soon.
+ added for compatibility purpose (1.0.0) */
+#include <mruby/error.h>
diff --git a/web/server/h2o/libh2o/deps/mruby/src/etc.c b/web/server/h2o/libh2o/deps/mruby/src/etc.c
new file mode 100644
index 00000000..9475ae30
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/etc.c
@@ -0,0 +1,234 @@
+/*
+** etc.c -
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/data.h>
+#include <mruby/class.h>
+#include <mruby/re.h>
+#include <mruby/irep.h>
+
+MRB_API struct RData*
+mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
+{
+ struct RData *data;
+
+ data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass);
+ data->data = ptr;
+ data->type = type;
+
+ return data;
+}
+
+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) {
+ 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));
+ }
+ 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_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) {
+ return NULL;
+ }
+ if (DATA_TYPE(obj) != type) {
+ return NULL;
+ }
+ return DATA_PTR(obj);
+}
+
+MRB_API void*
+mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
+{
+ mrb_data_check_type(mrb, obj, type);
+ return DATA_PTR(obj);
+}
+
+MRB_API mrb_sym
+mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
+{
+ mrb_sym id;
+
+ switch (mrb_type(name)) {
+ default:
+ name = mrb_check_string_type(mrb, name);
+ if (mrb_nil_p(name)) {
+ name = mrb_inspect(mrb, name);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name);
+ }
+ /* fall through */
+ case MRB_TT_STRING:
+ name = mrb_str_intern(mrb, name);
+ /* fall through */
+ case MRB_TT_SYMBOL:
+ id = mrb_symbol(name);
+ }
+ return id;
+}
+
+MRB_API mrb_int
+mrb_float_id(mrb_float f)
+{
+ const char *p = (const char*)&f;
+ int len = sizeof(f);
+ mrb_int id = 0;
+
+ /* normalize -0.0 to 0.0 */
+ if (f == 0) f = 0.0;
+ while (len--) {
+ id = id*65599 + *p;
+ p++;
+ }
+ id = id + (id>>5);
+
+ return id;
+}
+
+MRB_API mrb_int
+mrb_obj_id(mrb_value obj)
+{
+ mrb_int tt = mrb_type(obj);
+
+#define MakeID2(p,t) (mrb_int)(((intptr_t)(p))^(t))
+#define MakeID(p) MakeID2(p,tt)
+
+ switch (tt) {
+ case MRB_TT_FREE:
+ case MRB_TT_UNDEF:
+ return MakeID(0); /* not define */
+ case MRB_TT_FALSE:
+ if (mrb_nil_p(obj))
+ return MakeID(1);
+ return MakeID(0);
+ case MRB_TT_TRUE:
+ return MakeID(1);
+ case MRB_TT_SYMBOL:
+ return MakeID(mrb_symbol(obj));
+ case MRB_TT_FIXNUM:
+ return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
+ case MRB_TT_FLOAT:
+ return MakeID(mrb_float_id(mrb_float(obj)));
+ case MRB_TT_STRING:
+ case MRB_TT_OBJECT:
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_ICLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_PROC:
+ case MRB_TT_ARRAY:
+ 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:
+ return MakeID(mrb_ptr(obj));
+ }
+}
+
+#ifdef MRB_WORD_BOXING
+MRB_API mrb_value
+mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
+{
+ mrb_value v;
+
+ v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
+ v.value.fp->f = f;
+ return v;
+}
+
+MRB_API mrb_value
+mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f)
+{
+ 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);
+}
+
+MRB_API mrb_value
+mrb_word_boxing_cptr_value(mrb_state *mrb, void *p)
+{
+ mrb_value v;
+
+ v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class);
+ v.value.vp->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;
+}
+
+#if defined _MSC_VER && _MSC_VER < 1900
+
+#ifndef va_copy
+static void
+mrb_msvc_va_copy(va_list *dest, va_list src)
+{
+ *dest = src;
+}
+#define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src)
+#endif
+
+MRB_API int
+mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg)
+{
+ int cnt;
+ va_list argcp;
+ va_copy(argcp, arg);
+ if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) {
+ cnt = _vscprintf(format, arg);
+ }
+ va_end(argcp);
+ return cnt;
+}
+
+MRB_API int
+mrb_msvc_snprintf(char *s, size_t n, const char *format, ...)
+{
+ va_list arg;
+ int ret;
+ va_start(arg, format);
+ ret = mrb_msvc_vsnprintf(s, n, format, arg);
+ va_end(arg);
+ return ret;
+}
+
+#endif /* defined _MSC_VER && _MSC_VER < 1900 */
diff --git a/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep b/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep
diff --git a/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c b/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c
new file mode 100644
index 00000000..0a8b22b4
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c
@@ -0,0 +1,372 @@
+/*
+
+Most code in this file originates from musl (src/stdio/vfprintf.c)
+which, just like mruby itself, is licensed under the MIT license.
+
+Copyright (c) 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <math.h>
+#include <float.h>
+#include <ctype.h>
+
+#include <mruby.h>
+#include <mruby/string.h>
+
+struct fmt_args {
+ mrb_state *mrb;
+ mrb_value str;
+};
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#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);
+}
+
+#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);
+}
+
+static const char xdigits[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static char*
+fmt_u(uint32_t x, char *s)
+{
+ for (; x; x /= 10) *--s = '0' + x % 10;
+ return s;
+}
+
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+
+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;
+ }
+
+ y = frexp((double)y, &e2) * 2;
+ if (y) e2--;
+
+ if ((t|32)=='a') {
+ long double round = 8.0;
+ ptrdiff_t re;
+
+ if (t&32) prefix += 9;
+ pl += 2;
+
+ if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+ else re=LDBL_MANT_DIG/4-1-p;
+
+ if (re) {
+ while (re--) round*=16;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ }
+ else {
+ y+=round;
+ y-=round;
+ }
+ }
+
+ 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 (p<0) p=6;
+
+ if (y) y *= 268435456.0, e2-=28;
+
+ if (e2<0) a=r=z=big;
+ else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+ do {
+ *z = (uint32_t)y;
+ y = 1000000000*(y-*z++);
+ } while (y);
+
+ while (e2>0) {
+ uint32_t carry=0;
+ int sh=MIN(29,e2);
+ for (d=z-1; d>=a; d--) {
+ uint64_t x = ((uint64_t)*d<<sh)+carry;
+ *d = x % 1000000000;
+ carry = (uint32_t)(x / 1000000000);
+ }
+ if (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;
+ }
+ 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)++;
+ }
+ for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
+ }
+ }
+ if (z>d+1) z=d+1;
+ }
+ for (; z>a && !z[-1]; z--);
+
+ if ((t|32)=='g') {
+ if (!p) p++;
+ if (p>e && e>=-4) {
+ t--;
+ p-=e+1;
+ }
+ else {
+ t-=2;
+ p--;
+ }
+ if (!(fl&ALT_FORM)) {
+ /* Count trailing zeros in last place */
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ else j=9;
+ if ((t|32)=='f')
+ p = MIN(p,MAX(0,9*(z-r-1)-j));
+ else
+ p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ }
+ }
+ 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;
+ }
+
+ 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);
+ }
+ 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);
+ }
+ 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;
+ }
+ ++fmt;
+
+ if (*fmt == '.') {
+ ++fmt;
+ for (p = 0; ISDIGIT(*fmt); ++fmt) {
+ p = 10 * p + (*fmt - '0');
+ }
+ }
+ 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;
+ }
+}
+
+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");
+ }
+ return f.str;
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/gc.c b/web/server/h2o/libh2o/deps/mruby/src/gc.c
new file mode 100644
index 00000000..d602bfb7
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/gc.c
@@ -0,0 +1,1824 @@
+/*
+** gc.c - garbage collector for mruby
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/proc.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/gc.h>
+#include <mruby/error.h>
+#include <mruby/throw.h>
+
+/*
+ = Tri-color Incremental Garbage Collection
+
+ mruby's GC is Tri-color Incremental GC with Mark & Sweep.
+ Algorithm details are omitted.
+ Instead, the implementation part is described below.
+
+ == Object's Color
+
+ Each object can be painted in three colors:
+
+ * White - Unmarked.
+ * Gray - Marked, But the child objects are unmarked.
+ * Black - Marked, the child objects are also marked.
+
+ == Two White Types
+
+ There're 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).
+
+ A and B will be switched just at the beginning of the next GC cycle. At
+ that time, all the dead objects have been swept, while the newly created
+ objects in the current GC cycle which finally remains White are now
+ regarded as dead objects. Instead of traversing all the White-A objects and
+ painting them as White-B, just switch the meaning of White-A and White-B as
+ this will be much cheaper.
+
+ As a result, the objects we sweep in the current GC cycle are always
+ left from the previous GC cycle. This allows us to sweep objects
+ incrementally, without the disturbance of the newly created objects.
+
+ == Execution Timing
+
+ GC Execution Time and Each step interval are decided by live objects count.
+ List of Adjustment API:
+
+ * gc_interval_ratio_set
+ * gc_step_ratio_set
+
+ For details, see the comments for each function.
+
+ == Write Barrier
+
+ mruby implementer and C extension library writer must insert a write
+ barrier when updating a reference from a field of an object.
+ When updating a reference from a field of object A to object B,
+ two different types of write barrier are available:
+
+ * mrb_field_write_barrier - target B object for a mark.
+ * mrb_write_barrier - target A object for a mark.
+
+ == Generational Mode
+
+ mruby's GC offers an Generational Mode while re-using the tri-color GC
+ infrastructure. It will treat the Black objects as Old objects after each
+ sweep phase, instead of painting them White. The key ideas are still the same
+ as traditional generational GC:
+
+ * Minor GC - just traverse the Young objects (Gray objects) in the mark
+ phase, then only sweep the newly created objects, and leave
+ the Old objects live.
+
+ * Major GC - same as a full regular GC cycle.
+
+ The difference from "traditional" generational GC is, that the major GC
+ in mruby is triggered incrementally in a tri-color manner.
+
+
+ For details, see the comments for each function.
+
+*/
+
+struct free_obj {
+ MRB_OBJECT_HEADER;
+ struct RBasic *next;
+};
+
+typedef struct {
+ union {
+ struct free_obj free;
+ struct RBasic basic;
+ struct RObject object;
+ struct RClass klass;
+ struct RString string;
+ struct RArray array;
+ struct RHash hash;
+ struct RRange range;
+ struct RData data;
+ struct RProc proc;
+ struct REnv env;
+ struct RException exc;
+ struct RBreak brk;
+#ifdef MRB_WORD_BOXING
+ struct RFloat floatv;
+ struct RCptr cptr;
+#endif
+ } as;
+} RVALUE;
+
+#ifdef GC_PROFILE
+#include <stdio.h>
+#include <sys/time.h>
+
+static double program_invoke_time = 0;
+static double gc_time = 0;
+static double gc_total_time = 0;
+
+static double
+gettimeofday_time(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec * 1e-6;
+}
+
+#define GC_INVOKE_TIME_REPORT(with) do {\
+ fprintf(stderr, "%s\n", with);\
+ fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
+ fprintf(stderr, "is_generational: %d\n", is_generational(gc));\
+ fprintf(stderr, "is_major_gc: %d\n", is_major_gc(gc));\
+} while(0)
+
+#define GC_TIME_START do {\
+ gc_time = gettimeofday_time();\
+} while(0)
+
+#define GC_TIME_STOP_AND_REPORT do {\
+ gc_time = gettimeofday_time() - gc_time;\
+ gc_total_time += gc_time;\
+ fprintf(stderr, "gc_state: %d\n", gc->state);\
+ fprintf(stderr, "live: %zu\n", gc->live);\
+ fprintf(stderr, "majorgc_old_threshold: %zu\n", gc->majorgc_old_threshold);\
+ fprintf(stderr, "gc_threshold: %zu\n", gc->threshold);\
+ fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
+ fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
+} while(0)
+#else
+#define GC_INVOKE_TIME_REPORT(s)
+#define GC_TIME_START
+#define GC_TIME_STOP_AND_REPORT
+#endif
+
+#ifdef GC_DEBUG
+#define DEBUG(x) (x)
+#else
+#define DEBUG(x)
+#endif
+
+#ifndef MRB_HEAP_PAGE_SIZE
+#define MRB_HEAP_PAGE_SIZE 1024
+#endif
+
+#define GC_STEP_SIZE 1024
+
+/* white: 011, black: 100, gray: 000 */
+#define GC_GRAY 0
+#define GC_WHITE_A 1
+#define GC_WHITE_B (1 << 1)
+#define GC_BLACK (1 << 2)
+#define GC_WHITES (GC_WHITE_A | GC_WHITE_B)
+#define GC_COLOR_MASK 7
+
+#define paint_gray(o) ((o)->color = GC_GRAY)
+#define paint_black(o) ((o)->color = GC_BLACK)
+#define paint_white(o) ((o)->color = GC_WHITES)
+#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 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_API void*
+mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
+{
+ void *p2;
+
+ p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
+ if (!p2 && len > 0 && mrb->gc.heaps) {
+ mrb_full_gc(mrb);
+ p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
+ }
+
+ return p2;
+}
+
+MRB_API void*
+mrb_realloc(mrb_state *mrb, void *p, size_t len)
+{
+ void *p2;
+
+ 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));
+ }
+ }
+ else {
+ mrb->gc.out_of_memory = FALSE;
+ }
+
+ return p2;
+}
+
+MRB_API void*
+mrb_malloc(mrb_state *mrb, size_t len)
+{
+ return mrb_realloc(mrb, 0, len);
+}
+
+MRB_API void*
+mrb_malloc_simple(mrb_state *mrb, size_t len)
+{
+ return mrb_realloc_simple(mrb, 0, len);
+}
+
+MRB_API void*
+mrb_calloc(mrb_state *mrb, size_t nelem, size_t len)
+{
+ void *p;
+
+ if (nelem > 0 && len > 0 &&
+ nelem <= SIZE_MAX / len) {
+ size_t size;
+ size = nelem * len;
+ p = mrb_malloc(mrb, size);
+
+ memset(p, 0, size);
+ }
+ else {
+ p = NULL;
+ }
+
+ return p;
+}
+
+MRB_API void
+mrb_free(mrb_state *mrb, void *p)
+{
+ (mrb->allocf)(mrb, p, 0, mrb->allocf_ud);
+}
+
+MRB_API mrb_bool
+mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) {
+ return is_dead(&mrb->gc, object);
+}
+
+static void
+link_heap_page(mrb_gc *gc, mrb_heap_page *page)
+{
+ page->next = gc->heaps;
+ if (gc->heaps)
+ gc->heaps->prev = page;
+ gc->heaps = page;
+}
+
+static void
+unlink_heap_page(mrb_gc *gc, mrb_heap_page *page)
+{
+ if (page->prev)
+ page->prev->next = page->next;
+ if (page->next)
+ page->next->prev = page->prev;
+ if (gc->heaps == page)
+ gc->heaps = page->next;
+ page->prev = NULL;
+ page->next = NULL;
+}
+
+static void
+link_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
+{
+ page->free_next = gc->free_heaps;
+ if (gc->free_heaps) {
+ gc->free_heaps->free_prev = page;
+ }
+ gc->free_heaps = page;
+}
+
+static void
+unlink_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
+{
+ if (page->free_prev)
+ page->free_prev->free_next = page->free_next;
+ if (page->free_next)
+ page->free_next->free_prev = page->free_prev;
+ if (gc->free_heaps == page)
+ gc->free_heaps = page->free_next;
+ page->free_prev = NULL;
+ page->free_next = NULL;
+}
+
+static void
+add_heap(mrb_state *mrb, mrb_gc *gc)
+{
+ mrb_heap_page *page = (mrb_heap_page *)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE));
+ RVALUE *p, *e;
+ struct RBasic *prev = NULL;
+
+ for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ p->as.free.tt = MRB_TT_FREE;
+ p->as.free.next = prev;
+ prev = &p->as.basic;
+ }
+ page->freelist = prev;
+
+ link_heap_page(gc, page);
+ link_free_heap_page(gc, page);
+}
+
+#define DEFAULT_GC_INTERVAL_RATIO 200
+#define DEFAULT_GC_STEP_RATIO 200
+#define DEFAULT_MAJOR_GC_INC_RATIO 200
+#define is_generational(gc) ((gc)->generational)
+#define is_major_gc(gc) (is_generational(gc) && (gc)->full)
+#define is_minor_gc(gc) (is_generational(gc) && !(gc)->full)
+
+void
+mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
+{
+#ifndef MRB_GC_FIXED_ARENA
+ gc->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
+ gc->arena_capa = MRB_GC_ARENA_SIZE;
+#endif
+
+ gc->current_white_part = GC_WHITE_A;
+ gc->heaps = NULL;
+ gc->free_heaps = NULL;
+ add_heap(mrb, gc);
+ gc->interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
+ gc->step_ratio = DEFAULT_GC_STEP_RATIO;
+#ifndef MRB_GC_TURN_OFF_GENERATIONAL
+ gc->generational = TRUE;
+ gc->full = TRUE;
+#endif
+
+#ifdef GC_PROFILE
+ program_invoke_time = gettimeofday_time();
+#endif
+}
+
+static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
+
+void
+free_heap(mrb_state *mrb, mrb_gc *gc)
+{
+ mrb_heap_page *page = gc->heaps;
+ mrb_heap_page *tmp;
+ RVALUE *p, *e;
+
+ while (page) {
+ tmp = page;
+ page = page->next;
+ for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ if (p->as.free.tt != MRB_TT_FREE)
+ obj_free(mrb, &p->as.basic, TRUE);
+ }
+ mrb_free(mrb, tmp);
+ }
+}
+
+void
+mrb_gc_destroy(mrb_state *mrb, mrb_gc *gc)
+{
+ free_heap(mrb, gc);
+#ifndef MRB_GC_FIXED_ARENA
+ mrb_free(mrb, gc->arena);
+#endif
+}
+
+static void
+gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
+{
+#ifdef MRB_GC_FIXED_ARENA
+ if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
+ /* arena overflow error */
+ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err));
+ }
+#else
+ if (gc->arena_idx >= gc->arena_capa) {
+ /* extend arena */
+ gc->arena_capa = (int)(gc->arena_capa * 1.5);
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*gc->arena_capa);
+ }
+#endif
+ gc->arena[gc->arena_idx++] = p;
+}
+
+/* mrb_gc_protect() leaves the object in the arena */
+MRB_API void
+mrb_gc_protect(mrb_state *mrb, mrb_value obj)
+{
+ if (mrb_immediate_p(obj)) return;
+ gc_protect(mrb, &mrb->gc, mrb_basic_ptr(obj));
+}
+
+#define GC_ROOT_NAME "_gc_root_"
+
+/* mrb_gc_register() keeps the object from GC.
+
+ Register your object when it's exported to C world,
+ without reference from Ruby world, e.g. callback
+ arguments. Don't forget to remove the object using
+ mrb_gc_unregister, otherwise your object will leak.
+*/
+
+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);
+
+ if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) {
+ table = mrb_ary_new(mrb);
+ mrb_gv_set(mrb, root, table);
+ }
+ mrb_ary_push(mrb, table, obj);
+}
+
+/* mrb_gc_unregister() removes the object from GC root. */
+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);
+ struct RArray *a;
+ mrb_int i;
+
+ if (mrb_nil_p(table)) return;
+ if (mrb_type(table) != MRB_TT_ARRAY) {
+ 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)) {
+ mrb_int len = ARY_LEN(a)-1;
+ mrb_value *ptr = ARY_PTR(a);
+
+ ARY_SET_LEN(a, len);
+ memmove(&ptr[i], &ptr[i + 1], (len - i) * sizeof(mrb_value));
+ break;
+ }
+ }
+}
+
+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 } } };
+ mrb_gc *gc = &mrb->gc;
+
+ if (cls) {
+ enum mrb_vtype tt;
+
+ switch (cls->tt) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_ENV:
+ break;
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
+ }
+ tt = MRB_INSTANCE_TT(cls);
+ if (tt != MRB_TT_FALSE &&
+ ttype != MRB_TT_SCLASS &&
+ ttype != MRB_TT_ICLASS &&
+ ttype != MRB_TT_ENV &&
+ ttype != tt) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
+ }
+ }
+
+#ifdef MRB_GC_STRESS
+ mrb_full_gc(mrb);
+#endif
+ if (gc->threshold < gc->live) {
+ mrb_incremental_gc(mrb);
+ }
+ if (gc->free_heaps == NULL) {
+ add_heap(mrb, gc);
+ }
+
+ p = gc->free_heaps->freelist;
+ gc->free_heaps->freelist = ((struct free_obj*)p)->next;
+ if (gc->free_heaps->freelist == NULL) {
+ unlink_free_heap_page(gc, gc->free_heaps);
+ }
+
+ gc->live++;
+ gc_protect(mrb, gc, p);
+ *(RVALUE *)p = RVALUE_zero;
+ p->tt = ttype;
+ p->c = cls;
+ paint_partial_white(gc, p);
+ return p;
+}
+
+static inline void
+add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
+{
+#ifdef MRB_GC_STRESS
+ if (obj->tt > MRB_TT_MAXDEFINE) {
+ abort();
+ }
+#endif
+ paint_gray(obj);
+ obj->gcnext = gc->gray_list;
+ gc->gray_list = obj;
+}
+
+static void
+mark_context_stack(mrb_state *mrb, struct mrb_context *c)
+{
+ size_t i;
+ size_t e;
+ mrb_value nil;
+ int nregs;
+
+ if (c->stack == NULL) return;
+ e = c->stack - c->stbase;
+ if (c->ci) {
+ nregs = c->ci->argc + 2;
+ if (c->ci->nregs > nregs)
+ nregs = c->ci->nregs;
+ e += nregs;
+ }
+ if (c->stbase + e > c->stend) e = c->stend - c->stbase;
+ for (i=0; i<e; i++) {
+ mrb_value v = c->stbase[i];
+
+ if (!mrb_immediate_p(v)) {
+ mrb_gc_mark(mrb, mrb_basic_ptr(v));
+ }
+ }
+ e = c->stend - c->stbase;
+ nil = mrb_nil_value();
+ for (; i<e; i++) {
+ c->stbase[i] = nil;
+ }
+}
+
+static void
+mark_context(mrb_state *mrb, struct mrb_context *c)
+{
+ int i;
+ mrb_callinfo *ci;
+
+ if (c->status == MRB_FIBER_TERMINATED) return;
+
+ /* mark VM stack */
+ mark_context_stack(mrb, 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);
+ }
+ }
+ /* mark ensure stack */
+ for (i=0; i<c->esize; i++) {
+ if (c->ensure[i] == NULL) break;
+ mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
+ }
+ /* mark fibers */
+ mrb_gc_mark(mrb, (struct RBasic*)c->fib);
+ if (c->prev) {
+ mark_context(mrb, c->prev);
+ }
+}
+
+static void
+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:
+ {
+ struct RClass *c = (struct RClass*)obj;
+ if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN))
+ mrb_gc_mark_mt(mrb, c);
+ mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super);
+ }
+ break;
+
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ {
+ struct RClass *c = (struct RClass*)obj;
+
+ mrb_gc_mark_mt(mrb, c);
+ mrb_gc_mark(mrb, (struct RBasic*)c->super);
+ }
+ /* fall through */
+
+ case MRB_TT_OBJECT:
+ case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
+ mrb_gc_mark_iv(mrb, (struct RObject*)obj);
+ break;
+
+ case MRB_TT_PROC:
+ {
+ struct RProc *p = (struct RProc*)obj;
+
+ mrb_gc_mark(mrb, (struct RBasic*)p->env);
+ mrb_gc_mark(mrb, (struct RBasic*)p->target_class);
+ if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
+ mrb_gc_mark(mrb, (struct RBasic*)p->body.irep->target_class);
+ }
+ }
+ break;
+
+ case MRB_TT_ENV:
+ {
+ struct REnv *e = (struct REnv*)obj;
+ mrb_int i, len;
+
+ if (MRB_ENV_STACK_SHARED_P(e)) {
+ if (e->cxt.c->fib) {
+ mrb_gc_mark(mrb, (struct RBasic*)e->cxt.c->fib);
+ }
+ break;
+ }
+ len = MRB_ENV_STACK_LEN(e);
+ for (i=0; i<len; i++) {
+ mrb_gc_mark_value(mrb, e->stack[i]);
+ }
+ }
+ break;
+
+ case MRB_TT_FIBER:
+ {
+ struct mrb_context *c = ((struct RFiber*)obj)->cxt;
+
+ if (c) mark_context(mrb, c);
+ }
+ break;
+
+ case MRB_TT_ARRAY:
+ {
+ struct RArray *a = (struct RArray*)obj;
+ size_t i, e;
+
+ for (i=0,e=ARY_LEN(a); i<e; i++) {
+ mrb_gc_mark_value(mrb, ARY_PTR(a)[i]);
+ }
+ }
+ break;
+
+ case MRB_TT_HASH:
+ mrb_gc_mark_iv(mrb, (struct RObject*)obj);
+ mrb_gc_mark_hash(mrb, (struct RHash*)obj);
+ break;
+
+ case MRB_TT_STRING:
+ break;
+
+ case MRB_TT_RANGE:
+ {
+ struct RRange *r = (struct RRange*)obj;
+
+ if (r->edges) {
+ mrb_gc_mark_value(mrb, r->edges->beg);
+ mrb_gc_mark_value(mrb, r->edges->end);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+MRB_API void
+mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
+{
+ if (obj == 0) return;
+ if (!is_white(obj)) return;
+ mrb_assert((obj)->tt != MRB_TT_FREE);
+ add_gray_list(mrb, &mrb->gc, obj);
+}
+
+static void
+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;
+
+ case MRB_TT_FLOAT:
+#ifdef MRB_WORD_BOXING
+ break;
+#else
+ return;
+#endif
+
+ case MRB_TT_OBJECT:
+ mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ break;
+
+ case MRB_TT_EXCEPTION:
+ mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ break;
+
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ mrb_gc_free_mt(mrb, (struct RClass*)obj);
+ mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ break;
+ case MRB_TT_ICLASS:
+ if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN))
+ mrb_gc_free_mt(mrb, (struct RClass*)obj);
+ break;
+ case MRB_TT_ENV:
+ {
+ struct REnv *e = (struct REnv*)obj;
+
+ if (MRB_ENV_STACK_SHARED_P(e)) {
+ /* cannot be freed */
+ return;
+ }
+ mrb_free(mrb, e->stack);
+ e->stack = NULL;
+ }
+ break;
+
+ case MRB_TT_FIBER:
+ {
+ struct mrb_context *c = ((struct RFiber*)obj)->cxt;
+
+ if (!end && c && c != mrb->root_c) {
+ mrb_callinfo *ci = c->ci;
+ mrb_callinfo *ce = c->cibase;
+
+ 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)) {
+ mrb_env_unshare(mrb, e);
+ }
+ ci--;
+ }
+ mrb_free_context(mrb, c);
+ }
+ }
+ break;
+
+ case MRB_TT_ARRAY:
+ if (ARY_SHARED_P(obj))
+ mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared);
+ else if (!ARY_EMBED_P(obj))
+ mrb_free(mrb, ((struct RArray*)obj)->as.heap.ptr);
+ break;
+
+ case MRB_TT_HASH:
+ mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ mrb_gc_free_hash(mrb, (struct RHash*)obj);
+ break;
+
+ case MRB_TT_STRING:
+ mrb_gc_free_str(mrb, (struct RString*)obj);
+ break;
+
+ case MRB_TT_PROC:
+ {
+ struct RProc *p = (struct RProc*)obj;
+
+ if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
+ mrb_irep_decref(mrb, p->body.irep);
+ }
+ }
+ break;
+
+ case MRB_TT_RANGE:
+ mrb_free(mrb, ((struct RRange*)obj)->edges);
+ break;
+
+ case MRB_TT_DATA:
+ {
+ struct RData *d = (struct RData*)obj;
+ if (d->type && d->type->dfree) {
+ d->type->dfree(mrb, d->data);
+ }
+ mrb_gc_free_iv(mrb, (struct RObject*)obj);
+ }
+ break;
+
+ default:
+ break;
+ }
+ obj->tt = MRB_TT_FREE;
+}
+
+static void
+root_scan_phase(mrb_state *mrb, mrb_gc *gc)
+{
+ int i, e;
+
+ if (!is_minor_gc(gc)) {
+ gc->gray_list = NULL;
+ gc->atomic_gray_list = NULL;
+ }
+
+ mrb_gc_mark_gv(mrb);
+ /* mark arena */
+ for (i=0,e=gc->arena_idx; i<e; i++) {
+ mrb_gc_mark(mrb, gc->arena[i]);
+ }
+ /* mark class hierarchy */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
+
+ /* mark built-in classes */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->range_class);
+
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_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);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module);
+
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class);
+
+ /* mark top_self */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
+ /* mark exception */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
+ /* mark pre-allocated exception */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err);
+#ifdef MRB_GC_FIXED_ARENA
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err);
+#endif
+
+ mark_context(mrb, mrb->c);
+ if (mrb->root_c != mrb->c) {
+ mark_context(mrb, mrb->root_c);
+ }
+}
+
+static size_t
+gc_gray_mark(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++;
+ break;
+
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ {
+ struct RClass *c = (struct RClass*)obj;
+
+ children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
+ children += mrb_gc_mark_mt_size(mrb, c);
+ children++;
+ }
+ break;
+
+ case MRB_TT_OBJECT:
+ case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
+ children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
+ break;
+
+ case MRB_TT_ENV:
+ children += (int)obj->flags;
+ break;
+
+ case MRB_TT_FIBER:
+ {
+ struct mrb_context *c = ((struct RFiber*)obj)->cxt;
+ size_t i;
+ mrb_callinfo *ci;
+
+ if (!c) break;
+ /* mark stack */
+ i = c->stack - c->stbase;
+ if (c->ci) i += c->ci->nregs;
+ 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++)
+ ;
+ }
+ children += i;
+ }
+ break;
+
+ case MRB_TT_ARRAY:
+ {
+ struct RArray *a = (struct RArray*)obj;
+ children += ARY_LEN(a);
+ }
+ break;
+
+ case MRB_TT_HASH:
+ children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
+ children += mrb_gc_mark_hash_size(mrb, (struct RHash*)obj);
+ break;
+
+ case MRB_TT_PROC:
+ case MRB_TT_RANGE:
+ children+=2;
+ break;
+
+ default:
+ break;
+ }
+ return children;
+}
+
+
+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;
+ }
+}
+
+
+static size_t
+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);
+ }
+
+ return tried_marks;
+}
+
+static void
+final_marking_phase(mrb_state *mrb, mrb_gc *gc)
+{
+ int i, e;
+
+ /* mark arena */
+ for (i=0,e=gc->arena_idx; i<e; i++) {
+ mrb_gc_mark(mrb, gc->arena[i]);
+ }
+ mrb_gc_mark_gv(mrb);
+ mark_context(mrb, mrb->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);
+ gc->gray_list = gc->atomic_gray_list;
+ gc->atomic_gray_list = NULL;
+ gc_mark_gray_list(mrb, gc);
+ mrb_assert(gc->gray_list == NULL);
+}
+
+static void
+prepare_incremental_sweep(mrb_state *mrb, mrb_gc *gc)
+{
+ gc->state = MRB_GC_STATE_SWEEP;
+ gc->sweeps = gc->heaps;
+ gc->live_after_mark = gc->live;
+}
+
+static size_t
+incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
+{
+ mrb_heap_page *page = gc->sweeps;
+ size_t tried_sweep = 0;
+
+ while (page && (tried_sweep < limit)) {
+ RVALUE *p = objects(page);
+ RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
+ size_t freed = 0;
+ mrb_bool dead_slot = TRUE;
+ mrb_bool full = (page->freelist == NULL);
+
+ if (is_minor_gc(gc) && page->old) {
+ /* skip a slot which doesn't contain any young object */
+ p = e;
+ dead_slot = FALSE;
+ }
+ while (p<e) {
+ if (is_dead(gc, &p->as.basic)) {
+ if (p->as.basic.tt != MRB_TT_FREE) {
+ obj_free(mrb, &p->as.basic, FALSE);
+ if (p->as.basic.tt == MRB_TT_FREE) {
+ p->as.free.next = page->freelist;
+ page->freelist = (struct RBasic*)p;
+ freed++;
+ }
+ else {
+ dead_slot = FALSE;
+ }
+ }
+ }
+ else {
+ if (!is_generational(gc))
+ paint_partial_white(gc, &p->as.basic); /* next gc target */
+ dead_slot = FALSE;
+ }
+ p++;
+ }
+
+ /* free dead slot */
+ if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
+ mrb_heap_page *next = page->next;
+
+ unlink_heap_page(gc, page);
+ unlink_free_heap_page(gc, page);
+ mrb_free(mrb, page);
+ page = next;
+ }
+ else {
+ if (full && freed > 0) {
+ link_free_heap_page(gc, page);
+ }
+ if (page->freelist == NULL && is_minor_gc(gc))
+ page->old = TRUE;
+ else
+ page->old = FALSE;
+ page = page->next;
+ }
+ tried_sweep += MRB_HEAP_PAGE_SIZE;
+ gc->live -= freed;
+ gc->live_after_mark -= freed;
+ }
+ gc->sweeps = page;
+ return tried_sweep;
+}
+
+static size_t
+incremental_gc(mrb_state *mrb, mrb_gc *gc, size_t limit)
+{
+ switch (gc->state) {
+ case MRB_GC_STATE_ROOT:
+ root_scan_phase(mrb, gc);
+ gc->state = MRB_GC_STATE_MARK;
+ flip_white_part(gc);
+ return 0;
+ case MRB_GC_STATE_MARK:
+ if (gc->gray_list) {
+ return incremental_marking_phase(mrb, gc, limit);
+ }
+ else {
+ final_marking_phase(mrb, gc);
+ prepare_incremental_sweep(mrb, gc);
+ return 0;
+ }
+ case MRB_GC_STATE_SWEEP: {
+ size_t tried_sweep = 0;
+ tried_sweep = incremental_sweep_phase(mrb, gc, limit);
+ if (tried_sweep == 0)
+ gc->state = MRB_GC_STATE_ROOT;
+ return tried_sweep;
+ }
+ default:
+ /* unknown state */
+ mrb_assert(0);
+ return 0;
+ }
+}
+
+static void
+incremental_gc_until(mrb_state *mrb, mrb_gc *gc, mrb_gc_state to_state)
+{
+ do {
+ incremental_gc(mrb, gc, SIZE_MAX);
+ } while (gc->state != to_state);
+}
+
+static void
+incremental_gc_step(mrb_state *mrb, mrb_gc *gc)
+{
+ size_t limit = 0, result = 0;
+ limit = (GC_STEP_SIZE/100) * gc->step_ratio;
+ while (result < limit) {
+ result += incremental_gc(mrb, gc, limit);
+ if (gc->state == MRB_GC_STATE_ROOT)
+ break;
+ }
+
+ gc->threshold = gc->live + GC_STEP_SIZE;
+}
+
+static void
+clear_all_old(mrb_state *mrb, mrb_gc *gc)
+{
+ mrb_bool origin_mode = gc->generational;
+
+ mrb_assert(is_generational(gc));
+ if (is_major_gc(gc)) {
+ /* finish the half baked GC */
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ }
+
+ /* Sweep the dead objects, then reset all the live objects
+ * (including all the old objects, of course) to white. */
+ gc->generational = FALSE;
+ prepare_incremental_sweep(mrb, gc);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->generational = origin_mode;
+
+ /* The gray objects have already been painted as white */
+ gc->atomic_gray_list = gc->gray_list = NULL;
+}
+
+MRB_API void
+mrb_incremental_gc(mrb_state *mrb)
+{
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled || gc->iterating) return;
+
+ GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
+ GC_TIME_START;
+
+ if (is_minor_gc(gc)) {
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ }
+ else {
+ incremental_gc_step(mrb, gc);
+ }
+
+ if (gc->state == MRB_GC_STATE_ROOT) {
+ mrb_assert(gc->live >= gc->live_after_mark);
+ gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio;
+ if (gc->threshold < GC_STEP_SIZE) {
+ gc->threshold = GC_STEP_SIZE;
+ }
+
+ if (is_major_gc(gc)) {
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
+ }
+ else if (is_minor_gc(gc)) {
+ if (gc->live > gc->majorgc_old_threshold) {
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
+ }
+ }
+ }
+
+ GC_TIME_STOP_AND_REPORT;
+}
+
+/* Perform a full gc cycle */
+MRB_API void
+mrb_full_gc(mrb_state *mrb)
+{
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled || gc->iterating) return;
+
+ GC_INVOKE_TIME_REPORT("mrb_full_gc()");
+ GC_TIME_START;
+
+ if (is_generational(gc)) {
+ /* clear all the old objects back to young */
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
+ }
+ else if (gc->state != MRB_GC_STATE_ROOT) {
+ /* finish half baked GC cycle */
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ }
+
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio;
+
+ if (is_generational(gc)) {
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
+ }
+
+ GC_TIME_STOP_AND_REPORT;
+}
+
+MRB_API void
+mrb_garbage_collect(mrb_state *mrb)
+{
+ mrb_full_gc(mrb);
+}
+
+/*
+ * Field write barrier
+ * Paint obj(Black) -> value(White) to obj(Black) -> value(Gray).
+ */
+
+MRB_API void
+mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value)
+{
+ mrb_gc *gc = &mrb->gc;
+
+ if (!is_black(obj)) return;
+ if (!is_white(value)) return;
+
+ mrb_assert(gc->state == MRB_GC_STATE_MARK || (!is_dead(gc, value) && !is_dead(gc, obj)));
+ mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT);
+
+ if (is_generational(gc) || gc->state == MRB_GC_STATE_MARK) {
+ add_gray_list(mrb, gc, value);
+ }
+ else {
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
+ paint_partial_white(gc, obj); /* for never write barriers */
+ }
+}
+
+/*
+ * Write barrier
+ * Paint obj(Black) to obj(Gray).
+ *
+ * The object that is painted gray will be traversed atomically in final
+ * mark phase. So you use this write barrier if it's frequency written spot.
+ * e.g. Set element on Array.
+ */
+
+MRB_API void
+mrb_write_barrier(mrb_state *mrb, struct RBasic *obj)
+{
+ mrb_gc *gc = &mrb->gc;
+
+ if (!is_black(obj)) return;
+
+ mrb_assert(!is_dead(gc, obj));
+ mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT);
+ paint_gray(obj);
+ obj->gcnext = gc->atomic_gray_list;
+ gc->atomic_gray_list = obj;
+}
+
+/*
+ * call-seq:
+ * GC.start -> nil
+ *
+ * Initiates full garbage collection.
+ *
+ */
+
+static mrb_value
+gc_start(mrb_state *mrb, mrb_value obj)
+{
+ mrb_full_gc(mrb);
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * GC.enable -> true or false
+ *
+ * Enables garbage collection, returning <code>true</code> if garbage
+ * collection was previously disabled.
+ *
+ * GC.disable #=> false
+ * GC.enable #=> true
+ * GC.enable #=> false
+ *
+ */
+
+static mrb_value
+gc_enable(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool old = mrb->gc.disabled;
+
+ mrb->gc.disabled = FALSE;
+
+ return mrb_bool_value(old);
+}
+
+/*
+ * call-seq:
+ * GC.disable -> true or false
+ *
+ * Disables garbage collection, returning <code>true</code> if garbage
+ * collection was already disabled.
+ *
+ * GC.disable #=> false
+ * GC.disable #=> true
+ *
+ */
+
+static mrb_value
+gc_disable(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool old = mrb->gc.disabled;
+
+ mrb->gc.disabled = TRUE;
+
+ return mrb_bool_value(old);
+}
+
+/*
+ * call-seq:
+ * GC.interval_ratio -> fixnum
+ *
+ * Returns ratio of GC interval. Default value is 200(%).
+ *
+ */
+
+static mrb_value
+gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_fixnum_value(mrb->gc.interval_ratio);
+}
+
+/*
+ * call-seq:
+ * GC.interval_ratio = fixnum -> nil
+ *
+ * Updates ratio of GC interval. Default value is 200(%).
+ * GC start as soon as after end all step of GC if you set 100(%).
+ *
+ */
+
+static mrb_value
+gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
+{
+ mrb_int ratio;
+
+ mrb_get_args(mrb, "i", &ratio);
+ mrb->gc.interval_ratio = ratio;
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * GC.step_ratio -> fixnum
+ *
+ * Returns step span ratio of Incremental GC. Default value is 200(%).
+ *
+ */
+
+static mrb_value
+gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_fixnum_value(mrb->gc.step_ratio);
+}
+
+/*
+ * call-seq:
+ * GC.step_ratio = fixnum -> nil
+ *
+ * Updates step span ratio of Incremental GC. Default value is 200(%).
+ * 1 step of incrementalGC becomes long if a rate is big.
+ *
+ */
+
+static mrb_value
+gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
+{
+ mrb_int ratio;
+
+ mrb_get_args(mrb, "i", &ratio);
+ mrb->gc.step_ratio = ratio;
+ return mrb_nil_value();
+}
+
+static void
+change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
+{
+ if (gc->disabled || gc->iterating) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "generational mode changed when GC disabled");
+ return;
+ }
+ if (is_generational(gc) && !enable) {
+ clear_all_old(mrb, gc);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
+ gc->full = FALSE;
+ }
+ else if (!is_generational(gc) && enable) {
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
+ }
+ gc->generational = enable;
+}
+
+/*
+ * call-seq:
+ * GC.generational_mode -> true or false
+ *
+ * Returns generational or normal gc mode.
+ *
+ */
+
+static mrb_value
+gc_generational_mode_get(mrb_state *mrb, mrb_value self)
+{
+ return mrb_bool_value(mrb->gc.generational);
+}
+
+/*
+ * call-seq:
+ * GC.generational_mode = true or false -> true or false
+ *
+ * Changes to generational or normal gc mode.
+ *
+ */
+
+static mrb_value
+gc_generational_mode_set(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool enable;
+
+ mrb_get_args(mrb, "b", &enable);
+ if (mrb->gc.generational != enable)
+ change_gen_gc_mode(mrb, &mrb->gc, enable);
+
+ return mrb_bool_value(enable);
+}
+
+
+static void
+gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
+{
+ mrb_heap_page* page;
+
+ mrb_full_gc(mrb);
+ page = gc->heaps;
+ while (page != NULL) {
+ RVALUE *p;
+ int i;
+
+ p = objects(page);
+ for (i=0; i < MRB_HEAP_PAGE_SIZE; i++) {
+ if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK)
+ return;
+ }
+ page = page->next;
+ }
+}
+
+void
+mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
+{
+ mrb_bool iterating = mrb->gc.iterating;
+
+ mrb->gc.iterating = TRUE;
+ if (iterating) {
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+ }
+ else {
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+ mrb->jmp = prev_jmp;
+ mrb->gc.iterating = iterating;
+ } MRB_CATCH(&c_jmp) {
+ mrb->gc.iterating = iterating;
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
+ } MRB_END_EXC(&c_jmp);
+ }
+}
+
+#ifdef GC_TEST
+#ifdef GC_DEBUG
+static mrb_value gc_test(mrb_state *, mrb_value);
+#endif
+#endif
+
+void
+mrb_init_gc(mrb_state *mrb)
+{
+ struct RClass *gc;
+
+ gc = mrb_define_module(mrb, "GC");
+
+ mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, gc, "enable", gc_enable, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, gc, "disable", gc_disable, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, gc, "interval_ratio", gc_interval_ratio_get, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, gc, "interval_ratio=", gc_interval_ratio_set, MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, gc, "step_ratio", gc_step_ratio_get, MRB_ARGS_NONE());
+ 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/web/server/h2o/libh2o/deps/mruby/src/hash.c b/web/server/h2o/libh2o/deps/mruby/src/hash.c
new file mode 100644
index 00000000..93d55018
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/hash.c
@@ -0,0 +1,905 @@
+/*
+** hash.c - Hash class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/hash.h>
+#include <mruby/khash.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+
+/* a function to get hash value of a float number */
+mrb_int mrb_float_id(mrb_float f);
+
+static inline khint_t
+mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
+{
+ enum mrb_vtype t = mrb_type(key);
+ mrb_value hv;
+ khint_t h;
+
+ switch (t) {
+ case MRB_TT_STRING:
+ h = mrb_str_hash(mrb, key);
+ break;
+
+ case MRB_TT_TRUE:
+ case MRB_TT_FALSE:
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_FLOAT:
+ h = (khint_t)mrb_obj_id(key);
+ break;
+
+ default:
+ hv = mrb_funcall(mrb, key, "hash", 0);
+ h = (khint_t)t ^ mrb_fixnum(hv);
+ break;
+ }
+ return kh_int_hash_func(mrb, h);
+}
+
+static inline khint_t
+mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ enum mrb_vtype t = mrb_type(a);
+
+ switch (t) {
+ case MRB_TT_STRING:
+ return mrb_str_equal(mrb, a, b);
+
+ case MRB_TT_SYMBOL:
+ if (mrb_type(b) != MRB_TT_SYMBOL) 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);
+ case MRB_TT_FLOAT:
+ return (mrb_float)mrb_fixnum(a) == mrb_float(b);
+ default:
+ return FALSE;
+ }
+
+ 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;
+ }
+
+ default:
+ return mrb_eql(mrb, a, b);
+ }
+}
+
+KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal)
+
+static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
+
+static inline mrb_value
+mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
+{
+ 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;
+}
+
+#define KEY(key) mrb_hash_ht_key(mrb, key)
+
+void
+mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash)
+{
+ khiter_t k;
+ khash_t(ht) *h = hash->ht;
+
+ if (!h) return;
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ mrb_value key = kh_key(h, k);
+ mrb_value val = kh_value(h, k).v;
+
+ mrb_gc_mark_value(mrb, key);
+ mrb_gc_mark_value(mrb, val);
+ }
+ }
+}
+
+size_t
+mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash)
+{
+ if (!hash->ht) return 0;
+ return kh_size(hash->ht)*2;
+}
+
+void
+mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
+{
+ if (hash->ht) kh_destroy(ht, mrb, hash->ht);
+}
+
+
+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);
+ /* khash needs 1/4 empty space so it is not resized immediately */
+ h->ht = kh_init_size(ht, mrb, capa*4/3);
+ h->iv = 0;
+ return mrb_obj_value(h);
+}
+
+MRB_API mrb_value
+mrb_hash_new(mrb_state *mrb)
+{
+ return mrb_hash_new_capa(mrb, 0);
+}
+
+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);
+
+MRB_API mrb_value
+mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+ mrb_sym mid;
+
+ if (h) {
+ k = kh_get(ht, mrb, h, key);
+ if (k != kh_end(h))
+ return kh_value(h, k).v;
+ }
+
+ mid = mrb_intern_lit(mrb, "default");
+ if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
+ return hash_default(mrb, hash, key);
+ }
+ /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
+ return mrb_funcall_argv(mrb, hash, mid, 1, &key);
+}
+
+MRB_API mrb_value
+mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+
+ if (h) {
+ k = kh_get(ht, mrb, h, key);
+ if (k != kh_end(h))
+ return kh_value(h, k).v;
+ }
+
+ /* not found */
+ return def;
+}
+
+MRB_API void
+mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
+{
+ khash_t(ht) *h;
+ khiter_t k;
+ int r;
+
+ mrb_hash_modify(mrb, hash);
+ h = RHASH_TBL(hash);
+
+ if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb);
+ k = kh_put2(ht, mrb, h, key, &r);
+ kh_value(h, k).v = val;
+
+ if (r != 0) {
+ /* expand */
+ int ai = mrb_gc_arena_save(mrb);
+ key = kh_key(h, k) = KEY(key);
+ mrb_gc_arena_restore(mrb, ai);
+ kh_value(h, k).n = kh_size(h)-1;
+ }
+
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val);
+ return;
+}
+
+static mrb_value
+mrb_hash_dup(mrb_state *mrb, mrb_value hash)
+{
+ struct RHash* ret;
+ khash_t(ht) *h, *ret_h;
+ khiter_t k, ret_k;
+ mrb_value ifnone, vret;
+
+ h = RHASH_TBL(hash);
+ ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
+ ret->ht = kh_init(ht, mrb);
+
+ if (h && kh_size(h) > 0) {
+ ret_h = ret->ht;
+
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ int ai = mrb_gc_arena_save(mrb);
+ ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h, k)));
+ mrb_gc_arena_restore(mrb, ai);
+ kh_val(ret_h, ret_k).v = kh_val(h, k).v;
+ kh_val(ret_h, ret_k).n = kh_size(ret_h)-1;
+ }
+ }
+ }
+
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_DEFAULT;
+ }
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_PROC_DEFAULT;
+ }
+ vret = mrb_obj_value(ret);
+ ifnone = RHASH_IFNONE(hash);
+ if (!mrb_nil_p(ifnone)) {
+ mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ }
+ return vret;
+}
+
+MRB_API mrb_value
+mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
+{
+ return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash");
+}
+
+MRB_API khash_t(ht)*
+mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+
+ if (!h) {
+ return RHASH_TBL(hash) = kh_init(ht, mrb);
+ }
+ return h;
+}
+
+static void
+mrb_hash_modify(mrb_state *mrb, mrb_value hash)
+{
+ if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash");
+ }
+ mrb_hash_tbl(mrb, hash);
+}
+
+/* 15.2.13.4.16 */
+/*
+ * call-seq:
+ * Hash.new -> new_hash
+ * Hash.new(obj) -> new_hash
+ * Hash.new {|hash, key| block } -> new_hash
+ *
+ * Returns a new, empty hash. If this hash is subsequently accessed by
+ * a key that doesn't correspond to a hash entry, the value returned
+ * depends on the style of <code>new</code> used to create the hash. In
+ * the first form, the access returns <code>nil</code>. If
+ * <i>obj</i> is specified, this single object will be used for
+ * all <em>default values</em>. If a block is specified, it will be
+ * called with the hash object and the key, and should return the
+ * default value. It is the block's responsibility to store the value
+ * in the hash if required.
+ *
+ * h = Hash.new("Go Fish")
+ * h["a"] = 100
+ * h["b"] = 200
+ * h["a"] #=> 100
+ * h["c"] #=> "Go Fish"
+ * # The following alters the single default object
+ * h["c"].upcase! #=> "GO FISH"
+ * h["d"] #=> "GO FISH"
+ * h.keys #=> ["a", "b"]
+ *
+ * # While this creates a new default object each time
+ * h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
+ * h["c"] #=> "Go Fish: c"
+ * h["c"].upcase! #=> "GO FISH: C"
+ * h["d"] #=> "Go Fish: d"
+ * h.keys #=> ["c", "d"]
+ *
+ */
+
+static mrb_value
+mrb_hash_init(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value block, ifnone;
+ mrb_bool ifnone_p;
+
+ ifnone = mrb_nil_value();
+ mrb_get_args(mrb, "&|o?", &block, &ifnone, &ifnone_p);
+ mrb_hash_modify(mrb, hash);
+ if (!mrb_nil_p(block)) {
+ if (ifnone_p) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ }
+ 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);
+ }
+ return hash;
+}
+
+/* 15.2.13.4.2 */
+/*
+ * call-seq:
+ * hsh[key] -> value
+ *
+ * Element Reference---Retrieves the <i>value</i> object corresponding
+ * to the <i>key</i> object. If not found, returns the default value (see
+ * <code>Hash::new</code> for details).
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h["a"] #=> 100
+ * h["c"] #=> nil
+ *
+ */
+static mrb_value
+mrb_hash_aget(mrb_state *mrb, mrb_value self)
+{
+ mrb_value key;
+
+ 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:
+ * hsh.default(key=nil) -> obj
+ *
+ * Returns the default value, the value that would be returned by
+ * <i>hsh</i>[<i>key</i>] if <i>key</i> did not exist in <i>hsh</i>.
+ * See also <code>Hash::new</code> and <code>Hash#default=</code>.
+ *
+ * h = Hash.new #=> {}
+ * h.default #=> nil
+ * h.default(2) #=> nil
+ *
+ * h = Hash.new("cat") #=> {}
+ * h.default #=> "cat"
+ * h.default(2) #=> "cat"
+ *
+ * h = Hash.new {|h,k| h[k] = k.to_i*10} #=> {}
+ * h.default #=> nil
+ * h.default(2) #=> 20
+ */
+
+static mrb_value
+mrb_hash_default(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value key;
+ mrb_bool given;
+
+ mrb_get_args(mrb, "|o?", &key, &given);
+ 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);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
+ }
+ return mrb_nil_value();
+}
+
+/* 15.2.13.4.6 */
+/*
+ * call-seq:
+ * hsh.default = obj -> obj
+ *
+ * Sets the default value, the value returned for a key that does not
+ * exist in the hash. It is not possible to set the default to a
+ * <code>Proc</code> that will be executed on each key lookup.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.default = "Go fish"
+ * h["a"] #=> 100
+ * h["z"] #=> "Go fish"
+ * # This doesn't do what you might hope...
+ * h.default = proc do |hash, key|
+ * hash[key] = key + key
+ * end
+ * h[2] #=> #<Proc:0x401b3948@-:6>
+ * h["cat"] #=> #<Proc:0x401b3948@-:6>
+ */
+
+static mrb_value
+mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value ifnone;
+
+ mrb_get_args(mrb, "o", &ifnone);
+ mrb_hash_modify(mrb, hash);
+ mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT;
+ if (!mrb_nil_p(ifnone)) {
+ RHASH(hash)->flags |= MRB_HASH_DEFAULT;
+ }
+ else {
+ RHASH(hash)->flags &= ~MRB_HASH_DEFAULT;
+ }
+ return ifnone;
+}
+
+/* 15.2.13.4.7 */
+/*
+ * call-seq:
+ * hsh.default_proc -> anObject
+ *
+ * If <code>Hash::new</code> was invoked with a block, return that
+ * block, otherwise return <code>nil</code>.
+ *
+ * h = Hash.new {|h,k| h[k] = k*k } #=> {}
+ * p = h.default_proc #=> #<Proc:0x401b3d08@-:1>
+ * a = [] #=> []
+ * p.call(a, 2)
+ * a #=> [nil, nil, 4]
+ */
+
+
+static mrb_value
+mrb_hash_default_proc(mrb_state *mrb, mrb_value hash)
+{
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ return RHASH_PROCDEFAULT(hash);
+ }
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * hsh.default_proc = proc_obj -> proc_obj
+ *
+ * Sets the default proc to be executed on each key lookup.
+ *
+ * h.default_proc = proc do |hash, key|
+ * hash[key] = key + key
+ * end
+ * h[2] #=> 4
+ * h["cat"] #=> "catcat"
+ */
+
+static mrb_value
+mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value ifnone;
+
+ mrb_get_args(mrb, "o", &ifnone);
+ mrb_hash_modify(mrb, hash);
+ mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ if (!mrb_nil_p(ifnone)) {
+ RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
+ RHASH(hash)->flags |= MRB_HASH_DEFAULT;
+ }
+ else {
+ RHASH(hash)->flags &= ~MRB_HASH_DEFAULT;
+ RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT;
+ }
+
+ return ifnone;
+}
+
+MRB_API mrb_value
+mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+ mrb_value delVal;
+ mrb_int n;
+
+ if (h) {
+ k = kh_get(ht, mrb, h, key);
+ if (k != kh_end(h)) {
+ delVal = kh_value(h, k).v;
+ n = kh_value(h, k).n;
+ kh_del(ht, mrb, h, k);
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
+ if (kh_value(h, k).n > n) kh_value(h, k).n--;
+ }
+ return delVal;
+ }
+ }
+
+ /* not found */
+ return mrb_nil_value();
+}
+
+/* 15.2.13.4.8 */
+/*
+ * call-seq:
+ * hsh.delete(key) -> value
+ * hsh.delete(key) {| key | block } -> value
+ *
+ * Deletes and returns a key-value pair from <i>hsh</i> whose key is
+ * equal to <i>key</i>. If the key is not found, returns the
+ * <em>default value</em>. If the optional code block is given and the
+ * key is not found, pass in the key and return the result of
+ * <i>block</i>.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.delete("a") #=> 100
+ * h.delete("z") #=> nil
+ * h.delete("z") { |el| "#{el} not found" } #=> "z not found"
+ *
+ */
+static mrb_value
+mrb_hash_delete(mrb_state *mrb, mrb_value self)
+{
+ mrb_value key;
+
+ mrb_get_args(mrb, "o", &key);
+ mrb_hash_modify(mrb, self);
+ return mrb_hash_delete_key(mrb, self, key);
+}
+
+/* 15.2.13.4.24 */
+/*
+ * call-seq:
+ * hsh.shift -> anArray or obj
+ *
+ * Removes a key-value pair from <i>hsh</i> and returns it as the
+ * two-item array <code>[</code> <i>key, value</i> <code>]</code>, or
+ * the hash's default value if the hash is empty.
+ *
+ * h = { 1 => "a", 2 => "b", 3 => "c" }
+ * h.shift #=> [1, "a"]
+ * h #=> {2=>"b", 3=>"c"}
+ */
+
+static mrb_value
+mrb_hash_shift(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+ mrb_value delKey, delVal;
+
+ mrb_hash_modify(mrb, hash);
+ if (h && kh_size(h) > 0) {
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
+
+ delKey = kh_key(h, k);
+ mrb_gc_protect(mrb, delKey);
+ delVal = mrb_hash_delete_key(mrb, hash, delKey);
+ mrb_gc_protect(mrb, delVal);
+
+ return mrb_assoc_new(mrb, delKey, delVal);
+ }
+ }
+
+ 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 */
+/*
+ * call-seq:
+ * hsh.clear -> hsh
+ *
+ * Removes all key-value pairs from `hsh`.
+ *
+ * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
+ * h.clear #=> {}
+ *
+ */
+
+MRB_API mrb_value
+mrb_hash_clear(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+
+ mrb_hash_modify(mrb, hash);
+ if (h) kh_clear(ht, mrb, h);
+ return hash;
+}
+
+/* 15.2.13.4.3 */
+/* 15.2.13.4.26 */
+/*
+ * call-seq:
+ * hsh[key] = value -> value
+ * hsh.store(key, value) -> value
+ *
+ * Element Assignment---Associates the value given by
+ * <i>value</i> with the key given by <i>key</i>.
+ * <i>key</i> should not have its value changed while it is in
+ * use as a key (a <code>String</code> passed as a key will be
+ * duplicated and frozen).
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h["a"] = 9
+ * h["c"] = 4
+ * h #=> {"a"=>9, "b"=>200, "c"=>4}
+ *
+ */
+static mrb_value
+mrb_hash_aset(mrb_state *mrb, mrb_value self)
+{
+ mrb_value key, val;
+
+ mrb_get_args(mrb, "oo", &key, &val);
+ mrb_hash_set(mrb, self, key, val);
+ return val;
+}
+
+/* 15.2.13.4.20 */
+/* 15.2.13.4.25 */
+/*
+ * call-seq:
+ * hsh.length -> fixnum
+ * hsh.size -> fixnum
+ *
+ * Returns the number of key-value pairs in the hash.
+ *
+ * h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 }
+ * h.length #=> 4
+ * h.delete("a") #=> 200
+ * h.length #=> 3
+ */
+static mrb_value
+mrb_hash_size_m(mrb_state *mrb, mrb_value self)
+{
+ khash_t(ht) *h = RHASH_TBL(self);
+
+ if (!h) return mrb_fixnum_value(0);
+ return mrb_fixnum_value(kh_size(h));
+}
+
+/* 15.2.13.4.12 */
+/*
+ * call-seq:
+ * hsh.empty? -> true or false
+ *
+ * Returns <code>true</code> if <i>hsh</i> contains no key-value pairs.
+ *
+ * {}.empty? #=> true
+ *
+ */
+MRB_API mrb_value
+mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
+{
+ khash_t(ht) *h = RHASH_TBL(self);
+
+ if (h) return mrb_bool_value(kh_size(h) == 0);
+ return mrb_true_value();
+}
+
+/* 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;
+}
+
+/* 15.2.13.4.19 */
+/*
+ * call-seq:
+ * hsh.keys -> array
+ *
+ * Returns a new array populated with the keys from this hash. See also
+ * <code>Hash#values</code>.
+ *
+ * h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
+ * h.keys #=> ["a", "b", "c", "d"]
+ *
+ */
+
+MRB_API mrb_value
+mrb_hash_keys(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+ mrb_int end;
+ mrb_value ary;
+ mrb_value *p;
+
+ if (!h || kh_size(h) == 0) return mrb_ary_new(mrb);
+ ary = mrb_ary_new_capa(mrb, kh_size(h));
+ end = kh_size(h)-1;
+ mrb_ary_set(mrb, ary, end, mrb_nil_value());
+ p = RARRAY_PTR(ary);
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ mrb_value kv = kh_key(h, k);
+ mrb_hash_value hv = kh_value(h, k);
+
+ if (hv.n <= end) {
+ p[hv.n] = kv;
+ }
+ else {
+ p[end] = kv;
+ }
+ }
+ }
+ return ary;
+}
+
+/* 15.2.13.4.28 */
+/*
+ * call-seq:
+ * hsh.values -> array
+ *
+ * Returns a new array populated with the values from <i>hsh</i>. See
+ * also <code>Hash#keys</code>.
+ *
+ * h = { "a" => 100, "b" => 200, "c" => 300 }
+ * h.values #=> [100, 200, 300]
+ *
+ */
+
+MRB_API mrb_value
+mrb_hash_values(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ khiter_t k;
+ mrb_value ary;
+
+ if (!h) return mrb_ary_new(mrb);
+ ary = mrb_ary_new_capa(mrb, kh_size(h));
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ mrb_hash_value hv = kh_value(h, k);
+
+ mrb_ary_set(mrb, ary, hv.n, hv.v);
+ }
+ }
+ return ary;
+}
+
+/* 15.2.13.4.13 */
+/* 15.2.13.4.15 */
+/* 15.2.13.4.18 */
+/* 15.2.13.4.21 */
+/*
+ * call-seq:
+ * hsh.has_key?(key) -> true or false
+ * hsh.include?(key) -> true or false
+ * hsh.key?(key) -> true or false
+ * hsh.member?(key) -> true or false
+ *
+ * Returns <code>true</code> if the given key is present in <i>hsh</i>.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.has_key?("a") #=> true
+ * h.has_key?("z") #=> false
+ *
+ */
+
+static mrb_value
+mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value key;
+ khash_t(ht) *h;
+ khiter_t k;
+
+ mrb_get_args(mrb, "o", &key);
+
+ h = RHASH_TBL(hash);
+ if (h) {
+ k = kh_get(ht, mrb, h, key);
+ return mrb_bool_value(k != kh_end(h));
+ }
+ return mrb_false_value();
+}
+
+/* 15.2.13.4.14 */
+/* 15.2.13.4.27 */
+/*
+ * call-seq:
+ * hsh.has_value?(value) -> true or false
+ * hsh.value?(value) -> true or false
+ *
+ * Returns <code>true</code> if the given value is present for some key
+ * in <i>hsh</i>.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.has_value?(100) #=> true
+ * h.has_value?(999) #=> false
+ */
+
+static mrb_value
+mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value val;
+ khash_t(ht) *h;
+ khiter_t k;
+
+ mrb_get_args(mrb, "o", &val);
+ h = RHASH_TBL(hash);
+
+ if (h) {
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
+
+ if (mrb_equal(mrb, kh_value(h, k).v, val)) {
+ return mrb_true_value();
+ }
+ }
+ }
+ return mrb_false_value();
+}
+
+void
+mrb_init_hash(mrb_state *mrb)
+{
+ struct RClass *h;
+
+ 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, "[]", 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_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 */
+ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */
+ mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */
+ mrb_define_method(mrb, h, "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, "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, "shift", mrb_hash_shift, MRB_ARGS_NONE()); /* 15.2.13.4.24 */
+ mrb_define_method(mrb, h, "dup", mrb_hash_dup, MRB_ARGS_NONE());
+ 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, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/init.c b/web/server/h2o/libh2o/deps/mruby/src/init.c
new file mode 100644
index 00000000..afd69975
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/init.c
@@ -0,0 +1,51 @@
+/*
+** init.c - initialize mruby core
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+
+void mrb_init_symtbl(mrb_state*);
+void mrb_init_class(mrb_state*);
+void mrb_init_object(mrb_state*);
+void mrb_init_kernel(mrb_state*);
+void mrb_init_comparable(mrb_state*);
+void mrb_init_enumerable(mrb_state*);
+void mrb_init_symbol(mrb_state*);
+void mrb_init_string(mrb_state*);
+void mrb_init_exception(mrb_state*);
+void mrb_init_proc(mrb_state*);
+void mrb_init_array(mrb_state*);
+void mrb_init_hash(mrb_state*);
+void mrb_init_numeric(mrb_state*);
+void mrb_init_range(mrb_state*);
+void mrb_init_gc(mrb_state*);
+void mrb_init_math(mrb_state*);
+void mrb_init_version(mrb_state*);
+void mrb_init_mrblib(mrb_state*);
+
+#define DONE mrb_gc_arena_restore(mrb, 0);
+void
+mrb_init_core(mrb_state *mrb)
+{
+ mrb_init_symtbl(mrb); DONE;
+
+ mrb_init_class(mrb); DONE;
+ mrb_init_object(mrb); DONE;
+ mrb_init_kernel(mrb); DONE;
+ mrb_init_comparable(mrb); DONE;
+ mrb_init_enumerable(mrb); DONE;
+
+ mrb_init_symbol(mrb); DONE;
+ mrb_init_string(mrb); DONE;
+ mrb_init_exception(mrb); DONE;
+ mrb_init_proc(mrb); DONE;
+ mrb_init_array(mrb); DONE;
+ mrb_init_hash(mrb); DONE;
+ mrb_init_numeric(mrb); DONE;
+ mrb_init_range(mrb); DONE;
+ mrb_init_gc(mrb); DONE;
+ mrb_init_version(mrb); DONE;
+ mrb_init_mrblib(mrb); DONE;
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/kernel.c b/web/server/h2o/libh2o/deps/mruby/src/kernel.c
new file mode 100644
index 00000000..4e95ab24
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/kernel.c
@@ -0,0 +1,1238 @@
+/*
+** kernel.c - Kernel module
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/hash.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/istruct.h>
+
+typedef enum {
+ NOEX_PUBLIC = 0x00,
+ NOEX_NOSUPER = 0x01,
+ NOEX_PRIVATE = 0x02,
+ NOEX_PROTECTED = 0x04,
+ NOEX_MASK = 0x06,
+ NOEX_BASIC = 0x08,
+ NOEX_UNDEF = NOEX_NOSUPER,
+ NOEX_MODFUNC = 0x12,
+ NOEX_SUPER = 0x20,
+ NOEX_VCALL = 0x40,
+ NOEX_RESPONDS = 0x80
+} mrb_method_flag_t;
+
+MRB_API mrb_bool
+mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
+{
+ struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid);
+ if (MRB_PROC_CFUNC_P(me) && (me->body.func == func))
+ return TRUE;
+ return FALSE;
+}
+
+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);
+}
+
+/* 15.3.1.3.17 */
+/*
+ * call-seq:
+ * obj.inspect -> string
+ *
+ * Returns a string containing a human-readable representation of
+ * <i>obj</i>. If not overridden and no instance variables, uses the
+ * <code>to_s</code> method to generate the string.
+ * <i>obj</i>. If not overridden, uses the <code>to_s</code> method to
+ * generate the string.
+ *
+ * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
+ * Time.new.inspect #=> "2008-03-08 19:43:39 +0900"
+ */
+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)) {
+ return mrb_obj_iv_inspect(mrb, mrb_obj_ptr(obj));
+ }
+ return mrb_any_to_s(mrb, obj);
+}
+
+/* 15.3.1.3.2 */
+/*
+ * call-seq:
+ * obj === other -> true or false
+ *
+ * Case Equality---For class <code>Object</code>, effectively the same
+ * as calling <code>#==</code>, but typically overridden by descendants
+ * to provide meaningful semantics in <code>case</code> statements.
+ */
+static mrb_value
+mrb_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));
+}
+
+/* 15.3.1.3.3 */
+/* 15.3.1.3.33 */
+/*
+ * Document-method: __id__
+ * Document-method: object_id
+ *
+ * call-seq:
+ * obj.__id__ -> fixnum
+ * obj.object_id -> fixnum
+ *
+ * Returns an integer identifier for <i>obj</i>. The same number will
+ * be returned on all calls to <code>id</code> for a given object, and
+ * no two active objects will share an id.
+ * <code>Object#object_id</code> is a different concept from the
+ * <code>:name</code> notation, which returns the symbol id of
+ * <code>name</code>. Replaces the deprecated <code>Object#id</code>.
+ */
+mrb_value
+mrb_obj_id_m(mrb_state *mrb, mrb_value self)
+{
+ return mrb_fixnum_value(mrb_obj_id(self));
+}
+
+/* 15.3.1.2.2 */
+/* 15.3.1.2.5 */
+/* 15.3.1.3.6 */
+/* 15.3.1.3.25 */
+/*
+ * call-seq:
+ * block_given? -> true or false
+ * iterator? -> true or false
+ *
+ * Returns <code>true</code> if <code>yield</code> would execute a
+ * block in the current context. The <code>iterator?</code> form
+ * is mildly deprecated.
+ *
+ * def try
+ * if block_given?
+ * yield
+ * else
+ * "no block"
+ * end
+ * end
+ * try #=> "no block"
+ * try { "hello" } #=> "hello"
+ * try do "hello" end #=> "hello"
+ */
+static mrb_value
+mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_value *bp;
+
+ bp = ci->stackent + 1;
+ ci--;
+ if (ci <= mrb->c->cibase) {
+ return mrb_false_value();
+ }
+ /* block_given? called within block; check upper scope */
+ if (ci->proc->env) {
+ struct REnv *e = ci->proc->env;
+
+ while (e->c) {
+ e = (struct REnv*)e->c;
+ }
+ /* top-level does not have block slot (always false) */
+ if (e->stack == mrb->c->stbase)
+ return mrb_false_value();
+ if (e->stack && e->cioff < 0) {
+ /* use saved block arg position */
+ bp = &e->stack[-e->cioff];
+ ci = 0; /* no callinfo available */
+ }
+ else {
+ ci = e->cxt.c->cibase + e->cioff;
+ bp = ci[1].stackent + 1;
+ }
+ }
+ if (ci && ci->argc > 0) {
+ bp += ci->argc;
+ }
+ if (mrb_nil_p(*bp))
+ return mrb_false_value();
+ return mrb_true_value();
+}
+
+/* 15.3.1.3.7 */
+/*
+ * call-seq:
+ * obj.class -> class
+ *
+ * Returns the class of <i>obj</i>. This method must always be
+ * called with an explicit receiver, as <code>class</code> is also a
+ * reserved word in Ruby.
+ *
+ * 1.class #=> Fixnum
+ * self.class #=> Object
+ */
+static mrb_value
+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_FLAG_IS_PREPENDED) {
+ struct RClass *c0 = sc->super;
+ struct RClass *c1 = dc;
+
+ /* copy prepended iclasses */
+ while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) {
+ c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0)));
+ c1 = c1->super;
+ c0 = c0->super;
+ }
+ c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0)));
+ c1->super->flags |= MRB_FLAG_IS_ORIGIN;
+ }
+ 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_CLASS:
+ case MRB_TT_MODULE:
+ copy_class(mrb, dest, obj);
+ /* fall through */
+ 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);
+
+ 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_int i;
+
+ if (argc == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (at least 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);
+ }
+ return obj;
+}
+
+/* 15.3.1.3.13 */
+/*
+ * call-seq:
+ * obj.extend(module, ...) -> obj
+ *
+ * Adds to _obj_ the instance methods from each module given as a
+ * parameter.
+ *
+ * module Mod
+ * def hello
+ * "Hello from Mod.\n"
+ * end
+ * end
+ *
+ * class Klass
+ * def hello
+ * "Hello from Klass.\n"
+ * end
+ * end
+ *
+ * k = Klass.new
+ * k.hello #=> "Hello from Klass.\n"
+ * k.extend(Mod) #=> #<Klass:0x401b3bc8>
+ * k.hello #=> "Hello from Mod.\n"
+ */
+static mrb_value
+mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value *argv;
+ mrb_int argc;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ return mrb_obj_extend(mrb, argc, argv, self);
+}
+
+static mrb_value
+mrb_obj_freeze(mrb_state *mrb, mrb_value self)
+{
+ struct RBasic *b;
+
+ switch (mrb_type(self)) {
+ case MRB_TT_FALSE:
+ case MRB_TT_TRUE:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FLOAT:
+ return self;
+ default:
+ break;
+ }
+
+ b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ MRB_SET_FROZEN_FLAG(b);
+ }
+ return 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:
+ case MRB_TT_FLOAT:
+ return mrb_true_value();
+ default:
+ break;
+ }
+
+ b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ return mrb_false_value();
+ }
+ return mrb_true_value();
+}
+
+/* 15.3.1.3.15 */
+/*
+ * call-seq:
+ * obj.hash -> fixnum
+ *
+ * Generates a <code>Fixnum</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.
+ */
+MRB_API mrb_value
+mrb_obj_hash(mrb_state *mrb, mrb_value self)
+{
+ return mrb_fixnum_value(mrb_obj_id(self));
+}
+
+/* 15.3.1.3.16 */
+static mrb_value
+mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
+{
+ mrb_value orig;
+
+ 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");
+ }
+ return self;
+}
+
+
+MRB_API mrb_bool
+mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
+{
+ if (mrb_obj_class(mrb, obj) == c) return TRUE;
+ return FALSE;
+}
+
+/* 15.3.1.3.19 */
+/*
+ * call-seq:
+ * obj.instance_of?(class) -> true or false
+ *
+ * Returns <code>true</code> if <i>obj</i> is an instance of the given
+ * class. See also <code>Object#kind_of?</code>.
+ */
+static mrb_value
+obj_is_instance_of(mrb_state *mrb, mrb_value self)
+{
+ mrb_value arg;
+
+ mrb_get_args(mrb, "C", &arg);
+
+ return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg)));
+}
+
+/* 15.3.1.3.20 */
+/*
+ * call-seq:
+ * obj.instance_variable_defined?(symbol) -> true or false
+ *
+ * Returns <code>true</code> if the given instance variable is
+ * defined in <i>obj</i>.
+ *
+ * class Fred
+ * def initialize(p1, p2)
+ * @a, @b = p1, p2
+ * end
+ * end
+ * fred = Fred.new('cat', 99)
+ * fred.instance_variable_defined?(:@a) #=> true
+ * fred.instance_variable_defined?("@b") #=> true
+ * fred.instance_variable_defined?("@c") #=> false
+ */
+static mrb_value
+mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym sym;
+
+ mrb_get_args(mrb, "n", &sym);
+ mrb_iv_check(mrb, sym);
+ return mrb_bool_value(mrb_iv_defined(mrb, self, sym));
+}
+
+/* 15.3.1.3.21 */
+/*
+ * call-seq:
+ * obj.instance_variable_get(symbol) -> obj
+ *
+ * Returns the value of the given instance variable, or nil if the
+ * instance variable is not set. The <code>@</code> part of the
+ * variable name should be included for regular instance
+ * variables. Throws a <code>NameError</code> exception if the
+ * supplied symbol is not valid as an instance variable name.
+ *
+ * class Fred
+ * def initialize(p1, p2)
+ * @a, @b = p1, p2
+ * end
+ * end
+ * fred = Fred.new('cat', 99)
+ * fred.instance_variable_get(:@a) #=> "cat"
+ * fred.instance_variable_get("@b") #=> 99
+ */
+static mrb_value
+mrb_obj_ivar_get(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym iv_name;
+
+ mrb_get_args(mrb, "n", &iv_name);
+ mrb_iv_check(mrb, iv_name);
+ return mrb_iv_get(mrb, self, iv_name);
+}
+
+/* 15.3.1.3.22 */
+/*
+ * call-seq:
+ * obj.instance_variable_set(symbol, obj) -> obj
+ *
+ * Sets the instance variable names by <i>symbol</i> to
+ * <i>object</i>, thereby frustrating the efforts of the class's
+ * author to attempt to provide proper encapsulation. The variable
+ * did not have to exist prior to this call.
+ *
+ * class Fred
+ * def initialize(p1, p2)
+ * @a, @b = p1, p2
+ * end
+ * end
+ * fred = Fred.new('cat', 99)
+ * fred.instance_variable_set(:@a, 'dog') #=> "dog"
+ * fred.instance_variable_set(:@c, 'cat') #=> "cat"
+ * fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
+ */
+static mrb_value
+mrb_obj_ivar_set(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym iv_name;
+ mrb_value val;
+
+ mrb_get_args(mrb, "no", &iv_name, &val);
+ mrb_iv_check(mrb, iv_name);
+ mrb_iv_set(mrb, self, iv_name, val);
+ return val;
+}
+
+/* 15.3.1.3.24 */
+/* 15.3.1.3.26 */
+/*
+ * call-seq:
+ * obj.is_a?(class) -> true or false
+ * obj.kind_of?(class) -> true or false
+ *
+ * Returns <code>true</code> if <i>class</i> is the class of
+ * <i>obj</i>, or if <i>class</i> is one of the superclasses of
+ * <i>obj</i> or modules included in <i>obj</i>.
+ *
+ * module M; end
+ * class A
+ * include M
+ * end
+ * class B < A; end
+ * class C < B; end
+ * b = B.new
+ * b.instance_of? A #=> false
+ * b.instance_of? B #=> true
+ * b.instance_of? C #=> false
+ * b.instance_of? M #=> false
+ * b.kind_of? A #=> true
+ * b.kind_of? B #=> true
+ * b.kind_of? C #=> false
+ * b.kind_of? M #=> true
+ */
+static mrb_value
+mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value arg;
+
+ mrb_get_args(mrb, "C", &arg);
+
+ return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg)));
+}
+
+KHASH_DECLARE(st, mrb_sym, char, FALSE)
+KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal)
+
+static void
+method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
+{
+ khint_t i;
+
+ khash_t(mt) *h = klass->mt;
+ if (!h) return;
+ for (i=0;i<kh_end(h);i++) {
+ if (kh_exist(h, i) && kh_value(h, i)) {
+ kh_put(st, mrb, set, kh_key(h, i));
+ }
+ }
+}
+
+mrb_value
+mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
+{
+ khint_t i;
+ mrb_value ary;
+ mrb_bool prepended = FALSE;
+ struct RClass* oldklass;
+ khash_t(st)* set = kh_init(st, mrb);
+
+ if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) {
+ MRB_CLASS_ORIGIN(klass);
+ prepended = TRUE;
+ }
+
+ oldklass = 0;
+ while (klass && (klass != oldklass)) {
+ method_entry_loop(mrb, klass, set);
+ if ((klass->tt == MRB_TT_ICLASS && !prepended) ||
+ (klass->tt == MRB_TT_SCLASS)) {
+ }
+ else {
+ if (!recur) break;
+ }
+ oldklass = klass;
+ klass = klass->super;
+ }
+
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
+ }
+ }
+ kh_destroy(st, mrb, set);
+
+ return ary;
+}
+
+static mrb_value
+mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
+{
+ khint_t i;
+ mrb_value ary;
+ struct RClass* klass;
+ khash_t(st)* set = kh_init(st, mrb);
+
+ klass = mrb_class(mrb, obj);
+
+ if (klass && (klass->tt == MRB_TT_SCLASS)) {
+ method_entry_loop(mrb, klass, set);
+ klass = klass->super;
+ }
+ if (recur) {
+ while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
+ method_entry_loop(mrb, klass, set);
+ klass = klass->super;
+ }
+ }
+
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
+ }
+ }
+ kh_destroy(st, mrb, set);
+
+ return ary;
+}
+
+static mrb_value
+mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag)
+{
+ return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
+}
+/* 15.3.1.3.31 */
+/*
+ * call-seq:
+ * obj.methods -> array
+ *
+ * Returns a list of the names of methods publicly accessible in
+ * <i>obj</i>. This will include all the methods accessible in
+ * <i>obj</i>'s ancestors.
+ *
+ * class Klass
+ * def kMethod()
+ * end
+ * end
+ * k = Klass.new
+ * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?,
+ * # :class, :instance_variable_set,
+ * # :methods, :extend, :__send__, :instance_eval]
+ * k.methods.length #=> 42
+ */
+static mrb_value
+mrb_obj_methods_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */
+}
+
+/* 15.3.1.3.32 */
+/*
+ * call_seq:
+ * nil.nil? -> true
+ * <anything_else>.nil? -> false
+ *
+ * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
+ */
+static mrb_value
+mrb_false(mrb_state *mrb, mrb_value self)
+{
+ return mrb_false_value();
+}
+
+/* 15.3.1.3.36 */
+/*
+ * call-seq:
+ * obj.private_methods(all=true) -> array
+ *
+ * Returns the list of private methods accessible to <i>obj</i>. If
+ * the <i>all</i> parameter is set to <code>false</code>, only those methods
+ * in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_private_methods(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */
+}
+
+/* 15.3.1.3.37 */
+/*
+ * call-seq:
+ * obj.protected_methods(all=true) -> array
+ *
+ * Returns the list of protected methods accessible to <i>obj</i>. If
+ * the <i>all</i> parameter is set to <code>false</code>, only those methods
+ * in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_protected_methods(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */
+}
+
+/* 15.3.1.3.38 */
+/*
+ * call-seq:
+ * obj.public_methods(all=true) -> array
+ *
+ * Returns the list of public methods accessible to <i>obj</i>. If
+ * the <i>all</i> parameter is set to <code>false</code>, only those methods
+ * in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_public_methods(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */
+}
+
+/* 15.3.1.2.12 */
+/* 15.3.1.3.40 */
+/*
+ * call-seq:
+ * raise
+ * raise(string)
+ * raise(exception [, string])
+ *
+ * With no arguments, raises a <code>RuntimeError</code>
+ * With a single +String+ argument, raises a
+ * +RuntimeError+ with the string as a message. Otherwise,
+ * the first parameter should be the name of an +Exception+
+ * class (or an object that returns an +Exception+ object when sent
+ * an +exception+ message). The optional second parameter sets the
+ * message associated with the exception, and the third parameter is an
+ * array of callback information. Exceptions are caught by the
+ * +rescue+ clause of <code>begin...end</code> blocks.
+ *
+ * raise "Failed to create socket"
+ * raise ArgumentError, "No parameters", caller
+ */
+MRB_API mrb_value
+mrb_f_raise(mrb_state *mrb, mrb_value self)
+{
+ mrb_value a[2], exc;
+ int argc;
+
+
+ argc = mrb_get_args(mrb, "|oo", &a[0], &a[1]);
+ switch (argc) {
+ case 0:
+ mrb_raise(mrb, E_RUNTIME_ERROR, "");
+ break;
+ case 1:
+ if (mrb_string_p(a[0])) {
+ a[1] = a[0];
+ argc = 2;
+ a[0] = mrb_obj_value(E_RUNTIME_ERROR);
+ }
+ /* fall through */
+ default:
+ exc = mrb_make_exception(mrb, argc, a);
+ mrb_exc_raise(mrb, exc);
+ break;
+ }
+ return mrb_nil_value(); /* not reached */
+}
+
+/* 15.3.1.3.41 */
+/*
+ * call-seq:
+ * obj.remove_instance_variable(symbol) -> obj
+ *
+ * Removes the named instance variable from <i>obj</i>, returning that
+ * variable's value.
+ *
+ * class Dummy
+ * attr_reader :var
+ * def initialize
+ * @var = 99
+ * end
+ * def remove
+ * remove_instance_variable(:@var)
+ * end
+ * end
+ * d = Dummy.new
+ * d.var #=> 99
+ * d.remove #=> 99
+ * d.var #=> nil
+ */
+static mrb_value
+mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym sym;
+ mrb_value val;
+
+ mrb_get_args(mrb, "n", &sym);
+ mrb_iv_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));
+ }
+ return val;
+}
+
+void
+mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
+{
+ mrb_sym inspect;
+ mrb_value repr;
+
+ inspect = mrb_intern_lit(mrb, "inspect");
+ if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
+ /* method missing in inspect; avoid recursion */
+ repr = mrb_any_to_s(mrb, self);
+ }
+ else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 16) {
+ repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
+ if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
+ repr = mrb_any_to_s(mrb, self);
+ }
+ }
+ else {
+ repr = mrb_any_to_s(mrb, self);
+ }
+
+ mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
+ mrb_sym2str(mrb, name), repr);
+}
+
+/* 15.3.1.3.30 */
+/*
+ * call-seq:
+ * obj.method_missing(symbol [, *args] ) -> result
+ *
+ * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
+ * <i>symbol</i> is the symbol for the method called, and <i>args</i>
+ * are any arguments that were passed to it. By default, the interpreter
+ * raises an error when this method is called. However, it is possible
+ * to override the method to provide more dynamic behavior.
+ * If it is decided that a particular method should not be handled, then
+ * <i>super</i> should be called, so that ancestors can pick up the
+ * missing method.
+ * The example below creates
+ * a class <code>Roman</code>, which responds to methods with names
+ * consisting of roman numerals, returning the corresponding integer
+ * values.
+ *
+ * class Roman
+ * def romanToInt(str)
+ * # ...
+ * end
+ * def method_missing(methId)
+ * str = methId.id2name
+ * romanToInt(str)
+ * end
+ * end
+ *
+ * r = Roman.new
+ * r.iv #=> 4
+ * r.xxiii #=> 23
+ * r.mm #=> 2000
+ */
+#ifdef MRB_DEFAULT_METHOD_MISSING
+static mrb_value
+mrb_obj_missing(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym name;
+ mrb_value *a;
+ mrb_int alen;
+
+ 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:
+ * obj.respond_to?(symbol, include_private=false) -> true or false
+ *
+ * Returns +true+ if _obj_ responds to the given
+ * method. Private methods are included in the search only if the
+ * optional second parameter evaluates to +true+.
+ *
+ * If the method is not implemented,
+ * as Process.fork on Windows, File.lchmod on GNU/Linux, etc.,
+ * false is returned.
+ *
+ * If the method is not defined, <code>respond_to_missing?</code>
+ * method is called and the result is returned.
+ */
+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);
+ }
+
+ if (!respond_to_p) {
+ rtm_id = mrb_intern_lit(mrb, "respond_to_missing?");
+ if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) {
+ mrb_value args[2], v;
+ args[0] = mid;
+ args[1] = mrb_bool_value(priv);
+ v = mrb_funcall_argv(mrb, self, rtm_id, 2, args);
+ return mrb_bool_value(mrb_bool(v));
+ }
+ }
+ return mrb_bool_value(respond_to_p);
+}
+
+/* 15.3.1.3.45 */
+/*
+ * call-seq:
+ * obj.singleton_methods(all=true) -> array
+ *
+ * Returns an array of the names of singleton methods for <i>obj</i>.
+ * If the optional <i>all</i> parameter is true, the list will include
+ * methods in modules included in <i>obj</i>.
+ * Only public and protected singleton methods are returned.
+ *
+ * module Other
+ * def three() end
+ * end
+ *
+ * class Single
+ * def Single.four() end
+ * end
+ *
+ * a = Single.new
+ *
+ * def a.one()
+ * end
+ *
+ * class << a
+ * include Other
+ * def two()
+ * end
+ * end
+ *
+ * Single.singleton_methods #=> [:four]
+ * a.singleton_methods(false) #=> [:two, :one]
+ * a.singleton_methods #=> [:two, :one, :three]
+ */
+static mrb_value
+mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_bool recur = TRUE;
+ mrb_get_args(mrb, "|b", &recur);
+ return mrb_obj_singleton_methods(mrb, recur, self);
+}
+
+static mrb_value
+mod_define_singleton_method(mrb_state *mrb, mrb_value self)
+{
+ struct RProc *p;
+ mrb_sym mid;
+ mrb_value blk = mrb_nil_value();
+
+ mrb_get_args(mrb, "n&", &mid, &blk);
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ mrb_proc_copy(p, mrb_proc_ptr(blk));
+ p->flags |= MRB_PROC_STRICT;
+ mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, p);
+ return mrb_symbol_value(mid);
+}
+
+static mrb_value
+mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
+{
+ mrb_value v;
+ mrb_int i, len;
+ mrb_sym eqq = mrb_intern_lit(mrb, "===");
+ mrb_value ary = mrb_ary_splat(mrb, self);
+
+ mrb_get_args(mrb, "o", &v);
+ 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);
+ if (mrb_test(c)) return mrb_true_value();
+ }
+ return mrb_false_value();
+}
+
+/* 15.3.1.2.7 */
+/*
+ * call-seq:
+ * local_variables -> array
+ *
+ * Returns the names of local variables in the current scope.
+ *
+ * [mruby limitation]
+ * If variable symbol information was stripped out from
+ * compiled binary files using `mruby-strip -l`, this
+ * method always returns an empty array.
+ */
+static mrb_value
+mrb_local_variables(mrb_state *mrb, mrb_value self)
+{
+ struct RProc *proc;
+ mrb_irep *irep;
+ mrb_value vars;
+ size_t i;
+
+ proc = mrb->c->ci[-1].proc;
+
+ if (MRB_PROC_CFUNC_P(proc)) {
+ return mrb_ary_new(mrb);
+ }
+ vars = mrb_hash_new(mrb);
+ irep = proc->body.irep;
+ while (irep) {
+ if (!irep->lv) break;
+ for (i = 0; i + 1 < irep->nlocals; ++i) {
+ if (irep->lv[i].name) {
+ mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
+ }
+ }
+ if (!proc->env) break;
+ irep = irep->outer;
+ }
+
+ return mrb_hash_keys(mrb, vars);
+}
+
+mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value);
+void
+mrb_init_kernel(mrb_state *mrb)
+{
+ struct RClass *krn;
+
+ mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */
+ mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */
+ mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */
+ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */
+ mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */
+; /* 15.3.1.2.11 */
+ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */
+
+ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */
+ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */
+ mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */
+ mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */
+ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */
+ mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */
+ mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
+ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */
+ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE());
+ mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE());
+ mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */
+ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */
+ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */
+ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */
+ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */
+ mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */
+ mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */
+ mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */
+ mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */
+ mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */
+ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
+ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
+ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
+#ifdef MRB_DEFAULT_METHOD_MISSING
+ mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
+#endif
+ mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
+ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
+ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
+ mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */
+ mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */
+ mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */
+ mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */
+ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */
+ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */
+ mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */
+ mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */
+ mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY());
+ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */
+ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */
+
+ mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
+ mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone"));
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/load.c b/web/server/h2o/libh2o/deps/mruby/src/load.c
new file mode 100644
index 00000000..8ae607ff
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/load.c
@@ -0,0 +1,704 @@
+/*
+** load.c - mruby binary loader
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.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>
+
+#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);
+}
+
+static size_t
+offset_crc_body(void)
+{
+ struct rite_binary_header header;
+ return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc);
+}
+
+static mrb_irep*
+read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
+{
+ int i;
+ const uint8_t *src = bin;
+ ptrdiff_t diff;
+ uint16_t tt, pool_data_len, snl;
+ int plen;
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_irep *irep = mrb_add_irep(mrb);
+
+ /* skip record size */
+ src += sizeof(uint32_t);
+
+ /* number of local variable */
+ irep->nlocals = bin_to_uint16(src);
+ src += sizeof(uint16_t);
+
+ /* number of register variable */
+ irep->nregs = bin_to_uint16(src);
+ src += sizeof(uint16_t);
+
+ /* number of child irep */
+ irep->rlen = (size_t)bin_to_uint16(src);
+ src += sizeof(uint16_t);
+
+ /* Binary Data Section */
+ /* ISEQ BLOCK */
+ irep->ilen = (size_t)bin_to_uint32(src);
+ src += sizeof(uint32_t);
+ src += skip_padding(src);
+
+ if (irep->ilen > 0) {
+ if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
+ return NULL;
+ }
+ if ((flags & FLAG_SRC_MALLOC) == 0 &&
+ (flags & FLAG_BYTEORDER_NATIVE)) {
+ irep->iseq = (mrb_code*)src;
+ src += sizeof(uint32_t) * 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);
+ }
+ }
+ }
+ }
+
+ /* POOL BLOCK */
+ plen = bin_to_uint32(src); /* number of pool */
+ src += sizeof(uint32_t);
+ if (plen > 0) {
+ if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
+ return NULL;
+ }
+ irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen);
+
+ for (i = 0; i < plen; i++) {
+ mrb_value s;
+
+ 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:
+ irep->pool[i] = mrb_str_to_inum(mrb, s, 10, FALSE);
+ break;
+
+ case IREP_TT_FLOAT:
+ irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE));
+ break;
+
+ case IREP_TT_STRING:
+ irep->pool[i] = mrb_str_pool(mrb, s);
+ break;
+
+ default:
+ /* should not happen */
+ irep->pool[i] = mrb_nil_value();
+ break;
+ }
+ irep->plen++;
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ }
+
+ /* SYMS BLOCK */
+ irep->slen = (size_t)bin_to_uint32(src); /* syms length */
+ src += sizeof(uint32_t);
+ if (irep->slen > 0) {
+ if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
+ return NULL;
+ }
+ irep->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;
+ continue;
+ }
+
+ if (flags & FLAG_SRC_MALLOC) {
+ irep->syms[i] = mrb_intern(mrb, (char *)src, snl);
+ }
+ else {
+ irep->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;
+}
+
+static mrb_irep*
+read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
+{
+ mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags);
+ int i;
+
+ if (irep == NULL) {
+ return NULL;
+ }
+
+ bin += *len;
+ for (i=0; i<irep->rlen; i++) {
+ size_t rlen;
+
+ irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags);
+ if (irep->reps[i] == NULL) {
+ return NULL;
+ }
+ bin += rlen;
+ *len += rlen;
+ }
+ return irep;
+}
+
+static mrb_irep*
+read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
+{
+ size_t len;
+
+ bin += sizeof(struct rite_section_irep_header);
+ return read_irep_record(mrb, bin, &len, flags);
+}
+
+static int
+read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len)
+{
+ size_t i, fname_len, niseq;
+ char *fname;
+ uint16_t *lines;
+
+ *len = 0;
+ bin += sizeof(uint32_t); /* record size */
+ *len += sizeof(uint32_t);
+ fname_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ *len += sizeof(uint16_t);
+ fname = (char *)mrb_malloc(mrb, fname_len + 1);
+ memcpy(fname, bin, fname_len);
+ fname[fname_len] = '\0';
+ bin += fname_len;
+ *len += fname_len;
+
+ niseq = (size_t)bin_to_uint32(bin);
+ bin += sizeof(uint32_t); /* niseq */
+ *len += sizeof(uint32_t);
+
+ if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) {
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+ lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t));
+ for (i = 0; i < niseq; i++) {
+ lines[i] = bin_to_uint16(bin);
+ bin += sizeof(uint16_t); /* niseq */
+ *len += sizeof(uint16_t);
+ }
+
+ irep->filename = fname;
+ irep->lines = lines;
+ return MRB_DUMP_OK;
+}
+
+static int
+read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp)
+{
+ int result = read_lineno_record_1(mrb, bin, irep, lenp);
+ int i;
+
+ if (result != MRB_DUMP_OK) return result;
+ for (i = 0; i < irep->rlen; i++) {
+ size_t len;
+
+ result = read_lineno_record(mrb, bin, irep->reps[i], &len);
+ if (result != MRB_DUMP_OK) break;
+ bin += len;
+ *lenp += len;
+ }
+ return result;
+}
+
+static int
+read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep)
+{
+ size_t len;
+
+ len = 0;
+ bin += sizeof(struct rite_section_lineno_header);
+
+ /* Read Binary Data Section */
+ return read_lineno_record(mrb, bin, irep, &len);
+}
+
+static int
+read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
+{
+ const uint8_t *bin = start;
+ ptrdiff_t diff;
+ size_t record_size;
+ uint16_t f_idx;
+ int i;
+
+ 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;
+
+ 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);
+ bin += sizeof(uint16_t);
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file *file;
+ uint16_t filename_idx;
+ mrb_int len;
+
+ file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file));
+ irep->debug_info->files[f_idx] = file;
+
+ file->start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+
+ /* filename */
+ filename_idx = bin_to_uint16(bin);
+ 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);
+ file->line_type = (mrb_debug_line_type)bin_to_uint8(bin);
+ bin += sizeof(uint8_t);
+ switch (file->line_type) {
+ case mrb_debug_line_ary: {
+ uint32_t l;
+
+ file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count));
+ for (l = 0; l < file->line_entry_count; ++l) {
+ file->lines.ary[l] = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ }
+ } break;
+
+ 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));
+ for (l = 0; l < file->line_entry_count; ++l) {
+ file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ file->lines.flat_map[l].line = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ }
+ } break;
+
+ default: return MRB_DUMP_GENERAL_FAILURE;
+ }
+ }
+
+ diff = bin - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+
+ if (record_size != (size_t)diff) {
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < irep->rlen; i++) {
+ size_t len;
+ int ret;
+
+ ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
+ if (ret != MRB_DUMP_OK) return ret;
+ bin += len;
+ }
+
+ diff = bin - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+ *record_len = (size_t)diff;
+
+ return MRB_DUMP_OK;
+}
+
+static int
+read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
+{
+ const uint8_t *bin;
+ ptrdiff_t diff;
+ struct rite_section_debug_header *header;
+ uint16_t i;
+ size_t len = 0;
+ int result;
+ uint16_t filenames_len;
+ mrb_sym *filenames;
+
+ bin = start;
+ header = (struct rite_section_debug_header *)bin;
+ bin += sizeof(struct rite_section_debug_header);
+
+ filenames_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len);
+ for (i = 0; i < filenames_len; ++i) {
+ uint16_t f_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ if (flags & FLAG_SRC_MALLOC) {
+ filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
+ }
+ else {
+ filenames[i] = mrb_intern_static(mrb, (const char *)bin, (size_t)f_len);
+ }
+ bin += f_len;
+ }
+
+ result = read_debug_record(mrb, bin, irep, &len, filenames, filenames_len);
+ if (result != MRB_DUMP_OK) goto debug_exit;
+
+ bin += len;
+ diff = bin - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+ if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
+ result = MRB_DUMP_GENERAL_FAILURE;
+ }
+
+debug_exit:
+ mrb_free(mrb, filenames);
+ return result;
+}
+
+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;
+ ptrdiff_t diff;
+ int i;
+
+ irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (irep->nlocals - 1));
+
+ 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;
+ }
+ 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);
+ }
+ 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);
+ if (ret != MRB_DUMP_OK) return ret;
+ bin += len;
+ }
+
+ diff = bin - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+ *record_len = (size_t)diff;
+
+ return MRB_DUMP_OK;
+}
+
+static int
+read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
+{
+ const uint8_t *bin;
+ ptrdiff_t diff;
+ struct rite_section_lv_header const *header;
+ uint32_t i;
+ size_t len = 0;
+ int result;
+ uint32_t syms_len;
+ mrb_sym *syms;
+ mrb_sym (*intern_func)(mrb_state*, const char*, size_t) =
+ (flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static;
+
+ bin = start;
+ header = (struct rite_section_lv_header const*)bin;
+ bin += sizeof(struct rite_section_lv_header);
+
+ syms_len = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)syms_len);
+ for (i = 0; i < syms_len; ++i) {
+ uint16_t const str_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+
+ syms[i] = intern_func(mrb, (const char*)bin, str_len);
+ bin += str_len;
+ }
+
+ result = read_lv_record(mrb, bin, irep, &len, syms, syms_len);
+ if (result != MRB_DUMP_OK) goto lv_exit;
+
+ bin += len;
+ diff = bin - start;
+ mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
+ if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
+ result = MRB_DUMP_GENERAL_FAILURE;
+ }
+
+lv_exit:
+ mrb_free(mrb, syms);
+ return result;
+}
+
+static int
+read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, 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;
+ }
+ 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 {
+ return MRB_DUMP_INVALID_FILE_HEADER;
+ }
+
+ if (crc) {
+ *crc = bin_to_uint16(header->binary_crc);
+ }
+ *bin_size = (size_t)bin_to_uint32(header->binary_size);
+
+ return MRB_DUMP_OK;
+}
+
+static mrb_irep*
+read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
+{
+ int result;
+ 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);
+ 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);
+ 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);
+ if (result < MRB_DUMP_OK) {
+ return NULL;
+ }
+ }
+ else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) {
+ if (!irep) return NULL;
+ result = read_section_lv(mrb, bin, irep, flags);
+ if (result < MRB_DUMP_OK) {
+ return NULL;
+ }
+ }
+ 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;
+}
+
+mrb_irep*
+mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
+{
+#ifdef MRB_USE_ETEXT_EDATA
+ 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);
+}
+
+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"));
+}
+
+void mrb_codedump_all(mrb_state*, struct RProc*);
+
+static mrb_value
+load_irep(mrb_state *mrb, mrb_irep *irep, mrbc_context *c)
+{
+ struct RProc *proc;
+
+ if (!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);
+}
+
+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);
+}
+
+MRB_API mrb_value
+mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
+{
+ return mrb_load_irep_cxt(mrb, bin, NULL);
+}
+
+#ifndef MRB_DISABLE_STDIO
+
+mrb_irep*
+mrb_read_irep_file(mrb_state *mrb, FILE* fp)
+{
+ mrb_irep *irep = NULL;
+ uint8_t *buf;
+ const size_t header_size = sizeof(struct rite_binary_header);
+ size_t buf_size = 0;
+ uint8_t flags = 0;
+ int result;
+
+ if ((mrb == NULL) || (fp == NULL)) {
+ return NULL;
+ }
+
+ buf = (uint8_t*)mrb_malloc(mrb, header_size);
+ if (fread(buf, header_size, 1, fp) == 0) {
+ goto irep_exit;
+ }
+ result = read_binary_header(buf, &buf_size, NULL, &flags);
+ if (result != MRB_DUMP_OK || buf_size <= header_size) {
+ goto irep_exit;
+ }
+
+ buf = (uint8_t*)mrb_realloc(mrb, buf, buf_size);
+ if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) {
+ goto irep_exit;
+ }
+ irep = read_irep(mrb, buf, FLAG_SRC_MALLOC);
+
+irep_exit:
+ mrb_free(mrb, buf);
+ return irep;
+}
+
+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);
+}
+
+MRB_API mrb_value
+mrb_load_irep_file(mrb_state *mrb, FILE* fp)
+{
+ return mrb_load_irep_file_cxt(mrb, fp, NULL);
+}
+#endif /* MRB_DISABLE_STDIO */
diff --git a/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake b/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake
new file mode 100644
index 00000000..4558493d
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake
@@ -0,0 +1,19 @@
+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$/
+ 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/web/server/h2o/libh2o/deps/mruby/src/numeric.c b/web/server/h2o/libh2o/deps/mruby/src/numeric.c
new file mode 100644
index 00000000..afb8415a
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/numeric.c
@@ -0,0 +1,1355 @@
+/*
+** numeric.c - Numeric, Integer, Float, Fixnum class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+
+#ifdef MRB_USE_FLOAT
+#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 "%.7g"
+#else
+#define MRB_FLO_TO_STR_FMT "%.14g"
+#endif
+
+MRB_API mrb_float
+mrb_to_flo(mrb_state *mrb, mrb_value val)
+{
+ switch (mrb_type(val)) {
+ case MRB_TT_FIXNUM:
+ return (mrb_float)mrb_fixnum(val);
+ case MRB_TT_FLOAT:
+ break;
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "non float value");
+ }
+ return mrb_float(val);
+}
+
+/*
+ * call-seq:
+ *
+ * num ** other -> num
+ *
+ * Raises <code>num</code> the <code>other</code> power.
+ *
+ * 2.0**3 #=> 8.0
+ */
+static mrb_value
+num_pow(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_float d;
+
+ 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;
+
+ if (exp < 0) goto float_pow;
+ for (;;) {
+ if (exp & 1) {
+ if (mrb_int_mul_overflow(result, base, &result)) {
+ goto float_pow;
+ }
+ }
+ exp >>= 1;
+ if (exp == 0) break;
+ if (mrb_int_mul_overflow(base, base, &base)) {
+ goto float_pow;
+ }
+ }
+ return mrb_fixnum_value(result);
+ }
+ float_pow:
+ d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, d);
+}
+
+/* 15.2.8.3.4 */
+/* 15.2.9.3.4 */
+/*
+ * call-seq:
+ * num / 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)
+{
+ return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
+}
+
+/* 15.2.9.3.19(x) */
+/*
+ * call-seq:
+ * num.quo(numeric) -> real
+ *
+ * Returns most exact division.
+ */
+
+static mrb_value
+num_div(mrb_state *mrb, mrb_value x)
+{
+ mrb_float y;
+
+ mrb_get_args(mrb, "f", &y);
+ return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
+}
+
+/********************************************************************
+ *
+ * Document-class: Float
+ *
+ * <code>Float</code> objects represent inexact real numbers using
+ * the native architecture's double-precision floating point
+ * representation.
+ */
+
+/* 15.2.9.3.16(x) */
+/*
+ * call-seq:
+ * flt.to_s -> 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>".
+ */
+
+static mrb_value
+flo_to_s(mrb_state *mrb, mrb_value flt)
+{
+ if (isnan(mrb_float(flt))) {
+ return mrb_str_new_lit(mrb, "NaN");
+ }
+ return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
+}
+
+/* 15.2.9.3.2 */
+/*
+ * call-seq:
+ * float - other -> float
+ *
+ * Returns a new float which is the difference of <code>float</code>
+ * and <code>other</code>.
+ */
+
+static mrb_value
+flo_minus(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));
+}
+
+/* 15.2.9.3.3 */
+/*
+ * call-seq:
+ * float * other -> float
+ *
+ * Returns a new float which is the product of <code>float</code>
+ * and <code>other</code>.
+ */
+
+static mrb_value
+flo_mul(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));
+}
+
+static void
+flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp)
+{
+ mrb_float div;
+ mrb_float mod;
+
+ if (y == 0.0) {
+ if (x > 0.0) div = INFINITY;
+ else if (x < 0.0) div = -INFINITY;
+ else div = NAN; /* x == 0.0 */
+ mod = NAN;
+ }
+ else {
+ mod = fmod(x, y);
+ if (isinf(x) && isfinite(y))
+ div = x;
+ else
+ div = (x - mod) / y;
+ if (y*mod < 0) {
+ mod += y;
+ div -= 1.0;
+ }
+ }
+
+ if (modp) *modp = mod;
+ if (divp) *divp = div;
+}
+
+/* 15.2.9.3.5 */
+/*
+ * call-seq:
+ * flt % other -> float
+ * flt.modulo(other) -> float
+ *
+ * Return the modulo after division of <code>flt</code> by <code>other</code>.
+ *
+ * 6543.21.modulo(137) #=> 104.21
+ * 6543.21.modulo(137.24) #=> 92.9299999999996
+ */
+
+static mrb_value
+flo_mod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_float mod;
+
+ mrb_get_args(mrb, "o", &y);
+
+ flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
+ return mrb_float_value(mrb, mod);
+}
+
+/* 15.2.8.3.16 */
+/*
+ * call-seq:
+ * num.eql?(numeric) -> true or false
+ *
+ * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
+ * same type and have equal values.
+ *
+ * 1 == 1.0 #=> true
+ * 1.eql?(1.0) #=> false
+ * (1.0).eql?(1.0) #=> true
+ */
+static mrb_value
+fix_eql(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ 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));
+}
+
+static mrb_value
+flo_eql(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ 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));
+}
+
+/* 15.2.9.3.7 */
+/*
+ * call-seq:
+ * flt == obj -> true or false
+ *
+ * Returns <code>true</code> only if <i>obj</i> has the same value
+ * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
+ * requires <i>obj</i> to be a <code>Float</code>.
+ *
+ * 1.0 == 1 #=> true
+ *
+ */
+
+static mrb_value
+flo_eq(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_get_args(mrb, "o", &y);
+
+ switch (mrb_type(y)) {
+ case MRB_TT_FIXNUM:
+ return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
+ case MRB_TT_FLOAT:
+ return mrb_bool_value(mrb_float(x) == mrb_float(y));
+ default:
+ return mrb_false_value();
+ }
+}
+
+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_FLOAT:
+ return (int64_t)mrb_float(x);
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
+ break;
+ }
+ /* not reached */
+ return 0;
+}
+
+static mrb_value
+int64_value(mrb_state *mrb, int64_t v)
+{
+ if (FIXABLE(v)) {
+ return mrb_fixnum_value((mrb_int)v);
+ }
+ return mrb_float_value(mrb, (mrb_float)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);
+ return int64_value(mrb, ~v1);
+}
+
+static mrb_value
+flo_and(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 & v2);
+}
+
+static mrb_value
+flo_or(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 | v2);
+}
+
+static mrb_value
+flo_xor(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 ^ v2);
+}
+
+static mrb_value
+flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
+{
+ mrb_float val;
+
+ if (width == 0) {
+ return x;
+ }
+ val = mrb_float(x);
+ if (width < 0) {
+ while (width++) {
+ val /= 2;
+ }
+#if defined(_ISOC99_SOURCE)
+ val = trunc(val);
+#else
+ if (val > 0){
+ val = floor(val);
+ } else {
+ val = ceil(val);
+ }
+#endif
+ if (val == 0 && mrb_float(x) < 0) {
+ return mrb_fixnum_value(-1);
+ }
+ }
+ else {
+ while (width--) {
+ val *= 2;
+ }
+ }
+ if (FIXABLE_FLOAT(val)) {
+ return mrb_fixnum_value((mrb_int)val);
+ }
+ return mrb_float_value(mrb, val);
+}
+
+static mrb_value
+flo_lshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width;
+
+ mrb_get_args(mrb, "i", &width);
+ return flo_shift(mrb, x, -width);
+}
+
+static mrb_value
+flo_rshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width;
+
+ mrb_get_args(mrb, "i", &width);
+ return flo_shift(mrb, x, width);
+}
+
+/* 15.2.9.3.13 */
+/*
+ * call-seq:
+ * flt.to_f -> self
+ *
+ * As <code>flt</code> is already a float, returns +self+.
+ */
+
+static mrb_value
+flo_to_f(mrb_state *mrb, mrb_value num)
+{
+ return num;
+}
+
+/* 15.2.9.3.11 */
+/*
+ * call-seq:
+ * flt.infinite? -> nil, -1, +1
+ *
+ * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
+ * is finite, -infinity, or +infinity.
+ *
+ * (0.0).infinite? #=> nil
+ * (-1.0/0.0).infinite? #=> -1
+ * (+1.0/0.0).infinite? #=> 1
+ */
+
+static mrb_value
+flo_infinite_p(mrb_state *mrb, mrb_value num)
+{
+ mrb_float value = mrb_float(num);
+
+ if (isinf(value)) {
+ return mrb_fixnum_value(value < 0 ? -1 : 1);
+ }
+ return mrb_nil_value();
+}
+
+/* 15.2.9.3.9 */
+/*
+ * call-seq:
+ * flt.finite? -> true or false
+ *
+ * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
+ * point number (it is not infinite, and <code>nan?</code> is
+ * <code>false</code>).
+ *
+ */
+
+static mrb_value
+flo_finite_p(mrb_state *mrb, mrb_value num)
+{
+ return mrb_bool_value(isfinite(mrb_float(num)));
+}
+
+void
+mrb_check_num_exact(mrb_state *mrb, mrb_float num)
+{
+ if (isinf(num)) {
+ mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
+ }
+ if (isnan(num)) {
+ mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
+ }
+}
+
+/* 15.2.9.3.10 */
+/*
+ * call-seq:
+ * flt.floor -> integer
+ *
+ * Returns the largest integer less than or equal to <i>flt</i>.
+ *
+ * 1.2.floor #=> 1
+ * 2.0.floor #=> 2
+ * (-1.2).floor #=> -2
+ * (-2.0).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);
+}
+
+/* 15.2.9.3.8 */
+/*
+ * call-seq:
+ * flt.ceil -> integer
+ *
+ * Returns the smallest <code>Integer</code> greater than or equal to
+ * <i>flt</i>.
+ *
+ * 1.2.ceil #=> 2
+ * 2.0.ceil #=> 2
+ * (-1.2).ceil #=> -1
+ * (-2.0).ceil #=> -2
+ */
+
+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);
+}
+
+/* 15.2.9.3.12 */
+/*
+ * call-seq:
+ * 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
+ * is more than zero.
+ *
+ * 1.4.round #=> 1
+ * 1.5.round #=> 2
+ * 1.6.round #=> 2
+ * (-1.5).round #=> -2
+ *
+ * 1.234567.round(2) #=> 1.23
+ * 1.234567.round(3) #=> 1.235
+ * 1.234567.round(4) #=> 1.2346
+ * 1.234567.round(5) #=> 1.23457
+ *
+ * 34567.89.round(-5) #=> 0
+ * 34567.89.round(-4) #=> 30000
+ * 34567.89.round(-3) #=> 35000
+ * 34567.89.round(-2) #=> 34600
+ * 34567.89.round(-1) #=> 34570
+ * 34567.89.round(0) #=> 34568
+ * 34567.89.round(1) #=> 34567.9
+ * 34567.89.round(2) #=> 34567.89
+ * 34567.89.round(3) #=> 34567.89
+ *
+ */
+
+static mrb_value
+flo_round(mrb_state *mrb, mrb_value num)
+{
+ double number, f;
+ mrb_int ndigits = 0;
+ mrb_int i;
+
+ mrb_get_args(mrb, "|i", &ndigits);
+ number = mrb_float(num);
+
+ if (0 < ndigits && (isinf(number) || isnan(number))) {
+ return num;
+ }
+ mrb_check_num_exact(mrb, number);
+
+ f = 1.0;
+ i = ndigits >= 0 ? ndigits : -ndigits;
+ while (--i >= 0)
+ f = f*10.0;
+
+ if (isinf(f)) {
+ if (ndigits < 0) number = 0;
+ }
+ else {
+ double d;
+
+ if (ndigits < 0) number /= f;
+ else number *= f;
+
+ /* home-made inline implementation of round(3) */
+ if (number > 0.0) {
+ d = floor(number);
+ number = d + (number - d >= 0.5);
+ }
+ else if (number < 0.0) {
+ d = ceil(number);
+ number = d - (d - number >= 0.5);
+ }
+
+ if (ndigits < 0) number *= f;
+ else number /= f;
+ }
+
+ if (ndigits > 0) {
+ if (!isfinite(number)) return num;
+ return mrb_float_value(mrb, number);
+ }
+ return mrb_fixnum_value((mrb_int)number);
+}
+
+/* 15.2.9.3.14 */
+/* 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>.
+ */
+
+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);
+}
+
+static mrb_value
+flo_nan_p(mrb_state *mrb, mrb_value num)
+{
+ return mrb_bool_value(isnan(mrb_float(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>.
+ *
+ */
+
+
+/*
+ * 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.
+ */
+
+static mrb_value
+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)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (mrb_fixnum_p(y)) {
+ mrb_int b, c;
+
+ if (a == 0) return x;
+ b = mrb_fixnum(y);
+ if (mrb_int_mul_overflow(a, b, &c)) {
+ return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+}
+
+/* 15.2.8.3.3 */
+/*
+ * call-seq:
+ * fix * numeric -> numeric_result
+ *
+ * Performs multiplication: the class of the resulting object depends on
+ * the class of <code>numeric</code> and on the magnitude of the
+ * result.
+ */
+
+static mrb_value
+fix_mul(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ return mrb_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);
+ }
+ else {
+ if (x < 0)
+ div = - (-x / y);
+ else
+ div = x / y;
+ }
+ mod = x - div*y;
+ if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
+ mod += y;
+ div -= 1;
+ }
+ if (divp) *divp = div;
+ if (modp) *modp = mod;
+}
+
+/* 15.2.8.3.5 */
+/*
+ * call-seq:
+ * fix % other -> real
+ * fix.modulo(other) -> real
+ *
+ * Returns <code>fix</code> modulo <code>other</code>.
+ * See <code>numeric.divmod</code> for more information.
+ */
+
+static mrb_value
+fix_mod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_int a;
+
+ mrb_get_args(mrb, "o", &y);
+ a = mrb_fixnum(x);
+ if (mrb_fixnum_p(y)) {
+ mrb_int b, mod;
+
+ if ((b=mrb_fixnum(y)) == 0) {
+ return mrb_float_value(mrb, NAN);
+ }
+ fixdivmod(mrb, a, b, 0, &mod);
+ return mrb_fixnum_value(mod);
+ }
+ else {
+ mrb_float mod;
+
+ flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
+ return mrb_float_value(mrb, mod);
+ }
+}
+
+/*
+ * call-seq:
+ * fix.divmod(numeric) -> array
+ *
+ * See <code>Numeric#divmod</code>.
+ */
+static mrb_value
+fix_divmod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+
+ if (mrb_fixnum_p(y)) {
+ mrb_int div, mod;
+
+ if (mrb_fixnum(y) == 0) {
+ return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
+ mrb_float_value(mrb, NAN):
+ mrb_float_value(mrb, INFINITY)),
+ mrb_float_value(mrb, NAN));
+ }
+ fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
+ return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
+ }
+ 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);
+ b = mrb_float_value(mrb, mod);
+ return mrb_assoc_new(mrb, a, b);
+ }
+}
+
+static mrb_value
+flo_divmod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ 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);
+ b = mrb_float_value(mrb, mod);
+ return mrb_assoc_new(mrb, a, b);
+}
+
+/* 15.2.8.3.7 */
+/*
+ * call-seq:
+ * fix == other -> true or false
+ *
+ * Return <code>true</code> if <code>fix</code> equals <code>other</code>
+ * numerically.
+ *
+ * 1 == 2 #=> false
+ * 1 == 1.0 #=> true
+ */
+
+static mrb_value
+fix_equal(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ switch (mrb_type(y)) {
+ case MRB_TT_FIXNUM:
+ return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
+ case MRB_TT_FLOAT:
+ return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
+ default:
+ return mrb_false_value();
+ }
+}
+
+/* 15.2.8.3.8 */
+/*
+ * call-seq:
+ * ~fix -> integer
+ *
+ * One's complement: returns a number where each bit is flipped.
+ * ex.0---00001 (1)-> 1---11110 (-2)
+ * ex.0---00010 (2)-> 1---11101 (-3)
+ * ex.0---00100 (4)-> 1---11011 (-5)
+ */
+
+static mrb_value
+fix_rev(mrb_state *mrb, mrb_value num)
+{
+ mrb_int val = mrb_fixnum(num);
+
+ return mrb_fixnum_value(~val);
+}
+
+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_fixnum(x)));\
+} while(0)
+
+/* 15.2.8.3.9 */
+/*
+ * call-seq:
+ * fix & integer -> integer_result
+ *
+ * Bitwise AND.
+ */
+
+static mrb_value
+fix_and(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ bit_op(x, y, and, &);
+}
+
+/* 15.2.8.3.10 */
+/*
+ * call-seq:
+ * fix | integer -> integer_result
+ *
+ * Bitwise OR.
+ */
+
+static mrb_value
+fix_or(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ bit_op(x, y, or, |);
+}
+
+/* 15.2.8.3.11 */
+/*
+ * call-seq:
+ * fix ^ integer -> integer_result
+ *
+ * Bitwise EXCLUSIVE OR.
+ */
+
+static mrb_value
+fix_xor(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ bit_op(x, y, or, ^);
+}
+
+#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
+
+static mrb_value
+lshift(mrb_state *mrb, mrb_int val, mrb_int width)
+{
+ if (width < 0) { /* mrb_int overflow */
+ return mrb_float_value(mrb, INFINITY);
+ }
+ if (val > 0) {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val > (MRB_INT_MAX >> width))) {
+ goto bit_overflow;
+ }
+ return mrb_fixnum_value(val << width);
+ }
+ else {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val < (MRB_INT_MIN >> width))) {
+ goto bit_overflow;
+ }
+ return mrb_fixnum_value(val * (1u << width));
+ }
+
+bit_overflow:
+ {
+ mrb_float f = (mrb_float)val;
+ while (width--) {
+ f *= 2;
+ }
+ return mrb_float_value(mrb, f);
+ }
+}
+
+static mrb_value
+rshift(mrb_int val, mrb_int width)
+{
+ if (width < 0) { /* mrb_int overflow */
+ return mrb_fixnum_value(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);
+}
+
+/* 15.2.8.3.12 */
+/*
+ * call-seq:
+ * fix << count -> integer or float
+ *
+ * Shifts _fix_ left _count_ positions (right if _count_ is negative).
+ */
+
+static mrb_value
+fix_lshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width, val;
+
+ mrb_get_args(mrb, "i", &width);
+ if (width == 0) {
+ return x;
+ }
+ val = mrb_fixnum(x);
+ if (val == 0) return x;
+ if (width < 0) {
+ return rshift(val, -width);
+ }
+ return lshift(mrb, val, width);
+}
+
+/* 15.2.8.3.13 */
+/*
+ * call-seq:
+ * fix >> count -> integer or float
+ *
+ * Shifts _fix_ right _count_ positions (left if _count_ is negative).
+ */
+
+static mrb_value
+fix_rshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width, val;
+
+ mrb_get_args(mrb, "i", &width);
+ if (width == 0) {
+ return x;
+ }
+ val = mrb_fixnum(x);
+ if (val == 0) return x;
+ if (width < 0) {
+ return lshift(mrb, val, -width);
+ }
+ return rshift(val, width);
+}
+
+/* 15.2.8.3.23 */
+/*
+ * call-seq:
+ * fix.to_f -> float
+ *
+ * Converts <i>fix</i> to a <code>Float</code>.
+ *
+ */
+
+static mrb_value
+fix_to_f(mrb_state *mrb, mrb_value num)
+{
+ return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
+}
+
+/*
+ * Document-class: FloatDomainError
+ *
+ * Raised when attempting to convert special float values
+ * (in particular infinite or NaN)
+ * to numerical classes which don't support them.
+ *
+ * Float::INFINITY.to_r
+ *
+ * <em>raises the exception:</em>
+ *
+ * FloatDomainError: Infinity
+ */
+/* ------------------------------------------------------------------------*/
+MRB_API mrb_value
+mrb_flo_to_fixnum(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");
+ }
+ if (FIXABLE_FLOAT(d)) {
+ z = (mrb_int)d;
+ }
+ else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x);
+ }
+ }
+ return mrb_fixnum_value(z);
+}
+
+mrb_value
+mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (mrb_fixnum_p(y)) {
+ mrb_int b, c;
+
+ if (a == 0) return y;
+ b = mrb_fixnum(y);
+ if (mrb_int_add_overflow(a, b, &c)) {
+ return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
+}
+
+/* 15.2.8.3.1 */
+/*
+ * call-seq:
+ * fix + numeric -> numeric_result
+ *
+ * Performs addition: the class of the resulting object depends on
+ * the class of <code>numeric</code> and on the magnitude of the
+ * result.
+ */
+static mrb_value
+fix_plus(mrb_state *mrb, mrb_value self)
+{
+ mrb_value other;
+
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_plus(mrb, self, other);
+}
+
+mrb_value
+mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (mrb_fixnum_p(y)) {
+ mrb_int b, c;
+
+ b = mrb_fixnum(y);
+ if (mrb_int_sub_overflow(a, b, &c)) {
+ return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
+}
+
+/* 15.2.8.3.2 */
+/* 15.2.8.3.16 */
+/*
+ * call-seq:
+ * fix - numeric -> numeric_result
+ *
+ * Performs subtraction: the class of the resulting object depends on
+ * the class of <code>numeric</code> and on the magnitude of the
+ * result.
+ */
+static mrb_value
+fix_minus(mrb_state *mrb, mrb_value self)
+{
+ mrb_value other;
+
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_minus(mrb, self, other);
+}
+
+
+MRB_API mrb_value
+mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
+{
+ char buf[MRB_INT_BIT+1];
+ char *b = buf + sizeof buf;
+ mrb_int val = mrb_fixnum(x);
+
+ if (base < 2 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
+ }
+
+ if (val == 0) {
+ *--b = '0';
+ }
+ else if (val < 0) {
+ do {
+ *--b = mrb_digitmap[-(val % base)];
+ } while (val /= base);
+ *--b = '-';
+ }
+ else {
+ do {
+ *--b = mrb_digitmap[(int)(val % base)];
+ } while (val /= base);
+ }
+
+ return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
+}
+
+/* 15.2.8.3.25 */
+/*
+ * call-seq:
+ * fix.to_s(base=10) -> string
+ *
+ * Returns a string containing the representation of <i>fix</i> radix
+ * <i>base</i> (between 2 and 36).
+ *
+ * 12345.to_s #=> "12345"
+ * 12345.to_s(2) #=> "11000000111001"
+ * 12345.to_s(8) #=> "30071"
+ * 12345.to_s(10) #=> "12345"
+ * 12345.to_s(16) #=> "3039"
+ * 12345.to_s(36) #=> "9ix"
+ *
+ */
+static mrb_value
+fix_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);
+}
+
+/* 15.2.9.3.6 */
+/*
+ * call-seq:
+ * self.f <=> other.f => -1, 0, +1
+ * < => -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>.
+ */
+static mrb_value
+num_cmp(mrb_state *mrb, mrb_value self)
+{
+ mrb_value other;
+ mrb_float x, y;
+
+ mrb_get_args(mrb, "o", &other);
+
+ x = mrb_to_flo(mrb, self);
+ switch (mrb_type(other)) {
+ case MRB_TT_FIXNUM:
+ y = (mrb_float)mrb_fixnum(other);
+ break;
+ case MRB_TT_FLOAT:
+ y = mrb_float(other);
+ break;
+ default:
+ return mrb_nil_value();
+ }
+ if (x > y)
+ return mrb_fixnum_value(1);
+ else {
+ if (x < y)
+ return mrb_fixnum_value(-1);
+ return mrb_fixnum_value(0);
+ }
+}
+
+/* 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_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));
+}
+
+/* ------------------------------------------------------------------------*/
+void
+mrb_init_numeric(mrb_state *mrb)
+{
+ struct RClass *numeric, *integer, *fixnum, *fl;
+
+ /* 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 */
+
+ /* Integer Class */
+ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
+ MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
+ mrb_undef_class_method(mrb, integer, "new");
+ 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());
+ 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) */
+
+ /* 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 */
+ mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
+ 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) */
+
+ /* 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_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, "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, "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, "divmod", flo_divmod, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
+
+ mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
+ mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
+
+#ifdef INFINITY
+ mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
+#endif
+#ifdef NAN
+ mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
+#endif
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/object.c b/web/server/h2o/libh2o/deps/mruby/src/object.c
new file mode 100644
index 00000000..368e90b9
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/object.c
@@ -0,0 +1,610 @@
+/*
+** object.c - Object, NilClass, TrueClass, FalseClass class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+
+MRB_API mrb_bool
+mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
+{
+ if (mrb_type(v1) != mrb_type(v2)) return FALSE;
+ switch (mrb_type(v1)) {
+ case MRB_TT_TRUE:
+ return TRUE;
+
+ case MRB_TT_FALSE:
+ case MRB_TT_FIXNUM:
+ return (mrb_fixnum(v1) == mrb_fixnum(v2));
+ case MRB_TT_SYMBOL:
+ return (mrb_symbol(v1) == mrb_symbol(v2));
+
+ case MRB_TT_FLOAT:
+ return (mrb_float(v1) == mrb_float(v2));
+
+ default:
+ return (mrb_ptr(v1) == mrb_ptr(v2));
+ }
+}
+
+MRB_API mrb_bool
+mrb_obj_equal(mrb_state *mrb, mrb_value v1, mrb_value v2)
+{
+ /* temporary definition */
+ return mrb_obj_eq(mrb, v1, v2);
+}
+
+MRB_API mrb_bool
+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);
+ if (mrb_test(result)) return TRUE;
+ return FALSE;
+}
+
+/*
+ * Document-class: NilClass
+ *
+ * The class of the singleton object <code>nil</code>.
+ */
+
+/* 15.2.4.3.4 */
+/*
+ * call_seq:
+ * nil.nil? -> true
+ *
+ * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
+ */
+
+static mrb_value
+mrb_true(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_true_value();
+}
+
+/* 15.2.4.3.5 */
+/*
+ * call-seq:
+ * nil.to_s -> ""
+ *
+ * Always returns the empty string.
+ */
+
+static mrb_value
+nil_to_s(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_str_new(mrb, 0, 0);
+}
+
+static mrb_value
+nil_inspect(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_str_new_lit(mrb, "nil");
+}
+
+/***********************************************************************
+ * Document-class: TrueClass
+ *
+ * The global value <code>true</code> is the only instance of class
+ * <code>TrueClass</code> and represents a logically true value in
+ * boolean expressions. The class provides operators allowing
+ * <code>true</code> to be used in logical expressions.
+ */
+
+/* 15.2.5.3.1 */
+/*
+ * call-seq:
+ * true & obj -> true or false
+ *
+ * And---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>true</code> otherwise.
+ */
+
+static mrb_value
+true_and(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool obj2;
+
+ mrb_get_args(mrb, "b", &obj2);
+
+ return mrb_bool_value(obj2);
+}
+
+/* 15.2.5.3.2 */
+/*
+ * call-seq:
+ * true ^ obj -> !obj
+ *
+ * Exclusive Or---Returns <code>true</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>false</code>
+ * otherwise.
+ */
+
+static mrb_value
+true_xor(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool obj2;
+
+ mrb_get_args(mrb, "b", &obj2);
+ return mrb_bool_value(!obj2);
+}
+
+/* 15.2.5.3.3 */
+/*
+ * call-seq:
+ * true.to_s -> "true"
+ *
+ * The string representation of <code>true</code> is "true".
+ */
+
+static mrb_value
+true_to_s(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_str_new_lit(mrb, "true");
+}
+
+/* 15.2.5.3.4 */
+/*
+ * call-seq:
+ * true | obj -> true
+ *
+ * Or---Returns <code>true</code>. As <i>anObject</i> is an argument to
+ * a method call, it is always evaluated; there is no short-circuit
+ * evaluation in this case.
+ *
+ * true | puts("or")
+ * true || puts("logical or")
+ *
+ * <em>produces:</em>
+ *
+ * or
+ */
+
+static mrb_value
+true_or(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_true_value();
+}
+
+/*
+ * Document-class: FalseClass
+ *
+ * The global value <code>false</code> is the only instance of class
+ * <code>FalseClass</code> and represents a logically false value in
+ * boolean expressions. The class provides operators allowing
+ * <code>false</code> to participate correctly in logical expressions.
+ *
+ */
+
+/* 15.2.4.3.1 */
+/* 15.2.6.3.1 */
+/*
+ * call-seq:
+ * false & obj -> false
+ * nil & obj -> false
+ *
+ * And---Returns <code>false</code>. <i>obj</i> is always
+ * evaluated as it is the argument to a method call---there is no
+ * short-circuit evaluation in this case.
+ */
+
+static mrb_value
+false_and(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_false_value();
+}
+
+/* 15.2.4.3.2 */
+/* 15.2.6.3.2 */
+/*
+ * call-seq:
+ * false ^ obj -> true or false
+ * nil ^ obj -> true or false
+ *
+ * Exclusive Or---If <i>obj</i> is <code>nil</code> or
+ * <code>false</code>, returns <code>false</code>; otherwise, returns
+ * <code>true</code>.
+ *
+ */
+
+static mrb_value
+false_xor(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool obj2;
+
+ mrb_get_args(mrb, "b", &obj2);
+ return mrb_bool_value(obj2);
+}
+
+/* 15.2.4.3.3 */
+/* 15.2.6.3.4 */
+/*
+ * call-seq:
+ * false | obj -> true or false
+ * nil | obj -> true or false
+ *
+ * Or---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>; <code>true</code> otherwise.
+ */
+
+static mrb_value
+false_or(mrb_state *mrb, mrb_value obj)
+{
+ mrb_bool obj2;
+
+ mrb_get_args(mrb, "b", &obj2);
+ return mrb_bool_value(obj2);
+}
+
+/* 15.2.6.3.3 */
+/*
+ * call-seq:
+ * false.to_s -> "false"
+ *
+ * 'nuf said...
+ */
+
+static mrb_value
+false_to_s(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_str_new_lit(mrb, "false");
+}
+
+void
+mrb_init_object(mrb_state *mrb)
+{
+ struct RClass *n;
+ struct RClass *t;
+ struct RClass *f;
+
+ mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
+ MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE);
+ 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 */
+ mrb_define_method(mrb, n, "|", false_or, MRB_ARGS_REQ(1)); /* 15.2.4.3.3 */
+ mrb_define_method(mrb, n, "nil?", mrb_true, MRB_ARGS_NONE()); /* 15.2.4.3.4 */
+ mrb_define_method(mrb, n, "to_s", nil_to_s, MRB_ARGS_NONE()); /* 15.2.4.3.5 */
+ mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE());
+
+ mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class);
+ MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE);
+ mrb_undef_class_method(mrb, t, "new");
+ mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */
+ mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */
+ mrb_define_method(mrb, t, "to_s", true_to_s, MRB_ARGS_NONE()); /* 15.2.5.3.3 */
+ mrb_define_method(mrb, t, "|", true_or, MRB_ARGS_REQ(1)); /* 15.2.5.3.4 */
+ 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_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 */
+ mrb_define_method(mrb, f, "to_s", false_to_s, MRB_ARGS_NONE()); /* 15.2.6.3.3 */
+ mrb_define_method(mrb, f, "|", false_or, MRB_ARGS_REQ(1)); /* 15.2.6.3.4 */
+ mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE());
+}
+
+static mrb_value
+inspect_type(mrb_state *mrb, mrb_value val)
+{
+ 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));
+ }
+}
+
+static mrb_value
+convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise)
+{
+ mrb_sym m = 0;
+
+ m = mrb_intern_cstr(mrb, method);
+ if (!mrb_respond_to(mrb, val, m)) {
+ if (raise) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname));
+ }
+ return mrb_nil_value();
+ }
+ return mrb_funcall_argv(mrb, val, m, 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_value v;
+
+ if (mrb_type(val) == type) return val;
+ 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));
+ }
+ 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_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);
+ 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"},
+ {MRB_TT_FLOAT, "Float"},
+ {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)));
+ }
+}
+
+/* 15.3.1.3.46 */
+/*
+ * call-seq:
+ * obj.to_s => string
+ *
+ * Returns a string representing <i>obj</i>. The default
+ * <code>to_s</code> prints the object's class and an encoding of the
+ * object id. As a special case, the top-level object that is the
+ * initial execution context of Ruby programs returns "main."
+ */
+
+MRB_API mrb_value
+mrb_any_to_s(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value str = mrb_str_new_capa(mrb, 20);
+ const char *cname = mrb_obj_classname(mrb, 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)));
+ mrb_str_cat_lit(mrb, str, ">");
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * obj.is_a?(class) => true or false
+ * obj.kind_of?(class) => true or false
+ *
+ * Returns <code>true</code> if <i>class</i> is the class of
+ * <i>obj</i>, or if <i>class</i> is one of the superclasses of
+ * <i>obj</i> or modules included in <i>obj</i>.
+ *
+ * module M; end
+ * class A
+ * include M
+ * end
+ * class B < A; end
+ * class C < B; end
+ * b = B.new
+ * b.instance_of? A #=> false
+ * b.instance_of? B #=> true
+ * b.instance_of? C #=> false
+ * b.instance_of? M #=> false
+ * b.kind_of? A #=> true
+ * b.kind_of? B #=> true
+ * b.kind_of? C #=> false
+ * b.kind_of? M #=> true
+ */
+
+MRB_API mrb_bool
+mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
+{
+ struct RClass *cl = mrb_class(mrb, obj);
+
+ switch (c->tt) {
+ case MRB_TT_MODULE:
+ case MRB_TT_CLASS:
+ case MRB_TT_ICLASS:
+ case MRB_TT_SCLASS:
+ break;
+
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "class or module required");
+ }
+
+ MRB_CLASS_ORIGIN(c);
+ while (cl) {
+ if (cl == c || cl->mt == c->mt)
+ return TRUE;
+ cl = cl->super;
+ }
+ 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");
+}
+
+MRB_API mrb_value
+mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
+{
+ mrb_value tmp;
+
+ if (mrb_nil_p(val)) {
+ if (base != 0) goto arg_error;
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer");
+ }
+ switch (mrb_type(val)) {
+ 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);
+
+ case MRB_TT_FIXNUM:
+ if (base != 0) goto arg_error;
+ return val;
+
+ case MRB_TT_STRING:
+ string_conv:
+ return mrb_str_to_inum(mrb, val, base, TRUE);
+
+ default:
+ break;
+ }
+ if (base != 0) {
+ tmp = mrb_check_string_type(mrb, val);
+ if (!mrb_nil_p(tmp)) {
+ val = tmp;
+ goto string_conv;
+ }
+arg_error:
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
+ }
+ tmp = convert_type(mrb, val, "Integer", "to_int", FALSE);
+ if (mrb_nil_p(tmp)) {
+ return mrb_to_integer(mrb, val, "to_i");
+ }
+ return tmp;
+}
+
+MRB_API mrb_value
+mrb_Integer(mrb_state *mrb, mrb_value val)
+{
+ return mrb_convert_to_integer(mrb, val, 0);
+}
+
+MRB_API mrb_value
+mrb_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_FLOAT:
+ return val;
+
+ case MRB_TT_STRING:
+ 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");
+ }
+}
+
+MRB_API mrb_value
+mrb_inspect(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "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));
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/opcode.h b/web/server/h2o/libh2o/deps/mruby/src/opcode.h
new file mode 100644
index 00000000..fe4d17a2
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/opcode.h
@@ -0,0 +1,2 @@
+/* this header file is to be removed soon. */
+#include <mruby/opcode.h>
diff --git a/web/server/h2o/libh2o/deps/mruby/src/pool.c b/web/server/h2o/libh2o/deps/mruby/src/pool.c
new file mode 100644
index 00000000..db4546ab
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/pool.c
@@ -0,0 +1,198 @@
+/*
+** pool.c - memory pool
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <mruby.h>
+
+/* configuration section */
+/* allocated memory address should be multiple of POOL_ALIGNMENT */
+/* or undef it if alignment does not matter */
+#ifndef POOL_ALIGNMENT
+#if INTPTR_MAX == INT64_MAX
+#define POOL_ALIGNMENT 8
+#else
+#define POOL_ALIGNMENT 4
+#endif
+#endif
+/* page size of memory pool */
+#ifndef POOL_PAGE_SIZE
+#define POOL_PAGE_SIZE 16000
+#endif
+/* end of configuration section */
+
+struct mrb_pool_page {
+ struct mrb_pool_page *next;
+ size_t offset;
+ size_t len;
+ void *last;
+ char page[];
+};
+
+struct mrb_pool {
+ mrb_state *mrb;
+ struct mrb_pool_page *pages;
+};
+
+#undef TEST_POOL
+#ifdef TEST_POOL
+
+#define mrb_malloc_simple(m,s) malloc(s)
+#define mrb_free(m,p) free(p)
+#endif
+
+#ifdef POOL_ALIGNMENT
+# define ALIGN_PADDING(x) ((SIZE_MAX - (x) + 1) & (POOL_ALIGNMENT - 1))
+#else
+# define ALIGN_PADDING(x) (0)
+#endif
+
+MRB_API mrb_pool*
+mrb_pool_open(mrb_state *mrb)
+{
+ mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool));
+
+ if (pool) {
+ pool->mrb = mrb;
+ pool->pages = NULL;
+ }
+
+ return pool;
+}
+
+MRB_API void
+mrb_pool_close(mrb_pool *pool)
+{
+ struct mrb_pool_page *page, *tmp;
+
+ if (!pool) return;
+ page = pool->pages;
+ while (page) {
+ tmp = page;
+ page = page->next;
+ mrb_free(pool->mrb, tmp);
+ }
+ mrb_free(pool->mrb, pool);
+}
+
+static struct mrb_pool_page*
+page_alloc(mrb_pool *pool, size_t len)
+{
+ struct mrb_pool_page *page;
+
+ if (len < POOL_PAGE_SIZE)
+ len = POOL_PAGE_SIZE;
+ page = (struct mrb_pool_page *)mrb_malloc_simple(pool->mrb, sizeof(struct mrb_pool_page)+len);
+ if (page) {
+ page->offset = 0;
+ page->len = len;
+ }
+
+ return page;
+}
+
+MRB_API void*
+mrb_pool_alloc(mrb_pool *pool, size_t len)
+{
+ struct mrb_pool_page *page;
+ size_t n;
+
+ if (!pool) return NULL;
+ len += ALIGN_PADDING(len);
+ page = pool->pages;
+ while (page) {
+ if (page->offset + len <= page->len) {
+ n = page->offset;
+ page->offset += len;
+ page->last = (char*)page->page+n;
+ return page->last;
+ }
+ page = page->next;
+ }
+ page = page_alloc(pool, len);
+ if (!page) return NULL;
+ page->offset = len;
+ page->next = pool->pages;
+ pool->pages = page;
+
+ page->last = (void*)page->page;
+ return page->last;
+}
+
+MRB_API mrb_bool
+mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len)
+{
+ struct mrb_pool_page *page;
+
+ if (!pool) return FALSE;
+ len += ALIGN_PADDING(len);
+ page = pool->pages;
+ while (page) {
+ if (page->last == p) {
+ size_t beg;
+
+ beg = (char*)p - page->page;
+ if (beg + len > page->len) return FALSE;
+ return TRUE;
+ }
+ page = page->next;
+ }
+ return FALSE;
+}
+
+MRB_API void*
+mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen)
+{
+ struct mrb_pool_page *page;
+ void *np;
+
+ if (!pool) return NULL;
+ oldlen += ALIGN_PADDING(oldlen);
+ newlen += ALIGN_PADDING(newlen);
+ page = pool->pages;
+ while (page) {
+ if (page->last == p) {
+ size_t beg;
+
+ beg = (char*)p - page->page;
+ if (beg + oldlen != page->offset) break;
+ if (beg + newlen > page->len) {
+ page->offset = beg;
+ break;
+ }
+ page->offset = beg + newlen;
+ return p;
+ }
+ page = page->next;
+ }
+ np = mrb_pool_alloc(pool, newlen);
+ if (np == NULL) {
+ return NULL;
+ }
+ memcpy(np, p, oldlen);
+ return np;
+}
+
+#ifdef TEST_POOL
+int
+main(void)
+{
+ int i, len = 250;
+ mrb_pool *pool;
+ void *p;
+
+ pool = mrb_pool_open(NULL);
+ p = mrb_pool_alloc(pool, len);
+ for (i=1; i<20; i++) {
+ printf("%p (len=%d) %ud\n", p, len, mrb_pool_can_realloc(pool, p, len*2));
+ p = mrb_pool_realloc(pool, p, len, len*2);
+ len *= 2;
+ }
+ mrb_pool_close(pool);
+ return 0;
+}
+#endif
diff --git a/web/server/h2o/libh2o/deps/mruby/src/print.c b/web/server/h2o/libh2o/deps/mruby/src/print.c
new file mode 100644
index 00000000..03b5eadf
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/print.c
@@ -0,0 +1,47 @@
+/*
+** print.c - Kernel.#p
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+
+#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);
+ }
+}
+#else
+# define printstr(obj, stream) (void)0
+#endif
+
+MRB_API void
+mrb_p(mrb_state *mrb, mrb_value obj)
+{
+ 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);
+}
+
+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);
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/proc.c b/web/server/h2o/libh2o/deps/mruby/src/proc.c
new file mode 100644
index 00000000..10a2c4f3
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/proc.c
@@ -0,0 +1,294 @@
+/*
+** proc.c - Proc class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/opcode.h>
+
+static mrb_code call_iseq[] = {
+ MKOP_A(OP_CALL, 0),
+};
+
+struct RProc*
+mrb_proc_new(mrb_state *mrb, 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->target_class = 0;
+ if (ci) {
+ if (ci->proc)
+ p->target_class = ci->proc->target_class;
+ if (!p->target_class)
+ p->target_class = ci->target_class;
+ }
+ p->body.irep = irep;
+ p->env = 0;
+ mrb_irep_incref(mrb, irep);
+
+ return p;
+}
+
+static struct REnv*
+env_new(mrb_state *mrb, int nlocals)
+{
+ struct REnv *e;
+
+ e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
+ MRB_SET_ENV_STACK_LEN(e, nlocals);
+ e->cxt.c = mrb->c;
+ e->cioff = mrb->c->ci - mrb->c->cibase;
+ e->stack = mrb->c->stack;
+
+ return e;
+}
+
+static void
+closure_setup(mrb_state *mrb, struct RProc *p, int nlocals)
+{
+ struct REnv *e;
+
+ if (!mrb->c->ci->env) {
+ e = env_new(mrb, nlocals);
+ mrb->c->ci->env = e;
+ }
+ else {
+ e = mrb->c->ci->env;
+ }
+ p->env = e;
+ mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env);
+}
+
+struct RProc*
+mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
+{
+ struct RProc *p = mrb_proc_new(mrb, irep);
+
+ closure_setup(mrb, p, mrb->c->ci->proc->body.irep->nlocals);
+ return p;
+}
+
+MRB_API struct RProc*
+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->body.func = func;
+ p->flags |= MRB_PROC_CFUNC;
+ p->env = 0;
+
+ return p;
+}
+
+MRB_API struct RProc*
+mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv)
+{
+ struct RProc *p = mrb_proc_new_cfunc(mrb, func);
+ struct REnv *e;
+ int i;
+
+ p->env = e = env_new(mrb, argc);
+ mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env);
+ MRB_ENV_UNSHARE_STACK(e);
+ e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
+ if (argv) {
+ for (i = 0; i < argc; ++i) {
+ e->stack[i] = argv[i];
+ }
+ }
+ else {
+ for (i = 0; i < argc; ++i) {
+ SET_NIL_VALUE(e->stack[i]);
+ }
+ }
+ return p;
+}
+
+MRB_API struct RProc*
+mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
+{
+ return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL);
+}
+
+MRB_API mrb_value
+mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
+{
+ struct RProc *p = mrb->c->ci->proc;
+ struct REnv *e = p->env;
+
+ if (!MRB_PROC_CFUNC_P(p)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
+ }
+ if (!e) {
+ 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)));
+ }
+
+ return e->stack[idx];
+}
+
+void
+mrb_proc_copy(struct RProc *a, struct RProc *b)
+{
+ if (a->body.irep) {
+ /* already initialized proc */
+ return;
+ }
+ a->flags = b->flags;
+ a->body = b->body;
+ if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
+ a->body.irep->refcnt++;
+ }
+ a->target_class = b->target_class;
+ a->env = b->env;
+}
+
+static mrb_value
+mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
+{
+ mrb_value blk;
+ 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));
+ 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);
+ if (!MRB_PROC_STRICT_P(p) &&
+ mrb->c->ci > mrb->c->cibase && p->env == mrb->c->ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
+ }
+ return proc;
+}
+
+static mrb_value
+mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
+{
+ mrb_value proc;
+
+ mrb_get_args(mrb, "o", &proc);
+ if (mrb_type(proc) != MRB_TT_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)
+{
+ return MRB_PROC_CFUNC_P(p);
+}
+
+mrb_value
+mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self)
+{
+ return (p->body.func)(mrb, self);
+}
+
+/* 15.2.17.4.2 */
+static mrb_value
+mrb_proc_arity(mrb_state *mrb, mrb_value self)
+{
+ struct RProc *p = mrb_proc_ptr(self);
+ struct mrb_irep *irep;
+ mrb_code *iseq;
+ mrb_aspec aspec;
+ int ma, op, ra, pa, arity;
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ /* TODO cfunc aspec not implemented yet */
+ return mrb_fixnum_value(-1);
+ }
+
+ irep = p->body.irep;
+ if (!irep) {
+ return mrb_fixnum_value(0);
+ }
+
+ iseq = irep->iseq;
+ /* arity is depend on OP_ENTER */
+ if (GET_OPCODE(*iseq) != OP_ENTER) {
+ return mrb_fixnum_value(0);
+ }
+
+ aspec = GETARG_Ax(*iseq);
+ ma = MRB_ASPEC_REQ(aspec);
+ op = MRB_ASPEC_OPT(aspec);
+ ra = MRB_ASPEC_REST(aspec);
+ pa = MRB_ASPEC_POST(aspec);
+ arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
+
+ return mrb_fixnum_value(arity);
+}
+
+/* 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 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_type(blk) != MRB_TT_PROC) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
+ }
+ 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 blk;
+}
+
+void
+mrb_init_proc(mrb_state *mrb)
+{
+ struct RProc *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_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());
+
+ m = mrb_proc_new(mrb, call_irep);
+ mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m);
+ mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m);
+
+ mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */
+ mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/range.c b/web/server/h2o/libh2o/deps/mruby/src/range.c
new file mode 100644
index 00000000..eb9a9c61
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/range.c
@@ -0,0 +1,442 @@
+/*
+** range.c - Range class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/array.h>
+
+MRB_API struct RRange*
+mrb_range_ptr(mrb_state *mrb, mrb_value v)
+{
+ struct RRange *r = (struct RRange*)mrb_ptr(v);
+
+ if (r->edges == NULL) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range");
+ }
+ return r;
+}
+
+static void
+range_check(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ mrb_value ans;
+ enum mrb_vtype ta;
+ enum mrb_vtype tb;
+
+ ta = mrb_type(a);
+ tb = mrb_type(b);
+ if ((ta == MRB_TT_FIXNUM || ta == MRB_TT_FLOAT) &&
+ (tb == MRB_TT_FIXNUM || tb == MRB_TT_FLOAT)) {
+ return;
+ }
+
+ ans = mrb_funcall(mrb, a, "<=>", 1, b);
+ if (mrb_nil_p(ans)) {
+ /* 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)
+{
+ struct RRange *r;
+
+ range_check(mrb, beg, end);
+ r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class);
+ 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);
+}
+
+/*
+ * call-seq:
+ * rng.first => obj
+ * rng.begin => obj
+ *
+ * Returns the first object in <i>rng</i>.
+ */
+mrb_value
+mrb_range_beg(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+
+ return r->edges->beg;
+}
+
+/*
+ * call-seq:
+ * rng.end => obj
+ * rng.last => obj
+ *
+ * Returns the object that defines the end of <i>rng</i>.
+ *
+ * (1..10).end #=> 10
+ * (1...10).end #=> 10
+ */
+
+mrb_value
+mrb_range_end(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+
+ return r->edges->end;
+}
+
+/*
+ * call-seq:
+ * range.exclude_end? => true or false
+ *
+ * Returns <code>true</code> if <i>range</i> excludes its end value.
+ */
+mrb_value
+mrb_range_excl(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+
+ return mrb_bool_value(r->excl);
+}
+
+static void
+range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end)
+{
+ struct RRange *r = mrb_range_raw_ptr(range);
+
+ range_check(mrb, beg, end);
+ r->excl = exclude_end;
+ if (!r->edges) {
+ r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
+ }
+ r->edges->beg = beg;
+ r->edges->end = end;
+}
+/*
+ * call-seq:
+ * Range.new(start, end, exclusive=false) => range
+ *
+ * Constructs a range using the given <i>start</i> and <i>end</i>. If the third
+ * 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)
+{
+ mrb_value beg, end;
+ mrb_bool exclusive;
+ int n;
+
+ 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);
+ return range;
+}
+/*
+ * call-seq:
+ * range == obj => true or false
+ *
+ * Returns <code>true</code> only if
+ * 1) <i>obj</i> is a Range,
+ * 2) <i>obj</i> has equivalent beginning and end items (by comparing them with <code>==</code>),
+ * 3) <i>obj</i> has the same #exclude_end? setting as <i>rng</t>.
+ *
+ * (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)
+{
+ struct RRange *rr;
+ struct RRange *ro;
+ mrb_value obj, v1, v2;
+
+ mrb_get_args(mrb, "o", &obj);
+
+ 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? */
+ return mrb_false_value();
+ }
+
+ 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) {
+ 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)
+{
+ mrb_value val;
+ 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;
+ }
+
+ if (trunc) {
+ if (beg > len) return 2;
+ if (end > len) end = len;
+ }
+
+ if (end < 0) end += len;
+ if (!r->excl && (!trunc || end < len))
+ end++; /* include end point */
+ len = end - beg;
+ if (len < 0) len = 0;
+
+ *begp = beg;
+ *lenp = len;
+ return 1;
+}
+
+/* 15.2.14.4.12(x) */
+/*
+ * call-seq:
+ * rng.to_s -> string
+ *
+ * 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_str_dup(mrb, str);
+ mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
+ mrb_str_cat_str(mrb, str, str2);
+
+ return str;
+}
+
+/* 15.2.14.4.13(x) */
+/*
+ * call-seq:
+ * rng.inspect -> string
+ *
+ * Convert this range object to a printable form (using
+ * <code>inspect</code> to convert the start and end
+ * objects).
+ */
+
+static mrb_value
+range_inspect(mrb_state *mrb, mrb_value range)
+{
+ mrb_value str, str2;
+ struct RRange *r = mrb_range_ptr(mrb, range);
+
+ str = mrb_inspect(mrb, r->edges->beg);
+ str2 = mrb_inspect(mrb, r->edges->end);
+ str = mrb_str_dup(mrb, str);
+ mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
+ mrb_str_cat_str(mrb, str, str2);
+
+ return str;
+}
+
+/* 15.2.14.4.14(x) */
+/*
+ * call-seq:
+ * rng.eql?(obj) -> true or false
+ *
+ * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
+ * beginning and end items (by comparing them with #eql?), and has the same
+ * #exclude_end? setting as <i>rng</i>.
+ *
+ * (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;
+ 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();
+
+ 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)) {
+ return mrb_false_value();
+ }
+ return mrb_true_value();
+}
+
+/* 15.2.14.4.15(x) */
+static mrb_value
+range_initialize_copy(mrb_state *mrb, mrb_value copy)
+{
+ mrb_value src;
+ 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);
+
+ return copy;
+}
+
+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))
+{
+ mrb_int i, j, beg, len;
+ mrb_value result;
+ 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])));
+ }
+ else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) {
+ 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));
+ }
+
+ for (; j < beg + len; ++j) {
+ mrb_ary_push(mrb, result, mrb_nil_value());
+ }
+ }
+ else {
+ mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+mrb_init_range(mrb_state *mrb)
+{
+ struct RClass *r;
+
+ r = mrb_define_class(mrb, "Range", mrb->object_class); /* 15.2.14 */
+ 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, "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) */
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/state.c b/web/server/h2o/libh2o/deps/mruby/src/state.c
new file mode 100644
index 00000000..039d67d5
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/state.c
@@ -0,0 +1,303 @@
+/*
+** state.c - mrb_state open/close functions
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/variable.h>
+#include <mruby/debug.h>
+#include <mruby/string.h>
+
+void mrb_init_core(mrb_state*);
+void mrb_init_mrbgems(mrb_state*);
+
+void mrb_gc_init(mrb_state*, mrb_gc *gc);
+void mrb_gc_destroy(mrb_state*, mrb_gc *gc);
+
+static mrb_value
+inspect_main(mrb_state *mrb, mrb_value mod)
+{
+ return mrb_str_new_lit(mrb, "main");
+}
+
+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;
+
+ mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud);
+ if (mrb == NULL) return NULL;
+
+ *mrb = mrb_state_zero;
+ mrb->allocf_ud = 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);
+
+ return mrb;
+}
+
+void*
+mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud)
+{
+ if (size == 0) {
+ free(p);
+ return NULL;
+ }
+ else {
+ return realloc(p, size);
+ }
+}
+
+struct alloca_header {
+ struct alloca_header *next;
+ char buf[];
+};
+
+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)
+{
+ mrb_state *mrb = mrb_open_allocf(mrb_default_allocf, NULL);
+
+ return mrb;
+}
+
+MRB_API mrb_state*
+mrb_open_allocf(mrb_allocf f, void *ud)
+{
+ mrb_state *mrb = mrb_open_core(f, ud);
+
+ if (mrb == NULL) {
+ return NULL;
+ }
+
+#ifndef DISABLE_GEMS
+ mrb_init_mrbgems(mrb);
+ mrb_gc_arena_restore(mrb, 0);
+#endif
+ return mrb;
+}
+
+void mrb_free_symtbl(mrb_state *mrb);
+
+void
+mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
+{
+ irep->refcnt++;
+}
+
+void
+mrb_irep_decref(mrb_state *mrb, mrb_irep *irep)
+{
+ irep->refcnt--;
+ if (irep->refcnt == 0) {
+ mrb_irep_free(mrb, irep);
+ }
+}
+
+void
+mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
+{
+ int i;
+
+ 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]));
+ }
+#ifdef MRB_WORD_BOXING
+ else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) {
+ mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
+ }
+#endif
+ }
+ mrb_free(mrb, irep->pool);
+ mrb_free(mrb, irep->syms);
+ for (i=0; i<irep->rlen; i++) {
+ mrb_irep_decref(mrb, irep->reps[i]);
+ }
+ if (irep->outer)
+ mrb_irep_decref(mrb, irep->outer);
+ mrb_free(mrb, irep->reps);
+ mrb_free(mrb, irep->lv);
+ if (irep->own_filename) {
+ mrb_free(mrb, (void *)irep->filename);
+ }
+ mrb_free(mrb, irep->lines);
+ mrb_debug_info_free(mrb, irep->debug_info);
+ mrb_free(mrb, irep);
+}
+
+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';
+ }
+ }
+ 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
+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
+ }
+
+ /* free */
+ mrb_gc_free_gv(mrb);
+ mrb_free_context(mrb, mrb->root_c);
+ mrb_free_symtbl(mrb);
+ mrb_alloca_free(mrb);
+ mrb_gc_destroy(mrb, &mrb->gc);
+ mrb_free(mrb, mrb);
+}
+
+MRB_API mrb_irep*
+mrb_add_irep(mrb_state *mrb)
+{
+ static const mrb_irep mrb_irep_zero = { 0 };
+ mrb_irep *irep;
+
+ irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
+ *irep = mrb_irep_zero;
+ irep->refcnt = 1;
+ irep->own_filename = FALSE;
+
+ return irep;
+}
+
+MRB_API mrb_value
+mrb_top_self(mrb_state *mrb)
+{
+ if (!mrb->top_self) {
+ mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class);
+ mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE());
+ mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE());
+ }
+ return mrb_obj_value(mrb->top_self);
+}
+
+MRB_API void
+mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f)
+{
+#ifdef MRB_FIXED_STATE_ATEXIT_STACK
+ if (mrb->atexit_stack_len + 1 > MRB_FIXED_STATE_ATEXIT_STACK_SIZE) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "exceeded fixed state atexit stack limit");
+ }
+#else
+ size_t stack_size;
+
+ stack_size = sizeof(mrb_atexit_func) * (mrb->atexit_stack_len + 1);
+ if (mrb->atexit_stack_len == 0) {
+ mrb->atexit_stack = (mrb_atexit_func*)mrb_malloc(mrb, stack_size);
+ }
+ else {
+ mrb->atexit_stack = (mrb_atexit_func*)mrb_realloc(mrb, mrb->atexit_stack, stack_size);
+ }
+#endif
+
+ mrb->atexit_stack[mrb->atexit_stack_len++] = f;
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/string.c b/web/server/h2o/libh2o/deps/mruby/src/string.c
new file mode 100644
index 00000000..01d706fa
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/string.c
@@ -0,0 +1,3013 @@
+/*
+** string.c - String class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifdef _MSC_VER
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include <float.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/re.h>
+
+typedef struct mrb_shared_string {
+ mrb_bool nofree : 1;
+ int refcnt;
+ 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))
+
+static struct RString*
+str_new_static(mrb_state *mrb, const char *p, size_t len)
+{
+ struct RString *s;
+
+ 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 */
+ s->as.heap.ptr = (char *)p;
+ s->flags = MRB_STR_NOFREE;
+
+ return s;
+}
+
+static struct RString*
+str_new(mrb_state *mrb, const char *p, size_t len)
+{
+ struct RString *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);
+ }
+ }
+ else {
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ s->as.heap.len = (mrb_int)len;
+ s->as.heap.aux.capa = (mrb_int)len;
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1);
+ if (p) {
+ memcpy(s->as.heap.ptr, p, len);
+ }
+ }
+ RSTR_PTR(s)[len] = '\0';
+ return s;
+}
+
+static inline void
+str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj)
+{
+ s->c = mrb_str_ptr(obj)->c;
+}
+
+static mrb_value
+mrb_str_new_empty(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = str_new(mrb, 0, 0);
+
+ str_with_class(mrb, s, str);
+ return mrb_obj_value(s);
+}
+
+MRB_API mrb_value
+mrb_str_new_capa(mrb_state *mrb, size_t capa)
+{
+ struct RString *s;
+
+ s = mrb_obj_alloc_string(mrb);
+
+ if (capa >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big");
+ }
+ 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);
+#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;
+ }
+ }
+ else {
+ s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
+ s->as.heap.aux.capa = (mrb_int)capacity;
+ }
+}
+
+MRB_API mrb_value
+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)
+{
+ struct RString *s;
+ size_t len;
+
+ if (p) {
+ len = strlen(p);
+ }
+ else {
+ len = 0;
+ }
+
+ s = str_new(mrb, p, len);
+
+ return mrb_obj_value(s);
+}
+
+MRB_API mrb_value
+mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
+{
+ struct RString *s = str_new_static(mrb, p, len);
+ return mrb_obj_value(s);
+}
+
+static void
+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);
+ }
+}
+
+void
+mrb_gc_free_str(mrb_state *mrb, struct RString *str)
+{
+ if (RSTR_EMBED_P(str))
+ /* no code */;
+ else if (RSTR_SHARED_P(str))
+ str_decref(mrb, str->as.heap.aux.shared);
+ else if (!RSTR_NOFREE_P(str))
+ mrb_free(mrb, str->as.heap.ptr);
+}
+
+#ifdef MRB_UTF8_STRING
+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,
+ 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,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,
+};
+
+static mrb_int
+utf8len(const char* p, const char* e)
+{
+ mrb_int len;
+ mrb_int i;
+
+ len = utf8len_codepage[(unsigned char)*p];
+ if (p + len > e) return 1;
+ for (i = 1; i < len; ++i)
+ if ((p[i] & 0xc0) != 0x80)
+ return 1;
+ return len;
+}
+
+static mrb_int
+utf8_strlen(mrb_value str, mrb_int len)
+{
+ mrb_int total = 0;
+ char* p = RSTRING_PTR(str);
+ char* e = p;
+ if (RSTRING(str)->flags & MRB_STR_NO_UTF) {
+ return RSTRING_LEN(str);
+ }
+ e += len < 0 ? RSTRING_LEN(str) : len;
+ while (p<e) {
+ p += utf8len(p, e);
+ total++;
+ }
+ if (RSTRING_LEN(str) == total) {
+ RSTRING(str)->flags |= MRB_STR_NO_UTF;
+ }
+ return total;
+}
+
+#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1)
+
+/* 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);
+
+ for (b=i=0; p<e && i<idx; i++) {
+ n = utf8len(p, e);
+ b += n;
+ p += n;
+ }
+ return b;
+}
+
+/* map byte offset to character index */
+static mrb_int
+bytes2chars(char *p, mrb_int bi)
+{
+ mrb_int i, b, n;
+
+ for (b=i=0; b<bi; i++) {
+ n = utf8len_codepage[(unsigned char)*p];
+ b += n;
+ p += n;
+ }
+ if (b != bi) return -1;
+ return i;
+}
+
+#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value();
+#else
+#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
+#define chars2bytes(p, off, ci) (ci)
+#define bytes2chars(p, bi) (bi)
+#define BYTES_ALIGN_CHECK(pos)
+#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];
+
+ /* 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;
+}
+
+static mrb_int
+mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
+{
+ const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0;
+
+ if (m > n) return -1;
+ else if (m == n) {
+ return memcmp(x0, y0, m) == 0 ? 0 : -1;
+ }
+ else if (m < 1) {
+ return 0;
+ }
+ else if (m == 1) {
+ const unsigned char *ys = (const unsigned char *)memchr(y, *x, n);
+
+ if (ys)
+ return (mrb_int)(ys - y);
+ else
+ return -1;
+ }
+ return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
+}
+
+static void
+str_make_shared(mrb_state *mrb, struct RString *s)
+{
+ if (!RSTR_SHARED_P(s)) {
+ mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
+
+ shared->refcnt = 1;
+ if (RSTR_EMBED_P(s)) {
+ const mrb_int len = RSTR_EMBED_LEN(s);
+ char *const tmp = (char *)mrb_malloc(mrb, len+1);
+ memcpy(tmp, s->as.ary, len);
+ tmp[len] = '\0';
+ RSTR_UNSET_EMBED_FLAG(s);
+ s->as.heap.ptr = tmp;
+ s->as.heap.len = len;
+ shared->nofree = FALSE;
+ shared->ptr = s->as.heap.ptr;
+ }
+ else if (RSTR_NOFREE_P(s)) {
+ shared->nofree = TRUE;
+ shared->ptr = s->as.heap.ptr;
+ RSTR_UNSET_NOFREE_FLAG(s);
+ }
+ else {
+ shared->nofree = FALSE;
+ if (s->as.heap.aux.capa > s->as.heap.len) {
+ s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, s->as.heap.ptr, s->as.heap.len+1);
+ }
+ else {
+ shared->ptr = s->as.heap.ptr;
+ }
+ }
+ shared->len = s->as.heap.len;
+ s->as.heap.aux.shared = shared;
+ RSTR_SET_SHARED_FLAG(s);
+ }
+}
+
+static mrb_value
+byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ struct RString *orig, *s;
+ mrb_shared_string *shared;
+
+ orig = mrb_str_ptr(str);
+ if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) {
+ s = str_new(mrb, orig->as.ary+beg, len);
+ }
+ else {
+ str_make_shared(mrb, orig);
+ shared = orig->as.heap.aux.shared;
+ s = mrb_obj_alloc_string(mrb);
+ s->as.heap.ptr = orig->as.heap.ptr + beg;
+ s->as.heap.len = len;
+ s->as.heap.aux.shared = shared;
+ RSTR_SET_SHARED_FLAG(s);
+ shared->refcnt++;
+ }
+
+ return mrb_obj_value(s);
+}
+#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);
+}
+#else
+#define str_subseq(mrb, str, beg, len) 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_int clen = RSTRING_CHAR_LEN(str);
+
+ if (len < 0) return mrb_nil_value();
+ if (clen == 0) {
+ len = 0;
+ }
+ else if (beg < 0) {
+ beg = clen + beg;
+ }
+ if (beg > clen) return mrb_nil_value();
+ if (beg < 0) {
+ beg += clen;
+ if (beg < 0) return mrb_nil_value();
+ }
+ if (len > clen - beg)
+ len = clen - beg;
+ if (len <= 0) {
+ len = 0;
+ }
+ return str_subseq(mrb, str, beg, len);
+}
+
+MRB_API mrb_int
+mrb_str_index(mrb_state *mrb, mrb_value str, const char *sptr, mrb_int slen, mrb_int offset)
+{
+ mrb_int pos;
+ char *s;
+ mrb_int len;
+
+ len = RSTRING_LEN(str);
+ if (offset < 0) {
+ offset += len;
+ if (offset < 0) return -1;
+ }
+ if (len - offset < slen) return -1;
+ s = RSTRING_PTR(str);
+ if (offset) {
+ s += offset;
+ }
+ if (slen == 0) return offset;
+ /* need proceed one character at a time */
+ len = RSTRING_LEN(str) - offset;
+ pos = mrb_memsearch(sptr, slen, s, len);
+ if (pos < 0) return pos;
+ return pos + offset;
+}
+
+static mrb_int
+str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset)
+{
+ const char *ptr;
+ mrb_int len;
+
+ ptr = RSTRING_PTR(str2);
+ len = RSTRING_LEN(str2);
+
+ 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_RUNTIME_ERROR, "can't modify frozen string");
+ }
+}
+
+static mrb_value
+str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
+{
+ long len;
+
+ 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);
+ if (RSTR_SHARED_P(s1)) {
+ str_decref(mrb, s1->as.heap.aux.shared);
+ }
+ else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) {
+ mrb_free(mrb, s1->as.heap.ptr);
+ }
+
+ RSTR_UNSET_NOFREE_FLAG(s1);
+
+ if (RSTR_SHARED_P(s2)) {
+L_SHARE:
+ RSTR_UNSET_EMBED_FLAG(s1);
+ s1->as.heap.ptr = s2->as.heap.ptr;
+ s1->as.heap.len = len;
+ s1->as.heap.aux.shared = s2->as.heap.aux.shared;
+ RSTR_SET_SHARED_FLAG(s1);
+ s1->as.heap.aux.shared->refcnt++;
+ }
+ else {
+ if (len <= RSTRING_EMBED_LEN_MAX) {
+ RSTR_UNSET_SHARED_FLAG(s1);
+ RSTR_SET_EMBED_FLAG(s1);
+ memcpy(s1->as.ary, RSTR_PTR(s2), len);
+ RSTR_SET_EMBED_LEN(s1, len);
+ }
+ else {
+ str_make_shared(mrb, s2);
+ goto L_SHARE;
+ }
+ }
+
+ return mrb_obj_value(s1);
+}
+
+static mrb_int
+str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
+{
+ char *s, *sbeg, *t;
+ struct RString *ps = mrb_str_ptr(str);
+ mrb_int len = RSTRING_LEN(sub);
+
+ /* substring longer than string */
+ if (RSTR_LEN(ps) < len) return -1;
+ if (RSTR_LEN(ps) - pos < len) {
+ pos = RSTR_LEN(ps) - len;
+ }
+ sbeg = RSTR_PTR(ps);
+ s = RSTR_PTR(ps) + pos;
+ t = RSTRING_PTR(sub);
+ if (len) {
+ while (sbeg <= s) {
+ if (memcmp(s, t, len) == 0) {
+ return (mrb_int)(s - RSTR_PTR(ps));
+ }
+ s--;
+ }
+ return -1;
+ }
+ else {
+ return pos;
+ }
+}
+
+MRB_API mrb_int
+mrb_str_strlen(mrb_state *mrb, struct RString *s)
+{
+ mrb_int i, max = RSTR_LEN(s);
+ char *p = RSTR_PTR(s);
+
+ if (!p) return 0;
+ for (i=0; i<max; i++) {
+ if (p[i] == '\0') {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ }
+ }
+ return max;
+}
+
+#ifdef _WIN32
+#include <windows.h>
+
+char*
+mrb_utf8_from_locale(const char *str, int len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ int mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = (int)strlen(str);
+ wcssize = MultiByteToWideChar(GetACP(), 0, str, len, NULL, 0);
+ wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t));
+ if (!wcsp)
+ return NULL;
+ wcssize = MultiByteToWideChar(GetACP(), 0, str, len, wcsp, wcssize + 1);
+ wcsp[wcssize] = 0;
+
+ mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL);
+ mbsp = (char*) malloc((mbssize + 1));
+ if (!mbsp) {
+ free(wcsp);
+ return NULL;
+ }
+ mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL);
+ mbsp[mbssize] = 0;
+ free(wcsp);
+ return mbsp;
+}
+
+char*
+mrb_locale_from_utf8(const char *utf8, int len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ int mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = (int)strlen(utf8);
+ wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
+ wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t));
+ if (!wcsp)
+ return NULL;
+ wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wcsp, wcssize + 1);
+ wcsp[wcssize] = 0;
+ mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL);
+ mbsp = (char*) malloc((mbssize + 1));
+ if (!mbsp) {
+ free(wcsp);
+ return NULL;
+ }
+ mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL);
+ mbsp[mbssize] = 0;
+ free(wcsp);
+ return mbsp;
+}
+#endif
+
+MRB_API void
+mrb_str_modify(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;
+
+ 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)) {
+ char *p = s->as.heap.ptr;
+ mrb_int len = s->as.heap.len;
+
+ RSTR_UNSET_NOFREE_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 mrb_value
+mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
+{
+ mrb_int slen;
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(mrb, s);
+ slen = RSTR_LEN(s);
+ if (len != slen) {
+ if (slen < len || slen - len > 256) {
+ resize_capa(mrb, s, len);
+ }
+ RSTR_SET_LEN(s, len);
+ RSTR_PTR(s)[len] = '\0'; /* sentinel */
+ }
+ return str;
+}
+
+MRB_API char*
+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");
+ }
+
+ 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);
+ }
+ 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)
+{
+ struct RString *s = mrb_str_ptr(a);
+ struct RString *s2 = mrb_str_ptr(b);
+ struct RString *t;
+
+ t = str_new(mrb, 0, RSTR_LEN(s) + RSTR_LEN(s2));
+ memcpy(RSTR_PTR(t), RSTR_PTR(s), RSTR_LEN(s));
+ memcpy(RSTR_PTR(t) + RSTR_LEN(s), RSTR_PTR(s2), RSTR_LEN(s2));
+
+ return mrb_obj_value(t);
+}
+
+/* 15.2.10.5.2 */
+
+/*
+ * call-seq: (Caution! String("abcd") remain) for stack_argument
+ * String("abcdefg") = String("abcd") + String("efg")
+ *
+ * Returns a new string object containing a copy of <i>str</i>.
+ */
+static mrb_value
+mrb_str_plus_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ mrb_get_args(mrb, "S", &str);
+ return mrb_str_plus(mrb, self, str);
+}
+
+/* 15.2.10.5.26 */
+/* 15.2.10.5.33 */
+/*
+ * call-seq:
+ * "abcd".size => int
+ *
+ * Returns the length of string.
+ */
+static mrb_value
+mrb_str_size(mrb_state *mrb, mrb_value self)
+{
+ mrb_int len = RSTRING_CHAR_LEN(self);
+ return mrb_fixnum_value(len);
+}
+
+static mrb_value
+mrb_str_bytesize(mrb_state *mrb, mrb_value self)
+{
+ mrb_int len = RSTRING_LEN(self);
+ return mrb_fixnum_value(len);
+}
+
+/* 15.2.10.5.1 */
+/*
+ * call-seq:
+ * str * integer => new_str
+ *
+ * Copy---Returns a new <code>String</code> containing <i>integer</i> copies of
+ * the receiver.
+ *
+ * "Ho! " * 3 #=> "Ho! Ho! Ho! "
+ */
+static mrb_value
+mrb_str_times(mrb_state *mrb, mrb_value self)
+{
+ mrb_int n,len,times;
+ struct RString *str2;
+ char *p;
+
+ mrb_get_args(mrb, "i", &times);
+ if (times < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
+ }
+ if (times && MRB_INT_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);
+ memcpy(p, RSTRING_PTR(self), n);
+ while (n <= len/2) {
+ memcpy(p + n, p, n);
+ n *= 2;
+ }
+ memcpy(p + n, p, len-n);
+ }
+ p[RSTR_LEN(str2)] = '\0';
+
+ return mrb_obj_value(str2);
+}
+/* -------------------------------------------------------------- */
+
+#define lesser(a,b) (((a)>(b))?(b):(a))
+
+/* ---------------------------*/
+/*
+ * call-seq:
+ * mrb_value str1 <=> mrb_value str2 => int
+ * > 1
+ * = 0
+ * < -1
+ */
+MRB_API int
+mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
+{
+ mrb_int len;
+ mrb_int retval;
+ struct RString *s1 = mrb_str_ptr(str1);
+ struct RString *s2 = mrb_str_ptr(str2);
+
+ len = lesser(RSTR_LEN(s1), RSTR_LEN(s2));
+ retval = memcmp(RSTR_PTR(s1), RSTR_PTR(s2), len);
+ if (retval == 0) {
+ if (RSTR_LEN(s1) == RSTR_LEN(s2)) return 0;
+ if (RSTR_LEN(s1) > RSTR_LEN(s2)) return 1;
+ return -1;
+ }
+ if (retval > 0) return 1;
+ return -1;
+}
+
+/* 15.2.10.5.3 */
+
+/*
+ * call-seq:
+ * str <=> other_str => -1, 0, +1
+ *
+ * Comparison---Returns -1 if <i>other_str</i> is less than, 0 if
+ * <i>other_str</i> is equal to, and +1 if <i>other_str</i> is greater than
+ * <i>str</i>. If the strings are of different lengths, and the strings are
+ * equal when compared up to the shortest length, then the longer string is
+ * considered greater than the shorter one. If the variable <code>$=</code> is
+ * <code>false</code>, the comparison is based on comparing the binary values
+ * of each character in the string. In older versions of Ruby, setting
+ * <code>$=</code> allowed case-insensitive comparisons; this is now deprecated
+ * in favor of using <code>String#casecmp</code>.
+ *
+ * <code><=></code> is the basis for the methods <code><</code>,
+ * <code><=</code>, <code>></code>, <code>>=</code>, and <code>between?</code>,
+ * included from module <code>Comparable</code>. The method
+ * <code>String#==</code> does not use <code>Comparable#==</code>.
+ *
+ * "abcdef" <=> "abcde" #=> 1
+ * "abcdef" <=> "abcdef" #=> 0
+ * "abcdef" <=> "abcdefg" #=> -1
+ * "abcdef" <=> "ABCDEF" #=> 1
+ */
+static mrb_value
+mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
+{
+ mrb_value str2;
+ 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);
+ }
+ }
+ else {
+ result = mrb_str_cmp(mrb, str1, str2);
+ }
+ return mrb_fixnum_value(result);
+}
+
+static mrb_bool
+str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2)
+{
+ const mrb_int len = RSTRING_LEN(str1);
+
+ if (len != RSTRING_LEN(str2)) return FALSE;
+ if (memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), (size_t)len) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+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);
+ }
+ return str_eql(mrb, str1, str2);
+}
+
+/* 15.2.10.5.4 */
+/*
+ * call-seq:
+ * str == obj => true or false
+ *
+ * Equality---
+ * If <i>obj</i> is not a <code>String</code>, returns <code>false</code>.
+ * Otherwise, returns <code>false</code> or <code>true</code>
+ *
+ * caution:if <i>str</i> <code><=></code> <i>obj</i> returns zero.
+ */
+static mrb_value
+mrb_str_equal_m(mrb_state *mrb, mrb_value str1)
+{
+ mrb_value str2;
+
+ mrb_get_args(mrb, "o", &str2);
+
+ 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;
+}
+
+MRB_API const char*
+mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr)
+{
+ mrb_value str = mrb_str_to_str(mrb, ptr);
+ return RSTRING_PTR(str);
+}
+
+MRB_API mrb_int
+mrb_string_value_len(mrb_state *mrb, mrb_value ptr)
+{
+ mrb_value str = mrb_str_to_str(mrb, ptr);
+ return RSTRING_LEN(str);
+}
+
+void
+mrb_noregexp(mrb_state *mrb, mrb_value self)
+{
+ mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented");
+}
+
+void
+mrb_regexp_check(mrb_state *mrb, mrb_value obj)
+{
+ if (mrb_regexp_p(mrb, obj)) {
+ mrb_noregexp(mrb, obj);
+ }
+}
+
+MRB_API mrb_value
+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;
+
+ mrb_regexp_check(mrb, indx);
+ switch (mrb_type(indx)) {
+ case MRB_TT_FIXNUM:
+ idx = mrb_fixnum(indx);
+
+num_index:
+ str = str_substr(mrb, str, idx, 1);
+ if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value();
+ return str;
+
+ case MRB_TT_STRING:
+ if (str_index_str(mrb, str, indx, 0) != -1)
+ return mrb_str_dup(mrb, indx);
+ return mrb_nil_value();
+
+ case MRB_TT_RANGE:
+ goto range_arg;
+
+ 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();
+ default:
+ break;
+ }
+ }
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum");
+ }
+ idx = mrb_fixnum(indx);
+ goto num_index;
+ }
+ return mrb_nil_value(); /* not reached */
+}
+
+/* 15.2.10.5.6 */
+/* 15.2.10.5.34 */
+/*
+ * call-seq:
+ * str[fixnum] => fixnum or nil
+ * str[fixnum, fixnum] => new_str or nil
+ * str[range] => new_str or nil
+ * str[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>
+ * 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
+ * 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.
+ *
+ * If a <code>String</code> is given, that string is returned if it occurs in
+ * <i>str</i>. In both cases, <code>nil</code> is returned if there is no
+ * match.
+ *
+ * a = "hello there"
+ * a[1] #=> 101(1.8.7) "e"(1.9.2)
+ * a[1.1] #=> "e"(1.9.2)
+ * a[1,3] #=> "ell"
+ * a[1..3] #=> "ell"
+ * a[-3,2] #=> "er"
+ * a[-4..-2] #=> "her"
+ * a[12..-1] #=> nil
+ * a[-2..-4] #=> ""
+ * a["lo"] #=> "lo"
+ * a["bye"] #=> nil
+ */
+static mrb_value
+mrb_str_aref_m(mrb_state *mrb, mrb_value str)
+{
+ mrb_value a1, a2;
+ int argc;
+
+ argc = mrb_get_args(mrb, "o|o", &a1, &a2);
+ if (argc == 2) {
+ mrb_int n1, n2;
+
+ mrb_regexp_check(mrb, a1);
+ mrb_get_args(mrb, "ii", &n1, &n2);
+ return str_substr(mrb, str, n1, n2);
+ }
+ if (argc != 1) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
+ }
+ return mrb_str_aref(mrb, str, a1);
+}
+
+/* 15.2.10.5.8 */
+/*
+ * call-seq:
+ * str.capitalize! => str or nil
+ *
+ * Modifies <i>str</i> by converting the first character to uppercase and the
+ * remainder to lowercase. Returns <code>nil</code> if no changes are made.
+ *
+ * a = "hello"
+ * a.capitalize! #=> "Hello"
+ * a #=> "Hello"
+ * a.capitalize! #=> nil
+ */
+static mrb_value
+mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
+{
+ char *p, *pend;
+ mrb_bool modify = FALSE;
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(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)) {
+ *p = TOUPPER(*p);
+ modify = TRUE;
+ }
+ while (++p < pend) {
+ if (ISUPPER(*p)) {
+ *p = TOLOWER(*p);
+ modify = TRUE;
+ }
+ }
+ if (modify) return str;
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.7 */
+/*
+ * call-seq:
+ * str.capitalize => new_str
+ *
+ * Returns a copy of <i>str</i> with the first character converted to uppercase
+ * and the remainder to lowercase.
+ *
+ * "hello".capitalize #=> "Hello"
+ * "HELLO".capitalize #=> "Hello"
+ * "123ABC".capitalize #=> "123abc"
+ */
+static mrb_value
+mrb_str_capitalize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_capitalize_bang(mrb, str);
+ return str;
+}
+
+/* 15.2.10.5.10 */
+/*
+ * call-seq:
+ * str.chomp!(separator="\n") => str or nil
+ *
+ * Modifies <i>str</i> in place as described for <code>String#chomp</code>,
+ * returning <i>str</i>, or <code>nil</code> if no modifications were made.
+ */
+static mrb_value
+mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
+{
+ mrb_value rs;
+ mrb_int newline;
+ char *p, *pp;
+ mrb_int rslen;
+ mrb_int len;
+ mrb_int argc;
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(mrb, s);
+ argc = mrb_get_args(mrb, "|S", &rs);
+ len = RSTR_LEN(s);
+ if (argc == 0) {
+ if (len == 0) return mrb_nil_value();
+ smart_chomp:
+ if (RSTR_PTR(s)[len-1] == '\n') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
+ if (RSTR_LEN(s) > 0 &&
+ RSTR_PTR(s)[RSTR_LEN(s)-1] == '\r') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
+ }
+ }
+ else if (RSTR_PTR(s)[len-1] == '\r') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
+ }
+ else {
+ return mrb_nil_value();
+ }
+ RSTR_PTR(s)[RSTR_LEN(s)] = '\0';
+ return str;
+ }
+
+ if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value();
+ p = RSTR_PTR(s);
+ rslen = RSTRING_LEN(rs);
+ if (rslen == 0) {
+ while (len>0 && p[len-1] == '\n') {
+ len--;
+ if (len>0 && p[len-1] == '\r')
+ len--;
+ }
+ if (len < RSTR_LEN(s)) {
+ RSTR_SET_LEN(s, len);
+ p[len] = '\0';
+ return str;
+ }
+ return mrb_nil_value();
+ }
+ if (rslen > len) return mrb_nil_value();
+ newline = RSTRING_PTR(rs)[rslen-1];
+ if (rslen == 1 && newline == '\n')
+ newline = RSTRING_PTR(rs)[rslen-1];
+ if (rslen == 1 && newline == '\n')
+ goto smart_chomp;
+
+ pp = p + len - rslen;
+ if (p[len-1] == newline &&
+ (rslen <= 1 ||
+ memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) {
+ RSTR_SET_LEN(s, len - rslen);
+ p[RSTR_LEN(s)] = '\0';
+ return str;
+ }
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.9 */
+/*
+ * call-seq:
+ * 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>,
+ * <code>\r</code>, and <code>\r\n</code>).
+ *
+ * "hello".chomp #=> "hello"
+ * "hello\n".chomp #=> "hello"
+ * "hello\r\n".chomp #=> "hello"
+ * "hello\n\r".chomp #=> "hello\n"
+ * "hello\r".chomp #=> "hello"
+ * "hello \n there".chomp #=> "hello \n there"
+ * "hello".chomp("llo") #=> "he"
+ */
+static mrb_value
+mrb_str_chomp(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_chomp_bang(mrb, str);
+ return str;
+}
+
+/* 15.2.10.5.12 */
+/*
+ * call-seq:
+ * str.chop! => str or nil
+ *
+ * Processes <i>str</i> as for <code>String#chop</code>, returning <i>str</i>,
+ * or <code>nil</code> if <i>str</i> is the empty string. See also
+ * <code>String#chomp!</code>.
+ */
+static mrb_value
+mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(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);
+ if (p + clen>=e) break;
+ p += clen;
+ }
+ len = p - t;
+#else
+ len = RSTR_LEN(s) - 1;
+#endif
+ if (RSTR_PTR(s)[len] == '\n') {
+ if (len > 0 &&
+ RSTR_PTR(s)[len-1] == '\r') {
+ len--;
+ }
+ }
+ RSTR_SET_LEN(s, len);
+ RSTR_PTR(s)[len] = '\0';
+ return str;
+ }
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.11 */
+/*
+ * call-seq:
+ * str.chop => new_str
+ *
+ * Returns a new <code>String</code> with the last character removed. If the
+ * string ends with <code>\r\n</code>, both characters are removed. Applying
+ * <code>chop</code> to an empty string returns an empty
+ * string. <code>String#chomp</code> is often a safer alternative, as it leaves
+ * the string unchanged if it doesn't end in a record separator.
+ *
+ * "string\r\n".chop #=> "string"
+ * "string\n\r".chop #=> "string\n"
+ * "string\n".chop #=> "string"
+ * "string".chop #=> "strin"
+ * "x".chop #=> ""
+ */
+static mrb_value
+mrb_str_chop(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+ str = mrb_str_dup(mrb, self);
+ mrb_str_chop_bang(mrb, str);
+ return str;
+}
+
+/* 15.2.10.5.14 */
+/*
+ * call-seq:
+ * str.downcase! => str or nil
+ *
+ * Downcases the contents of <i>str</i>, returning <code>nil</code> if no
+ * changes were made.
+ */
+static mrb_value
+mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
+{
+ char *p, *pend;
+ mrb_bool modify = FALSE;
+ struct RString *s = mrb_str_ptr(str);
+
+ mrb_str_modify(mrb, s);
+ p = RSTR_PTR(s);
+ pend = RSTR_PTR(s) + RSTR_LEN(s);
+ while (p < pend) {
+ if (ISUPPER(*p)) {
+ *p = TOLOWER(*p);
+ modify = TRUE;
+ }
+ p++;
+ }
+
+ if (modify) return str;
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.13 */
+/*
+ * call-seq:
+ * str.downcase => new_str
+ *
+ * Returns a copy of <i>str</i> with all uppercase letters replaced with their
+ * lowercase counterparts. The operation is locale insensitive---only
+ * characters 'A' to 'Z' are affected.
+ *
+ * "hEllO".downcase #=> "hello"
+ */
+static mrb_value
+mrb_str_downcase(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_downcase_bang(mrb, str);
+ return str;
+}
+
+/* 15.2.10.5.16 */
+/*
+ * call-seq:
+ * str.empty? => true or false
+ *
+ * Returns <code>true</code> if <i>str</i> has a length of zero.
+ *
+ * "hello".empty? #=> false
+ * "".empty? #=> true
+ */
+static mrb_value
+mrb_str_empty_p(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+
+ return mrb_bool_value(RSTR_LEN(s) == 0);
+}
+
+/* 15.2.10.5.17 */
+/*
+ * call-seq:
+ * str.eql?(other) => true or false
+ *
+ * Two strings are equal if the have the same length and content.
+ */
+static mrb_value
+mrb_str_eql(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str2;
+ mrb_bool eql_p;
+
+ mrb_get_args(mrb, "o", &str2);
+ eql_p = (mrb_type(str2) == MRB_TT_STRING) && str_eql(mrb, self, str2);
+
+ return mrb_bool_value(eql_p);
+}
+
+MRB_API mrb_value
+mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ return str_substr(mrb, str, beg, len);
+}
+
+mrb_int
+mrb_str_hash(mrb_state *mrb, mrb_value str)
+{
+ /* 1-8-7 */
+ struct RString *s = mrb_str_ptr(str);
+ mrb_int len = RSTR_LEN(s);
+ char *p = RSTR_PTR(s);
+ uint64_t key = 0;
+
+ while (len--) {
+ key = key*65599 + *p;
+ p++;
+ }
+ return (mrb_int)(key + (key>>5));
+}
+
+/* 15.2.10.5.20 */
+/*
+ * call-seq:
+ * str.hash => fixnum
+ *
+ * Return a hash based on the string's length and content.
+ */
+static mrb_value
+mrb_str_hash_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_int key = mrb_str_hash(mrb, self);
+ return mrb_fixnum_value(key);
+}
+
+/* 15.2.10.5.21 */
+/*
+ * call-seq:
+ * str.include? other_str => true or false
+ * str.include? fixnum => true or false
+ *
+ * Returns <code>true</code> if <i>str</i> contains the given string or
+ * character.
+ *
+ * "hello".include? "lo" #=> true
+ * "hello".include? "ol" #=> false
+ * "hello".include? ?h #=> true
+ */
+static mrb_value
+mrb_str_include(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str2;
+
+ mrb_get_args(mrb, "S", &str2);
+ if (str_index_str(mrb, self, str2, 0) < 0)
+ return mrb_bool_value(FALSE);
+ return mrb_bool_value(TRUE);
+}
+
+/* 15.2.10.5.22 */
+/*
+ * 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.
+ * If the second parameter is present, it
+ * specifies the position in the string to begin the search.
+ *
+ * "hello".index('e') #=> 1
+ * "hello".index('lo') #=> 3
+ * "hello".index('a') #=> nil
+ * "hello".index(101) #=> 1(101=0x65='e')
+ * "hello".index(/[aeiou]/, -3) #=> 4
+ */
+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_get_args(mrb, "*!", &argv, &argc);
+ if (argc == 2) {
+ mrb_get_args(mrb, "oi", &sub, &pos);
+ }
+ else {
+ 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) {
+ 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;
+ }
+
+ 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 */
+/*
+ * call-seq:
+ * str.replace(other_str) => str
+ *
+ * s = "hello" #=> "hello"
+ * s.replace "world" #=> "world"
+ */
+static mrb_value
+mrb_str_replace(mrb_state *mrb, mrb_value str)
+{
+ mrb_value str2;
+
+ mrb_get_args(mrb, "S", &str2);
+ return str_replace(mrb, mrb_str_ptr(str), mrb_str_ptr(str2));
+}
+
+/* 15.2.10.5.23 */
+/*
+ * call-seq:
+ * String.new(str="") => new_str
+ *
+ * Returns a new string object containing a copy of <i>str</i>.
+ */
+static mrb_value
+mrb_str_init(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str2;
+
+ if (mrb_get_args(mrb, "|S", &str2) == 0) {
+ struct RString *s = str_new(mrb, 0, 0);
+ str2 = mrb_obj_value(s);
+ }
+ str_replace(mrb, mrb_str_ptr(self), mrb_str_ptr(str2));
+ return self;
+}
+
+/* 15.2.10.5.25 */
+/* 15.2.10.5.41 */
+/*
+ * call-seq:
+ * str.intern => symbol
+ * 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>.
+ *
+ * "Koala".intern #=> :Koala
+ * s = 'cat'.to_sym #=> :cat
+ * s == :cat #=> true
+ * s = '@cat'.to_sym #=> :@cat
+ * s == :@cat #=> true
+ *
+ * This can also be used to create symbols that cannot be represented using the
+ * <code>:xxx</code> notation.
+ *
+ * 'cat and dog'.to_sym #=> :"cat and dog"
+ */
+MRB_API mrb_value
+mrb_str_intern(mrb_state *mrb, mrb_value self)
+{
+ return mrb_symbol_value(mrb_intern_str(mrb, self));
+}
+/* ---------------------------------- */
+MRB_API mrb_value
+mrb_obj_as_string(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value str;
+
+ if (mrb_string_p(obj)) {
+ return obj;
+ }
+ str = mrb_funcall(mrb, obj, "to_s", 0);
+ if (!mrb_string_p(str))
+ return mrb_any_to_s(mrb, obj);
+ return str;
+}
+
+MRB_API mrb_value
+mrb_ptr_to_str(mrb_state *mrb, void *p)
+{
+ struct RString *p_str;
+ char *p1;
+ char *p2;
+ uintptr_t n = (uintptr_t)p;
+
+ p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4);
+ p1 = RSTR_PTR(p_str);
+ *p1++ = '0';
+ *p1++ = 'x';
+ p2 = p1;
+
+ do {
+ *p2++ = mrb_digitmap[n % 16];
+ n /= 16;
+ } while (n > 0);
+ *p2 = '\0';
+ RSTR_SET_LEN(p_str, (mrb_int)(p2 - RSTR_PTR(p_str)));
+
+ while (p1 < p2) {
+ const char c = *p1;
+ *p1++ = *--p2;
+ *p2 = c;
+ }
+
+ return mrb_obj_value(p_str);
+}
+
+MRB_API mrb_value
+mrb_string_type(mrb_state *mrb, mrb_value str)
+{
+ return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str");
+}
+
+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");
+}
+
+/* 15.2.10.5.30 */
+/*
+ * call-seq:
+ * str.reverse! => str
+ *
+ * Reverses <i>str</i> in place.
+ */
+static mrb_value
+mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
+{
+#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;
+
+ while (p<e) {
+ mrb_int clen = utf8len(p, e);
+ r -= clen;
+ memcpy(r, p, clen);
+ p += clen;
+ }
+ mrb_free(mrb, buf);
+ }
+ return str;
+
+ bytes:
+#endif
+ {
+ struct RString *s = mrb_str_ptr(str);
+ char *p, *e;
+ char c;
+
+ 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;
+ }
+}
+
+/* ---------------------------------- */
+/* 15.2.10.5.29 */
+/*
+ * call-seq:
+ * str.reverse => new_str
+ *
+ * Returns a new string with the characters from <i>str</i> in reverse order.
+ *
+ * "stressed".reverse #=> "desserts"
+ */
+static mrb_value
+mrb_str_reverse(mrb_state *mrb, mrb_value str)
+{
+ mrb_value str2 = mrb_str_dup(mrb, str);
+ mrb_str_reverse_bang(mrb, str2);
+ return str2;
+}
+
+/* 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
+ *
+ * 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.
+ *
+ * "hello".rindex('e') #=> 1
+ * "hello".rindex('l') #=> 3
+ * "hello".rindex('a') #=> nil
+ * "hello".rindex(101) #=> 1
+ * "hello".rindex(/[aeiou]/, -2) #=> 1
+ */
+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 (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)) */
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.35 */
+
+/*
+ * call-seq:
+ * str.split(pattern="\n", [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
+ * 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 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
+ * fields will be returned (if <i>limit</i> is <code>1</code>, the entire
+ * string is returned as the only entry in an array). If negative, there is no
+ * limit to the number of fields returned, and trailing null fields are not
+ * suppressed.
+ *
+ * " 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"]
+ * "1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"]
+ * "1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""]
+ */
+
+static mrb_value
+mrb_str_split_m(mrb_state *mrb, mrb_value str)
+{
+ int argc;
+ mrb_value spat = mrb_nil_value();
+ enum {awk, string, regexp} split_type = string;
+ mrb_int i = 0;
+ mrb_int beg;
+ mrb_int end;
+ mrb_int lim = 0;
+ mrb_bool lim_p;
+ mrb_value result, tmp;
+
+ argc = mrb_get_args(mrb, "|oi", &spat, &lim);
+ lim_p = (lim > 0 && argc == 2);
+ if (argc == 2) {
+ if (lim == 1) {
+ if (RSTRING_LEN(str) == 0)
+ return mrb_ary_new_capa(mrb, 0);
+ return mrb_ary_new_from_values(mrb, 1, &str);
+ }
+ i = 1;
+ }
+
+ 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);
+ }
+ }
+
+ result = mrb_ary_new(mrb);
+ beg = 0;
+ if (split_type == awk) {
+ mrb_bool skip = TRUE;
+ mrb_int idx = 0;
+ mrb_int str_len = RSTRING_LEN(str);
+ unsigned int c;
+ int ai = mrb_gc_arena_save(mrb);
+
+ idx = end = beg;
+ while (idx < str_len) {
+ c = (unsigned char)RSTRING_PTR(str)[idx++];
+ if (skip) {
+ if (ISSPACE(c)) {
+ beg = idx;
+ }
+ else {
+ end = idx;
+ skip = FALSE;
+ if (lim_p && lim <= i) break;
+ }
+ }
+ else if (ISSPACE(c)) {
+ mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg));
+ mrb_gc_arena_restore(mrb, ai);
+ skip = TRUE;
+ beg = idx;
+ if (lim_p) ++i;
+ }
+ else {
+ end = idx;
+ }
+ }
+ }
+ else if (split_type == string) {
+ mrb_int str_len = RSTRING_LEN(str);
+ mrb_int pat_len = RSTRING_LEN(spat);
+ mrb_int idx = 0;
+ int ai = mrb_gc_arena_save(mrb);
+
+ while (idx < str_len) {
+ if (pat_len > 0) {
+ end = mrb_memsearch(RSTRING_PTR(spat), pat_len, RSTRING_PTR(str)+idx, str_len - idx);
+ if (end < 0) break;
+ }
+ else {
+ end = chars2bytes(str, idx, 1);
+ }
+ mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end));
+ mrb_gc_arena_restore(mrb, ai);
+ idx += end + pat_len;
+ if (lim_p && lim <= ++i) break;
+ }
+ beg = idx;
+ }
+ else {
+ mrb_noregexp(mrb, str);
+ }
+ if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) {
+ if (RSTRING_LEN(str) == beg) {
+ tmp = mrb_str_new_empty(mrb, str);
+ }
+ else {
+ tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
+ }
+ mrb_ary_push(mrb, result, tmp);
+ }
+ if (!lim_p && lim == 0) {
+ mrb_int len;
+ while ((len = RARRAY_LEN(result)) > 0 &&
+ (tmp = RARRAY_PTR(result)[len-1], RSTRING_LEN(tmp) == 0))
+ mrb_ary_pop(mrb, result);
+ }
+
+ return result;
+}
+
+MRB_API mrb_value
+mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, int base, int badcheck)
+{
+ const char *p = str;
+ const char *pend = str + len;
+ char sign = 1;
+ int c;
+ uint64_t n = 0;
+ mrb_int val;
+
+#define conv_digit(c) \
+ (ISDIGIT(c) ? ((c) - '0') : \
+ ISLOWER(c) ? ((c) - 'a' + 10) : \
+ ISUPPER(c) ? ((c) - 'A' + 10) : \
+ -1)
+
+ if (!p) {
+ if (badcheck) goto bad;
+ return mrb_fixnum_value(0);
+ }
+ while (p<pend && ISSPACE(*p))
+ p++;
+
+ if (p[0] == '+') {
+ p++;
+ }
+ else if (p[0] == '-') {
+ p++;
+ sign = 0;
+ }
+ if (base <= 0) {
+ if (p[0] == '0') {
+ switch (p[1]) {
+ case 'x': case 'X':
+ base = 16;
+ break;
+ case 'b': case 'B':
+ base = 2;
+ break;
+ case 'o': case 'O':
+ base = 8;
+ break;
+ case 'd': case 'D':
+ base = 10;
+ break;
+ default:
+ base = 8;
+ break;
+ }
+ }
+ else if (base < -1) {
+ base = -base;
+ }
+ else {
+ base = 10;
+ }
+ }
+ switch (base) {
+ case 2:
+ if (p[0] == '0' && (p[1] == 'b'||p[1] == 'B')) {
+ p += 2;
+ }
+ break;
+ case 3:
+ break;
+ case 8:
+ if (p[0] == '0' && (p[1] == 'o'||p[1] == 'O')) {
+ p += 2;
+ }
+ case 4: case 5: case 6: case 7:
+ break;
+ case 10:
+ if (p[0] == '0' && (p[1] == 'd'||p[1] == 'D')) {
+ p += 2;
+ }
+ case 9: case 11: case 12: case 13: case 14: case 15:
+ break;
+ case 16:
+ if (p[0] == '0' && (p[1] == 'x'||p[1] == 'X')) {
+ p += 2;
+ }
+ break;
+ default:
+ if (base < 2 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
+ }
+ break;
+ } /* end of switch (base) { */
+ if (p>=pend) {
+ if (badcheck) goto bad;
+ return mrb_fixnum_value(0);
+ }
+ if (*p == '0') { /* squeeze preceding 0s */
+ p++;
+ while (p<pend) {
+ c = *p++;
+ if (c == '_') {
+ if (p<pend && *p == '_') {
+ if (badcheck) goto bad;
+ break;
+ }
+ continue;
+ }
+ if (c != '0') {
+ p--;
+ break;
+ }
+ }
+ if (*(p - 1) == '0')
+ p--;
+ }
+ if (p == pend) {
+ if (badcheck) goto bad;
+ return mrb_fixnum_value(0);
+ }
+ for ( ;p<pend;p++) {
+ if (*p == '_') {
+ p++;
+ if (p==pend) {
+ if (badcheck) goto bad;
+ continue;
+ }
+ if (*p == '_') {
+ if (badcheck) goto bad;
+ break;
+ }
+ }
+ if (badcheck && *p == '\0') {
+ goto nullbyte;
+ }
+ c = conv_digit(*p);
+ if (c < 0 || c >= base) {
+ break;
+ }
+ n *= base;
+ n += c;
+ if (n > (uint64_t)MRB_INT_MAX + (sign ? 0 : 1)) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer",
+ mrb_str_new(mrb, str, pend-str));
+ }
+ }
+ val = (mrb_int)n;
+ if (badcheck) {
+ if (p == str) goto bad; /* no number */
+ while (p<pend && ISSPACE(*p)) p++;
+ if (p<pend) goto bad; /* trailing garbage */
+ }
+
+ return mrb_fixnum_value(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)));
+ /* 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);
+}
+
+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);
+
+ 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);
+ }
+ return p;
+}
+
+MRB_API mrb_value
+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);
+ len = RSTRING_LEN(str);
+ return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
+}
+
+/* 15.2.10.5.38 */
+/*
+ * call-seq:
+ * str.to_i(base=10) => integer
+ *
+ * Returns the result of interpreting leading characters in <i>str</i> as an
+ * integer base <i>base</i> (between 2 and 36). 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</code> is returned. This method never raises an
+ * exception.
+ *
+ * "12345".to_i #=> 12345
+ * "99 red balloons".to_i #=> 99
+ * "0a".to_i #=> 0
+ * "0a".to_i(16) #=> 10
+ * "hello".to_i #=> 0
+ * "1100101".to_i(2) #=> 101
+ * "1100101".to_i(8) #=> 294977
+ * "1100101".to_i(10) #=> 1100101
+ * "1100101".to_i(16) #=> 17826049
+ */
+static mrb_value
+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));
+ }
+ return mrb_str_to_inum(mrb, self, base, FALSE);
+}
+
+MRB_API double
+mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
+{
+ char *end;
+ char buf[DBL_DIG * 4 + 10];
+ double d;
+
+ enum {max_width = 20};
+
+ if (!p) return 0.0;
+ while (ISSPACE(*p)) p++;
+
+ if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ return 0.0;
+ }
+ 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));
+ /* 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;
+ }
+ }
+ return d;
+}
+
+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);
+}
+
+/* 15.2.10.5.39 */
+/*
+ * call-seq:
+ * 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
+ * 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.
+ *
+ * "123.45e1".to_f #=> 1234.5
+ * "45.67 degrees".to_f #=> 45.67
+ * "thx1138".to_f #=> 0.0
+ */
+static mrb_value
+mrb_str_to_f(mrb_state *mrb, mrb_value self)
+{
+ return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, FALSE));
+}
+
+/* 15.2.10.5.40 */
+/*
+ * call-seq:
+ * str.to_s => str
+ * str.to_str => str
+ *
+ * Returns the receiver.
+ */
+static mrb_value
+mrb_str_to_s(mrb_state *mrb, mrb_value self)
+{
+ if (mrb_obj_class(mrb, self) != mrb->string_class) {
+ return mrb_str_dup(mrb, self);
+ }
+ return self;
+}
+
+/* 15.2.10.5.43 */
+/*
+ * call-seq:
+ * str.upcase! => str or nil
+ *
+ * Upcases the contents of <i>str</i>, returning <code>nil</code> if no changes
+ * were made.
+ */
+static mrb_value
+mrb_str_upcase_bang(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = mrb_str_ptr(str);
+ char *p, *pend;
+ mrb_bool modify = FALSE;
+
+ mrb_str_modify(mrb, s);
+ p = RSTRING_PTR(str);
+ pend = RSTRING_END(str);
+ while (p < pend) {
+ if (ISLOWER(*p)) {
+ *p = TOUPPER(*p);
+ modify = TRUE;
+ }
+ p++;
+ }
+
+ if (modify) return str;
+ return mrb_nil_value();
+}
+
+/* 15.2.10.5.42 */
+/*
+ * call-seq:
+ * str.upcase => new_str
+ *
+ * Returns a copy of <i>str</i> with all lowercase letters replaced with their
+ * uppercase counterparts. The operation is locale insensitive---only
+ * characters 'a' to 'z' are affected.
+ *
+ * "hEllO".upcase #=> "HELLO"
+ */
+static mrb_value
+mrb_str_upcase(mrb_state *mrb, mrb_value self)
+{
+ mrb_value str;
+
+ str = mrb_str_dup(mrb, self);
+ mrb_str_upcase_bang(mrb, str);
+ return str;
+}
+
+#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
+
+/*
+ * call-seq:
+ * str.dump -> new_str
+ *
+ * Produces a version of <i>str</i> with all nonprinting characters replaced by
+ * <code>\nnn</code> notation and all special characters escaped.
+ */
+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[2] = '0' + c % 8; c /= 8;
+ q[1] = '0' + c % 8; c /= 8;
+ q[0] = '0' + c % 8;
+ q += 3;
+ }
+ }
+ }
+ *q = '"';
+ return mrb_obj_value(result);
+}
+
+MRB_API mrb_value
+mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
+{
+ struct RString *s = mrb_str_ptr(str);
+ size_t capa;
+ size_t total;
+ ptrdiff_t off = -1;
+
+ if (len == 0) return str;
+ mrb_str_modify(mrb, s);
+ if (ptr >= RSTR_PTR(s) && ptr <= RSTR_PTR(s) + (size_t)RSTR_LEN(s)) {
+ off = ptr - RSTR_PTR(s);
+ }
+
+ capa = RSTR_CAPA(s);
+ total = RSTR_LEN(s)+len;
+ if (total >= MRB_INT_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) {
+ capa *= 2;
+ }
+ else {
+ capa = total+1;
+ }
+ }
+ if (capa <= total || capa > MRB_INT_MAX) {
+ goto size_error;
+ }
+ resize_capa(mrb, s, capa);
+ }
+ if (off != -1) {
+ 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);
+ RSTR_SET_LEN(s, total);
+ RSTR_PTR(s)[total] = '\0'; /* sentinel */
+ return str;
+}
+
+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));
+}
+
+MRB_API mrb_value
+mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2)
+{
+ return mrb_str_cat(mrb, str, RSTRING_PTR(str2), RSTRING_LEN(str2));
+}
+
+MRB_API mrb_value
+mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2)
+{
+ str2 = mrb_str_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
+ *
+ * Returns a printable version of _str_, surrounded by quote marks,
+ * with special characters escaped.
+ *
+ * str = "hello"
+ * str[3] = "\b"
+ * str.inspect #=> "\"hel\\bo\""
+ */
+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[3] = '0' + c % 8; c /= 8;
+ buf[2] = '0' + c % 8; c /= 8;
+ buf[1] = '0' + c % 8;
+ mrb_str_cat(mrb, result, buf, 4);
+ continue;
+ }
+ }
+ mrb_str_cat_lit(mrb, result, "\"");
+
+ return result;
+}
+
+/*
+ * call-seq:
+ * str.bytes -> array of fixnums
+ *
+ * Returns an array of bytes in _str_.
+ *
+ * str = "hello"
+ * str.bytes #=> [104, 101, 108, 108, 111]
+ */
+static mrb_value
+mrb_str_bytes(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = mrb_str_ptr(str);
+ mrb_value a = mrb_ary_new_capa(mrb, RSTR_LEN(s));
+ unsigned char *p = (unsigned char *)(RSTR_PTR(s)), *pend = p + RSTR_LEN(s);
+
+ while (p < pend) {
+ mrb_ary_push(mrb, a, mrb_fixnum_value(p[0]));
+ p++;
+ }
+ return a;
+}
+
+/* ---------------------------*/
+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->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
+ MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
+
+ mrb_define_method(mrb, s, "bytesize", mrb_str_bytesize, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */
+ mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */
+ 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, "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 */
+ mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */
+ mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */
+ mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */
+ mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */
+ mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */
+ mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */
+ mrb_define_method(mrb, s, "eql?", mrb_str_eql, MRB_ARGS_REQ(1)); /* 15.2.10.5.17 */
+
+ 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, "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 */
+ mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.26 */
+ mrb_define_method(mrb, s, "replace", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.28 */
+ mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); /* 15.2.10.5.29 */
+ mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); /* 15.2.10.5.30 */
+ mrb_define_method(mrb, s, "rindex", mrb_str_rindex, MRB_ARGS_ANY()); /* 15.2.10.5.31 */
+ mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */
+ 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 */
+
+ mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.38 */
+ mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */
+ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */
+ mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */
+ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */
+ 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());
+}
+
+/*
+ * 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;
+ register const char *p;
+ register 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;
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/symbol.c b/web/server/h2o/libh2o/deps/mruby/src/symbol.c
new file mode 100644
index 00000000..a3ab05c8
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/symbol.c
@@ -0,0 +1,494 @@
+/*
+** symbol.c - Symbol class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <limits.h>
+#include <string.h>
+#include <mruby.h>
+#include <mruby/khash.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
+#include <mruby/class.h>
+
+/* ------------------------------------------------------ */
+typedef struct symbol_name {
+ mrb_bool lit : 1;
+ uint16_t len;
+ const char *name;
+} symbol_name;
+
+static inline khint_t
+sym_hash_func(mrb_state *mrb, mrb_sym s)
+{
+ khint_t h = 0;
+ size_t i, len = mrb->symtbl[s].len;
+ const char *p = mrb->symtbl[s].name;
+
+ for (i=0; i<len; i++) {
+ h = (h << 5) - h + *p++;
+ }
+ return h;
+}
+#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)
+{
+ if (len >= RITE_LV_NULL_MARK) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
+}
+
+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;
+
+ 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);
+ }
+
+ /* registering a new symbol */
+ sym = ++mrb->symidx;
+ if (mrb->symcapa < sym) {
+ if (mrb->symcapa == 0) mrb->symcapa = 100;
+ else mrb->symcapa = (size_t)(mrb->symcapa * 1.2);
+ mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1));
+ }
+ sname = &mrb->symtbl[sym];
+ sname->len = (uint16_t)len;
+ if (lit || mrb_ro_data_p(name)) {
+ sname->name = name;
+ sname->lit = TRUE;
+ }
+ else {
+ 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);
+
+ return sym;
+}
+
+MRB_API mrb_sym
+mrb_intern(mrb_state *mrb, const char *name, size_t len)
+{
+ return sym_intern(mrb, name, len, FALSE);
+}
+
+MRB_API mrb_sym
+mrb_intern_static(mrb_state *mrb, const char *name, size_t len)
+{
+ return sym_intern(mrb, name, len, TRUE);
+}
+
+MRB_API mrb_sym
+mrb_intern_cstr(mrb_state *mrb, const char *name)
+{
+ return mrb_intern(mrb, name, strlen(name));
+}
+
+MRB_API mrb_sym
+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)
+{
+ khash_t(n2s) *h = mrb->name2sym;
+ symbol_name *sname = mrb->symtbl;
+ khiter_t k;
+
+ sym_validate_len(mrb, len);
+ sname->len = (uint16_t)len;
+ sname->name = name;
+
+ k = kh_get(n2s, mrb, h, 0);
+ if (k != kh_end(h)) {
+ return mrb_symbol_value(kh_key(h, k));
+ }
+ return mrb_nil_value();
+}
+
+MRB_API mrb_value
+mrb_check_intern_cstr(mrb_state *mrb, const char *name)
+{
+ return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
+}
+
+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));
+}
+
+/* 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)
+{
+ if (sym == 0 || mrb->symidx < sym) {
+ if (lenp) *lenp = 0;
+ return NULL;
+ }
+
+ if (lenp) *lenp = mrb->symtbl[sym].len;
+ return mrb->symtbl[sym].name;
+}
+
+void
+mrb_free_symtbl(mrb_state *mrb)
+{
+ mrb_sym i, lim;
+
+ for (i=1, lim=mrb->symidx+1; i<lim; i++) {
+ if (!mrb->symtbl[i].lit) {
+ mrb_free(mrb, (char*)mrb->symtbl[i].name);
+ }
+ }
+ mrb_free(mrb, mrb->symtbl);
+ kh_destroy(n2s, mrb, mrb->name2sym);
+}
+
+void
+mrb_init_symtbl(mrb_state *mrb)
+{
+ mrb->name2sym = kh_init(n2s, mrb);
+}
+
+/**********************************************************************
+ * Document-class: Symbol
+ *
+ * <code>Symbol</code> objects represent names and some strings
+ * inside the Ruby
+ * interpreter. They are generated using the <code>:name</code> and
+ * <code>:"string"</code> literals
+ * syntax, and by the various <code>to_sym</code> methods. The same
+ * <code>Symbol</code> object will be created for a given name or string
+ * for the duration of a program's execution, regardless of the context
+ * or meaning of that name. Thus if <code>Fred</code> is a constant in
+ * one context, a method in another, and a class in a third, the
+ * <code>Symbol</code> <code>:Fred</code> will be the same object in
+ * all three contexts.
+ *
+ * module One
+ * class Fred
+ * end
+ * $f1 = :Fred
+ * end
+ * module Two
+ * Fred = 1
+ * $f2 = :Fred
+ * end
+ * def Fred()
+ * end
+ * $f3 = :Fred
+ * $f1.object_id #=> 2514190
+ * $f2.object_id #=> 2514190
+ * $f3.object_id #=> 2514190
+ *
+ */
+
+
+/* 15.2.11.3.1 */
+/*
+ * call-seq:
+ * sym == obj -> true or false
+ *
+ * Equality---If <i>sym</i> and <i>obj</i> are exactly the same
+ * symbol, returns <code>true</code>.
+ */
+
+static mrb_value
+sym_equal(mrb_state *mrb, mrb_value sym1)
+{
+ mrb_value sym2;
+
+ mrb_get_args(mrb, "o", &sym2);
+
+ return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2));
+}
+
+/* 15.2.11.3.2 */
+/* 15.2.11.3.3 */
+/*
+ * call-seq:
+ * sym.id2name -> string
+ * sym.to_s -> string
+ *
+ * Returns the name or string corresponding to <i>sym</i>.
+ *
+ * :fred.id2name #=> "fred"
+ */
+static mrb_value
+mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
+{
+ mrb_sym id = mrb_symbol(sym);
+ const char *p;
+ mrb_int len;
+
+ p = mrb_sym2name_len(mrb, id, &len);
+ return mrb_str_new_static(mrb, p, len);
+}
+
+/* 15.2.11.3.4 */
+/*
+ * call-seq:
+ * sym.to_sym -> sym
+ * sym.intern -> sym
+ *
+ * In general, <code>to_sym</code> returns the <code>Symbol</code> corresponding
+ * to an object. As <i>sym</i> is already a symbol, <code>self</code> is returned
+ * in this case.
+ */
+
+static mrb_value
+sym_to_sym(mrb_state *mrb, mrb_value sym)
+{
+ return sym;
+}
+
+/* 15.2.11.3.5(x) */
+/*
+ * call-seq:
+ * sym.inspect -> string
+ *
+ * Returns the representation of <i>sym</i> as a symbol literal.
+ *
+ * :fred.inspect #=> ":fred"
+ */
+
+#if __STDC__
+# define SIGN_EXTEND_CHAR(c) ((signed char)(c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+# define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128)
+#endif
+#define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_'))
+
+static mrb_bool
+is_special_global_name(const char* m)
+{
+ switch (*m) {
+ case '~': case '*': case '$': case '?': case '!': case '@':
+ case '/': case '\\': case ';': case ',': case '.': case '=':
+ case ':': case '<': case '>': case '\"':
+ case '&': case '`': case '\'': case '+':
+ case '0':
+ ++m;
+ break;
+ case '-':
+ ++m;
+ if (is_identchar(*m)) m += 1;
+ break;
+ default:
+ if (!ISDIGIT(*m)) return FALSE;
+ do ++m; while (ISDIGIT(*m));
+ break;
+ }
+ return !*m;
+}
+
+static mrb_bool
+symname_p(const char *name)
+{
+ const char *m = name;
+ mrb_bool localid = FALSE;
+
+ if (!m) return FALSE;
+ switch (*m) {
+ case '\0':
+ return FALSE;
+
+ case '$':
+ if (is_special_global_name(++m)) return TRUE;
+ goto id;
+
+ case '@':
+ if (*++m == '@') ++m;
+ goto id;
+
+ case '<':
+ switch (*++m) {
+ case '<': ++m; break;
+ case '=': if (*++m == '>') ++m; break;
+ default: break;
+ }
+ break;
+
+ case '>':
+ switch (*++m) {
+ case '>': case '=': ++m; break;
+ default: break;
+ }
+ break;
+
+ case '=':
+ switch (*++m) {
+ case '~': ++m; break;
+ case '=': if (*++m == '=') ++m; break;
+ default: return FALSE;
+ }
+ break;
+
+ case '*':
+ if (*++m == '*') ++m;
+ break;
+ case '!':
+ switch (*++m) {
+ case '=': case '~': ++m;
+ }
+ break;
+ case '+': case '-':
+ if (*++m == '@') ++m;
+ break;
+ case '|':
+ if (*++m == '|') ++m;
+ break;
+ case '&':
+ if (*++m == '&') ++m;
+ break;
+
+ case '^': case '/': case '%': case '~': case '`':
+ ++m;
+ break;
+
+ case '[':
+ if (*++m != ']') return FALSE;
+ if (*++m == '=') ++m;
+ break;
+
+ default:
+ localid = !ISUPPER(*m);
+id:
+ if (*m != '_' && !ISALPHA(*m)) return FALSE;
+ while (is_identchar(*m)) m += 1;
+ if (localid) {
+ switch (*m) {
+ case '!': case '?': case '=': ++m;
+ default: break;
+ }
+ }
+ break;
+ }
+ return *m ? FALSE : TRUE;
+}
+
+static mrb_value
+sym_inspect(mrb_state *mrb, mrb_value sym)
+{
+ mrb_value str;
+ const char *name;
+ mrb_int len;
+ mrb_sym id = mrb_symbol(sym);
+ char *sp;
+
+ name = mrb_sym2name_len(mrb, id, &len);
+ str = mrb_str_new(mrb, 0, len+1);
+ sp = RSTRING_PTR(str);
+ RSTRING_PTR(str)[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);
+ sp = RSTRING_PTR(str);
+ sp[0] = ':';
+ sp[1] = '"';
+ }
+ return str;
+}
+
+MRB_API mrb_value
+mrb_sym2str(mrb_state *mrb, mrb_sym sym)
+{
+ mrb_int len;
+ const char *name = mrb_sym2name_len(mrb, sym, &len);
+
+ if (!name) return mrb_undef_value(); /* can't happen */
+ return mrb_str_new_static(mrb, name, len);
+}
+
+MRB_API const char*
+mrb_sym2name(mrb_state *mrb, mrb_sym sym)
+{
+ mrb_int len;
+ const char *name = mrb_sym2name_len(mrb, sym, &len);
+
+ if (!name) return NULL;
+ if (symname_p(name) && strlen(name) == (size_t)len) {
+ return name;
+ }
+ else {
+ mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
+ return RSTRING_PTR(str);
+ }
+}
+
+#define lesser(a,b) (((a)>(b))?(b):(a))
+
+static mrb_value
+sym_cmp(mrb_state *mrb, mrb_value s1)
+{
+ mrb_value s2;
+ mrb_sym sym1, sym2;
+
+ mrb_get_args(mrb, "o", &s2);
+ if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value();
+ sym1 = mrb_symbol(s1);
+ sym2 = mrb_symbol(s2);
+ if (sym1 == sym2) return mrb_fixnum_value(0);
+ else {
+ const char *p1, *p2;
+ int retval;
+ mrb_int len, len1, len2;
+
+ p1 = mrb_sym2name_len(mrb, sym1, &len1);
+ p2 = mrb_sym2name_len(mrb, sym2, &len2);
+ len = lesser(len1, len2);
+ retval = memcmp(p1, p2, len);
+ if (retval == 0) {
+ if (len1 == len2) return mrb_fixnum_value(0);
+ if (len1 > len2) return mrb_fixnum_value(1);
+ return mrb_fixnum_value(-1);
+ }
+ if (retval > 0) return mrb_fixnum_value(1);
+ return mrb_fixnum_value(-1);
+ }
+}
+
+void
+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_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));
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/value_array.h b/web/server/h2o/libh2o/deps/mruby/src/value_array.h
new file mode 100644
index 00000000..bc5f28b0
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/value_array.h
@@ -0,0 +1,27 @@
+#ifndef MRB_VALUE_ARRAY_H__
+#define MRB_VALUE_ARRAY_H__
+
+#include <mruby.h>
+
+static inline void
+value_move(mrb_value *s1, const mrb_value *s2, size_t n)
+{
+ if (s1 > s2 && s1 < s2 + n)
+ {
+ s1 += n;
+ s2 += n;
+ while (n-- > 0) {
+ *--s1 = *--s2;
+ }
+ }
+ else if (s1 != s2) {
+ while (n-- > 0) {
+ *s1++ = *s2++;
+ }
+ }
+ else {
+ /* nothing to do. */
+ }
+}
+
+#endif /* MRB_VALUE_ARRAY_H__ */
diff --git a/web/server/h2o/libh2o/deps/mruby/src/variable.c b/web/server/h2o/libh2o/deps/mruby/src/variable.c
new file mode 100644
index 00000000..50fc7068
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/variable.c
@@ -0,0 +1,987 @@
+/*
+** variable.c - mruby variables
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+
+typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
+
+#include <mruby/khash.h>
+
+#ifndef MRB_IVHASH_INIT_SIZE
+#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE
+#endif
+
+KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE)
+KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal)
+
+/* Instance variable table structure */
+typedef struct iv_tbl {
+ khash_t(iv) h;
+} iv_tbl;
+
+/*
+ * Creates the instance variable table.
+ *
+ * Parameters
+ * mrb
+ * Returns
+ * the instance variable table.
+ */
+static iv_tbl*
+iv_new(mrb_state *mrb)
+{
+ return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE);
+}
+
+/*
+ * Set the value for the symbol in the instance variable table.
+ *
+ * Parameters
+ * mrb
+ * t the instance variable table to be set in.
+ * sym the symbol to be used as the key.
+ * val the value to be set.
+ */
+static void
+iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
+{
+ khash_t(iv) *h = &t->h;
+ khiter_t k;
+
+ k = kh_put(iv, mrb, h, sym);
+ kh_value(h, k) = val;
+}
+
+/*
+ * Get a value for a symbol from the instance variable table.
+ *
+ * Parameters
+ * mrb
+ * t the variable table to be searched.
+ * sym the symbol to be used as the key.
+ * vp the value pointer. Receives the value if the specified symbol is
+ * contained in the instance variable table.
+ * Returns
+ * true if the specified symbol is contained in the instance variable table.
+ */
+static mrb_bool
+iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
+{
+ khash_t(iv) *h = &t->h;
+ khiter_t k;
+
+ k = kh_get(iv, mrb, h, sym);
+ if (k != kh_end(h)) {
+ if (vp) *vp = kh_value(h, k);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Deletes the value for the symbol from the instance variable table.
+ *
+ * Parameters
+ * t the variable table to be searched.
+ * sym the symbol to be used as the key.
+ * vp the value pointer. Receive the deleted value if the symbol is
+ * contained in the instance variable table.
+ * Returns
+ * true if the specified symbol is contained in the instance variable table.
+ */
+static mrb_bool
+iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
+{
+ if (t == NULL) return FALSE;
+ else {
+ khash_t(iv) *h = &t->h;
+ khiter_t k;
+
+ k = kh_get(iv, mrb, h, sym);
+ if (k != kh_end(h)) {
+ mrb_value val = kh_value(h, k);
+ kh_del(iv, mrb, h, k);
+ if (vp) *vp = val;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static mrb_bool
+iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
+{
+ if (t == NULL) {
+ return TRUE;
+ }
+ else {
+ khash_t(iv) *h = &t->h;
+ khiter_t k;
+ int n;
+
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p);
+ if (n > 0) return FALSE;
+ if (n < 0) {
+ kh_del(iv, mrb, h, k);
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+static size_t
+iv_size(mrb_state *mrb, iv_tbl *t)
+{
+ if (t) {
+ return kh_size(&t->h);
+ }
+ return 0;
+}
+
+static iv_tbl*
+iv_copy(mrb_state *mrb, iv_tbl *t)
+{
+ return (iv_tbl*)kh_copy(iv, mrb, &t->h);
+}
+
+static void
+iv_free(mrb_state *mrb, iv_tbl *t)
+{
+ kh_destroy(iv, mrb, &t->h);
+}
+
+static int
+iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_gc_mark_value(mrb, v);
+ return 0;
+}
+
+static void
+mark_tbl(mrb_state *mrb, iv_tbl *t)
+{
+ if (t) {
+ iv_foreach(mrb, t, iv_mark_i, 0);
+ }
+}
+
+void
+mrb_gc_mark_gv(mrb_state *mrb)
+{
+ mark_tbl(mrb, mrb->globals);
+}
+
+void
+mrb_gc_free_gv(mrb_state *mrb)
+{
+ if (mrb->globals)
+ iv_free(mrb, mrb->globals);
+}
+
+void
+mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj)
+{
+ mark_tbl(mrb, obj->iv);
+}
+
+size_t
+mrb_gc_mark_iv_size(mrb_state *mrb, struct RObject *obj)
+{
+ return iv_size(mrb, obj->iv);
+}
+
+void
+mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj)
+{
+ if (obj->iv) {
+ iv_free(mrb, obj->iv);
+ }
+}
+
+mrb_value
+mrb_vm_special_get(mrb_state *mrb, mrb_sym i)
+{
+ return mrb_fixnum_value(0);
+}
+
+void
+mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v)
+{
+}
+
+static mrb_bool
+obj_iv_p(mrb_value obj)
+{
+ switch (mrb_type(obj)) {
+ case MRB_TT_OBJECT:
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ case MRB_TT_HASH:
+ case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+MRB_API mrb_value
+mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
+{
+ mrb_value v;
+
+ if (obj->iv && iv_get(mrb, obj->iv, sym, &v))
+ return v;
+ return mrb_nil_value();
+}
+
+MRB_API mrb_value
+mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
+{
+ if (obj_iv_p(obj)) {
+ return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym);
+ }
+ return mrb_nil_value();
+}
+
+MRB_API void
+mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
+{
+ iv_tbl *t = obj->iv;
+
+ if (MRB_FROZEN_P(obj)) {
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
+ }
+ if (!t) {
+ t = obj->iv = iv_new(mrb);
+ }
+ mrb_write_barrier(mrb, (struct RBasic*)obj);
+ iv_put(mrb, t, sym, v);
+}
+
+MRB_API void
+mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
+{
+ if (obj_iv_p(obj)) {
+ mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v);
+ }
+ else {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable");
+ }
+}
+
+MRB_API mrb_bool
+mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
+{
+ iv_tbl *t;
+
+ t = obj->iv;
+ if (t) {
+ return iv_get(mrb, t, sym, NULL);
+ }
+ return FALSE;
+}
+
+MRB_API mrb_bool
+mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
+{
+ if (!obj_iv_p(obj)) return FALSE;
+ return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
+}
+
+#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
+
+MRB_API mrb_bool
+mrb_iv_p(mrb_state *mrb, mrb_sym iv_name)
+{
+ const char *s;
+ mrb_int i, len;
+
+ s = mrb_sym2name_len(mrb, iv_name, &len);
+ if (len < 2) return FALSE;
+ if (s[0] != '@') return FALSE;
+ if (s[1] == '@') return FALSE;
+ for (i=1; i<len; i++) {
+ if (!identchar(s[i])) return FALSE;
+ }
+ return TRUE;
+}
+
+MRB_API void
+mrb_iv_check(mrb_state *mrb, mrb_sym iv_name)
+{
+ if (!mrb_iv_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_API void
+mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
+{
+ struct RObject *d = mrb_obj_ptr(dest);
+ struct RObject *s = mrb_obj_ptr(src);
+
+ if (d->iv) {
+ iv_free(mrb, d->iv);
+ d->iv = 0;
+ }
+ if (s->iv) {
+ mrb_write_barrier(mrb, (struct RBasic*)d);
+ d->iv = iv_copy(mrb, s->iv);
+ }
+}
+
+static int
+inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_value str = *(mrb_value*)p;
+ const char *s;
+ mrb_int len;
+ mrb_value ins;
+ char *sp = RSTRING_PTR(str);
+
+ /* need not to show internal data */
+ if (sp[0] == '-') { /* first element */
+ sp[0] = '#';
+ mrb_str_cat_lit(mrb, str, " ");
+ }
+ else {
+ mrb_str_cat_lit(mrb, str, ", ");
+ }
+ s = mrb_sym2name_len(mrb, sym, &len);
+ mrb_str_cat(mrb, str, s, len);
+ mrb_str_cat_lit(mrb, str, "=");
+ if (mrb_type(v) == MRB_TT_OBJECT) {
+ ins = mrb_any_to_s(mrb, v);
+ }
+ else {
+ ins = mrb_inspect(mrb, v);
+ }
+ mrb_str_cat_str(mrb, str, ins);
+ return 0;
+}
+
+mrb_value
+mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
+{
+ iv_tbl *t = obj->iv;
+ size_t len = iv_size(mrb, t);
+
+ if (len > 0) {
+ const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
+ mrb_value str = mrb_str_new_capa(mrb, 30);
+
+ 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));
+
+ iv_foreach(mrb, t, inspect_i, &str);
+ mrb_str_cat_lit(mrb, str, ">");
+ return str;
+ }
+ return mrb_any_to_s(mrb, mrb_obj_value(obj));
+}
+
+MRB_API mrb_value
+mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
+{
+ if (obj_iv_p(obj)) {
+ iv_tbl *t = mrb_obj_ptr(obj)->iv;
+ mrb_value val;
+
+ if (t && iv_del(mrb, t, sym, &val)) {
+ return val;
+ }
+ }
+ return mrb_undef_value();
+}
+
+mrb_value
+mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym)
+{
+ /* get self */
+ return mrb_iv_get(mrb, mrb->c->stack[0], sym);
+}
+
+void
+mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
+{
+ /* get self */
+ mrb_iv_set(mrb, mrb->c->stack[0], sym, v);
+}
+
+static int
+iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_value ary;
+ const char* s;
+ mrb_int len;
+
+ ary = *(mrb_value*)p;
+ s = mrb_sym2name_len(mrb, sym, &len);
+ if (len > 1 && s[0] == '@' && s[1] != '@') {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ }
+ return 0;
+}
+
+/* 15.3.1.3.23 */
+/*
+ * call-seq:
+ * obj.instance_variables -> array
+ *
+ * Returns an array of instance variable names for the receiver. Note
+ * that simply defining an accessor does not create the corresponding
+ * instance variable.
+ *
+ * class Fred
+ * attr_accessor :a1
+ * def initialize
+ * @iv = 3
+ * end
+ * end
+ * Fred.new.instance_variables #=> [:@iv]
+ */
+mrb_value
+mrb_obj_instance_variables(mrb_state *mrb, mrb_value self)
+{
+ mrb_value ary;
+
+ ary = mrb_ary_new(mrb);
+ if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) {
+ iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary);
+ }
+ return ary;
+}
+
+static int
+cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_value ary;
+ const char* s;
+ mrb_int len;
+
+ ary = *(mrb_value*)p;
+ s = mrb_sym2name_len(mrb, sym, &len);
+ if (len > 2 && s[0] == '@' && s[1] == '@') {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ }
+ return 0;
+}
+
+/* 15.2.2.4.19 */
+/*
+ * call-seq:
+ * mod.class_variables -> array
+ *
+ * Returns an array of the names of class variables in <i>mod</i>.
+ *
+ * class One
+ * @@var1 = 1
+ * end
+ * class Two < One
+ * @@var2 = 2
+ * end
+ * One.class_variables #=> [:@@var1]
+ * Two.class_variables #=> [:@@var2]
+ */
+mrb_value
+mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value ary;
+ struct RClass *c;
+
+ ary = mrb_ary_new(mrb);
+ c = mrb_class_ptr(mod);
+ while (c) {
+ if (c->iv) {
+ iv_foreach(mrb, c->iv, cv_i, &ary);
+ }
+ c = c->super;
+ }
+ return ary;
+}
+
+MRB_API mrb_value
+mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
+{
+ struct RClass * cls = c;
+ mrb_value v;
+ int given = FALSE;
+
+ while (c) {
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ given = TRUE;
+ }
+ c = c->super;
+ }
+ if (given) return 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__"));
+ c = mrb_class_ptr(klass);
+ if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) {
+ given = FALSE;
+ while (c) {
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ given = TRUE;
+ }
+ c = c->super;
+ }
+ if (given) return v;
+ }
+ }
+ mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
+ mrb_sym2str(mrb, sym), mrb_obj_value(cls));
+ /* not reached */
+ return mrb_nil_value();
+}
+
+MRB_API mrb_value
+mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
+{
+ return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym);
+}
+
+MRB_API void
+mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
+{
+ struct RClass * cls = c;
+
+ while (c) {
+ if (c->iv) {
+ iv_tbl *t = c->iv;
+
+ if (iv_get(mrb, t, sym, NULL)) {
+ mrb_write_barrier(mrb, (struct RBasic*)c);
+ iv_put(mrb, t, sym, v);
+ return;
+ }
+ }
+ c = c->super;
+ }
+
+ if (cls && cls->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+
+ klass = mrb_obj_iv_get(mrb, (struct RObject*)cls,
+ mrb_intern_lit(mrb, "__attached__"));
+ switch (mrb_type(klass)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ c = mrb_class_ptr(klass);
+ break;
+ default:
+ c = cls;
+ break;
+ }
+ }
+ else{
+ c = cls;
+ }
+
+ if (!c->iv) {
+ c->iv = iv_new(mrb);
+ }
+
+ mrb_write_barrier(mrb, (struct RBasic*)c);
+ iv_put(mrb, c->iv, sym, v);
+}
+
+MRB_API void
+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_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
+{
+ while (c) {
+ if (c->iv) {
+ iv_tbl *t = c->iv;
+ if (iv_get(mrb, t, sym, NULL)) return TRUE;
+ }
+ c = c->super;
+ }
+
+ return FALSE;
+}
+
+MRB_API mrb_bool
+mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
+{
+ return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym);
+}
+
+mrb_value
+mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
+{
+ struct RClass *c = mrb->c->ci->proc->target_class;
+
+ if (!c) c = mrb->c->ci->target_class;
+
+ return mrb_mod_cv_get(mrb, c, sym);
+}
+
+void
+mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
+{
+ struct RClass *c = mrb->c->ci->proc->target_class;
+
+ if (!c) c = mrb->c->ci->target_class;
+ mrb_mod_cv_set(mrb, c, sym, v);
+}
+
+static void
+mod_const_check(mrb_state *mrb, mrb_value mod)
+{
+ switch (mrb_type(mod)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ break;
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module");
+ break;
+ }
+}
+
+static mrb_value
+const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
+{
+ struct RClass *c = base;
+ mrb_value v;
+ iv_tbl *t;
+ mrb_bool retry = FALSE;
+ mrb_value name;
+
+L_RETRY:
+ while (c) {
+ if (c->iv) {
+ t = c->iv;
+ if (iv_get(mrb, t, sym, &v))
+ return v;
+ }
+ c = c->super;
+ }
+ if (!retry && base && base->tt == MRB_TT_MODULE) {
+ c = mrb->object_class;
+ retry = TRUE;
+ 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);
+}
+
+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);
+}
+
+mrb_value
+mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
+{
+ struct RClass *c = mrb->c->ci->proc->target_class;
+ struct RClass *c2;
+ mrb_value v;
+ mrb_irep *irep;
+
+ if (!c) c = mrb->c->ci->target_class;
+ mrb_assert(c != NULL);
+
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ return v;
+ }
+ c2 = c;
+ while (c2 && c2->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)c2,
+ mrb_intern_lit(mrb, "__attached__"));
+ c2 = mrb_class_ptr(klass);
+ }
+ if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2;
+ mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc));
+ irep = mrb->c->ci->proc->body.irep;
+ while (irep) {
+ if (irep->target_class) {
+ c2 = irep->target_class;
+ if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) {
+ return v;
+ }
+ }
+ irep = irep->outer;
+ }
+ return const_get(mrb, c, sym);
+}
+
+MRB_API void
+mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
+{
+ mod_const_check(mrb, mod);
+ if (mrb_type(v) == MRB_TT_CLASS || mrb_type(v) == MRB_TT_MODULE) {
+ mrb_class_name_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(v), sym);
+ }
+ mrb_iv_set(mrb, mod, sym, v);
+}
+
+void
+mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
+{
+ struct RClass *c = mrb->c->ci->proc->target_class;
+
+ if (!c) c = mrb->c->ci->target_class;
+ mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
+}
+
+MRB_API void
+mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
+{
+ mod_const_check(mrb, mod);
+ mrb_iv_remove(mrb, mod, sym);
+}
+
+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);
+}
+
+MRB_API void
+mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val)
+{
+ mrb_define_const(mrb, mrb->object_class, name, val);
+}
+
+static int
+const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_value ary;
+ const char* s;
+ mrb_int len;
+
+ ary = *(mrb_value*)p;
+ s = mrb_sym2name_len(mrb, sym, &len);
+ if (len >= 1 && ISUPPER(s[0])) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ }
+ return 0;
+}
+
+/* 15.2.2.4.24 */
+/*
+ * call-seq:
+ * mod.constants -> array
+ *
+ * Returns an array of all names of contants defined in the receiver.
+ */
+mrb_value
+mrb_mod_constants(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value ary;
+ mrb_bool inherit = TRUE;
+ struct RClass *c = mrb_class_ptr(mod);
+
+ mrb_get_args(mrb, "|b", &inherit);
+ ary = mrb_ary_new(mrb);
+ while (c) {
+ if (c->iv) {
+ iv_foreach(mrb, c->iv, const_i, &ary);
+ }
+ if (!inherit) break;
+ c = c->super;
+ if (c == mrb->object_class) break;
+ }
+ return ary;
+}
+
+MRB_API mrb_value
+mrb_gv_get(mrb_state *mrb, mrb_sym sym)
+{
+ mrb_value v;
+
+ if (!mrb->globals) {
+ return mrb_nil_value();
+ }
+ if (iv_get(mrb, mrb->globals, sym, &v))
+ return v;
+ return mrb_nil_value();
+}
+
+MRB_API void
+mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
+{
+ iv_tbl *t;
+
+ if (!mrb->globals) {
+ t = mrb->globals = iv_new(mrb);
+ }
+ else {
+ t = mrb->globals;
+ }
+ iv_put(mrb, t, sym, v);
+}
+
+MRB_API void
+mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
+{
+ if (!mrb->globals) {
+ return;
+ }
+ iv_del(mrb, mrb->globals, sym, NULL);
+}
+
+static int
+gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ mrb_value ary;
+
+ ary = *(mrb_value*)p;
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ return 0;
+}
+
+/* 15.3.1.2.4 */
+/* 15.3.1.3.14 */
+/*
+ * call-seq:
+ * global_variables -> array
+ *
+ * Returns an array of the names of global variables.
+ *
+ * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
+ */
+mrb_value
+mrb_f_global_variables(mrb_state *mrb, mrb_value self)
+{
+ iv_tbl *t = mrb->globals;
+ mrb_value ary = mrb_ary_new(mrb);
+ size_t i;
+ char buf[3];
+
+ if (t) {
+ iv_foreach(mrb, t, gv_i, &ary);
+ }
+ buf[0] = '$';
+ buf[2] = 0;
+ for (i = 1; i <= 9; ++i) {
+ buf[1] = (char)(i + '0');
+ mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2)));
+ }
+ return ary;
+}
+
+static mrb_bool
+mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
+{
+ struct RClass *klass = mrb_class_ptr(mod);
+ struct RClass *tmp;
+ mrb_bool mod_retry = 0;
+
+ tmp = klass;
+retry:
+ while (tmp) {
+ if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) {
+ return TRUE;
+ }
+ if (!recurse && (klass != mrb->object_class)) break;
+ tmp = tmp->super;
+ }
+ if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) {
+ mod_retry = 1;
+ tmp = mrb->object_class;
+ goto retry;
+ }
+ return FALSE;
+}
+
+MRB_API mrb_bool
+mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+ return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE);
+}
+
+MRB_API mrb_bool
+mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+ return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE);
+}
+
+MRB_API mrb_value
+mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id)
+{
+ return mrb_iv_get(mrb, obj, id);
+}
+
+struct csym_arg {
+ struct RClass *c;
+ mrb_sym sym;
+};
+
+static int
+csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
+{
+ struct csym_arg *a = (struct csym_arg*)p;
+ struct RClass *c = a->c;
+
+ if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) {
+ a->sym = sym;
+ return 1; /* stop iteration */
+ }
+ return 0;
+}
+
+static mrb_sym
+find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c)
+{
+ struct csym_arg arg;
+
+ if (!outer) return 0;
+ arg.c = c;
+ arg.sym = 0;
+ iv_foreach(mrb, outer->iv, csym_i, &arg);
+ return arg.sym;
+}
+
+mrb_value
+mrb_class_find_path(mrb_state *mrb, struct RClass *c)
+{
+ mrb_value outer, path;
+ mrb_sym name;
+ const char *str;
+ mrb_int len;
+ mrb_sym osym = mrb_intern_lit(mrb, "__outer__");
+
+ outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym);
+ if (mrb_nil_p(outer)) return outer;
+ name = find_class_sym(mrb, mrb_class_ptr(outer), c);
+ if (name == 0) return mrb_nil_value();
+ str = mrb_class_name(mrb, mrb_class_ptr(outer));
+ path = mrb_str_new_capa(mrb, 40);
+ mrb_str_cat_cstr(mrb, path, str);
+ mrb_str_cat_cstr(mrb, path, "::");
+
+ str = mrb_sym2name_len(mrb, name, &len);
+ mrb_str_cat(mrb, path, str, len);
+ iv_del(mrb, c->iv, osym, NULL);
+ iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
+ return path;
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/version.c b/web/server/h2o/libh2o/deps/mruby/src/version.c
new file mode 100644
index 00000000..350bc167
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/version.c
@@ -0,0 +1,17 @@
+#include <mruby.h>
+#include <mruby/variable.h>
+
+void
+mrb_init_version(mrb_state* mrb)
+{
+ mrb_value mruby_version = mrb_str_new_lit(mrb, MRUBY_VERSION);
+
+ mrb_define_global_const(mrb, "RUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_RUBY_VERSION));
+ mrb_define_global_const(mrb, "RUBY_ENGINE", mrb_str_new_lit(mrb, MRUBY_RUBY_ENGINE));
+ mrb_define_global_const(mrb, "RUBY_ENGINE_VERSION", mruby_version);
+ mrb_define_global_const(mrb, "MRUBY_VERSION", mruby_version);
+ mrb_define_global_const(mrb, "MRUBY_RELEASE_NO", mrb_fixnum_value(MRUBY_RELEASE_NO));
+ mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE));
+ mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION));
+ mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT));
+}
diff --git a/web/server/h2o/libh2o/deps/mruby/src/vm.c b/web/server/h2o/libh2o/deps/mruby/src/vm.c
new file mode 100644
index 00000000..f413211e
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/mruby/src/vm.c
@@ -0,0 +1,2909 @@
+/*
+** vm.c - virtual machine for mruby
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <math.h>
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/hash.h>
+#include <mruby/irep.h>
+#include <mruby/numeric.h>
+#include <mruby/proc.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/opcode.h>
+#include "value_array.h"
+#include <mruby/throw.h>
+
+#ifdef MRB_DISABLE_STDIO
+#if defined(__cplusplus)
+extern "C" {
+#endif
+void abort(void);
+#if defined(__cplusplus)
+} /* extern "C" { */
+#endif
+#endif
+
+#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
+#endif
+
+/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */
+#ifndef MRB_FUNCALL_DEPTH_MAX
+#define MRB_FUNCALL_DEPTH_MAX 512
+#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
+#define MRB_STACK_MAX (0x40000 - MRB_STACK_GROWTH)
+#endif
+
+#ifdef VM_DEBUG
+# define DEBUG(x) (x)
+#else
+# define DEBUG(x)
+#endif
+
+
+#ifndef MRB_GC_FIXED_ARENA
+static void
+mrb_gc_arena_shrink(mrb_state *mrb, int idx)
+{
+ mrb_gc *gc = &mrb->gc;
+ int capa = gc->arena_capa;
+
+ if (idx < capa / 4) {
+ capa >>= 2;
+ if (capa < MRB_GC_ARENA_SIZE) {
+ capa = MRB_GC_ARENA_SIZE;
+ }
+ if (capa != gc->arena_capa) {
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
+ gc->arena_capa = capa;
+ }
+ }
+}
+#else
+#define mrb_gc_arena_shrink(mrb,idx)
+#endif
+
+#define CALL_MAXARGS 127
+
+void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
+
+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
+ while (count-- > 0) {
+ SET_NIL_VALUE(*from);
+ from++;
+ }
+#endif
+}
+
+static inline void
+stack_copy(mrb_value *dst, const mrb_value *src, size_t size)
+{
+ while (size-- > 0) {
+ *dst++ = *src++;
+ }
+}
+
+static void
+stack_init(mrb_state *mrb)
+{
+ struct mrb_context *c = mrb->c;
+
+ /* 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;
+}
+
+static inline void
+envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size)
+{
+ mrb_callinfo *ci = mrb->c->cibase;
+
+ if (newbase == oldbase) return;
+ while (ci <= mrb->c->ci) {
+ struct REnv *e = ci->env;
+ mrb_value *st;
+
+ if (e && MRB_ENV_STACK_SHARED_P(e) &&
+ (st = e->stack) && oldbase <= st && st < oldbase+size) {
+ ptrdiff_t off = e->stack - oldbase;
+
+ e->stack = newbase + off;
+ }
+ ci->stackent = newbase + (ci->stackent - oldbase);
+ ci++;
+ }
+}
+
+/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */
+
+static void
+stack_extend_alloc(mrb_state *mrb, int room)
+{
+ mrb_value *oldbase = mrb->c->stbase;
+ 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;
+
+ if (off > size) size = off;
+#ifdef MRB_STACK_EXTEND_DOUBLING
+ if (room <= size)
+ size *= 2;
+ else
+ size += room;
+#else
+ /* Use linear stack growth.
+ It is slightly slower than doubling the stack space,
+ but it saves memory on small devices. */
+ if (room <= MRB_STACK_GROWTH)
+ size += MRB_STACK_GROWTH;
+ else
+ size += room;
+#endif
+
+ newstack = (mrb_value *)mrb_realloc(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, size);
+ 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,
+ to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
+ if (size > MRB_STACK_MAX) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+ }
+}
+
+static inline void
+stack_extend(mrb_state *mrb, int room)
+{
+ if (mrb->c->stack + room >= mrb->c->stend) {
+ stack_extend_alloc(mrb, room);
+ }
+}
+
+static inline struct REnv*
+uvenv(mrb_state *mrb, int up)
+{
+ struct REnv *e = mrb->c->ci->proc->env;
+
+ while (up--) {
+ if (!e) return NULL;
+ e = (struct REnv*)e->c;
+ }
+ return e;
+}
+
+static inline mrb_bool
+is_strict(mrb_state *mrb, struct REnv *e)
+{
+ ptrdiff_t cioff = e->cioff;
+
+ if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc &&
+ MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static inline struct REnv*
+top_env(mrb_state *mrb, struct RProc *proc)
+{
+ struct REnv *e = proc->env;
+
+ if (is_strict(mrb, e)) return e;
+ while (e->c) {
+ e = (struct REnv*)e->c;
+ if (is_strict(mrb, e)) return e;
+ }
+ return e;
+}
+
+#define CI_ACC_SKIP -1
+#define CI_ACC_DIRECT -2
+#define CI_ACC_RESUMED -3
+
+static inline mrb_callinfo*
+cipush(mrb_state *mrb)
+{
+ 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;
+
+ c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2);
+ c->ci = c->cibase + size;
+ c->ciend = c->cibase + size * 2;
+ }
+ ci = ++c->ci;
+ *ci = ci_zero;
+ ci->epos = mrb->c->eidx;
+ ci->ridx = ridx;
+
+ return ci;
+}
+
+MRB_API void
+mrb_env_unshare(mrb_state *mrb, struct REnv *e)
+{
+ if (e == NULL) return;
+ else {
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+ ptrdiff_t cioff = e->cioff;
+ mrb_value *p;
+
+ if (!MRB_ENV_STACK_SHARED_P(e)) return;
+ if (e->cxt.c != mrb->c) return;
+ if (e->cioff == 0 && e->cxt.c == mrb->root_c) return;
+ MRB_ENV_UNSHARE_STACK(e);
+ if (!e->c) {
+ /* save block argument position (negated) */
+ e->cioff = -e->cxt.c->cibase[cioff].argc-1;
+ if (e->cioff == 0) e->cioff = -2; /* blkarg position for vararg (1:args, 2:blk) */
+ }
+ e->cxt.mid = e->cxt.c->cibase[cioff].mid;
+ p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
+ if (len > 0) {
+ stack_copy(p, e->stack, len);
+ }
+ e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
+ }
+}
+
+static inline void
+cipop(mrb_state *mrb)
+{
+ struct mrb_context *c = mrb->c;
+ struct REnv *env = c->ci->env;
+
+ c->ci--;
+ mrb_env_unshare(mrb, env);
+}
+
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+
+static void
+ecall(mrb_state *mrb, int i)
+{
+ struct RProc *p;
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_value *self = mrb->c->stack;
+ struct RObject *exc;
+ ptrdiff_t cioff;
+ int ai = mrb_gc_arena_save(mrb);
+
+ if (i<0) return;
+ if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+ }
+ p = mrb->c->ensure[i];
+ if (!p) return;
+ mrb->c->ensure[i] = NULL;
+ cioff = ci - mrb->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->nregs = p->body.irep->nregs;
+ ci->target_class = p->target_class;
+ mrb->c->stack = mrb->c->stack + ci[-1].nregs;
+ exc = mrb->exc; mrb->exc = 0;
+ if (exc) {
+ mrb_gc_protect(mrb, mrb_obj_value(exc));
+ }
+ mrb_run(mrb, p, *self);
+ mrb->c->ci = mrb->c->cibase + cioff;
+ if (!mrb->exc) mrb->exc = exc;
+ mrb_gc_arena_restore(mrb, ai);
+}
+
+#ifndef MRB_FUNCALL_ARGC_MAX
+#define MRB_FUNCALL_ARGC_MAX 16
+#endif
+
+MRB_API mrb_value
+mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...)
+{
+ mrb_value argv[MRB_FUNCALL_ARGC_MAX];
+ va_list ap;
+ mrb_int i;
+ mrb_sym mid = mrb_intern_cstr(mrb, name);
+
+ 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);
+}
+
+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;
+
+ if (!mrb->jmp) {
+ struct mrb_jmpbuf c_jmp;
+ ptrdiff_t nth_ci = mrb->c->ci - mrb->c->cibase;
+
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ /* recursive call */
+ val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
+ mrb->jmp = 0;
+ }
+ 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;
+ val = mrb_obj_value(mrb->exc);
+ }
+ MRB_END_EXC(&c_jmp);
+ mrb->jmp = 0;
+ }
+ else {
+ struct RProc *p;
+ struct RClass *c;
+ mrb_callinfo *ci;
+ int n;
+ ptrdiff_t voff = -1;
+
+ if (!mrb->c->stack) {
+ stack_init(mrb);
+ }
+ n = mrb->c->ci->nregs;
+ if (argc < 0) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc));
+ }
+ c = mrb_class(mrb, self);
+ p = mrb_method_search_vm(mrb, &c, mid);
+ if (!p) {
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
+ p = mrb_method_search_vm(mrb, &c, missing);
+ if (!p) {
+ mrb_method_missing(mrb, mid, self, args);
+ }
+ mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
+ stack_extend(mrb, n+2);
+ mrb->c->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->proc = p;
+ ci->stackent = mrb->c->stack;
+ ci->argc = argc;
+ ci->target_class = c;
+ mrb->c->stack = mrb->c->stack + n;
+ if (mrb->c->stbase <= argv && argv < mrb->c->stend) {
+ voff = argv - mrb->c->stbase;
+ }
+ if (MRB_PROC_CFUNC_P(p)) {
+ ci->nregs = argc + 2;
+ stack_extend(mrb, ci->nregs);
+ }
+ else if (argc >= CALL_MAXARGS) {
+ mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
+ stack_extend(mrb, ci->nregs);
+ mrb->c->stack[1] = args;
+ ci->argc = -1;
+ argc = 1;
+ }
+ else {
+ if (argc < 0) argc = 1;
+ ci->nregs = p->body.irep->nregs + argc;
+ stack_extend(mrb, ci->nregs);
+ }
+ if (voff >= 0) {
+ argv = mrb->c->stbase + voff;
+ }
+ mrb->c->stack[0] = self;
+ if (ci->argc > 0) {
+ stack_copy(mrb->c->stack+1, argv, argc);
+ }
+ mrb->c->stack[argc+1] = blk;
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ int ai = mrb_gc_arena_save(mrb);
+
+ ci->acc = CI_ACC_DIRECT;
+ val = p->body.func(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, p, self);
+ }
+ }
+ mrb_gc_protect(mrb, val);
+ return val;
+}
+
+MRB_API mrb_value
+mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv)
+{
+ 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)
+{
+ mrb_callinfo *ci = mrb->c->ci;
+
+ mrb->c->stack[0] = self;
+ ci->proc = p;
+ ci->target_class = p->target_class;
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+ ci->nregs = p->body.irep->nregs;
+ stack_extend(mrb, (ci->argc < 0 && ci->nregs < 3) ? 3 : ci->nregs);
+
+ ci = cipush(mrb);
+ ci->nregs = 0;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+/* 15.3.1.3.4 */
+/* 15.3.1.3.44 */
+/*
+ * call-seq:
+ * obj.send(symbol [, args...]) -> obj
+ * obj.__send__(symbol [, args...]) -> obj
+ *
+ * Invokes the method identified by _symbol_, passing it any
+ * arguments specified. You can use <code>__send__</code> if the name
+ * +send+ clashes with an existing method in _obj_.
+ *
+ * class Klass
+ * def hello(*args)
+ * "Hello " + args.join(' ')
+ * end
+ * end
+ * k = Klass.new
+ * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
+ */
+MRB_API mrb_value
+mrb_f_send(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym name;
+ mrb_value block, *argv, *regs;
+ mrb_int argc, i, len;
+ struct RProc *p;
+ struct RClass *c;
+ mrb_callinfo *ci;
+
+ mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
+ ci = mrb->c->ci;
+ if (ci->acc < 0) {
+ funcall:
+ return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
+ }
+
+ c = mrb_class(mrb, self);
+ p = mrb_method_search_vm(mrb, &c, name);
+
+ if (!p) { /* call method_mising */
+ goto funcall;
+ }
+
+ ci->mid = name;
+ ci->target_class = c;
+ regs = mrb->c->stack+1;
+ /* remove first symbol from arguments */
+ if (ci->argc >= 0) {
+ for (i=0,len=ci->argc; i<len; i++) {
+ regs[i] = regs[i+1];
+ }
+ ci->argc--;
+ }
+ else { /* variable length arguments */
+ mrb_ary_shift(mrb, regs[0]);
+ }
+
+ return mrb_exec_irep(mrb, self, p);
+}
+
+static mrb_value
+eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ ci = mrb->c->ci;
+ if (ci->acc == CI_ACC_DIRECT) {
+ ci->target_class = c;
+ return mrb_yield_cont(mrb, blk, self, 1, &self);
+ }
+ ci->target_class = c;
+ p = mrb_proc_ptr(blk);
+ ci->proc = p;
+ ci->argc = 1;
+ ci->mid = ci[-1].mid;
+ if (MRB_PROC_CFUNC_P(p)) {
+ stack_extend(mrb, 3);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
+ return p->body.func(mrb, self);
+ }
+ ci->nregs = p->body.irep->nregs;
+ stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
+ ci = cipush(mrb);
+ ci->nregs = 0;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+/* 15.2.2.4.35 */
+/*
+ * call-seq:
+ * mod.class_eval {| | block } -> obj
+ * mod.module_eval {| | block } -> obj
+ *
+ * Evaluates block in the context of _mod_. This can
+ * be used to add methods to a class. <code>module_eval</code> returns
+ * the result of evaluating its argument.
+ */
+mrb_value
+mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value a, b;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
+ }
+ return eval_under(mrb, mod, b, mrb_class_ptr(mod));
+}
+
+/* 15.3.1.3.18 */
+/*
+ * call-seq:
+ * obj.instance_eval {| | block } -> obj
+ *
+ * Evaluates the given block,within the context of the receiver (_obj_).
+ * In order to set the context, the variable +self+ is set to _obj_ while
+ * the code is executing, giving the code access to _obj_'s
+ * instance variables. In the version of <code>instance_eval</code>
+ * that takes a +String+, the optional second and third
+ * parameters supply a filename and starting line number that are used
+ * when reporting compilation errors.
+ *
+ * class KlassWithSecret
+ * def initialize
+ * @secret = 99
+ * end
+ * end
+ * k = KlassWithSecret.new
+ * k.instance_eval { @secret } #=> 99
+ */
+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:
+ case MRB_TT_FLOAT:
+ c = 0;
+ break;
+ default:
+ cv = mrb_singleton_class(mrb, self);
+ c = mrb_class_ptr(cv);
+ break;
+ }
+ return eval_under(mrb, self, b, c);
+}
+
+MRB_API mrb_value
+mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
+{
+ struct RProc *p;
+ mrb_sym mid = mrb->c->ci->mid;
+ mrb_callinfo *ci;
+ int n = mrb->c->ci->nregs;
+ mrb_value val;
+
+ if (mrb_nil_p(b)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ 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 = argc;
+ ci->target_class = c;
+ ci->acc = CI_ACC_SKIP;
+ mrb->c->stack = mrb->c->stack + n;
+ ci->nregs = MRB_PROC_CFUNC_P(p) ? argc+2 : p->body.irep->nregs;
+ stack_extend(mrb, ci->nregs);
+
+ mrb->c->stack[0] = self;
+ if (argc > 0) {
+ stack_copy(mrb->c->stack+1, argv, argc);
+ }
+ mrb->c->stack[argc+1] = mrb_nil_value();
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ val = p->body.func(mrb, self);
+ mrb->c->stack = mrb->c->ci->stackent;
+ }
+ else {
+ ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase;
+ val = mrb_run(mrb, p, self);
+ mrb->c->ci = mrb->c->cibase + cioff;
+ }
+ cipop(mrb);
+ return val;
+}
+
+MRB_API mrb_value
+mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
+{
+ struct RProc *p = mrb_proc_ptr(b);
+
+ return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
+}
+
+MRB_API mrb_value
+mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
+{
+ struct RProc *p = mrb_proc_ptr(b);
+
+ return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
+}
+
+mrb_value
+mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ if (mrb_nil_p(b)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ if (mrb_type(b) != MRB_TT_PROC) {
+ mrb_raise(mrb, E_TYPE_ERROR, "not a block");
+ }
+
+ p = mrb_proc_ptr(b);
+ ci = mrb->c->ci;
+
+ stack_extend(mrb, 3);
+ mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
+ mrb->c->stack[2] = mrb_nil_value();
+ ci->argc = -1;
+ return mrb_exec_irep(mrb, self, p);
+}
+
+mrb_value
+mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
+{
+ struct RProc *proc;
+ mrb_irep *irep;
+ mrb_value ary;
+ struct RClass *c;
+
+ mrb_get_args(mrb, "");
+ ary = mrb_ary_new(mrb);
+ proc = mrb->c->ci[-1].proc; /* callee proc */
+ c = proc->target_class;
+ mrb_ary_push(mrb, ary, mrb_obj_value(c));
+ mrb_assert(!MRB_PROC_CFUNC_P(proc));
+ irep = proc->body.irep;
+ while (irep) {
+ if (irep->target_class && irep->target_class != c) {
+ c = irep->target_class;
+ mrb_ary_push(mrb, ary, mrb_obj_value(c));
+ }
+ irep = irep->outer;
+ }
+ return ary;
+}
+
+static struct RBreak*
+break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
+{
+ struct RBreak *brk;
+
+ brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
+ brk->iv = NULL;
+ brk->proc = p;
+ brk->val = val;
+
+ return brk;
+}
+
+typedef enum {
+ LOCALJUMP_ERROR_RETURN = 0,
+ LOCALJUMP_ERROR_BREAK = 1,
+ LOCALJUMP_ERROR_YIELD = 2
+} localjump_error_kind;
+
+static void
+localjump_error(mrb_state *mrb, localjump_error_kind kind)
+{
+ char kind_str[3][7] = { "return", "break", "yield" };
+ char kind_str_len[] = { 6, 5, 5 };
+ static const char lead[] = "unexpected ";
+ mrb_value msg;
+ mrb_value exc;
+
+ msg = mrb_str_new_capa(mrb, sizeof(lead) + 7);
+ mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
+ mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
+ exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
+ mrb_exc_set(mrb, exc);
+}
+
+static void
+argnum_error(mrb_state *mrb, mrb_int num)
+{
+ mrb_value exc;
+ mrb_value str;
+ mrb_int argc = mrb->c->ci->argc;
+
+ if (argc < 0) {
+ mrb_value args = mrb->c->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));
+ }
+ else {
+ str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
+ mrb_fixnum_value(argc), mrb_fixnum_value(num));
+ }
+ exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
+ mrb_exc_set(mrb, exc);
+}
+
+void
+irep_uplink(mrb_state *mrb, mrb_irep *outer, mrb_irep *irep)
+{
+ if (irep->outer != outer) {
+ if (irep->outer) {
+ mrb_irep_decref(mrb, irep->outer);
+ }
+ irep->outer = outer;
+ mrb_irep_incref(mrb, outer);
+ }
+}
+
+#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
+#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)
+#endif
+
+#ifdef MRB_BYTECODE_DECODE_OPTION
+#define BYTECODE_DECODER(x) ((mrb)->bytecode_decoder)?(mrb)->bytecode_decoder((mrb), (x)):(x)
+#else
+#define BYTECODE_DECODER(x) (x)
+#endif
+
+
+#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
+#define DIRECT_THREADED
+#endif
+
+#ifndef DIRECT_THREADED
+
+#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) {
+#define CASE(op) case op:
+#define NEXT pc++; break
+#define JUMP break
+#define END_DISPATCH }}
+
+#else
+
+#define INIT_DISPATCH JUMP; return mrb_nil_value();
+#define CASE(op) L_ ## op:
+#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
+#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
+
+#define END_DISPATCH
+
+#endif
+
+MRB_API mrb_value
+mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+{
+ 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;
+
+ if (!c->stack) {
+ stack_init(mrb);
+ }
+ if (stack_keep > nregs)
+ nregs = stack_keep;
+ stack_extend(mrb, nregs);
+ stack_clear(c->stack + stack_keep, nregs - stack_keep);
+ c->stack[0] = self;
+ result = mrb_vm_exec(mrb, proc, irep->iseq);
+ if (c->ci - c->cibase > cioff) {
+ 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;
+ }
+ return result;
+}
+
+MRB_API mrb_value
+mrb_vm_exec(mrb_state *mrb, struct RProc *proc, 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_code i;
+ int ai = mrb_gc_arena_save(mrb);
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+
+#ifdef DIRECT_THREADED
+ static void *optable[] = {
+ &&L_OP_NOP, &&L_OP_MOVE,
+ &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL,
+ &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF,
+ &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL,
+ &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV,
+ &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST,
+ &&L_OP_GETUPVAR, &&L_OP_SETUPVAR,
+ &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT,
+ &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP,
+ &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND,
+ &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER,
+ &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH,
+ &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV,
+ &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE,
+ &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST,
+ &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH,
+ &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS,
+ &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC,
+ &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS,
+ &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR,
+ };
+#endif
+
+ mrb_bool exc_catched = FALSE;
+RETRY_TRY_BLOCK:
+
+ MRB_TRY(&c_jmp) {
+
+ if (exc_catched) {
+ exc_catched = FALSE;
+ if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK)
+ goto L_BREAK;
+ goto L_RAISE;
+ }
+ mrb->jmp = &c_jmp;
+ mrb->c->ci->proc = proc;
+ mrb->c->ci->nregs = irep->nregs;
+
+#define regs (mrb->c->stack)
+ INIT_DISPATCH {
+ CASE(OP_NOP) {
+ /* do nothing */
+ NEXT;
+ }
+
+ CASE(OP_MOVE) {
+ /* A B R(A) := R(B) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ regs[a] = regs[b];
+ NEXT;
+ }
+
+ CASE(OP_LOADL) {
+ /* A Bx R(A) := Pool(Bx) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+#ifdef MRB_WORD_BOXING
+ mrb_value val = pool[bx];
+ if (mrb_float_p(val)) {
+ val = mrb_float_value(mrb, mrb_float(val));
+ }
+ regs[a] = val;
+#else
+ regs[a] = pool[bx];
+#endif
+ NEXT;
+ }
+
+ CASE(OP_LOADI) {
+ /* A sBx R(A) := sBx */
+ SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i));
+ NEXT;
+ }
+
+ CASE(OP_LOADSYM) {
+ /* A Bx R(A) := Syms(Bx) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ SET_SYM_VALUE(regs[a], syms[bx]);
+ NEXT;
+ }
+
+ CASE(OP_LOADSELF) {
+ /* A R(A) := self */
+ int a = GETARG_A(i);
+ regs[a] = regs[0];
+ NEXT;
+ }
+
+ CASE(OP_LOADT) {
+ /* A R(A) := true */
+ int a = GETARG_A(i);
+ SET_TRUE_VALUE(regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_LOADF) {
+ /* A R(A) := false */
+ int a = GETARG_A(i);
+ SET_FALSE_VALUE(regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETGLOBAL) {
+ /* A Bx R(A) := getglobal(Syms(Bx)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_gv_get(mrb, syms[bx]);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETGLOBAL) {
+ /* A Bx setglobal(Syms(Bx), R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_gv_set(mrb, syms[bx], regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETSPECIAL) {
+ /* A Bx R(A) := Special[Bx] */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_vm_special_get(mrb, bx);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETSPECIAL) {
+ /* A Bx Special[Bx] := R(A) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_special_set(mrb, bx, regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETIV) {
+ /* A Bx R(A) := ivget(Bx) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_vm_iv_get(mrb, syms[bx]);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETIV) {
+ /* A Bx ivset(Syms(Bx),R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_iv_set(mrb, syms[bx], regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETCV) {
+ /* A Bx R(A) := cvget(Syms(Bx)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val;
+ ERR_PC_SET(mrb, pc);
+ val = mrb_vm_cv_get(mrb, syms[bx]);
+ ERR_PC_CLR(mrb);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETCV) {
+ /* A Bx cvset(Syms(Bx),R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_cv_set(mrb, syms[bx], regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETCONST) {
+ /* A Bx R(A) := constget(Syms(Bx)) */
+ mrb_value val;
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_sym sym = syms[bx];
+
+ ERR_PC_SET(mrb, pc);
+ val = mrb_vm_const_get(mrb, sym);
+ ERR_PC_CLR(mrb);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETCONST) {
+ /* A Bx constset(Syms(Bx),R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_const_set(mrb, syms[bx], regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETMCNST) {
+ /* A Bx R(A) := R(A)::Syms(Bx) */
+ mrb_value val;
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+
+ ERR_PC_SET(mrb, pc);
+ val = mrb_const_get(mrb, regs[a], syms[bx]);
+ ERR_PC_CLR(mrb);
+ regs[a] = val;
+ NEXT;
+ }
+
+ CASE(OP_SETMCNST) {
+ /* A Bx R(A+1)::Syms(Bx) := R(A) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_GETUPVAR) {
+ /* A B C R(A) := uvget(B,C) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value *regs_a = regs + a;
+ struct REnv *e = uvenv(mrb, c);
+
+ if (!e) {
+ *regs_a = mrb_nil_value();
+ }
+ else {
+ *regs_a = e->stack[b];
+ }
+ NEXT;
+ }
+
+ CASE(OP_SETUPVAR) {
+ /* A B C uvset(B,C,R(A)) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+
+ struct REnv *e = uvenv(mrb, c);
+
+ if (e) {
+ mrb_value *regs_a = regs + a;
+
+ if (b < MRB_ENV_STACK_LEN(e)) {
+ e->stack[b] = *regs_a;
+ mrb_write_barrier(mrb, (struct RBasic*)e);
+ }
+ }
+ NEXT;
+ }
+
+ CASE(OP_JMP) {
+ /* sBx pc+=sBx */
+ int sbx = GETARG_sBx(i);
+ pc += sbx;
+ JUMP;
+ }
+
+ CASE(OP_JMPIF) {
+ /* A sBx if R(A) pc+=sBx */
+ int a = GETARG_A(i);
+ int sbx = GETARG_sBx(i);
+ if (mrb_test(regs[a])) {
+ pc += sbx;
+ JUMP;
+ }
+ NEXT;
+ }
+
+ CASE(OP_JMPNOT) {
+ /* A sBx if !R(A) pc+=sBx */
+ int a = GETARG_A(i);
+ int sbx = GETARG_sBx(i);
+ if (!mrb_test(regs[a])) {
+ pc += sbx;
+ JUMP;
+ }
+ NEXT;
+ }
+
+ CASE(OP_ONERR) {
+ /* sBx pc+=sBx on exception */
+ int sbx = GETARG_sBx(i);
+ if (mrb->c->rsize <= mrb->c->ci->ridx) {
+ if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE;
+ else mrb->c->rsize *= 2;
+ mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize);
+ }
+ mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx;
+ NEXT;
+ }
+
+ CASE(OP_RESCUE) {
+ /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value exc;
+
+ if (c == 0) {
+ exc = mrb_obj_value(mrb->exc);
+ mrb->exc = 0;
+ }
+ else { /* continued; exc taken from R(A) */
+ exc = regs[a];
+ }
+ if (b != 0) {
+ mrb_value e = regs[b];
+ struct RClass *ec;
+
+ switch (mrb_type(e)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ break;
+ default:
+ {
+ mrb_value exc;
+
+ exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ "class or module required for rescue clause");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ }
+ ec = mrb_class_ptr(e);
+ regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec));
+ }
+ if (a != 0 && c == 0) {
+ regs[a] = exc;
+ }
+ NEXT;
+ }
+
+ CASE(OP_POPERR) {
+ /* A A.times{rescue_pop()} */
+ int a = GETARG_A(i);
+
+ mrb->c->ci->ridx -= a;
+ NEXT;
+ }
+
+ CASE(OP_RAISE) {
+ /* A raise(R(A)) */
+ int a = GETARG_A(i);
+
+ mrb_exc_set(mrb, regs[a]);
+ goto L_RAISE;
+ }
+
+ CASE(OP_EPUSH) {
+ /* Bx ensure_push(SEQ[Bx]) */
+ int bx = GETARG_Bx(i);
+ struct RProc *p;
+
+ p = mrb_closure_new(mrb, irep->reps[bx]);
+ /* push ensure_stack */
+ if (mrb->c->esize <= mrb->c->eidx+1) {
+ if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE;
+ else mrb->c->esize *= 2;
+ mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize);
+ }
+ mrb->c->ensure[mrb->c->eidx++] = p;
+ mrb->c->ensure[mrb->c->eidx] = NULL;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_EPOP) {
+ /* A A.times{ensure_pop().call} */
+ int a = GETARG_A(i);
+ mrb_callinfo *ci = mrb->c->ci;
+ int n, epos = ci->epos;
+
+ for (n=0; n<a && mrb->c->eidx > epos; n++) {
+ ecall(mrb, --mrb->c->eidx);
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ NEXT;
+ }
+
+ CASE(OP_LOADNIL) {
+ /* A R(A) := nil */
+ int a = GETARG_A(i);
+
+ SET_NIL_VALUE(regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_SENDB) {
+ /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
+ /* fall through */
+ };
+
+ L_SEND:
+ CASE(OP_SEND) {
+ /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
+ int a = GETARG_A(i);
+ int n = GETARG_C(i);
+ int argc = (n == CALL_MAXARGS) ? -1 : n;
+ int bidx = (argc < 0) ? a+2 : a+n+1;
+ struct RProc *m;
+ struct RClass *c;
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_value recv, blk;
+ mrb_sym mid = syms[GETARG_B(i)];
+
+ mrb_assert(bidx < ci->nregs);
+
+ recv = regs[a];
+ if (GET_OPCODE(i) != OP_SENDB) {
+ SET_NIL_VALUE(regs[bidx]);
+ blk = regs[bidx];
+ }
+ else {
+ blk = regs[bidx];
+ if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+ blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ /* The stack might have been reallocated during mrb_convert_type(),
+ see #3622 */
+ regs[bidx] = blk;
+ }
+ }
+ c = mrb_class(mrb, recv);
+ m = mrb_method_search_vm(mrb, &c, mid);
+ if (!m) {
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1);
+ ERR_PC_SET(mrb, pc);
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ if (argc >= 0) {
+ if (a+2 >= irep->nregs) {
+ stack_extend(mrb, a+3);
+ }
+ regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ regs[a+2] = blk;
+ argc = -1;
+ }
+ mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid));
+ mid = missing;
+ }
+
+ /* push callinfo */
+ ci = cipush(mrb);
+ ci->mid = mid;
+ ci->proc = m;
+ ci->stackent = mrb->c->stack;
+ ci->target_class = c;
+ ci->argc = argc;
+
+ ci->pc = pc + 1;
+ ci->acc = a;
+
+ /* prepare stack */
+ mrb->c->stack += a;
+
+ if (MRB_PROC_CFUNC_P(m)) {
+ ci->nregs = (argc < 0) ? 3 : n+2;
+ recv = m->body.func(mrb, recv);
+ mrb_gc_arena_restore(mrb, ai);
+ mrb_gc_arena_shrink(mrb, ai);
+ if (mrb->exc) goto L_RAISE;
+ ci = mrb->c->ci;
+ if (GET_OPCODE(i) == OP_SENDB) {
+ if (mrb_type(blk) == MRB_TT_PROC) {
+ struct RProc *p = mrb_proc_ptr(blk);
+ if (p && !MRB_PROC_STRICT_P(p) && p->env == ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
+ }
+ }
+ }
+ if (!ci->target_class) { /* return from context modifying method (resume/yield) */
+ if (ci->acc == CI_ACC_RESUMED) {
+ mrb->jmp = prev_jmp;
+ return recv;
+ }
+ else {
+ mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
+ proc = ci[-1].proc;
+ irep = proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ }
+ }
+ mrb->c->stack[0] = recv;
+ /* pop stackpos */
+ mrb->c->stack = ci->stackent;
+ pc = ci->pc;
+ cipop(mrb);
+ JUMP;
+ }
+ else {
+ /* setup environment for calling method */
+ proc = mrb->c->ci->proc = m;
+ irep = m->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ ci->nregs = irep->nregs;
+ stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs);
+ pc = irep->iseq;
+ JUMP;
+ }
+ }
+
+ CASE(OP_FSEND) {
+ /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
+ /* not implemented yet */
+ NEXT;
+ }
+
+ CASE(OP_CALL) {
+ /* A R(A) := self.call(frame.argc, frame.argv) */
+ mrb_callinfo *ci;
+ mrb_value recv = mrb->c->stack[0];
+ struct RProc *m = mrb_proc_ptr(recv);
+
+ /* replace callinfo */
+ ci = mrb->c->ci;
+ ci->target_class = m->target_class;
+ ci->proc = m;
+ if (m->env) {
+ mrb_sym mid;
+
+ if (MRB_ENV_STACK_SHARED_P(m->env)) {
+ mid = m->env->cxt.c->cibase[m->env->cioff].mid;
+ }
+ else {
+ mid = m->env->cxt.mid;
+ }
+ if (mid) ci->mid = mid;
+ if (!m->env->stack) {
+ m->env->stack = mrb->c->stack;
+ }
+ }
+
+ /* prepare stack */
+ if (MRB_PROC_CFUNC_P(m)) {
+ recv = m->body.func(mrb, recv);
+ mrb_gc_arena_restore(mrb, ai);
+ 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;
+ pc = ci->pc;
+ cipop(mrb);
+ irep = mrb->c->ci->proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ JUMP;
+ }
+ else {
+ /* setup environment for calling method */
+ proc = m;
+ irep = m->body.irep;
+ if (!irep) {
+ mrb->c->stack[0] = mrb_nil_value();
+ goto L_RETURN;
+ }
+ pool = irep->pool;
+ syms = irep->syms;
+ ci->nregs = irep->nregs;
+ stack_extend(mrb, ci->nregs);
+ if (ci->argc < 0) {
+ if (irep->nregs > 3) {
+ stack_clear(regs+3, irep->nregs-3);
+ }
+ }
+ else if (ci->argc+2 < irep->nregs) {
+ stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2);
+ }
+ if (m->env) {
+ regs[0] = m->env->stack[0];
+ }
+ pc = irep->iseq;
+ JUMP;
+ }
+ }
+
+ CASE(OP_SUPER) {
+ /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
+ int a = GETARG_A(i);
+ int n = GETARG_C(i);
+ int argc = (n == CALL_MAXARGS) ? -1 : n;
+ int bidx = (argc < 0) ? a+2 : a+n+1;
+ struct RProc *m;
+ struct RClass *c;
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_value recv, blk;
+ mrb_sym mid = ci->mid;
+
+ mrb_assert(bidx < ci->nregs);
+
+ if (mid == 0 || !ci->target_class) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ recv = regs[0];
+ 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 or ci stack might have been reallocated during
+ mrb_convert_type(), see #3622 and #3784 */
+ regs[bidx] = blk;
+ ci = mrb->c->ci;
+ }
+ c = ci->target_class->super;
+ m = mrb_method_search_vm(mrb, &c, mid);
+ if (!m) {
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1);
+ ERR_PC_SET(mrb, pc);
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ mid = missing;
+ if (argc >= 0) {
+ if (a+2 >= ci->nregs) {
+ stack_extend(mrb, a+3);
+ }
+ regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ regs[a+2] = blk;
+ argc = -1;
+ }
+ mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
+ }
+
+ /* push callinfo */
+ ci = cipush(mrb);
+ ci->mid = mid;
+ ci->proc = m;
+ ci->stackent = mrb->c->stack;
+ ci->target_class = c;
+ ci->pc = pc + 1;
+ ci->argc = argc;
+
+ /* prepare stack */
+ mrb->c->stack += a;
+ mrb->c->stack[0] = recv;
+
+ if (MRB_PROC_CFUNC_P(m)) {
+ mrb_value v;
+ ci->nregs = (argc < 0) ? 3 : n+2;
+ v = m->body.func(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) */
+ if (ci->acc == CI_ACC_RESUMED) {
+ mrb->jmp = prev_jmp;
+ return v;
+ }
+ else {
+ mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
+ proc = ci[-1].proc;
+ irep = proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ }
+ }
+ mrb->c->stack[0] = v;
+ /* pop stackpos */
+ mrb->c->stack = ci->stackent;
+ pc = ci->pc;
+ cipop(mrb);
+ JUMP;
+ }
+ else {
+ /* fill callinfo */
+ ci->acc = a;
+
+ /* setup environment for calling method */
+ ci->proc = m;
+ irep = m->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ ci->nregs = irep->nregs;
+ stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs);
+ pc = irep->iseq;
+ JUMP;
+ }
+ }
+
+ CASE(OP_ARGARY) {
+ /* A Bx R(A) := argument array (16=6:1:5:4) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ int m1 = (bx>>10)&0x3f;
+ int r = (bx>>9)&0x1;
+ int m2 = (bx>>4)&0x1f;
+ int lv = (bx>>0)&0xf;
+ mrb_value *stack;
+
+ if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) {
+ mrb_value exc;
+
+ L_NOSUPER:
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ if (lv == 0) stack = regs + 1;
+ else {
+ struct REnv *e = uvenv(mrb, lv-1);
+ if (!e) goto L_NOSUPER;
+ if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1)
+ goto L_NOSUPER;
+ stack = e->stack + 1;
+ }
+ if (r == 0) {
+ regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack);
+ }
+ else {
+ mrb_value *pp = NULL;
+ struct RArray *rest;
+ int len = 0;
+
+ if (mrb_array_p(stack[m1])) {
+ struct RArray *ary = mrb_ary_ptr(stack[m1]);
+
+ pp = ARY_PTR(ary);
+ len = ARY_LEN(ary);
+ }
+ regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
+ rest = mrb_ary_ptr(regs[a]);
+ if (m1 > 0) {
+ stack_copy(ARY_PTR(rest), stack, m1);
+ }
+ if (len > 0) {
+ stack_copy(ARY_PTR(rest)+m1, pp, len);
+ }
+ if (m2 > 0) {
+ stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2);
+ }
+ ARY_SET_LEN(rest, m1+len+m2);
+ }
+ regs[a+1] = stack[m1+r+m2];
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_ENTER) {
+ /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
+ /* number of optional arguments times OP_JMP should follow */
+ mrb_aspec ax = GETARG_Ax(i);
+ int m1 = MRB_ASPEC_REQ(ax);
+ int o = MRB_ASPEC_OPT(ax);
+ int r = MRB_ASPEC_REST(ax);
+ int m2 = MRB_ASPEC_POST(ax);
+ /* unused
+ int k = MRB_ASPEC_KEY(ax);
+ int kd = MRB_ASPEC_KDICT(ax);
+ int b = MRB_ASPEC_BLOCK(ax);
+ */
+ int argc = mrb->c->ci->argc;
+ mrb_value *argv = regs+1;
+ mrb_value *argv0 = argv;
+ int len = m1 + o + r + m2;
+ mrb_value *blk = &argv[argc < 0 ? 1 : argc];
+
+ if (argc < 0) {
+ struct RArray *ary = mrb_ary_ptr(regs[1]);
+ argv = ARY_PTR(ary);
+ argc = ARY_LEN(ary);
+ mrb_gc_protect(mrb, regs[1]);
+ }
+ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
+ if (argc >= 0) {
+ if (argc < m1 + m2 || (r == 0 && argc > len)) {
+ argnum_error(mrb, m1+m2);
+ goto L_RAISE;
+ }
+ }
+ }
+ else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
+ mrb_gc_protect(mrb, argv[0]);
+ argc = RARRAY_LEN(argv[0]);
+ argv = RARRAY_PTR(argv[0]);
+ }
+ if (argc < len) {
+ int mlen = m2;
+ if (argc < m1+m2) {
+ if (m1 < argc)
+ mlen = argc - m1;
+ else
+ mlen = 0;
+ }
+ regs[len+1] = *blk; /* move block */
+ SET_NIL_VALUE(regs[argc+1]);
+ if (argv0 != argv) {
+ value_move(&regs[1], argv, argc-mlen); /* m1 + o */
+ }
+ if (argc < m1) {
+ stack_clear(&regs[argc+1], m1-argc);
+ }
+ if (mlen) {
+ value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
+ }
+ if (mlen < m2) {
+ stack_clear(&regs[len-m2+mlen+1], m2-mlen);
+ }
+ if (r) {
+ regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
+ }
+ if (o == 0 || argc < m1+m2) pc++;
+ else
+ pc += argc - m1 - m2 + 1;
+ }
+ else {
+ int rnum = 0;
+ if (argv0 != argv) {
+ regs[len+1] = *blk; /* move block */
+ value_move(&regs[1], argv, m1+o);
+ }
+ if (r) {
+ rnum = argc-m1-o-m2;
+ regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
+ }
+ if (m2) {
+ if (argc-m2 > m1) {
+ value_move(&regs[m1+o+r+1], &argv[m1+o+rnum], m2);
+ }
+ }
+ if (argv0 == argv) {
+ regs[len+1] = *blk; /* move block */
+ }
+ pc += o + 1;
+ }
+ mrb->c->ci->argc = len;
+ /* clear local (but non-argument) variables */
+ if (irep->nlocals-len-2 > 0) {
+ stack_clear(&regs[len+2], irep->nlocals-len-2);
+ }
+ JUMP;
+ }
+
+ CASE(OP_KARG) {
+ /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
+ /* if C == 2; raise unless kdict.empty? */
+ /* OP_JMP should follow to skip init code */
+ NEXT;
+ }
+
+ CASE(OP_KDICT) {
+ /* A C R(A) := kdict */
+ NEXT;
+ }
+
+ L_RETURN:
+ i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL);
+ /* fall through */
+ CASE(OP_RETURN) {
+ /* A B return R(A) (B=normal,in-block return/break) */
+ mrb_callinfo *ci;
+
+ ci = mrb->c->ci;
+ if (ci->mid) {
+ mrb_value blk;
+
+ if (ci->argc < 0) {
+ blk = regs[2];
+ }
+ else {
+ blk = regs[ci->argc+1];
+ }
+ if (mrb_type(blk) == MRB_TT_PROC) {
+ struct RProc *p = mrb_proc_ptr(blk);
+
+ if (!MRB_PROC_STRICT_P(p) &&
+ ci > mrb->c->cibase && p->env == ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
+ }
+ }
+ }
+
+ if (mrb->exc) {
+ mrb_callinfo *ci0;
+ mrb_value *stk;
+
+ L_RAISE:
+ ci0 = ci = mrb->c->ci;
+ if (ci == mrb->c->cibase) {
+ if (ci->ridx == 0) goto L_FTOP;
+ goto L_RESCUE;
+ }
+ stk = mrb->c->stack;
+ while (ci[0].ridx == ci[-1].ridx) {
+ cipop(mrb);
+ mrb->c->stack = ci->stackent;
+ if (ci->acc == CI_ACC_SKIP && prev_jmp) {
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
+ }
+ ci = mrb->c->ci;
+ if (ci == mrb->c->cibase) {
+ mrb->c->stack = stk;
+ if (ci->ridx == 0) {
+ L_FTOP: /* fiber top */
+ if (mrb->c == mrb->root_c) {
+ mrb->c->stack = mrb->c->stbase;
+ goto L_STOP;
+ }
+ else {
+ struct mrb_context *c = mrb->c;
+
+ if (c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ }
+ mrb->c = c->prev;
+ c->prev = NULL;
+ goto L_RAISE;
+ }
+ }
+ break;
+ }
+ /* call ensure only when we skip this callinfo */
+ if (ci[0].ridx == ci[-1].ridx) {
+ mrb_value *org_stbase = mrb->c->stbase;
+ while (mrb->c->eidx > ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
+ ci = mrb->c->ci;
+ if (org_stbase != mrb->c->stbase) {
+ stk = mrb->c->stack;
+ }
+ }
+ }
+ }
+ L_RESCUE:
+ if (ci->ridx == 0) goto L_STOP;
+ proc = ci->proc;
+ irep = proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ if (ci != ci0) {
+ mrb->c->stack = ci[1].stackent;
+ }
+ stack_extend(mrb, irep->nregs);
+ pc = mrb->c->rescue[--ci->ridx];
+ }
+ else {
+ int acc;
+ mrb_value v;
+
+ v = regs[GETARG_A(i)];
+ mrb_gc_protect(mrb, v);
+ switch (GETARG_B(i)) {
+ case OP_R_RETURN:
+ /* Fall through to OP_R_NORMAL otherwise */
+ if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) {
+ struct REnv *e = top_env(mrb, proc);
+ mrb_callinfo *ce;
+
+ if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) {
+ localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+ goto L_RAISE;
+ }
+
+ ce = mrb->c->cibase + e->cioff;
+ while (ci > ce) {
+ mrb_env_unshare(mrb, ci->env);
+ if (ci->acc < 0) {
+ localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+ goto L_RAISE;
+ }
+ ci--;
+ }
+ mrb_env_unshare(mrb, ci->env);
+ if (ce == mrb->c->cibase) {
+ localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+ goto L_RAISE;
+ }
+ mrb->c->stack = mrb->c->ci->stackent;
+ mrb->c->ci = ce;
+ break;
+ }
+ case OP_R_NORMAL:
+ NORMAL_RETURN:
+ if (ci == mrb->c->cibase) {
+ if (!mrb->c->prev) { /* toplevel return */
+ localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+ goto L_RAISE;
+ }
+ if (mrb->c->prev->ci == mrb->c->prev->cibase) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ while (mrb->c->eidx > 0) {
+ ecall(mrb, --mrb->c->eidx);
+ }
+ /* automatic yield at the end */
+ mrb->c->status = MRB_FIBER_TERMINATED;
+ mrb->c = mrb->c->prev;
+ mrb->c->status = MRB_FIBER_RUNNING;
+ }
+ ci = mrb->c->ci;
+ break;
+ case OP_R_BREAK:
+ if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
+ if (MRB_PROC_ORPHAN_P(proc)) {
+ mrb_value exc;
+
+ L_BREAK_ERROR:
+ exc = mrb_exc_new_str_lit(mrb, E_LOCALJUMP_ERROR,
+ "break from proc-closure");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
+ goto L_BREAK_ERROR;
+ }
+ if (proc->env->cxt.c != mrb->c) {
+ goto L_BREAK_ERROR;
+ }
+ while (mrb->c->eidx > mrb->c->ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
+ }
+ /* break from fiber block */
+ if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
+ struct mrb_context *c = mrb->c;
+
+ mrb->c = c->prev;
+ c->prev = NULL;
+ }
+ ci = mrb->c->ci;
+ if (ci->acc < 0) {
+ mrb_gc_arena_restore(mrb, ai);
+ mrb->c->vmexec = FALSE;
+ mrb->exc = (struct RObject*)break_new(mrb, proc, v);
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
+ }
+ if (FALSE) {
+ L_BREAK:
+ v = ((struct RBreak*)mrb->exc)->val;
+ proc = ((struct RBreak*)mrb->exc)->proc;
+ mrb->exc = NULL;
+ ci = mrb->c->ci;
+ }
+ mrb->c->stack = ci->stackent;
+ mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ while (ci > mrb->c->ci) {
+ mrb_env_unshare(mrb, ci->env);
+ if (ci[-1].acc == CI_ACC_SKIP) {
+ mrb->c->ci = ci;
+ goto L_BREAK_ERROR;
+ }
+ ci--;
+ }
+ mrb_env_unshare(mrb, ci->env);
+ break;
+ default:
+ /* cannot happen */
+ break;
+ }
+ while (mrb->c->eidx > mrb->c->ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
+ }
+ if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+ mrb_gc_arena_restore(mrb, ai);
+ mrb->c->vmexec = FALSE;
+ mrb->jmp = prev_jmp;
+ return v;
+ }
+ ci = mrb->c->ci;
+ acc = ci->acc;
+ mrb->c->stack = ci->stackent;
+ 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;
+ DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid)));
+ proc = mrb->c->ci->proc;
+ irep = proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+
+ regs[acc] = v;
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ JUMP;
+ }
+
+ CASE(OP_TAILCALL) {
+ /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */
+ int a = GETARG_A(i);
+ int n = GETARG_C(i);
+ struct RProc *m;
+ struct RClass *c;
+ mrb_callinfo *ci;
+ mrb_value recv;
+ mrb_sym mid = syms[GETARG_B(i)];
+
+ recv = regs[a];
+ c = mrb_class(mrb, recv);
+ m = mrb_method_search_vm(mrb, &c, mid);
+ if (!m) {
+ mrb_value sym = mrb_symbol_value(mid);
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args;
+
+ if (n == CALL_MAXARGS) {
+ args = regs[a+1];
+ }
+ else {
+ args = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ }
+ ERR_PC_SET(mrb, pc);
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ mid = missing;
+ if (n == CALL_MAXARGS) {
+ mrb_ary_unshift(mrb, regs[a+1], sym);
+ }
+ else {
+ value_move(regs+a+2, regs+a+1, ++n);
+ regs[a+1] = sym;
+ }
+ }
+
+ /* replace callinfo */
+ ci = mrb->c->ci;
+ ci->mid = mid;
+ ci->target_class = c;
+ if (n == CALL_MAXARGS) {
+ ci->argc = -1;
+ }
+ else {
+ ci->argc = n;
+ }
+
+ /* move stack */
+ value_move(mrb->c->stack, &regs[a], ci->argc+1);
+
+ if (MRB_PROC_CFUNC_P(m)) {
+ mrb_value v = m->body.func(mrb, recv);
+ mrb->c->stack[0] = v;
+ mrb_gc_arena_restore(mrb, ai);
+ goto L_RETURN;
+ }
+ else {
+ /* setup environment for calling method */
+ irep = m->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ if (ci->argc < 0) {
+ stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
+ }
+ else {
+ stack_extend(mrb, irep->nregs);
+ }
+ pc = irep->iseq;
+ }
+ JUMP;
+ }
+
+ CASE(OP_BLKPUSH) {
+ /* A Bx R(A) := block (16=6:1:5:4) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ int m1 = (bx>>10)&0x3f;
+ int r = (bx>>9)&0x1;
+ int m2 = (bx>>4)&0x1f;
+ int lv = (bx>>0)&0xf;
+ mrb_value *stack;
+
+ if (lv == 0) stack = regs + 1;
+ else {
+ struct REnv *e = uvenv(mrb, lv-1);
+ if (!e || e->cioff == 0 ||
+ (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0) ||
+ MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) {
+ localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
+ goto L_RAISE;
+ }
+ stack = e->stack + 1;
+ }
+ if (mrb_nil_p(stack[m1+r+m2])) {
+ localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
+ goto L_RAISE;
+ }
+ regs[a] = stack[m1+r+m2];
+ NEXT;
+ }
+
+#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
+#define OP_MATH_BODY(op,v1,v2) do {\
+ v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
+} while(0)
+
+ CASE(OP_ADD) {
+ /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
+ int a = GETARG_A(i);
+
+ /* need to check if op is overridden */
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
+ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
+ {
+ mrb_int x, y, z;
+ mrb_value *regs_a = regs + a;
+
+ x = mrb_fixnum(regs_a[0]);
+ y = mrb_fixnum(regs_a[1]);
+ if (mrb_int_add_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
+ break;
+ }
+ SET_INT_VALUE(regs[a], z);
+ }
+ break;
+ 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;
+ case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
+ regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
+ break;
+ default:
+ goto L_SEND;
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_SUB) {
+ /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
+ int a = GETARG_A(i);
+
+ /* need to check if op is overridden */
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
+ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
+ {
+ mrb_int x, y, z;
+
+ x = mrb_fixnum(regs[a]);
+ y = mrb_fixnum(regs[a+1]);
+ if (mrb_int_sub_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
+ break;
+ }
+ SET_INT_VALUE(regs[a], z);
+ }
+ break;
+ 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;
+ default:
+ goto L_SEND;
+ }
+ NEXT;
+ }
+
+ CASE(OP_MUL) {
+ /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
+ int a = GETARG_A(i);
+
+ /* need to check if op is overridden */
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
+ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
+ {
+ mrb_int x, y, z;
+
+ x = mrb_fixnum(regs[a]);
+ y = mrb_fixnum(regs[a+1]);
+ if (mrb_int_mul_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y);
+ break;
+ }
+ SET_INT_VALUE(regs[a], z);
+ }
+ break;
+ 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;
+ default:
+ goto L_SEND;
+ }
+ NEXT;
+ }
+
+ CASE(OP_DIV) {
+ /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
+ int a = GETARG_A(i);
+
+ /* need to check if op is overridden */
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
+ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
+ {
+ mrb_int x = mrb_fixnum(regs[a]);
+ mrb_int y = mrb_fixnum(regs[a+1]);
+ double f;
+ if (y == 0) {
+ if (x > 0) f = INFINITY;
+ else if (x < 0) f = -INFINITY;
+ else /* if (x == 0) */ f = NAN;
+ }
+ else {
+ f = (mrb_float)x / (mrb_float)y;
+ }
+ SET_FLOAT_VALUE(mrb, regs[a], f);
+ }
+ break;
+ 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]);
+ double f;
+ if (y == 0) {
+ f = INFINITY;
+ }
+ else {
+ f = x / y;
+ }
+ SET_FLOAT_VALUE(mrb, regs[a], f);
+ }
+#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;
+ default:
+ goto L_SEND;
+ }
+#ifdef MRB_NAN_BOXING
+ if (isnan(mrb_float(regs[a]))) {
+ mrb_value v = mrb_float_value(mrb, mrb_float(regs[a]));
+ regs[a] = v;
+ }
+#endif
+ NEXT;
+ }
+
+ CASE(OP_ADDI) {
+ /* A B C R(A) := R(A)+C (Syms[B]=:+)*/
+ int a = GETARG_A(i);
+
+ /* need to check if + is overridden */
+ switch (mrb_type(regs[a])) {
+ case MRB_TT_FIXNUM:
+ {
+ mrb_int x = mrb_fixnum(regs[a]);
+ mrb_int y = GETARG_C(i);
+ mrb_int z;
+
+ if (mrb_int_add_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
+ break;
+ }
+ SET_INT_VALUE(regs[a], z);
+ }
+ break;
+ case MRB_TT_FLOAT:
+#ifdef MRB_WORD_BOXING
+ {
+ mrb_float x = mrb_float(regs[a]);
+ SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i));
+ }
+#else
+ mrb_float(regs[a]) += GETARG_C(i);
+#endif
+ break;
+ default:
+ SET_INT_VALUE(regs[a+1], GETARG_C(i));
+ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
+ goto L_SEND;
+ }
+ NEXT;
+ }
+
+ CASE(OP_SUBI) {
+ /* A B C R(A) := R(A)-C (Syms[B]=:-)*/
+ int a = GETARG_A(i);
+ mrb_value *regs_a = regs + a;
+
+ /* need to check if + is overridden */
+ switch (mrb_type(regs_a[0])) {
+ case MRB_TT_FIXNUM:
+ {
+ mrb_int x = mrb_fixnum(regs_a[0]);
+ mrb_int y = GETARG_C(i);
+ mrb_int z;
+
+ if (mrb_int_sub_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
+ }
+ else {
+ SET_INT_VALUE(regs_a[0], z);
+ }
+ }
+ break;
+ case MRB_TT_FLOAT:
+#ifdef MRB_WORD_BOXING
+ {
+ mrb_float x = mrb_float(regs[a]);
+ SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i));
+ }
+#else
+ mrb_float(regs_a[0]) -= GETARG_C(i);
+#endif
+ break;
+ default:
+ SET_INT_VALUE(regs_a[1], GETARG_C(i));
+ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
+ goto L_SEND;
+ }
+ NEXT;
+ }
+
+#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
+
+#define OP_CMP(op) 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):\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
+ break;\
+ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\
+ break;\
+ case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
+ result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\
+ break;\
+ case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
+ result = OP_CMP_BODY(op,mrb_float,mrb_float);\
+ break;\
+ default:\
+ goto L_SEND;\
+ }\
+ if (result) {\
+ SET_TRUE_VALUE(regs[a]);\
+ }\
+ else {\
+ SET_FALSE_VALUE(regs[a]);\
+ }\
+} while(0)
+
+ CASE(OP_EQ) {
+ /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/
+ int a = GETARG_A(i);
+ if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
+ SET_TRUE_VALUE(regs[a]);
+ }
+ else {
+ OP_CMP(==);
+ }
+ NEXT;
+ }
+
+ CASE(OP_LT) {
+ /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
+ int a = GETARG_A(i);
+ OP_CMP(<);
+ NEXT;
+ }
+
+ CASE(OP_LE) {
+ /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/
+ int a = GETARG_A(i);
+ OP_CMP(<=);
+ NEXT;
+ }
+
+ CASE(OP_GT) {
+ /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/
+ int a = GETARG_A(i);
+ OP_CMP(>);
+ NEXT;
+ }
+
+ CASE(OP_GE) {
+ /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/
+ int a = GETARG_A(i);
+ OP_CMP(>=);
+ NEXT;
+ }
+
+ CASE(OP_ARRAY) {
+ /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value v = mrb_ary_new_from_values(mrb, c, &regs[b]);
+ regs[a] = v;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_ARYCAT) {
+ /* A B mrb_ary_concat(R(A),R(B)) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ mrb_value splat = mrb_ary_splat(mrb, regs[b]);
+ mrb_ary_concat(mrb, regs[a], splat);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_ARYPUSH) {
+ /* A B R(A).push(R(B)) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ mrb_ary_push(mrb, regs[a], regs[b]);
+ NEXT;
+ }
+
+ CASE(OP_AREF) {
+ /* A B C R(A) := R(B)[C] */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value v = regs[b];
+
+ if (!mrb_array_p(v)) {
+ if (c == 0) {
+ regs[a] = v;
+ }
+ else {
+ SET_NIL_VALUE(regs[a]);
+ }
+ }
+ else {
+ v = mrb_ary_ref(mrb, v, c);
+ regs[a] = v;
+ }
+ NEXT;
+ }
+
+ CASE(OP_ASET) {
+ /* A B C R(B)[C] := R(A) */
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_ary_set(mrb, regs[b], c, regs[a]);
+ NEXT;
+ }
+
+ CASE(OP_APOST) {
+ /* A B C *R(A),R(A+1)..R(A+C) := R(A) */
+ int a = GETARG_A(i);
+ mrb_value v = regs[a];
+ int pre = GETARG_B(i);
+ int post = GETARG_C(i);
+ struct RArray *ary;
+ int len, idx;
+
+ if (!mrb_array_p(v)) {
+ v = mrb_ary_new_from_values(mrb, 1, &regs[a]);
+ }
+ ary = mrb_ary_ptr(v);
+ len = ARY_LEN(ary);
+ if (len > pre + post) {
+ v = mrb_ary_new_from_values(mrb, len - pre - post, ARY_PTR(ary)+pre);
+ regs[a++] = v;
+ while (post--) {
+ regs[a++] = ARY_PTR(ary)[len-post-1];
+ }
+ }
+ else {
+ v = mrb_ary_new_capa(mrb, 0);
+ regs[a++] = v;
+ for (idx=0; idx+pre<len; idx++) {
+ regs[a+idx] = ARY_PTR(ary)[pre+idx];
+ }
+ while (idx < post) {
+ SET_NIL_VALUE(regs[a+idx]);
+ idx++;
+ }
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_STRING) {
+ /* A Bx R(A) := str_new(Lit(Bx)) */
+ mrb_value str = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+ regs[GETARG_A(i)] = str;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_STRCAT) {
+ /* A B R(A).concat(R(B)) */
+ mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
+ NEXT;
+ }
+
+ CASE(OP_HASH) {
+ /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ int lim = b+c*2;
+ mrb_value hash = mrb_hash_new_capa(mrb, c);
+
+ while (b < lim) {
+ mrb_hash_set(mrb, hash, regs[b], regs[b+1]);
+ b+=2;
+ }
+ regs[GETARG_A(i)] = hash;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_LAMBDA) {
+ /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
+ struct RProc *p;
+ int a = GETARG_A(i);
+ int b = GETARG_b(i);
+ int c = GETARG_c(i);
+ mrb_irep *nirep = irep->reps[b];
+
+ irep_uplink(mrb, irep, nirep);
+ if (c & OP_L_CAPTURE) {
+ p = mrb_closure_new(mrb, nirep);
+ }
+ else {
+ p = mrb_proc_new(mrb, nirep);
+ }
+ if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
+ regs[a] = mrb_obj_value(p);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_OCLASS) {
+ /* A R(A) := ::Object */
+ regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
+ NEXT;
+ }
+
+ CASE(OP_CLASS) {
+ /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
+ struct RClass *c = 0, *baseclass;
+ int a = GETARG_A(i);
+ mrb_value base, super;
+ mrb_sym id = syms[GETARG_B(i)];
+
+ base = regs[a];
+ super = regs[a+1];
+ if (mrb_nil_p(base)) {
+ baseclass = mrb->c->ci->proc->target_class;
+ if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+ base = mrb_obj_value(baseclass);
+ }
+ c = mrb_vm_define_class(mrb, base, super, id);
+ regs[a] = mrb_obj_value(c);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_MODULE) {
+ /* A B R(A) := newmodule(R(A),Syms(B)) */
+ struct RClass *c = 0, *baseclass;
+ int a = GETARG_A(i);
+ mrb_value base;
+ mrb_sym id = syms[GETARG_B(i)];
+
+ base = regs[a];
+ if (mrb_nil_p(base)) {
+ baseclass = mrb->c->ci->proc->target_class;
+ if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+ base = mrb_obj_value(baseclass);
+ }
+ c = mrb_vm_define_module(mrb, base, id);
+ regs[a] = mrb_obj_value(c);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_EXEC) {
+ /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_callinfo *ci;
+ mrb_value recv = regs[a];
+ struct RProc *p;
+ mrb_irep *nirep = irep->reps[bx];
+
+ irep_uplink(mrb, irep, nirep);
+ nirep->target_class = mrb_class_ptr(recv);
+ /* prepare closure */
+ p = mrb_closure_new(mrb, nirep);
+ p->c = NULL;
+
+ /* prepare stack */
+ ci = cipush(mrb);
+ ci->pc = pc + 1;
+ 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 closure */
+ p->target_class = ci->target_class;
+ ci->proc = p;
+
+ irep = p->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ ci->nregs = irep->nregs;
+ stack_extend(mrb, ci->nregs);
+ stack_clear(regs+1, ci->nregs-1);
+ pc = irep->iseq;
+ JUMP;
+ }
+
+ CASE(OP_METHOD) {
+ /* A B R(A).newmethod(Syms(B),R(A+1)) */
+ int a = GETARG_A(i);
+ struct RClass *c = mrb_class_ptr(regs[a]);
+ struct RProc *p = mrb_proc_ptr(regs[a+1]);
+
+ mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], p);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_SCLASS) {
+ /* A B R(A) := R(B).singleton_class */
+ regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_TCLASS) {
+ /* A R(A) := target_class */
+ if (!mrb->c->ci->target_class) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
+ NEXT;
+ }
+
+ CASE(OP_RANGE) {
+ /* A B C R(A) := range_new(R(B),R(B+1),C) */
+ int b = GETARG_B(i);
+ mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
+ regs[GETARG_A(i)] = val;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_DEBUG) {
+ /* A B C debug print R(A),R(B),R(C) */
+#ifdef MRB_ENABLE_DEBUG_HOOK
+ mrb->debug_op_hook(mrb, irep, pc, regs);
+#else
+#ifndef MRB_DISABLE_STDIO
+ printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
+#else
+ abort();
+#endif
+#endif
+ NEXT;
+ }
+
+ CASE(OP_STOP) {
+ /* stop VM */
+ L_STOP:
+ {
+ int epos = mrb->c->ci->epos;
+
+ while (mrb->c->eidx > epos) {
+ ecall(mrb, --mrb->c->eidx);
+ }
+ }
+ ERR_PC_CLR(mrb);
+ mrb->jmp = prev_jmp;
+ if (mrb->exc) {
+ return mrb_obj_value(mrb->exc);
+ }
+ return regs[irep->nlocals];
+ }
+
+ CASE(OP_ERR) {
+ /* Bx raise RuntimeError with message Lit(Bx) */
+ mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+ mrb_value exc;
+
+ if (GETARG_A(i) == 0) {
+ exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg);
+ }
+ else {
+ exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
+ }
+ ERR_PC_SET(mrb, pc);
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ }
+ END_DISPATCH;
+#undef regs
+
+ }
+ MRB_CATCH(&c_jmp) {
+ exc_catched = TRUE;
+ goto RETRY_TRY_BLOCK;
+ }
+ MRB_END_EXC(&c_jmp);
+}
+
+MRB_API mrb_value
+mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
+{
+ if (mrb->c->ci->argc < 0) {
+ return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */
+ }
+ else {
+ return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ }
+}
+
+MRB_API mrb_value
+mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned 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->c->ci->env = NULL;
+ return mrb_vm_run(mrb, proc, self, stack_keep);
+ }
+ ci = cipush(mrb);
+ ci->mid = 0;
+ ci->nregs = 1; /* protect the receiver */
+ ci->acc = CI_ACC_SKIP;
+ ci->target_class = mrb->object_class;
+ v = mrb_vm_run(mrb, proc, self, stack_keep);
+ cipop(mrb);
+
+ return v;
+}
+
+#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
+# if !defined(MRB_ENABLE_CXX_ABI)
+} /* end of extern "C" */
+# endif
+mrb_int mrb_jmpbuf::jmpbuf_id = 0;
+# if !defined(MRB_ENABLE_CXX_ABI)
+extern "C" {
+# endif
+#endif