summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c13
-rw-r--r--src/backtrace.c22
-rw-r--r--src/class.c24
-rw-r--r--src/codedump.c24
-rw-r--r--src/compar.c2
-rw-r--r--src/debug.c6
-rw-r--r--src/dump.c14
-rw-r--r--src/enum.c2
-rw-r--r--src/error.c26
-rw-r--r--src/error.h2
-rw-r--r--src/etc.c12
-rw-r--r--src/fmt_fp.c11
-rw-r--r--src/gc.c710
-rw-r--r--src/hash.c76
-rw-r--r--src/init.c2
-rw-r--r--src/kernel.c20
-rw-r--r--src/load.c16
-rw-r--r--src/numeric.c41
-rw-r--r--src/object.c14
-rw-r--r--src/opcode.h2
-rw-r--r--src/pool.c2
-rw-r--r--src/print.c27
-rw-r--r--src/proc.c8
-rw-r--r--src/range.c10
-rw-r--r--src/state.c29
-rw-r--r--src/string.c1091
-rw-r--r--src/symbol.c10
-rw-r--r--src/value_array.h2
-rw-r--r--src/variable.c44
-rw-r--r--src/version.c7
-rw-r--r--src/vm.c46
31 files changed, 1276 insertions, 1039 deletions
diff --git a/src/array.c b/src/array.c
index 2622ee528..9b8a49584 100644
--- a/src/array.c
+++ b/src/array.c
@@ -4,11 +4,11 @@
** 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 <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
@@ -1068,7 +1068,7 @@ mrb_init_array(mrb_state *mrb)
{
struct RClass *a;
- a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
+ mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
@@ -1101,4 +1101,5 @@ mrb_init_array(mrb_state *mrb)
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/src/backtrace.c b/src/backtrace.c
index a672a6c95..80a5e2935 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -4,15 +4,15 @@
** 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.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>
struct backtrace_location {
int i;
@@ -25,7 +25,7 @@ struct backtrace_location {
typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
struct print_backtrace_args {
FILE *stream;
@@ -165,7 +165,7 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
overwritten. So invoke these functions just after detecting exceptions.
*/
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
MRB_API void
mrb_print_backtrace(mrb_state *mrb)
diff --git a/src/class.c b/src/class.c
index c3c3e0b8f..ccbbe2544 100644
--- a/src/class.c
+++ b/src/class.c
@@ -5,15 +5,15 @@
*/
#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.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>
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -622,7 +622,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
format++;
if (i < argc && mrb_nil_p(*sp)) {
*ps = NULL;
- i++;
+ i++; sp++;
break;
}
}
@@ -647,7 +647,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc && mrb_nil_p(*sp)) {
*pb = 0;
*pl = 0;
- i++;
+ i++; sp++;
break;
}
}
@@ -740,7 +740,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
format++;
if (i < argc && mrb_nil_p(*sp)) {
*datap = 0;
- i++;
+ i++; sp++;
break;
}
}
diff --git a/src/codedump.c b/src/codedump.c
index 755c78d15..4f4b6de57 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -1,11 +1,11 @@
-#include "mruby.h"
-#include "mruby/irep.h"
-#include "mruby/debug.h"
-#include "mruby/opcode.h"
-#include "mruby/string.h"
-#include "mruby/proc.h"
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+#include <mruby/opcode.h>
+#include <mruby/string.h>
+#include <mruby/proc.h>
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
static int
print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
{
@@ -53,7 +53,7 @@ print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r)
static void
codedump(mrb_state *mrb, mrb_irep *irep)
{
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
int i;
int ai;
mrb_code c;
@@ -189,7 +189,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv(mrb, irep, c, RA);
break;
case OP_JMP:
- printf("OP_JMP\t\t%03d\n", i+GETARG_sBx(c));
+ 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));
@@ -240,11 +240,11 @@ codedump(mrb_state *mrb, mrb_irep *irep)
switch (GETARG_B(c)) {
case OP_R_NORMAL:
case OP_R_RETURN:
- printf("\treturn"); break;
+ printf("\treturn\t"); break;
case OP_R_BREAK:
- printf("\tbreak"); break;
+ printf("\tbreak\t"); break;
default:
- printf("\tbroken"); break;
+ printf("\tbroken\t"); break;
break;
}
print_lv(mrb, irep, c, RA);
diff --git a/src/compar.c b/src/compar.c
index 0186b942f..0032fc859 100644
--- a/src/compar.c
+++ b/src/compar.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void
mrb_init_comparable(mrb_state *mrb)
diff --git a/src/debug.c b/src/debug.c
index 4ac692086..cc2d37034 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -1,7 +1,7 @@
#include <string.h>
-#include "mruby.h"
-#include "mruby/irep.h"
-#include "mruby/debug.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)
diff --git a/src/dump.c b/src/dump.c
index 734f38043..8870c6c65 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -6,11 +6,11 @@
#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"
+#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
@@ -989,7 +989,7 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size
return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size);
}
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
int
mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
@@ -1092,4 +1092,4 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
return result;
}
-#endif /* ENABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO */
diff --git a/src/enum.c b/src/enum.c
index 3def9e860..adb815bf1 100644
--- a/src/enum.c
+++ b/src/enum.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void
mrb_init_enumerable(mrb_state *mrb)
diff --git a/src/error.c b/src/error.c
index 359e5737b..d15f9e76f 100644
--- a/src/error.c
+++ b/src/error.c
@@ -7,16 +7,16 @@
#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"
+#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)
@@ -206,7 +206,7 @@ MRB_API mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
mrb->exc = mrb_obj_ptr(exc);
- if (!mrb->out_of_memory) {
+ if (!mrb->gc.out_of_memory) {
exc_debug_info(mrb, mrb->exc);
}
if (!mrb->jmp) {
@@ -309,7 +309,7 @@ mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
MRB_API void
mrb_warn(mrb_state *mrb, const char *fmt, ...)
{
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
va_list ap;
mrb_value str;
@@ -324,7 +324,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...)
MRB_API mrb_noreturn void
mrb_bug(mrb_state *mrb, const char *fmt, ...)
{
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
va_list ap;
mrb_value str;
diff --git a/src/error.h b/src/error.h
index 0e0dacf63..eb755ec7f 100644
--- a/src/error.h
+++ b/src/error.h
@@ -1,3 +1,3 @@
/* this header file is to be removed soon.
added for compatibility purpose (1.0.0) */
-#include "mruby/error.h"
+#include <mruby/error.h>
diff --git a/src/etc.c b/src/etc.c
index f5a502795..0ad56fe96 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -4,12 +4,12 @@
** 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"
+#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)
diff --git a/src/fmt_fp.c b/src/fmt_fp.c
index b27ebd6e9..b20eb895f 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -33,8 +33,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <float.h>
#include <ctype.h>
-#include "mruby.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/string.h>
struct fmt_args {
mrb_state *mrb;
@@ -90,11 +90,6 @@ fmt_u(uint32_t x, char *s)
typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
#endif
-#if ((defined(__CYGWIN__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__)
-#undef frexpl
-#define frexpl frexp
-#endif
-
static int
fmt_fp(struct fmt_args *f, long double y, int w, int p, int fl, int t)
{
@@ -127,7 +122,7 @@ fmt_fp(struct fmt_args *f, long double y, int w, int p, int fl, int t)
return MAX(w, 3+pl);
}
- y = frexpl(y, &e2) * 2;
+ y = frexp((double)y, &e2) * 2;
if (y) e2--;
if ((t|32)=='a') {
diff --git a/src/gc.c b/src/gc.c
index 15e1bd423..02e058f88 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -6,17 +6,17 @@
#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.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>
/*
= Tri-color Incremental Garbage Collection
@@ -136,7 +136,7 @@ gettimeofday_time(void)
#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(mrb));\
+ fprintf(stderr, "is_generational: %d\n", is_generational(gc));\
fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
} while(0)
@@ -147,10 +147,10 @@ gettimeofday_time(void)
#define GC_TIME_STOP_AND_REPORT do {\
gc_time = gettimeofday_time() - gc_time;\
gc_total_time += gc_time;\
- fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
- fprintf(stderr, "live: %zu\n", mrb->live);\
- fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
- fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
+ 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)
@@ -166,8 +166,32 @@ gettimeofday_time(void)
#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)
@@ -175,7 +199,7 @@ 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->heaps) {
+ if (!p2 && len > 0 && mrb->gc.heaps) {
mrb_full_gc(mrb);
p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
}
@@ -183,7 +207,6 @@ mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
return p2;
}
-
MRB_API void*
mrb_realloc(mrb_state *mrb, void *p, size_t len)
{
@@ -191,16 +214,16 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
p2 = mrb_realloc_simple(mrb, p, len);
if (!p2 && len) {
- if (mrb->out_of_memory) {
+ if (mrb->gc.out_of_memory) {
/* mrb_panic(mrb); */
}
else {
- mrb->out_of_memory = TRUE;
+ mrb->gc.out_of_memory = TRUE;
mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
}
}
else {
- mrb->out_of_memory = FALSE;
+ mrb->gc.out_of_memory = FALSE;
}
return p2;
@@ -244,101 +267,98 @@ mrb_free(mrb_state *mrb, void *p)
(mrb->allocf)(mrb, p, 0, mrb->allocf_ud);
}
-#ifndef MRB_HEAP_PAGE_SIZE
-#define MRB_HEAP_PAGE_SIZE 1024
-#endif
-
-struct heap_page {
- struct RBasic *freelist;
- struct heap_page *prev;
- struct heap_page *next;
- struct heap_page *free_next;
- struct heap_page *free_prev;
- mrb_bool old:1;
- RVALUE objects[MRB_HEAP_PAGE_SIZE];
-};
+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_state *mrb, struct heap_page *page)
+link_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
- page->next = mrb->heaps;
- if (mrb->heaps)
- mrb->heaps->prev = page;
- mrb->heaps = page;
+ page->next = gc->heaps;
+ if (gc->heaps)
+ gc->heaps->prev = page;
+ gc->heaps = page;
}
static void
-unlink_heap_page(mrb_state *mrb, struct heap_page *page)
+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 (mrb->heaps == page)
- mrb->heaps = page->next;
+ if (gc->heaps == page)
+ gc->heaps = page->next;
page->prev = NULL;
page->next = NULL;
}
static void
-link_free_heap_page(mrb_state *mrb, struct heap_page *page)
+link_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
- page->free_next = mrb->free_heaps;
- if (mrb->free_heaps) {
- mrb->free_heaps->free_prev = page;
+ page->free_next = gc->free_heaps;
+ if (gc->free_heaps) {
+ gc->free_heaps->free_prev = page;
}
- mrb->free_heaps = page;
+ gc->free_heaps = page;
}
static void
-unlink_free_heap_page(mrb_state *mrb, struct heap_page *page)
+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 (mrb->free_heaps == page)
- mrb->free_heaps = page->free_next;
+ 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)
+add_heap(mrb_state *mrb, mrb_gc *gc)
{
- struct heap_page *page = (struct heap_page *)mrb_calloc(mrb, 1, sizeof(struct heap_page));
+ 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 = page->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ 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(mrb, page);
- link_free_heap_page(mrb, page);
+ 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(mrb) ((mrb)->is_generational_gc_mode)
-#define is_major_gc(mrb) (is_generational(mrb) && (mrb)->gc_full)
-#define is_minor_gc(mrb) (is_generational(mrb) && !(mrb)->gc_full)
+#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_init_heap(mrb_state *mrb)
+mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
{
- mrb->heaps = NULL;
- mrb->free_heaps = NULL;
- add_heap(mrb);
- mrb->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
- mrb->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
+#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
- mrb->is_generational_gc_mode = TRUE;
- mrb->gc_full = TRUE;
+ gc->generational = TRUE;
+ gc->full = TRUE;
#endif
#ifdef GC_PROFILE
@@ -349,16 +369,16 @@ mrb_init_heap(mrb_state *mrb)
static void obj_free(mrb_state *mrb, struct RBasic *obj);
void
-mrb_free_heap(mrb_state *mrb)
+free_heap(mrb_state *mrb, mrb_gc *gc)
{
- struct heap_page *page = mrb->heaps;
- struct heap_page *tmp;
+ mrb_heap_page *page = gc->heaps;
+ mrb_heap_page *tmp;
RVALUE *p, *e;
while (page) {
tmp = page;
page = page->next;
- for (p = tmp->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ 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);
}
@@ -366,30 +386,87 @@ mrb_free_heap(mrb_state *mrb)
}
}
+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, struct RBasic *p)
+gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
{
#ifdef MRB_GC_FIXED_ARENA
- if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) {
+ if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
/* arena overflow error */
- mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
+ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
}
#else
- if (mrb->arena_idx >= mrb->arena_capa) {
+ if (gc->arena_idx >= gc->arena_capa) {
/* extend arena */
- mrb->arena_capa = (int)(mrb->arena_capa * 1.5);
- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa);
+ 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
- mrb->arena[mrb->arena_idx++] = p;
+ 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_basic_ptr(obj));
+ 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 obejct 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, j;
+
+ 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=j=0; i<a->len; i++) {
+ if (!mrb_obj_eq(mrb, a->ptr[i], obj)) {
+ a->ptr[j++] = a->ptr[i];
+ }
+ }
+ a->len = j;
}
MRB_API struct RBasic*
@@ -397,34 +474,35 @@ 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;
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
#endif
- if (mrb->gc_threshold < mrb->live) {
+ if (gc->threshold < gc->live) {
mrb_incremental_gc(mrb);
}
- if (mrb->free_heaps == NULL) {
- add_heap(mrb);
+ if (gc->free_heaps == NULL) {
+ add_heap(mrb, gc);
}
- p = mrb->free_heaps->freelist;
- mrb->free_heaps->freelist = ((struct free_obj*)p)->next;
- if (mrb->free_heaps->freelist == NULL) {
- unlink_free_heap_page(mrb, mrb->free_heaps);
+ 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);
}
- mrb->live++;
- gc_protect(mrb, p);
+ gc->live++;
+ gc_protect(mrb, gc, p);
*(RVALUE *)p = RVALUE_zero;
p->tt = ttype;
p->c = cls;
- paint_partial_white(mrb, p);
+ paint_partial_white(gc, p);
return p;
}
static inline void
-add_gray_list(mrb_state *mrb, struct RBasic *obj)
+add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
#ifdef MRB_GC_STRESS
if (obj->tt > MRB_TT_MAXDEFINE) {
@@ -432,8 +510,8 @@ add_gray_list(mrb_state *mrb, struct RBasic *obj)
}
#endif
paint_gray(obj);
- obj->gcnext = mrb->gray_list;
- mrb->gray_list = obj;
+ obj->gcnext = gc->gray_list;
+ gc->gray_list = obj;
}
static void
@@ -490,11 +568,11 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
}
static void
-gc_mark_children(mrb_state *mrb, struct RBasic *obj)
+gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
mrb_assert(is_gray(obj));
paint_black(obj);
- mrb->gray_list = obj->gcnext;
+ gc->gray_list = obj->gcnext;
mrb_gc_mark(mrb, (struct RBasic*)obj->c);
switch (obj->tt) {
case MRB_TT_ICLASS:
@@ -596,7 +674,7 @@ 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, obj);
+ add_gray_list(mrb, &mrb->gc, obj);
}
static void
@@ -700,19 +778,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
}
static void
-root_scan_phase(mrb_state *mrb)
+root_scan_phase(mrb_state *mrb, mrb_gc *gc)
{
size_t i, e;
- if (!is_minor_gc(mrb)) {
- mrb->gray_list = NULL;
- mrb->atomic_gray_list = NULL;
+ 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=mrb->arena_idx; i<e; i++) {
- mrb_gc_mark(mrb, mrb->arena[i]);
+ 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);
@@ -733,11 +811,11 @@ root_scan_phase(mrb_state *mrb)
}
static size_t
-gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
+gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
size_t children = 0;
- gc_mark_children(mrb, obj);
+ gc_mark_children(mrb, gc, obj);
switch (obj->tt) {
case MRB_TT_ICLASS:
@@ -816,68 +894,68 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
static void
-gc_mark_gray_list(mrb_state *mrb) {
- while (mrb->gray_list) {
- if (is_gray(mrb->gray_list))
- gc_mark_children(mrb, mrb->gray_list);
+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
- mrb->gray_list = mrb->gray_list->gcnext;
+ gc->gray_list = gc->gray_list->gcnext;
}
}
static size_t
-incremental_marking_phase(mrb_state *mrb, size_t limit)
+incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
size_t tried_marks = 0;
- while (mrb->gray_list && tried_marks < limit) {
- tried_marks += gc_gray_mark(mrb, mrb->gray_list);
+ 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)
+final_marking_phase(mrb_state *mrb, mrb_gc *gc)
{
mark_context_stack(mrb, mrb->root_c);
- gc_mark_gray_list(mrb);
- mrb_assert(mrb->gray_list == NULL);
- mrb->gray_list = mrb->atomic_gray_list;
- mrb->atomic_gray_list = NULL;
- gc_mark_gray_list(mrb);
- mrb_assert(mrb->gray_list == NULL);
+ 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)
+prepare_incremental_sweep(mrb_state *mrb, mrb_gc *gc)
{
- mrb->gc_state = GC_STATE_SWEEP;
- mrb->sweeps = mrb->heaps;
- mrb->gc_live_after_mark = mrb->live;
+ 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, size_t limit)
+incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
- struct heap_page *page = mrb->sweeps;
+ mrb_heap_page *page = gc->sweeps;
size_t tried_sweep = 0;
while (page && (tried_sweep < limit)) {
- RVALUE *p = page->objects;
+ 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(mrb) && page->old) {
+ 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(mrb, &p->as.basic)) {
+ if (is_dead(gc, &p->as.basic)) {
if (p->as.basic.tt != MRB_TT_FREE) {
obj_free(mrb, &p->as.basic);
p->as.free.next = page->freelist;
@@ -886,8 +964,8 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
}
}
else {
- if (!is_generational(mrb))
- paint_partial_white(mrb, &p->as.basic); /* next gc target */
+ if (!is_generational(gc))
+ paint_partial_white(gc, &p->as.basic); /* next gc target */
dead_slot = 0;
}
p++;
@@ -895,54 +973,54 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
/* free dead slot */
if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
- struct heap_page *next = page->next;
+ mrb_heap_page *next = page->next;
- unlink_heap_page(mrb, page);
- unlink_free_heap_page(mrb, page);
+ 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(mrb, page);
+ link_free_heap_page(gc, page);
}
- if (page->freelist == NULL && is_minor_gc(mrb))
+ if (page->freelist == NULL && is_minor_gc(gc))
page->old = TRUE;
else
page->old = FALSE;
page = page->next;
}
tried_sweep += MRB_HEAP_PAGE_SIZE;
- mrb->live -= freed;
- mrb->gc_live_after_mark -= freed;
+ gc->live -= freed;
+ gc->live_after_mark -= freed;
}
- mrb->sweeps = page;
+ gc->sweeps = page;
return tried_sweep;
}
static size_t
-incremental_gc(mrb_state *mrb, size_t limit)
+incremental_gc(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
- switch (mrb->gc_state) {
- case GC_STATE_ROOT:
- root_scan_phase(mrb);
- mrb->gc_state = GC_STATE_MARK;
- flip_white_part(mrb);
+ 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 GC_STATE_MARK:
- if (mrb->gray_list) {
- return incremental_marking_phase(mrb, limit);
+ case MRB_GC_STATE_MARK:
+ if (gc->gray_list) {
+ return incremental_marking_phase(mrb, gc, limit);
}
else {
- final_marking_phase(mrb);
- prepare_incremental_sweep(mrb);
+ final_marking_phase(mrb, gc);
+ prepare_incremental_sweep(mrb, gc);
return 0;
}
- case GC_STATE_SWEEP: {
+ case MRB_GC_STATE_SWEEP: {
size_t tried_sweep = 0;
- tried_sweep = incremental_sweep_phase(mrb, limit);
+ tried_sweep = incremental_sweep_phase(mrb, gc, limit);
if (tried_sweep == 0)
- mrb->gc_state = GC_STATE_ROOT;
+ gc->state = MRB_GC_STATE_ROOT;
return tried_sweep;
}
default:
@@ -953,79 +1031,81 @@ incremental_gc(mrb_state *mrb, size_t limit)
}
static void
-incremental_gc_until(mrb_state *mrb, enum gc_state to_state)
+incremental_gc_until(mrb_state *mrb, mrb_gc *gc, mrb_gc_state to_state)
{
do {
- incremental_gc(mrb, SIZE_MAX);
- } while (mrb->gc_state != to_state);
+ incremental_gc(mrb, gc, SIZE_MAX);
+ } while (gc->state != to_state);
}
static void
-incremental_gc_step(mrb_state *mrb)
+incremental_gc_step(mrb_state *mrb, mrb_gc *gc)
{
size_t limit = 0, result = 0;
- limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio;
+ limit = (GC_STEP_SIZE/100) * gc->step_ratio;
while (result < limit) {
- result += incremental_gc(mrb, limit);
- if (mrb->gc_state == GC_STATE_ROOT)
+ result += incremental_gc(mrb, gc, limit);
+ if (gc->state == MRB_GC_STATE_ROOT)
break;
}
- mrb->gc_threshold = mrb->live + GC_STEP_SIZE;
+ gc->threshold = gc->live + GC_STEP_SIZE;
}
static void
-clear_all_old(mrb_state *mrb)
+clear_all_old(mrb_state *mrb, mrb_gc *gc)
{
- mrb_bool origin_mode = mrb->is_generational_gc_mode;
+ mrb_bool origin_mode = gc->generational;
- mrb_assert(is_generational(mrb));
- if (is_major_gc(mrb)) {
+ mrb_assert(is_generational(gc));
+ if (is_major_gc(gc)) {
/* finish the half baked GC */
- incremental_gc_until(mrb, GC_STATE_ROOT);
+ 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. */
- mrb->is_generational_gc_mode = FALSE;
- prepare_incremental_sweep(mrb);
- incremental_gc_until(mrb, GC_STATE_ROOT);
- mrb->is_generational_gc_mode = origin_mode;
+ 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 */
- mrb->atomic_gray_list = mrb->gray_list = NULL;
+ gc->atomic_gray_list = gc->gray_list = NULL;
}
MRB_API void
mrb_incremental_gc(mrb_state *mrb)
{
- if (mrb->gc_disabled) return;
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled) return;
GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
GC_TIME_START;
- if (is_minor_gc(mrb)) {
- incremental_gc_until(mrb, GC_STATE_ROOT);
+ if (is_minor_gc(gc)) {
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
}
else {
- incremental_gc_step(mrb);
+ incremental_gc_step(mrb, gc);
}
- if (mrb->gc_state == GC_STATE_ROOT) {
- mrb_assert(mrb->live >= mrb->gc_live_after_mark);
- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
- if (mrb->gc_threshold < GC_STEP_SIZE) {
- mrb->gc_threshold = GC_STEP_SIZE;
+ 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(mrb)) {
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->gc_full = FALSE;
+ 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(mrb)) {
- if (mrb->live > mrb->majorgc_old_threshold) {
- clear_all_old(mrb);
- mrb->gc_full = TRUE;
+ else if (is_minor_gc(gc)) {
+ if (gc->live > gc->majorgc_old_threshold) {
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
}
}
}
@@ -1037,26 +1117,29 @@ mrb_incremental_gc(mrb_state *mrb)
MRB_API void
mrb_full_gc(mrb_state *mrb)
{
- if (mrb->gc_disabled) return;
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled) return;
+
GC_INVOKE_TIME_REPORT("mrb_full_gc()");
GC_TIME_START;
- if (is_generational(mrb)) {
+ if (is_generational(gc)) {
/* clear all the old objects back to young */
- clear_all_old(mrb);
- mrb->gc_full = TRUE;
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
}
- else if (mrb->gc_state != GC_STATE_ROOT) {
+ else if (gc->state != MRB_GC_STATE_ROOT) {
/* finish half baked GC cycle */
- incremental_gc_until(mrb, GC_STATE_ROOT);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
}
- incremental_gc_until(mrb, GC_STATE_ROOT);
- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio;
- if (is_generational(mrb)) {
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->gc_full = FALSE;
+ 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;
@@ -1071,27 +1154,29 @@ mrb_garbage_collect(mrb_state *mrb)
MRB_API int
mrb_gc_arena_save(mrb_state *mrb)
{
- return mrb->arena_idx;
+ return mrb->gc.arena_idx;
}
MRB_API void
mrb_gc_arena_restore(mrb_state *mrb, int idx)
{
+ mrb_gc *gc = &mrb->gc;
+
#ifndef MRB_GC_FIXED_ARENA
- int capa = mrb->arena_capa;
+ int capa = gc->arena_capa;
if (idx < capa / 2) {
capa = (int)(capa * 0.66);
if (capa < MRB_GC_ARENA_SIZE) {
capa = MRB_GC_ARENA_SIZE;
}
- if (capa != mrb->arena_capa) {
- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa);
- mrb->arena_capa = capa;
+ if (capa != gc->arena_capa) {
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
+ gc->arena_capa = capa;
}
}
#endif
- mrb->arena_idx = idx;
+ gc->arena_idx = idx;
}
/*
@@ -1102,18 +1187,20 @@ mrb_gc_arena_restore(mrb_state *mrb, int idx)
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(!is_dead(mrb, value) && !is_dead(mrb, obj));
- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
+ 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(mrb) || mrb->gc_state == GC_STATE_MARK) {
- add_gray_list(mrb, value);
+ if (is_generational(gc) || gc->state == MRB_GC_STATE_MARK) {
+ add_gray_list(mrb, gc, value);
}
else {
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
- paint_partial_white(mrb, obj); /* for never write barriers */
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
+ paint_partial_white(gc, obj); /* for never write barriers */
}
}
@@ -1129,13 +1216,15 @@ mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value
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(mrb, obj));
- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
+ mrb_assert(!is_dead(gc, obj));
+ mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT);
paint_gray(obj);
- obj->gcnext = mrb->atomic_gray_list;
- mrb->atomic_gray_list = obj;
+ obj->gcnext = gc->atomic_gray_list;
+ gc->atomic_gray_list = obj;
}
/*
@@ -1169,9 +1258,9 @@ gc_start(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_enable(mrb_state *mrb, mrb_value obj)
{
- mrb_bool old = mrb->gc_disabled;
+ mrb_bool old = mrb->gc.disabled;
- mrb->gc_disabled = FALSE;
+ mrb->gc.disabled = FALSE;
return mrb_bool_value(old);
}
@@ -1191,9 +1280,9 @@ gc_enable(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_disable(mrb_state *mrb, mrb_value obj)
{
- mrb_bool old = mrb->gc_disabled;
+ mrb_bool old = mrb->gc.disabled;
- mrb->gc_disabled = TRUE;
+ mrb->gc.disabled = TRUE;
return mrb_bool_value(old);
}
@@ -1209,7 +1298,7 @@ gc_disable(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc_interval_ratio);
+ return mrb_fixnum_value(mrb->gc.interval_ratio);
}
/*
@@ -1227,7 +1316,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
mrb_int ratio;
mrb_get_args(mrb, "i", &ratio);
- mrb->gc_interval_ratio = ratio;
+ mrb->gc.interval_ratio = ratio;
return mrb_nil_value();
}
@@ -1242,7 +1331,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc_step_ratio);
+ return mrb_fixnum_value(mrb->gc.step_ratio);
}
/*
@@ -1260,24 +1349,24 @@ gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
mrb_int ratio;
mrb_get_args(mrb, "i", &ratio);
- mrb->gc_step_ratio = ratio;
+ mrb->gc.step_ratio = ratio;
return mrb_nil_value();
}
static void
-change_gen_gc_mode(mrb_state *mrb, mrb_bool enable)
+change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
{
- if (is_generational(mrb) && !enable) {
- clear_all_old(mrb);
- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
- mrb->gc_full = FALSE;
+ 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(mrb) && enable) {
- incremental_gc_until(mrb, GC_STATE_ROOT);
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->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;
}
- mrb->is_generational_gc_mode = enable;
+ gc->generational = enable;
}
/*
@@ -1291,7 +1380,7 @@ change_gen_gc_mode(mrb_state *mrb, mrb_bool enable)
static mrb_value
gc_generational_mode_get(mrb_state *mrb, mrb_value self)
{
- return mrb_bool_value(mrb->is_generational_gc_mode);
+ return mrb_bool_value(mrb->gc.generational);
}
/*
@@ -1308,21 +1397,22 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
mrb_bool enable;
mrb_get_args(mrb, "b", &enable);
- if (mrb->is_generational_gc_mode != enable)
- change_gen_gc_mode(mrb, enable);
+ if (mrb->gc.generational != enable)
+ change_gen_gc_mode(mrb, &mrb->gc, enable);
return mrb_bool_value(enable);
}
-void
-mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
+
+static void
+gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
{
- struct heap_page* page = mrb->heaps;
+ mrb_heap_page* page = gc->heaps;
while (page != NULL) {
RVALUE *p, *pend;
- p = page->objects;
+ p = objects(page);
pend = p + MRB_HEAP_PAGE_SIZE;
for (;p < pend; p++) {
(*callback)(mrb, &p->as.basic, data);
@@ -1332,6 +1422,12 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo
}
}
+void
+mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
+{
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+}
+
#ifdef GC_TEST
#ifdef GC_DEBUG
static mrb_value gc_test(mrb_state *, mrb_value);
@@ -1368,42 +1464,43 @@ 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");
- mrb->is_generational_gc_mode = FALSE;
+ 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(mrb, value);
+ paint_partial_white(gc, value);
- puts(" in GC_STATE_MARK");
- mrb->gc_state = GC_STATE_MARK;
+ 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 GC_STATE_SWEEP");
- paint_partial_white(mrb, value);
- mrb->gc_state = GC_STATE_SWEEP;
+ 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 & mrb->current_white_part);
- mrb_assert(value->color & mrb->current_white_part);
+ mrb_assert(obj->color & gc->current_white_part);
+ mrb_assert(value->color & gc->current_white_part);
puts(" fail with black");
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
paint_white(obj);
- paint_partial_white(mrb, value);
+ paint_partial_white(gc, value);
mrb_field_write_barrier(mrb, obj, value);
- mrb_assert(obj->color & mrb->current_white_part);
+ mrb_assert(obj->color & gc->current_white_part);
puts(" fail with gray");
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
paint_black(obj);
paint_gray(value);
mrb_field_write_barrier(mrb, obj, value);
@@ -1416,9 +1513,9 @@ test_mrb_field_write_barrier(void)
obj = mrb_basic_ptr(mrb_ary_new(mrb));
mrb_value value = mrb_str_new_lit(mrb, "value");
paint_black(obj);
- paint_partial_white(mrb, mrb_basic_ptr(value));
+ paint_partial_white(gc, mrb_basic_ptr(value));
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
mrb_field_write_barrier_value(mrb, obj, value);
mrb_assert(is_gray(mrb_basic_ptr(value)));
@@ -1432,17 +1529,18 @@ 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 GC_STATE_MARK");
- mrb->gc_state = GC_STATE_MARK;
+ puts(" in MRB_GC_STATE_MARK");
+ gc->state = MRB_GC_STATE_MARK;
mrb_write_barrier(mrb, obj);
mrb_assert(is_gray(obj));
- mrb_assert(mrb->atomic_gray_list == obj);
+ mrb_assert(gc->atomic_gray_list == obj);
puts(" fail with gray");
@@ -1459,19 +1557,20 @@ 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, FALSE);
- mrb_assert(mrb->gray_list == NULL);
+ 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, obj1);
- mrb_assert(mrb->gray_list == obj1);
+ 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, obj2);
- mrb_assert(mrb->gray_list == obj2);
- mrb_assert(mrb->gray_list->gcnext == obj1);
+ 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);
@@ -1484,13 +1583,14 @@ test_gc_gray_mark(void)
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, obj);
+ gray_num = gc_gray_mark(mrb, gc, obj);
mrb_assert(is_black(obj));
mrb_assert(gray_num > 1);
@@ -1498,9 +1598,9 @@ test_gc_gray_mark(void)
obj_v = mrb_ary_new(mrb);
value_v = mrb_str_new_lit(mrb, "test");
paint_gray(mrb_basic_ptr(obj_v));
- paint_partial_white(mrb, mrb_basic_ptr(value_v));
+ paint_partial_white(gc, mrb_basic_ptr(value_v));
mrb_ary_push(mrb, obj_v, value_v);
- gray_num = gc_gray_mark(mrb, mrb_basic_ptr(obj_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);
@@ -1514,32 +1614,33 @@ test_incremental_gc(void)
mrb_state *mrb = mrb_open();
size_t max = ~0, live = 0, total = 0, freed = 0;
RVALUE *free;
- struct heap_page *page;
+ mrb_heap_page *page;
+ mrb_gc *gc = &mrb->gc;
puts("test_incremental_gc");
- change_gen_gc_mode(mrb, FALSE);
+ change_gen_gc_mode(mrb, gc, FALSE);
puts(" in mrb_full_gc");
mrb_full_gc(mrb);
- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
- puts(" in GC_STATE_ROOT");
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_MARK);
- puts(" in GC_STATE_MARK");
- incremental_gc_until(mrb, GC_STATE_SWEEP);
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
+ 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 GC_STATE_SWEEP");
- page = mrb->heaps;
+ puts(" in MRB_GC_STATE_SWEEP");
+ page = gc->heaps;
while (page) {
- RVALUE *p = page->objects;
+ 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(mrb, &p->as.basic)) {
+ if (is_gray(&p->as.basic) && !is_dead(gc, &p->as.basic)) {
printf("%p\n", &p->as.basic);
}
p++;
@@ -1548,44 +1649,44 @@ test_incremental_gc(void)
total += MRB_HEAP_PAGE_SIZE;
}
- mrb_assert(mrb->gray_list == NULL);
+ mrb_assert(gc->gray_list == NULL);
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
+ incremental_gc(mrb, gc, max);
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
+ incremental_gc(mrb, gc, max);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
- free = (RVALUE*)mrb->heaps->freelist;
+ free = (RVALUE*)gc->heaps->freelist;
while (free) {
freed++;
free = (RVALUE*)free->as.free.next;
}
- mrb_assert(mrb->live == live);
- mrb_assert(mrb->live == total-freed);
+ mrb_assert(gc->live == live);
+ mrb_assert(gc->live == total-freed);
puts("test_incremental_gc(gen)");
- incremental_gc_until(mrb, GC_STATE_SWEEP);
- change_gen_gc_mode(mrb, TRUE);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP);
+ change_gen_gc_mode(mrb, gc, TRUE);
- mrb_assert(mrb->gc_full == FALSE);
- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
+ mrb_assert(gc->full == FALSE);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
puts(" in minor");
- mrb_assert(is_minor_gc(mrb));
- mrb_assert(mrb->majorgc_old_threshold > 0);
- mrb->majorgc_old_threshold = 0;
+ mrb_assert(is_minor_gc(gc));
+ mrb_assert(gc->majorgc_old_threshold > 0);
+ gc->majorgc_old_threshold = 0;
mrb_incremental_gc(mrb);
- mrb_assert(mrb->gc_full == TRUE);
- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
+ mrb_assert(gc->full == TRUE);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
puts(" in major");
- mrb_assert(is_major_gc(mrb));
+ mrb_assert(is_major_gc(gc));
do {
mrb_incremental_gc(mrb);
- } while (mrb->gc_state != GC_STATE_ROOT);
- mrb_assert(mrb->gc_full == FALSE);
+ } while (gc->state != MRB_GC_STATE_ROOT);
+ mrb_assert(gc->full == FALSE);
mrb_close(mrb);
}
@@ -1594,18 +1695,19 @@ void
test_incremental_sweep_phase(void)
{
mrb_state *mrb = mrb_open();
+ mrb_gc *gc = &mrb->gc;
puts("test_incremental_sweep_phase");
- add_heap(mrb);
- mrb->sweeps = mrb->heaps;
+ add_heap(mrb, gc);
+ gc->sweeps = gc->heaps;
- mrb_assert(mrb->heaps->next->next == NULL);
- mrb_assert(mrb->free_heaps->next->next == NULL);
- incremental_sweep_phase(mrb, MRB_HEAP_PAGE_SIZE*3);
+ 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(mrb->heaps->next == NULL);
- mrb_assert(mrb->heaps == mrb->free_heaps);
+ mrb_assert(gc->heaps->next == NULL);
+ mrb_assert(gc->heaps == gc->free_heaps);
mrb_close(mrb);
}
diff --git a/src/hash.c b/src/hash.c
index ffb8bd931..ac7256987 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -4,13 +4,13 @@
** 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"
+#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);
@@ -294,22 +294,22 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash)
* 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"]
+ * 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"]
*
*/
@@ -517,10 +517,10 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
* 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"
+ * 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
@@ -541,9 +541,9 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
* 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"}
+ * h = { 1 => "a", 2 => "b", 3 => "c" }
+ * h.shift #=> [1, "a"]
+ * h #=> {2=>"b", 3=>"c"}
*/
static mrb_value
@@ -580,10 +580,10 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
* call-seq:
* hsh.clear -> hsh
*
- * Removes all key-value pairs from <i>hsh</i>.
+ * Removes all key-value pairs from `hsh`.
*
- * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
- * h.clear #=> {}
+ * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
+ * h.clear #=> {}
*
*/
@@ -609,10 +609,10 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
* 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}
+ * h = { "a" => 100, "b" => 200 }
+ * h["a"] = 9
+ * h["c"] = 4
+ * h #=> {"a"=>9, "b"=>200, "c"=>4}
*
*/
static mrb_value
@@ -827,7 +827,7 @@ mrb_init_hash(mrb_state *mrb)
{
struct RClass *h;
- h = mrb->hash_class = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
+ 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 */
diff --git a/src/init.c b/src/init.c
index 955d6e3a1..9a6496df1 100644
--- a/src/init.c
+++ b/src/init.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void mrb_init_symtbl(mrb_state*);
void mrb_init_class(mrb_state*);
diff --git a/src/kernel.c b/src/kernel.c
index 225f7fa54..af6a49be1 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -4,13 +4,13 @@
** 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"
-#include "mruby/variable.h"
-#include "mruby/error.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
typedef enum {
NOEX_PUBLIC = 0x00,
@@ -654,13 +654,13 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
{
khint_t i;
mrb_value ary;
- mrb_bool prepended;
+ 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 = 1;
+ prepended = TRUE;
}
oldklass = 0;
@@ -1097,7 +1097,7 @@ mrb_init_kernel(mrb_state *mrb)
{
struct RClass *krn;
- krn = mrb->kernel_module = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */
+ 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 */
diff --git a/src/load.c b/src/load.c
index 36fae9aee..da88f0d3a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -7,12 +7,12 @@
#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"
+#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
@@ -642,7 +642,7 @@ mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
return mrb_load_irep_cxt(mrb, bin, NULL);
}
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
MRB_API mrb_irep*
mrb_read_irep_file(mrb_state *mrb, FILE* fp)
@@ -704,4 +704,4 @@ mrb_load_irep_file(mrb_state *mrb, FILE* fp)
{
return mrb_load_irep_file_cxt(mrb, fp, NULL);
}
-#endif /* ENABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO */
diff --git a/src/numeric.c b/src/numeric.c
index 1a3c903f0..7b49b29f7 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -9,10 +9,10 @@
#include <math.h>
#include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
#ifdef MRB_USE_FLOAT
#define floor(f) floorf(f)
@@ -821,14 +821,28 @@ static mrb_value
lshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
mrb_assert(width > 0);
- if (width > NUMERIC_SHIFT_WIDTH_MAX) {
+ if (val > 0) {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val > (MRB_INT_MAX >> width))) {
+ goto bit_overflow;
+ }
+ } else {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val < (MRB_INT_MIN >> width))) {
+ goto bit_overflow;
+ }
+ }
+
+ return mrb_fixnum_value(val << width);
+
+bit_overflow:
+ {
mrb_float f = (mrb_float)val;
while (width--) {
f *= 2;
}
return mrb_float_value(mrb, f);
}
- return mrb_fixnum_value(val << width);
}
static mrb_value
@@ -856,7 +870,7 @@ fix_shift_get_width(mrb_state *mrb, mrb_int *width)
/* 15.2.8.3.12 */
/*
* call-seq:
- * fix << count -> integer
+ * fix << count -> integer or float
*
* Shifts _fix_ left _count_ positions (right if _count_ is negative).
*/
@@ -881,7 +895,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.13 */
/*
* call-seq:
- * fix >> count -> integer
+ * fix >> count -> integer or float
*
* Shifts _fix_ right _count_ positions (left if _count_ is negative).
*/
@@ -950,7 +964,12 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
if (isnan(d)) {
mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
}
- z = (mrb_int)d;
+ if (FIXABLE(d)) {
+ z = (mrb_int)d;
+ }
+ else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x);
+ }
}
return mrb_fixnum_value(z);
}
@@ -1161,7 +1180,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
/* Fixnum Class */
- fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
+ 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 */
@@ -1181,7 +1200,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
/* Float Class */
- fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
+ mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
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 */
diff --git a/src/object.c b/src/object.c
index 2e0bd245f..9d768664e 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,10 +4,10 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
@@ -264,7 +264,7 @@ mrb_init_object(mrb_state *mrb)
struct RClass *t;
struct RClass *f;
- n = mrb->nil_class = mrb_define_class(mrb, "NilClass", mrb->object_class);
+ mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
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 */
@@ -273,7 +273,7 @@ mrb_init_object(mrb_state *mrb)
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());
- t = mrb->true_class = mrb_define_class(mrb, "TrueClass", mrb->object_class);
+ mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class);
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 */
@@ -281,7 +281,7 @@ mrb_init_object(mrb_state *mrb)
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());
- f = mrb->false_class = mrb_define_class(mrb, "FalseClass", mrb->object_class);
+ mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class);
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 */
diff --git a/src/opcode.h b/src/opcode.h
index 2446f92ed..fe4d17a21 100644
--- a/src/opcode.h
+++ b/src/opcode.h
@@ -1,2 +1,2 @@
/* this header file is to be removed soon. */
-#include "mruby/opcode.h"
+#include <mruby/opcode.h>
diff --git a/src/pool.c b/src/pool.c
index 285cca6c3..18f66fc27 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -7,7 +7,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
-#include "mruby.h"
+#include <mruby.h>
/* configuration section */
/* allocated memory address should be multiple of POOL_ALIGNMENT */
diff --git a/src/print.c b/src/print.c
index 077fa4f06..03b5eadfa 100644
--- a/src/print.c
+++ b/src/print.c
@@ -4,11 +4,11 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
static void
printstr(mrb_value obj, FILE *stream)
{
@@ -24,35 +24,24 @@ printstr(mrb_value obj, FILE *stream)
MRB_API void
mrb_p(mrb_state *mrb, mrb_value obj)
{
- mrb_value val = mrb_inspect(mrb, obj);
-
- printstr(val, stdout);
+ printstr(mrb_inspect(mrb, obj), stdout);
}
MRB_API void
mrb_print_error(mrb_state *mrb)
{
- mrb_value s;
-
mrb_print_backtrace(mrb);
- s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
- printstr(s, stderr);
+ printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr);
}
MRB_API void
mrb_show_version(mrb_state *mrb)
{
- mrb_value msg;
-
- msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION"));
- printstr(msg, stdout);
+ 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)
{
- mrb_value msg;
-
- msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT"));
- printstr(msg, stdout);
+ printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")), stdout);
}
diff --git a/src/proc.c b/src/proc.c
index 8a2b6bbb6..34037b167 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -4,10 +4,10 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/proc.h"
-#include "mruby/opcode.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),
diff --git a/src/range.c b/src/range.c
index b58b6a1c8..bc8b11419 100644
--- a/src/range.c
+++ b/src/range.c
@@ -4,11 +4,11 @@
** 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"
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/array.h>
#define RANGE_CLASS (mrb_class_get(mrb, "Range"))
diff --git a/src/state.c b/src/state.c
index 2efd34334..c8c0658e4 100644
--- a/src/state.c
+++ b/src/state.c
@@ -6,16 +6,18 @@
#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"
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/variable.h>
+#include <mruby/debug.h>
+#include <mruby/string.h>
-void mrb_init_heap(mrb_state*);
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)
{
@@ -35,15 +37,9 @@ mrb_open_core(mrb_allocf f, void *ud)
*mrb = mrb_state_zero;
mrb->allocf_ud = ud;
mrb->allocf = f;
- mrb->current_white_part = MRB_GC_WHITE_A;
mrb->atexit_stack_len = 0;
-#ifndef MRB_GC_FIXED_ARENA
- mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
- mrb->arena_capa = MRB_GC_ARENA_SIZE;
-#endif
-
- mrb_init_heap(mrb);
+ 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;
@@ -122,7 +118,6 @@ mrb_open_allocf(mrb_allocf f, void *ud)
}
void mrb_free_symtbl(mrb_state *mrb);
-void mrb_free_heap(mrb_state *mrb);
void
mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
@@ -234,6 +229,7 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *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) {
@@ -248,11 +244,8 @@ mrb_close(mrb_state *mrb)
mrb_gc_free_gv(mrb);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
- mrb_free_heap(mrb);
mrb_alloca_free(mrb);
-#ifndef MRB_GC_FIXED_ARENA
- mrb_free(mrb, mrb->arena);
-#endif
+ mrb_gc_destroy(mrb, &mrb->gc);
mrb_free(mrb, mrb);
}
diff --git a/src/string.c b/src/string.c
index e93fd4606..7983a925e 100644
--- a/src/string.c
+++ b/src/string.c
@@ -9,14 +9,12 @@
#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"
-
-const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+#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;
@@ -25,198 +23,7 @@ typedef struct mrb_shared_string {
mrb_int len;
} mrb_shared_string;
-static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
-static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
-
-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, size_t len)
-{
- wchar_t* wcsp;
- char* mbsp;
- size_t mbssize, wcssize;
-
- if (len == 0)
- return strdup("");
- if (len == -1)
- len = 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, size_t len)
-{
- wchar_t* wcsp;
- char* mbsp;
- size_t mbssize, wcssize;
-
- if (len == 0)
- return strdup("");
- if (len == -1)
- len = 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
-
-static inline void
-resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
-{
- 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 = capacity;
- }
- }
- else {
- s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
- s->as.heap.aux.capa = capacity;
- }
-}
-
-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);
- }
-}
-
-static void
-check_frozen(mrb_state *mrb, struct RString *s)
-{
- if (RSTR_FROZEN_P(s)) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
- }
-}
-
-MRB_API void
-mrb_str_modify(mrb_state *mrb, struct RString *s)
-{
- check_frozen(mrb, s);
- if (RSTR_SHARED_P(s)) {
- mrb_shared_string *shared = s->as.heap.aux.shared;
-
- if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
- s->as.heap.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;
- ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
- if (p) {
- memcpy(ptr, p, len);
- }
- ptr[len] = '\0';
- s->as.heap.ptr = ptr;
- s->as.heap.aux.capa = len;
- str_decref(mrb, shared);
- }
- RSTR_UNSET_SHARED_FLAG(s);
- return;
- }
- if (RSTR_NOFREE_P(s)) {
- char *p = s->as.heap.ptr;
-
- s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
- if (p) {
- memcpy(RSTR_PTR(s), p, s->as.heap.len);
- }
- RSTR_PTR(s)[s->as.heap.len] = '\0';
- s->as.heap.aux.capa = s->as.heap.len;
- RSTR_UNSET_NOFREE_FLAG(s);
- return;
- }
-}
-
-static mrb_value
-mrb_str_freeze(mrb_state *mrb, mrb_value str)
-{
- struct RString *s = mrb_str_ptr(str);
-
- RSTR_SET_FROZEN_FLAG(s);
- return str;
-}
-
-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;
-}
+const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
@@ -307,6 +114,26 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
return mrb_obj_value(s);
}
+static inline void
+resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
+{
+ 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 = capacity;
+ }
+ }
+ else {
+ s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
+ s->as.heap.aux.capa = capacity;
+ }
+}
+
static void
str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
{
@@ -386,6 +213,18 @@ mrb_str_new_static(mrb_state *mrb, const char *p, size_t 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)
{
@@ -397,20 +236,126 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str)
mrb_free(mrb, str->as.heap.ptr);
}
-MRB_API char*
-mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
+#ifdef MRB_UTF8_STRING
+static const char utf8len_codepage[256] =
{
- struct RString *s;
+ 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,
+};
- if (!mrb_string_p(str0)) {
- mrb_raise(mrb, E_TYPE_ERROR, "expected String");
+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;
+ e += len < 0 ? RSTRING_LEN(str) : len;
+ while (p<e) {
+ p += utf8len(p, e);
+ total++;
}
+ return total;
+}
- 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");
+#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 RSTR_PTR(s);
+ 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(p, p+bi);
+ b += n;
+ p += n;
+ }
+ return i;
+}
+
+#else
+#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
+#define chars2bytes(p, off, ci) (ci)
+#define bytes2chars(p, bi) (bi)
+#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, 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 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 = y, *ye = ys + n;
+ for (; y < ye; ++y) {
+ if (*x == *y)
+ return y - ys;
+ }
+ return -1;
+ }
+ return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
}
static void
@@ -451,6 +396,339 @@ str_make_shared(mrb_state *mrb, struct RString *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)) {
+ 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 (beg + len > clen)
+ len = clen - beg;
+ if (len <= 0) {
+ len = 0;
+ }
+ return str_subseq(mrb, str, beg, len);
+}
+
+static mrb_int
+str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
+{
+ mrb_int pos;
+ char *s, *sptr;
+ mrb_int len, slen;
+
+ len = RSTRING_LEN(str);
+ slen = RSTRING_LEN(sub);
+ 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 */
+ sptr = RSTRING_PTR(sub);
+ slen = RSTRING_LEN(sub);
+ len = RSTRING_LEN(str) - offset;
+ pos = mrb_memsearch(sptr, slen, s, len);
+ if (pos < 0) return pos;
+ return pos + offset;
+}
+
+static void
+check_frozen(mrb_state *mrb, struct RString *s)
+{
+ if (RSTR_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);
+ 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 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, size_t len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ size_t mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = 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, size_t len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ size_t mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = 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);
+ if (RSTR_SHARED_P(s)) {
+ mrb_shared_string *shared = s->as.heap.aux.shared;
+
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.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;
+ ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
+ if (p) {
+ memcpy(ptr, p, len);
+ }
+ ptr[len] = '\0';
+ s->as.heap.ptr = ptr;
+ s->as.heap.aux.capa = len;
+ str_decref(mrb, shared);
+ }
+ RSTR_UNSET_SHARED_FLAG(s);
+ return;
+ }
+ if (RSTR_NOFREE_P(s)) {
+ char *p = s->as.heap.ptr;
+
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
+ if (p) {
+ memcpy(RSTR_PTR(s), p, s->as.heap.len);
+ }
+ RSTR_PTR(s)[s->as.heap.len] = '\0';
+ s->as.heap.aux.capa = s->as.heap.len;
+ RSTR_UNSET_NOFREE_FLAG(s);
+ return;
+ }
+}
+
+static mrb_value
+mrb_str_freeze(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = mrb_str_ptr(str);
+
+ RSTR_SET_FROZEN_FLAG(s);
+ return str;
+}
+
+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")
@@ -519,15 +797,22 @@ mrb_str_plus_m(mrb_state *mrb, mrb_value self)
/* 15.2.10.5.33 */
/*
* call-seq:
- * len = strlen(String("abcd"))
+ * "abcd".size => int
*
* Returns the length of string.
*/
static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
- struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(RSTR_LEN(s));
+ 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 */
@@ -742,77 +1027,6 @@ mrb_regexp_check(mrb_state *mrb, mrb_value obj)
}
}
-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, 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 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 = y, *ye = ys + n;
- for (; y < ye; ++y) {
- if (*x == *y)
- return y - ys;
- }
- return -1;
- }
- return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
-}
-
-static mrb_int
-mrb_str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
-{
- mrb_int pos;
- char *s, *sptr;
- mrb_int len, slen;
-
- len = RSTRING_LEN(str);
- slen = RSTRING_LEN(sub);
- 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 */
- sptr = RSTRING_PTR(sub);
- slen = RSTRING_LEN(sub);
- len = RSTRING_LEN(str) - offset;
- pos = mrb_memsearch(sptr, slen, s, len);
- if (pos < 0) return pos;
- return pos + offset;
-}
-
MRB_API mrb_value
mrb_str_dup(mrb_state *mrb, mrb_value str)
{
@@ -834,12 +1048,12 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx)
idx = mrb_fixnum(indx);
num_index:
- str = mrb_str_substr(mrb, str, idx, 1);
+ 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 (mrb_str_index(mrb, str, indx, 0) != -1)
+ if (str_index(mrb, str, indx, 0) != -1)
return mrb_str_dup(mrb, indx);
return mrb_nil_value();
@@ -848,9 +1062,9 @@ num_index:
{
mrb_int beg, len;
- len = RSTRING_LEN(str);
+ len = RSTRING_CHAR_LEN(str);
if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
- return mrb_str_subseq(mrb, str, beg, len);
+ return str_subseq(mrb, str, beg, len);
}
else {
return mrb_nil_value();
@@ -917,7 +1131,7 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str)
argc = mrb_get_args(mrb, "o|o", &a1, &a2);
if (argc == 2) {
mrb_regexp_check(mrb, a1);
- return mrb_str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2));
+ return str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2));
}
if (argc != 1) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
@@ -987,7 +1201,7 @@ mrb_str_capitalize(mrb_state *mrb, mrb_value self)
/* 15.2.10.5.10 */
/*
* call-seq:
- * str.chomp!(separator=$/) => str or nil
+ * 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.
@@ -1061,7 +1275,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
/* 15.2.10.5.9 */
/*
* call-seq:
- * str.chomp(separator=$/) => new_str
+ * str.chomp(separator="\n") => new_str
*
* Returns a new <code>String</code> with the given record separator removed
* from the end of <i>str</i> (if present). If <code>$/</code> has not been
@@ -1104,7 +1318,18 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value 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') {
@@ -1232,47 +1457,10 @@ mrb_str_eql(mrb_state *mrb, mrb_value self)
return mrb_bool_value(eql_p);
}
-static mrb_value
-mrb_str_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)) {
- 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);
-}
-
MRB_API mrb_value
mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
{
- if (len < 0) return mrb_nil_value();
- if (!RSTRING_LEN(str)) {
- len = 0;
- }
- if (beg > RSTRING_LEN(str)) return mrb_nil_value();
- if (beg < 0) {
- beg += RSTRING_LEN(str);
- if (beg < 0) return mrb_nil_value();
- }
- if (beg + len > RSTRING_LEN(str))
- len = RSTRING_LEN(str) - beg;
- if (len <= 0) {
- len = 0;
- }
- return mrb_str_subseq(mrb, str, beg, len);
+ return str_substr(mrb, str, beg, len);
}
mrb_int
@@ -1331,7 +1519,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
}
else {
str2 = mrb_str_to_str(mrb, str2);
- i = mrb_str_index(mrb, self, str2, 0);
+ i = str_index(mrb, self, str2, 0);
include_p = (i != -1);
}
@@ -1361,12 +1549,12 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
* "hello".index(/[aeiou]/, -3) #=> 4
*/
static mrb_value
-mrb_str_index_m(mrb_state *mrb, mrb_value str)
+mrb_str_index(mrb_state *mrb, mrb_value str)
{
mrb_value *argv;
mrb_int argc;
mrb_value sub;
- mrb_int pos;
+ mrb_int pos, clen;
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 2) {
@@ -1381,25 +1569,17 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
sub = mrb_nil_value();
}
mrb_regexp_check(mrb, sub);
+ clen = RSTRING_CHAR_LEN(str);
if (pos < 0) {
- pos += RSTRING_LEN(str);
+ pos += clen;
if (pos < 0) {
return mrb_nil_value();
}
}
+ if (pos >= clen) return mrb_nil_value();
+ pos = chars2bytes(str, 0, pos);
switch (mrb_type(sub)) {
- case MRB_TT_FIXNUM: {
- mrb_int c = mrb_fixnum(sub);
- mrb_int len = RSTRING_LEN(str);
- unsigned char *p = (unsigned char*)RSTRING_PTR(str);
-
- for (;pos<len;pos++) {
- if (p[pos] == c) return mrb_fixnum_value(pos);
- }
- return mrb_nil_value();
- }
-
default: {
mrb_value tmp;
@@ -1411,57 +1591,17 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
}
/* fall through */
case MRB_TT_STRING:
- pos = mrb_str_index(mrb, str, sub, pos);
+ pos = str_index(mrb, str, sub, pos);
break;
}
if (pos == -1) return mrb_nil_value();
+ pos = bytes2chars(RSTRING_PTR(str), pos);
return mrb_fixnum_value(pos);
}
#define STR_REPLACE_SHARED_MIN 10
-static mrb_value
-str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
-{
- long len;
-
- check_frozen(mrb, s1);
- 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);
-}
-
/* 15.2.10.5.24 */
/* 15.2.10.5.28 */
/*
@@ -1581,107 +1721,81 @@ 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.29 */
+/* 15.2.10.5.30 */
/*
* call-seq:
- * str.reverse => new_str
- *
- * Returns a new string with the characters from <i>str</i> in reverse order.
+ * str.reverse! => str
*
- * "stressed".reverse #=> "desserts"
+ * Reverses <i>str</i> in place.
*/
static mrb_value
-mrb_str_reverse(mrb_state *mrb, mrb_value str)
+mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
{
- struct RString *s2;
- char *s, *e, *p;
+#ifdef MRB_UTF8_STRING
+ mrb_int utf8_len = RSTRING_CHAR_LEN(str);
+ mrb_int len = RSTRING_LEN(str);
- if (RSTRING_LEN(str) <= 1) return mrb_str_dup(mrb, str);
+ if (utf8_len == len) goto bytes;
+ if (utf8_len > 1) {
+ char *buf;
+ char *p, *e, *r;
- s2 = str_new(mrb, 0, RSTRING_LEN(str));
- str_with_class(mrb, s2, str);
- s = RSTRING_PTR(str); e = RSTRING_END(str) - 1;
- p = RSTR_PTR(s2);
+ mrb_str_modify(mrb, mrb_str_ptr(str));
+ len = RSTRING_LEN(str);
+ buf = mrb_malloc(mrb, (size_t)len);
+ p = buf;
+ e = buf + len;
- while (e >= s) {
- *p++ = *e--;
+ 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 mrb_obj_value(s2);
-}
+ return 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)
-{
- struct RString *s = mrb_str_ptr(str);
- char *p, *e;
- char c;
+ 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) {
+ 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;
}
- return str;
}
+/* ---------------------------------- */
+/* 15.2.10.5.29 */
/*
* call-seq:
- * str.rindex(substring [, fixnum]) => fixnum or nil
- * str.rindex(fixnum [, fixnum]) => fixnum or nil
- * str.rindex(regexp [, fixnum]) => fixnum or nil
+ * str.reverse => new_str
*
- * Returns the index of the last occurrence of the given <i>substring</i>,
- * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns
- * <code>nil</code> if not found. If the second parameter is present, it
- * specifies the position in the string to end the search---characters beyond
- * this point will not be considered.
+ * Returns a new string with the characters from <i>str</i> in reverse order.
*
- * "hello".rindex('e') #=> 1
- * "hello".rindex('l') #=> 3
- * "hello".rindex('a') #=> nil
- * "hello".rindex(101) #=> 1
- * "hello".rindex(/[aeiou]/, -2) #=> 1
+ * "stressed".reverse #=> "desserts"
*/
-static mrb_int
-mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
+static mrb_value
+mrb_str_reverse(mrb_state *mrb, mrb_value str)
{
- 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 s - RSTR_PTR(ps);
- }
- s--;
- }
- return -1;
- }
- else {
- return pos;
- }
+ mrb_value str2 = mrb_str_dup(mrb, str);
+ mrb_str_reverse_bang(mrb, str2);
+ return str2;
}
/* 15.2.10.5.31 */
@@ -1704,13 +1818,13 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
* "hello".rindex(/[aeiou]/, -2) #=> 1
*/
static mrb_value
-mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
+mrb_str_rindex(mrb_state *mrb, mrb_value str)
{
mrb_value *argv;
mrb_int argc;
mrb_value sub;
mrb_value vpos;
- mrb_int pos, len = RSTRING_LEN(str);
+ mrb_int pos, len = RSTRING_CHAR_LEN(str);
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 2) {
@@ -1733,19 +1847,11 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
else
sub = mrb_nil_value();
}
+ pos = chars2bytes(str, 0, pos);
+ len = chars2bytes(str, pos, len);
mrb_regexp_check(mrb, sub);
switch (mrb_type(sub)) {
- case MRB_TT_FIXNUM: {
- mrb_int c = mrb_fixnum(sub);
- unsigned char *p = (unsigned char*)RSTRING_PTR(str);
-
- for (pos=len-1;pos>=0;pos--) {
- if (p[pos] == c) return mrb_fixnum_value(pos);
- }
- return mrb_nil_value();
- }
-
default: {
mrb_value tmp;
@@ -1757,8 +1863,11 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
}
/* fall through */
case MRB_TT_STRING:
- pos = mrb_str_rindex(mrb, str, sub, pos);
- if (pos >= 0) return mrb_fixnum_value(pos);
+ pos = str_rindex(mrb, str, sub, pos);
+ if (pos >= 0) {
+ pos = bytes2chars(RSTRING_PTR(str), pos);
+ return mrb_fixnum_value(pos);
+ }
break;
} /* end of switch (TYPE(sub)) */
@@ -1769,7 +1878,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
/*
* call-seq:
- * str.split(pattern=$;, [limit]) => anArray
+ * str.split(pattern="\n", [limit]) => anArray
*
* Divides <i>str</i> into substrings based on a delimiter, returning an array
* of these substrings.
@@ -1867,7 +1976,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
else if (ISSPACE(c)) {
- mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, beg, end-beg));
+ mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg));
mrb_gc_arena_restore(mrb, ai);
skip = TRUE;
beg = idx;
@@ -1889,9 +1998,9 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
end = mrb_memsearch(RSTRING_PTR(spat), pat_len, RSTRING_PTR(str)+idx, str_len - idx);
if (end < 0) break;
} else {
- end = 1;
+ end = chars2bytes(str, idx, 1);
}
- mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, idx, end));
+ 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;
@@ -1906,7 +2015,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
tmp = mrb_str_new_empty(mrb, str);
}
else {
- tmp = mrb_str_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
+ tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
}
mrb_ary_push(mrb, result, tmp);
}
@@ -2477,7 +2586,21 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
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, pend))) {
buf[0] = '\\'; buf[1] = c;
@@ -2551,10 +2674,10 @@ mrb_init_string(mrb_state *mrb)
mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string");
- s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
+ 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_size, MRB_ARGS_NONE());
+ 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 */
@@ -2574,7 +2697,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */
mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */
- mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
+ mrb_define_method(mrb, s, "index", mrb_str_index, 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 */
@@ -2582,7 +2705,7 @@ mrb_init_string(mrb_state *mrb)
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_m, MRB_ARGS_ANY()); /* 15.2.10.5.31 */
+ 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 */
diff --git a/src/symbol.c b/src/symbol.c
index f1c0bf80a..c39e88012 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -6,10 +6,10 @@
#include <limits.h>
#include <string.h>
-#include "mruby.h"
-#include "mruby/khash.h"
-#include "mruby/string.h"
-#include "mruby/dump.h"
+#include <mruby.h>
+#include <mruby/khash.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
/* ------------------------------------------------------ */
typedef struct symbol_name {
@@ -478,7 +478,7 @@ mrb_init_symbol(mrb_state *mrb)
{
struct RClass *sym;
- sym = mrb->symbol_class = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
+ mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
mrb_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 */
diff --git a/src/value_array.h b/src/value_array.h
index cabd2426d..bc5f28b06 100644
--- a/src/value_array.h
+++ b/src/value_array.h
@@ -1,7 +1,7 @@
#ifndef MRB_VALUE_ARRAY_H__
#define MRB_VALUE_ARRAY_H__
-#include "mruby.h"
+#include <mruby.h>
static inline void
value_move(mrb_value *s1, const mrb_value *s2, size_t n)
diff --git a/src/variable.c b/src/variable.c
index efe6fad12..bda7b2a98 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -4,11 +4,11 @@
** 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"
+#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*);
@@ -282,7 +282,7 @@ iv_free(mrb_state *mrb, iv_tbl *t)
#else
-#include "mruby/khash.h"
+#include <mruby/khash.h>
#ifndef MRB_IVHASH_INIT_SIZE
#define MRB_IVHASH_INIT_SIZE 8
@@ -759,17 +759,29 @@ MRB_API mrb_value
mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym)
{
struct RClass * cls = c;
+ mrb_value v;
while (c) {
- if (c->iv) {
- iv_tbl *t = c->iv;
- mrb_value v;
-
- if (iv_get(mrb, t, sym, &v))
- return v;
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ return v;
}
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__"));
+ c = mrb_class_ptr(klass);
+ if (c->tt == MRB_TT_CLASS) {
+ while (c) {
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ return v;
+ }
+ c = c->super;
+ }
+ }
+ }
mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
mrb_sym2str(mrb, sym), mrb_obj_value(cls));
/* not reached */
@@ -914,6 +926,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
return v;
}
+ if (c->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)c,
+ mrb_intern_lit(mrb, "__attached__"));
+ c2 = mrb_class_ptr(klass);
+ if (c2->tt == MRB_TT_CLASS)
+ c = c2;
+ }
c2 = c;
for (;;) {
c2 = mrb_class_outer_module(mrb, c2);
diff --git a/src/version.c b/src/version.c
index fc3b2fc7a..5bcecb3aa 100644
--- a/src/version.c
+++ b/src/version.c
@@ -1,11 +1,14 @@
-#include "mruby.h"
-#include "mruby/variable.h"
+#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", mrb_str_new_lit(mrb, 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));
diff --git a/src/vm.c b/src/vm.c
index 8419931d0..391646017 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -7,22 +7,22 @@
#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 <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"
+#include <mruby/throw.h>
-#ifndef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
#if defined(__cplusplus)
extern "C" {
#endif
@@ -52,7 +52,7 @@ The value below allows about 60000 recursive calls in the simplest case. */
# define DEBUG(x)
#endif
-#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)
+#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
static inline void
stack_clear(mrb_value *from, size_t count)
@@ -693,7 +693,7 @@ argnum_error(mrb_state *mrb, mrb_int num)
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0;
-#ifdef ENABLE_DEBUG
+#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)
@@ -2178,6 +2178,7 @@ RETRY_TRY_BLOCK:
CASE(OP_STRCAT) {
/* A B R(A).concat(R(B)) */
mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
+ regs = mrb->c->stack;
NEXT;
}
@@ -2207,15 +2208,6 @@ RETRY_TRY_BLOCK:
}
else {
p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]);
- if (c & OP_L_METHOD) {
- if (p->target_class->tt == MRB_TT_SCLASS) {
- mrb_value klass;
- klass = mrb_obj_iv_get(mrb,
- (struct RObject *)p->target_class,
- mrb_intern_lit(mrb, "__attached__"));
- p->target_class = mrb_class_ptr(klass);
- }
- }
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
regs[GETARG_A(i)] = mrb_obj_value(p);
@@ -2348,10 +2340,10 @@ RETRY_TRY_BLOCK:
CASE(OP_DEBUG) {
/* A B C debug print R(A),R(B),R(C) */
-#ifdef ENABLE_DEBUG
+#ifdef MRB_ENABLE_DEBUG_HOOK
mrb->debug_op_hook(mrb, irep, pc, regs);
#else
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
#else
abort();