diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 13 | ||||
| -rw-r--r-- | src/backtrace.c | 22 | ||||
| -rw-r--r-- | src/class.c | 24 | ||||
| -rw-r--r-- | src/codedump.c | 24 | ||||
| -rw-r--r-- | src/compar.c | 2 | ||||
| -rw-r--r-- | src/debug.c | 6 | ||||
| -rw-r--r-- | src/dump.c | 14 | ||||
| -rw-r--r-- | src/enum.c | 2 | ||||
| -rw-r--r-- | src/error.c | 26 | ||||
| -rw-r--r-- | src/error.h | 2 | ||||
| -rw-r--r-- | src/etc.c | 12 | ||||
| -rw-r--r-- | src/fmt_fp.c | 11 | ||||
| -rw-r--r-- | src/gc.c | 710 | ||||
| -rw-r--r-- | src/hash.c | 76 | ||||
| -rw-r--r-- | src/init.c | 2 | ||||
| -rw-r--r-- | src/kernel.c | 20 | ||||
| -rw-r--r-- | src/load.c | 16 | ||||
| -rw-r--r-- | src/numeric.c | 41 | ||||
| -rw-r--r-- | src/object.c | 14 | ||||
| -rw-r--r-- | src/opcode.h | 2 | ||||
| -rw-r--r-- | src/pool.c | 2 | ||||
| -rw-r--r-- | src/print.c | 27 | ||||
| -rw-r--r-- | src/proc.c | 8 | ||||
| -rw-r--r-- | src/range.c | 10 | ||||
| -rw-r--r-- | src/state.c | 29 | ||||
| -rw-r--r-- | src/string.c | 1091 | ||||
| -rw-r--r-- | src/symbol.c | 10 | ||||
| -rw-r--r-- | src/value_array.h | 2 | ||||
| -rw-r--r-- | src/variable.c | 44 | ||||
| -rw-r--r-- | src/version.c | 7 | ||||
| -rw-r--r-- | src/vm.c | 46 |
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> @@ -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') { @@ -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)); @@ -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(); |
