summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc/guides/debugger.md2
-rw-r--r--doc/guides/mrbconf.md13
-rw-r--r--doc/limitations.md16
-rw-r--r--examples/targets/build_config_ArduinoDue.rb1
-rw-r--r--examples/targets/build_config_RX630.rb1
-rw-r--r--examples/targets/build_config_chipKITMax32.rb1
-rw-r--r--include/mrbconf.h6
-rw-r--r--include/mruby.h79
-rw-r--r--include/mruby/array.h40
-rw-r--r--include/mruby/boxing_word.h2
-rw-r--r--include/mruby/class.h2
-rw-r--r--include/mruby/compile.h2
-rw-r--r--include/mruby/dump.h2
-rw-r--r--include/mruby/error.h7
-rw-r--r--include/mruby/gc.h5
-rw-r--r--include/mruby/hash.h2
-rw-r--r--include/mruby/numeric.h12
-rw-r--r--include/mruby/proc.h7
-rw-r--r--include/mruby/string.h7
-rw-r--r--include/mruby/value.h12
-rw-r--r--include/mruby/version.h8
-rw-r--r--lib/mruby/gem.rb6
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb57
-rw-r--r--mrbgems/mruby-array-ext/src/array.c22
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb49
-rw-r--r--mrbgems/mruby-bin-debugger/bintest/print.rb4
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c2
-rw-r--r--mrbgems/mruby-bin-mruby-config/mrbgem.rake2
-rw-r--r--mrbgems/mruby-bin-mruby-config/mruby-config4
-rw-r--r--mrbgems/mruby-bin-mruby-config/mruby-config.bat8
-rw-r--r--mrbgems/mruby-bin-mruby/mrbgem.rake3
-rw-r--r--mrbgems/mruby-bin-mruby/tools/mruby/mruby.c5
-rw-r--r--mrbgems/mruby-class-ext/src/class.c7
-rw-r--r--mrbgems/mruby-class-ext/test/module.rb36
-rw-r--r--mrbgems/mruby-compiler/bintest/mrbc.rb9
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c90
-rw-r--r--mrbgems/mruby-compiler/core/parse.y80
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb2
-rw-r--r--mrbgems/mruby-enum-lazy/mrblib/lazy.rb2
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb2
-rw-r--r--mrbgems/mruby-eval/src/eval.c114
-rw-r--r--mrbgems/mruby-fiber/src/fiber.c46
-rw-r--r--mrbgems/mruby-hash-ext/mrbgem.rake5
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb76
-rw-r--r--mrbgems/mruby-hash-ext/src/hash-ext.c2
-rw-r--r--mrbgems/mruby-hash-ext/test/hash.rb24
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb14
-rw-r--r--mrbgems/mruby-object-ext/src/object.c7
-rw-r--r--mrbgems/mruby-objectspace/src/mruby_objectspace.c14
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c5
-rw-r--r--mrbgems/mruby-random/src/random.c8
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c177
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb68
-rw-r--r--mrbgems/mruby-string-ext/mrbgem.rake1
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb44
-rw-r--r--mrbgems/mruby-string-ext/src/string.c141
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb29
-rw-r--r--mrbgems/mruby-struct/src/struct.c22
-rw-r--r--mrbgems/mruby-struct/test/struct.rb13
-rw-r--r--mrbgems/mruby-time/src/time.c49
-rw-r--r--mrblib/00class.rb2
-rw-r--r--mrblib/10error.rb4
-rw-r--r--mrblib/array.rb39
-rw-r--r--mrblib/enum.rb46
-rw-r--r--mrblib/string.rb2
-rw-r--r--src/array.c419
-rw-r--r--src/backtrace.c415
-rw-r--r--src/class.c143
-rw-r--r--src/codedump.c11
-rw-r--r--src/error.c111
-rw-r--r--src/gc.c174
-rw-r--r--src/hash.c6
-rw-r--r--src/init.c4
-rw-r--r--src/kernel.c74
-rw-r--r--src/numeric.c213
-rw-r--r--src/object.c8
-rw-r--r--src/pool.c4
-rw-r--r--src/proc.c3
-rw-r--r--src/state.c1
-rw-r--r--src/string.c59
-rw-r--r--src/variable.c154
-rw-r--r--src/vm.c862
-rw-r--r--tasks/libmruby.rake2
-rw-r--r--tasks/toolchains/android.rake2
-rw-r--r--test/assert.rb8
-rw-r--r--test/bintest.rb6
-rw-r--r--test/t/array.rb4
-rw-r--r--test/t/class.rb14
-rw-r--r--test/t/codegen.rb18
-rw-r--r--test/t/exception.rb4
-rw-r--r--test/t/iterations.rb61
-rw-r--r--test/t/kernel.rb4
-rw-r--r--test/t/module.rb48
-rw-r--r--test/t/superclass.rb3
-rw-r--r--test/t/syntax.rb2
96 files changed, 2671 insertions, 1737 deletions
diff --git a/README.md b/README.md
index 700357dcb..9d0c611b2 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
## How to get mruby
-The stable version 1.2.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.2.0.zip](https://github.com/mruby/mruby/archive/1.2.0.zip)
+The stable version 1.3.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.3.0.zip](https://github.com/mruby/mruby/archive/1.3.0.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md
index 366701c88..72f2c2b32 100644
--- a/doc/guides/debugger.md
+++ b/doc/guides/debugger.md
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
```bash
$ mrdb --version
-mruby 1.2.0 (2014-11-17)
+mruby 1.3.0 (2017-7-4)
```
## 2.2 Basic Operation
diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md
index fabd7208b..f957f8ce2 100644
--- a/doc/guides/mrbconf.md
+++ b/doc/guides/mrbconf.md
@@ -122,20 +122,9 @@ largest value of required alignment.
* If defined `Float` will be a mruby object with `RBasic`.
## Instance variable configuration.
-`MRB_USE_IV_SEGLIST`
-* If defined enable segmented list in instance variable table instead of khash.
-* Segmented list is a linked list of key and value segments.
-* It will linear search instead of hash search.
-
-`MRB_SEGMENT_SIZE`
+`MRB_IV_SEGMENT_SIZE`
* Default value is `4`.
* Specifies size of each segment in segment list.
-* Ignored when `MRB_USE_IV_SEGLIST` isn't defined.
-
-`MRB_IVHASH_INIT_SIZE`
-* Default value is `8`.
-* Specifies initial size for instance variable table.
-* Ignored when `MRB_USE_IV_SEGLIST` is defined.
## Other configuration.
`MRB_UTF8_STRING`
diff --git a/doc/limitations.md b/doc/limitations.md
index c15b3ba81..db8db9a5c 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -38,7 +38,7 @@ puts [1,2,3]
3
```
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
```
[1, 2, 3]
@@ -61,7 +61,7 @@ end
```ZeroDivisionError``` is raised.
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
No exception is raised.
@@ -77,7 +77,7 @@ def test; eval 'test'; end; test
```SystemStackError``` is raised.
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
Segmentation fault.
@@ -105,7 +105,7 @@ p Liste.new "foobar"
``` [] ```
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
```ArgumentError``` is raised.
@@ -135,7 +135,7 @@ false
true
```
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
```
true
@@ -158,7 +158,7 @@ defined?(Foo)
nil
```
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
```NameError``` is raised.
@@ -175,7 +175,7 @@ alias $a $__a__
``` nil ```
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
Syntax error
@@ -197,7 +197,7 @@ end
```ArgumentError``` is raised.
The re-defined ```+``` operator does not accept any arguments.
-#### mruby [1.2.0 (2015-11-17)]
+#### mruby [1.3.0 (2017-7-4)]
``` 'ab' ```
Behavior of the operator wasn't changed.
diff --git a/examples/targets/build_config_ArduinoDue.rb b/examples/targets/build_config_ArduinoDue.rb
index 740dcfa02..527aaa4f6 100644
--- a/examples/targets/build_config_ArduinoDue.rb
+++ b/examples/targets/build_config_ArduinoDue.rb
@@ -46,7 +46,6 @@ MRuby::CrossBuild.new("ArduinoDue") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
- cc.defines << %w(MRB_USE_IV_SEGLIST)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
cc.defines << %w(MRB_GC_STRESS)
diff --git a/examples/targets/build_config_RX630.rb b/examples/targets/build_config_RX630.rb
index 8e387c29d..fd17eae99 100644
--- a/examples/targets/build_config_RX630.rb
+++ b/examples/targets/build_config_RX630.rb
@@ -32,7 +32,6 @@ MRuby::CrossBuild.new("RX630") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_USE_FLOAT)
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
- cc.defines << %w(MRB_USE_IV_SEGLIST)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
cc.defines << %w(MRB_GC_STRESS)
diff --git a/examples/targets/build_config_chipKITMax32.rb b/examples/targets/build_config_chipKITMax32.rb
index c3a146e4e..951f71483 100644
--- a/examples/targets/build_config_chipKITMax32.rb
+++ b/examples/targets/build_config_chipKITMax32.rb
@@ -43,7 +43,6 @@ MRuby::CrossBuild.new("chipKITMax32") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
- cc.defines << %w(MRB_USE_IV_SEGLIST)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
cc.defines << %w(MRB_GC_STRESS)
diff --git a/include/mrbconf.h b/include/mrbconf.h
index 4796919c2..b246b970c 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -52,12 +52,6 @@
/* number of object per heap page */
//#define MRB_HEAP_PAGE_SIZE 1024
-/* use segmented list for IV table */
-//#define MRB_USE_IV_SEGLIST
-
-/* initial size for IV khash; ignored when MRB_USE_IV_SEGLIST is set */
-//#define MRB_IVHASH_INIT_SIZE 8
-
/* if _etext and _edata available, mruby can reduce memory used by symbols */
//#define MRB_USE_ETEXT_EDATA
diff --git a/include/mruby.h b/include/mruby.h
index 8adce289b..18f54fd2f 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -65,6 +65,13 @@
#include "mrbconf.h"
+#ifndef DBL_EPSILON
+#define DBL_EPSILON ((double)2.22044604925031308085e-16L)
+#endif
+#ifndef LDBL_EPSILON
+#define LDBL_EPSILON (1.08420217248550443401e-19L)
+#endif
+
#ifdef MRB_USE_FLOAT
#define MRB_FLOAT_EPSILON FLT_EPSILON
#else
@@ -113,7 +120,7 @@ typedef struct {
mrb_value *stackent;
int nregs;
int ridx;
- int eidx;
+ int epos;
struct REnv *env;
mrb_code *pc; /* return address */
mrb_code *err; /* error position */
@@ -143,7 +150,7 @@ struct mrb_context {
mrb_code **rescue; /* exception handler stack */
int rsize;
struct RProc **ensure; /* ensure handler stack */
- int esize;
+ int esize, eidx;
enum mrb_fiber_state status;
mrb_bool vmexec;
@@ -152,14 +159,6 @@ struct mrb_context {
struct mrb_jmpbuf;
-typedef struct {
- const char *filename;
- int lineno;
- struct RClass *klass;
- char sep;
- mrb_sym method_id;
-} mrb_backtrace_entry;
-
typedef void (*mrb_atexit_func)(struct mrb_state*);
#define MRB_STATE_NO_REGEXP 1
@@ -174,15 +173,9 @@ typedef struct mrb_state {
struct mrb_context *c;
struct mrb_context *root_c;
+ struct iv_tbl *globals; /* global variable table */
struct RObject *exc; /* exception */
- struct {
- struct RObject *exc;
- int n;
- int n_allocated;
- mrb_backtrace_entry *entries;
- } backtrace;
- struct iv_tbl *globals; /* global variable table */
struct RObject *top_self;
struct RClass *object_class; /* Object class */
@@ -1043,11 +1036,27 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
+static inline int mrb_gc_arena_save(mrb_state*);
+static inline void mrb_gc_arena_restore(mrb_state*,int);
+
+static inline int
+mrb_gc_arena_save(mrb_state *mrb)
+{
+ return mrb->gc.arena_idx;
+}
+
+static inline void
+mrb_gc_arena_restore(mrb_state *mrb, int idx)
+{
+ mrb->gc.arena_idx = idx;
+}
+
+MRB_API int mrb_gc_arena_save(mrb_state*);
+MRB_API void mrb_gc_arena_restore(mrb_state*,int);
+
MRB_API void mrb_garbage_collect(mrb_state*);
MRB_API void mrb_full_gc(mrb_state*);
MRB_API void mrb_incremental_gc(mrb_state *);
-MRB_API int mrb_gc_arena_save(mrb_state*);
-MRB_API void mrb_gc_arena_restore(mrb_state*,int);
MRB_API void mrb_gc_mark(mrb_state*,struct RBasic*);
#define mrb_gc_mark_value(mrb,val) do {\
if (!mrb_immediate_p(val)) mrb_gc_mark((mrb), mrb_basic_ptr(val)); \
@@ -1121,6 +1130,11 @@ MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c);
+/* continue execution to the proc */
+/* this function should always be called as the last function of a method */
+/* e.g. return mrb_yield_cont(mrb, proc, self, argc, argv); */
+mrb_value mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv);
+
/* mrb_gc_protect() leaves the object in the arena */
MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj);
/* mrb_gc_register() keeps the object from GC. */
@@ -1187,6 +1201,33 @@ MRB_API void mrb_show_copyright(mrb_state *mrb);
MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
+#if 0
+/* memcpy and memset does not work with gdb reverse-next on my box */
+/* use naive memcpy and memset instead */
+#undef memcpy
+#undef memset
+static inline void*
+mrbmemcpy(void *dst, const void *src, size_t n)
+{
+ char *d = (char*)dst;
+ const char *s = (const char*)src;
+ while (n--)
+ *d++ = *s++;
+ return d;
+}
+#define memcpy(a,b,c) mrbmemcpy(a,b,c)
+
+static inline void*
+mrbmemset(void *s, int c, size_t n)
+{
+ char *t = (char*)s;
+ while (n--)
+ *t++ = c;
+ return s;
+}
+#define memset(a,b,c) mrbmemset(a,b,c)
+#endif
+
MRB_END_DECL
#endif /* MRUBY_H */
diff --git a/include/mruby/array.h b/include/mruby/array.h
index e553faf92..bd3124d8c 100644
--- a/include/mruby/array.h
+++ b/include/mruby/array.h
@@ -21,22 +21,48 @@ typedef struct mrb_shared_array {
mrb_value *ptr;
} mrb_shared_array;
+#define MRB_ARY_EMBED_LEN_MAX ((mrb_int)(sizeof(void*)*3/sizeof(mrb_value)))
struct RArray {
MRB_OBJECT_HEADER;
- mrb_int len;
union {
- mrb_int capa;
- mrb_shared_array *shared;
- } aux;
- mrb_value *ptr;
+ struct {
+ mrb_int len;
+ union {
+ mrb_int capa;
+ mrb_shared_array *shared;
+ } aux;
+ mrb_value *ptr;
+ } heap;
+ mrb_value embed[MRB_ARY_EMBED_LEN_MAX];
+ } as;
};
#define mrb_ary_ptr(v) ((struct RArray*)(mrb_ptr(v)))
#define mrb_ary_value(p) mrb_obj_value((void*)(p))
#define RARRAY(v) ((struct RArray*)(mrb_ptr(v)))
-#define RARRAY_LEN(a) (RARRAY(a)->len)
-#define RARRAY_PTR(a) ((const mrb_value*)RARRAY(a)->ptr)
+#define MRB_ARY_EMBED 4
+#define MRB_ARY_EMBED_MASK 3
+#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED)
+#define ARY_SET_EMBED_FLAG(a) ((a)->flags |= MRB_ARY_EMBED)
+#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED|MRB_ARY_EMBED_MASK))
+#define ARY_EMBED_LEN(a) ((a)->flags & MRB_ARY_EMBED_MASK)
+#define ARY_SET_EMBED_LEN(a,len) (a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((len)&MRB_ARY_EMBED_MASK);
+#define ARY_EMBED_PTR(a) (&((a)->as.embed[0]))
+
+#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len)
+#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
+#define RARRAY_LEN(a) ARY_LEN(RARRAY(a))
+#define RARRAY_PTR(a) ARY_PTR(RARRAY(a))
+#define ARY_SET_LEN(a,n) do {\
+ if (ARY_EMBED_P(a)) {\
+ mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \
+ ARY_SET_EMBED_LEN(a,n);\
+ }\
+ else\
+ (a)->as.heap.len = (n);\
+} while (0)
+#define ARY_CAPA(a) (ARY_EMBED_P(a)?MRB_ARY_EMBED_LEN_MAX:(a)->as.heap.aux.capa)
#define MRB_ARY_SHARED 256
#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h
index 6ca491585..d1c457fae 100644
--- a/include/mruby/boxing_word.h
+++ b/include/mruby/boxing_word.h
@@ -66,7 +66,7 @@ MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float);
#define mrb_ptr(o) (o).value.p
#define mrb_cptr(o) (o).value.vp->p
#define mrb_float(o) (o).value.fp->f
-#define mrb_fixnum(o) (o).value.i
+#define mrb_fixnum(o) ((mrb_int)(o).value.i)
#define mrb_symbol(o) (o).value.sym
static inline enum mrb_vtype
diff --git a/include/mruby/class.h b/include/mruby/class.h
index ce953af3b..0526386d6 100644
--- a/include/mruby/class.h
+++ b/include/mruby/class.h
@@ -51,7 +51,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
}
}
-// TODO: figure out where to put user flags
+/* TODO: figure out where to put user flags */
#define MRB_FLAG_IS_FROZEN (1 << 18)
#define MRB_FLAG_IS_PREPENDED (1 << 19)
#define MRB_FLAG_IS_ORIGIN (1 << 20)
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index ad3f19db1..13e04d0fc 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -33,6 +33,8 @@ typedef struct mrbc_context {
mrb_bool no_exec:1;
mrb_bool keep_lv:1;
mrb_bool no_optimize:1;
+
+ size_t parser_nerr;
} mrbc_context;
MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb);
diff --git a/include/mruby/dump.h b/include/mruby/dump.h
index 165a20b3f..f56d66a32 100644
--- a/include/mruby/dump.h
+++ b/include/mruby/dump.h
@@ -52,7 +52,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
/* Rite Binary File header */
#define RITE_BINARY_IDENT "RITE"
#define RITE_BINARY_IDENT_LIL "ETIR"
-#define RITE_BINARY_FORMAT_VER "0003"
+#define RITE_BINARY_FORMAT_VER "0004"
#define RITE_COMPILER_NAME "MATZ"
#define RITE_COMPILER_VERSION "0000"
diff --git a/include/mruby/error.h b/include/mruby/error.h
index bb67e7bd8..0a262550e 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -32,6 +32,13 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va
/* declaration for fail method */
MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ struct iv_tbl *iv;
+ struct RProc *proc;
+ mrb_value val;
+};
+
/**
* Protect
*
diff --git a/include/mruby/gc.h b/include/mruby/gc.h
index 81950f169..ce214aa56 100644
--- a/include/mruby/gc.h
+++ b/include/mruby/gc.h
@@ -17,7 +17,9 @@ MRB_BEGIN_DECL
struct mrb_state;
-typedef void (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data);
+#define MRB_EACH_OBJ_OK 0
+#define MRB_EACH_OBJ_BREAK 1
+typedef int (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data);
void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data);
MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c);
@@ -62,6 +64,7 @@ typedef struct mrb_gc {
size_t threshold;
int interval_ratio;
int step_ratio;
+ mrb_bool iterating :1;
mrb_bool disabled :1;
mrb_bool full :1;
mrb_bool generational :1;
diff --git a/include/mruby/hash.h b/include/mruby/hash.h
index 55ad6a921..1a870785a 100644
--- a/include/mruby/hash.h
+++ b/include/mruby/hash.h
@@ -24,7 +24,7 @@ struct RHash {
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
#define mrb_hash_value(p) mrb_obj_value((void*)(p))
-MRB_API mrb_value mrb_hash_new_capa(mrb_state*, int);
+MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int);
/*
* Initializes a new hash.
diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h
index 36489b1ce..40c8c4a20 100644
--- a/include/mruby/numeric.h
+++ b/include/mruby/numeric.h
@@ -16,9 +16,13 @@
*/
MRB_BEGIN_DECL
-#define POSFIXABLE(f) ((f) <= MRB_INT_MAX)
-#define NEGFIXABLE(f) ((f) >= MRB_INT_MIN)
-#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
+#define TYPED_POSFIXABLE(f,t) ((f) <= (t)MRB_INT_MAX)
+#define TYPED_NEGFIXABLE(f,t) ((f) >= (t)MRB_INT_MIN)
+#define TYPED_FIXABLE(f,t) (TYPED_POSFIXABLE(f,t) && TYPED_NEGFIXABLE(f,t))
+#define POSFIXABLE(f) TYPED_POSFIXABLE(f,mrb_int)
+#define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int)
+#define FIXABLE(f) TYPED_FIXABLE(f,mrb_int)
+#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,double)
MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base);
@@ -42,9 +46,11 @@ mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y);
# define MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#endif
+/*
// Clang 3.8 and 3.9 have problem compiling mruby in 32-bit mode, when MRB_INT64 is set
// because of missing __mulodi4 and similar functions in its runtime. We need to use custom
// implementation for them.
+*/
#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#if defined(__clang__) && (__clang_major__ == 3) && (__clang_minor__ >= 8) && \
defined(MRB_32BIT) && defined(MRB_INT64)
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 5965a2b39..9c2666289 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -18,8 +18,11 @@ MRB_BEGIN_DECL
struct REnv {
MRB_OBJECT_HEADER;
mrb_value *stack;
- mrb_sym mid;
ptrdiff_t cioff;
+ union {
+ mrb_sym mid;
+ struct mrb_context *c;
+ } cxt;
};
#define MRB_SET_ENV_STACK_LEN(e,len) (e)->flags = (unsigned int)(len)
@@ -52,6 +55,8 @@ struct RProc {
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC) != 0)
#define MRB_PROC_STRICT 256
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
+#define MRB_PROC_ORPHAN 512
+#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
diff --git a/include/mruby/string.h b/include/mruby/string.h
index b18093218..c3fbb063d 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -84,6 +84,13 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
void mrb_gc_free_str(mrb_state*, struct RString*);
MRB_API void mrb_str_modify(mrb_state*, struct RString*);
+
+/*
+ * Finds the index of a substring in a string
+ */
+MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_int);
+#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off);
+
/*
* Appends self to other. Returns self as a concatnated string.
*
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 54d197f8f..98c68d657 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -116,7 +116,8 @@ enum mrb_vtype {
MRB_TT_DATA, /* 21 */
MRB_TT_FIBER, /* 22 */
MRB_TT_ISTRUCT, /* 23 */
- MRB_TT_MAXDEFINE /* 24 */
+ MRB_TT_BREAK, /* 24 */
+ MRB_TT_MAXDEFINE /* 25 */
};
#include <mruby/object.h>
@@ -266,6 +267,14 @@ mrb_undef_value(void)
}
#ifdef MRB_USE_ETEXT_EDATA
+#if (defined(__APPLE__) && defined(__MACH__))
+#include <mach-o/getsect.h>
+static inline mrb_bool
+mrb_ro_data_p(const char *p)
+{
+ return (const char*)get_etext() < p && p < (const char*)get_edata();
+}
+#else
extern char _etext[];
#ifdef MRB_NO_INIT_ARRAY_START
extern char _edata[];
@@ -284,6 +293,7 @@ mrb_ro_data_p(const char *p)
return _etext < p && p < (char*)&__init_array_start;
}
#endif
+#endif
#else
# define mrb_ro_data_p(p) FALSE
#endif
diff --git a/include/mruby/version.h b/include/mruby/version.h
index 20c39ec79..8414bf204 100644
--- a/include/mruby/version.h
+++ b/include/mruby/version.h
@@ -42,7 +42,7 @@ MRB_BEGIN_DECL
/*
* Minor release version number.
*/
-#define MRUBY_RELEASE_MINOR 2
+#define MRUBY_RELEASE_MINOR 3
/*
* Tiny release version number.
@@ -62,17 +62,17 @@ MRB_BEGIN_DECL
/*
* Release year.
*/
-#define MRUBY_RELEASE_YEAR 2015
+#define MRUBY_RELEASE_YEAR 2017
/*
* Release month.
*/
-#define MRUBY_RELEASE_MONTH 11
+#define MRUBY_RELEASE_MONTH 7
/*
* Release day.
*/
-#define MRUBY_RELEASE_DAY 17
+#define MRUBY_RELEASE_DAY 4
/*
* Release date as a string.
diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb
index 1f7cde529..27a1d358c 100644
--- a/lib/mruby/gem.rb
+++ b/lib/mruby/gem.rb
@@ -63,9 +63,6 @@ module MRuby
objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X"))
end
- @generate_functions = !(@rbfiles.empty? && @objs.empty?)
- @objs << objfile("#{build_dir}/gem_init") if @generate_functions
-
@test_rbfiles = Dir.glob("#{dir}/test/**/*.rb")
@test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
@@ -83,6 +80,9 @@ module MRuby
instance_eval(&@initializer)
+ @generate_functions = !(@rbfiles.empty? && @objs.empty?)
+ @objs << objfile("#{build_dir}/gem_init") if @generate_functions
+
if !name || !licenses || !authors
fail "#{name || dir} required to set name, license(s) and author(s)"
end
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index 1e6d4d581..716eabe06 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -595,31 +595,58 @@ class Array
def bsearch(&block)
return to_enum :bsearch unless block_given?
+ if idx = bsearch_index(&block)
+ self[idx]
+ else
+ nil
+ end
+ end
+
+ ##
+ # call-seq:
+ # ary.bsearch_index {|x| block } -> int or nil
+ #
+ # By using binary search, finds an index of a value from this array which
+ # meets the given condition in O(log n) where n is the size of the array.
+ #
+ # It supports two modes, depending on the nature of the block and they are
+ # exactly the same as in the case of #bsearch method with the only difference
+ # being that this method returns the index of the element instead of the
+ # element itself. For more details consult the documentation for #bsearch.
+
+ def bsearch_index(&block)
+ return to_enum :bsearch_index unless block_given?
+
low = 0
- high = self.size
+ high = size
satisfied = false
+
while low < high
- mid = low + ((high - low) / 2).truncate
- val = self[mid]
- v = block.call(val)
- if v.is_a?(Integer)
- return val if v == 0
- smaller = v < 0
- elsif v == true
+ mid = ((low+high)/2).truncate
+ res = block.call self[mid]
+
+ case res
+ when 0 # find-any mode: Found!
+ return mid
+ when Numeric # find-any mode: Continue...
+ in_lower_half = res < 0
+ when true # find-min mode
+ in_lower_half = true
satisfied = true
- smaller = true
- elsif v == false || v.nil?
- smaller = false
+ when false, nil # find-min mode
+ in_lower_half = false
+ else
+ raise TypeError, 'invalid block result (must be numeric, true, false or nil)'
end
- if smaller
+
+ if in_lower_half
high = mid
else
low = mid + 1
end
end
- return nil if low == self.size
- return nil unless satisfied
- self[low]
+
+ satisfied ? low : nil
end
##
diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
index 6919186bd..72e5080f1 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -174,7 +174,7 @@ static mrb_value
mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int i, j, k, len;
+ mrb_int i, j, k, len, alen = ARY_LEN(a);
mrb_value index;
mrb_value val;
mrb_value *ptr;
@@ -185,7 +185,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
switch (mrb_type(index)) {
case MRB_TT_RANGE:
- if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
+ if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) {
goto delete_pos_len;
}
else {
@@ -202,25 +202,25 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
i = mrb_fixnum(index);
delete_pos_len:
- if (i < 0) i += a->len;
- if (i < 0 || a->len < i) return mrb_nil_value();
+ if (i < 0) i += alen;
+ if (i < 0 || alen < i) return mrb_nil_value();
if (len < 0) return mrb_nil_value();
- if (a->len == i) return mrb_ary_new(mrb);
- if (len > a->len - i) len = a->len - i;
+ if (alen == i) return mrb_ary_new(mrb);
+ if (len > alen - i) len = alen - i;
ary = mrb_ary_new_capa(mrb, len);
-
+ ptr = ARY_PTR(a);
for (j = i, k = 0; k < len; ++j, ++k) {
- mrb_ary_push(mrb, ary, a->ptr[j]);
+ mrb_ary_push(mrb, ary, ptr[j]);
}
- ptr = a->ptr + i;
- for (j = i; j < a->len - len; ++j) {
+ ptr += i;
+ for (j = i; j < alen - len; ++j) {
*ptr = *(ptr+len);
++ptr;
}
- mrb_ary_resize(mrb, self, a->len - len);
+ mrb_ary_resize(mrb, self, alen - len);
return ary;
}
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
index 95a796cf9..c0db1b1cc 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -228,18 +228,47 @@ end
assert("Array#bsearch") do
# Find minimum mode
- a = [0, 4, 7, 10, 12]
- assert_include [4, 7], a.bsearch {|x| x >= 4 }
- assert_equal 7, a.bsearch {|x| x >= 6 }
- assert_equal 0, a.bsearch {|x| x >= -1 }
- assert_nil a.bsearch {|x| x >= 100 }
+ a = [0, 2, 4]
+ assert_equal 0, a.bsearch{ |x| x >= -1 }
+ assert_equal 0, a.bsearch{ |x| x >= 0 }
+ assert_equal 2, a.bsearch{ |x| x >= 1 }
+ assert_equal 2, a.bsearch{ |x| x >= 2 }
+ assert_equal 4, a.bsearch{ |x| x >= 3 }
+ assert_equal 4, a.bsearch{ |x| x >= 4 }
+ assert_nil a.bsearch{ |x| x >= 5 }
# Find any mode
- a = [0, 4, 7, 10, 12]
- assert_include [4, 7], a.bsearch {|x| 1 - (x / 4).truncate }
- assert_nil a.bsearch {|x| 4 - (x / 2).truncate }
- assert_equal(nil, a.bsearch {|x| 1 })
- assert_equal(nil, a.bsearch {|x| -1 })
+ a = [0, 4, 8]
+ def between(lo, x, hi)
+ if x < lo
+ 1
+ elsif x > hi
+ -1
+ else
+ 0
+ end
+ end
+ assert_nil a.bsearch{ |x| between(-3, x, -1) }
+ assert_equal 0, a.bsearch{ |x| between(-1, x, 1) }
+ assert_nil a.bsearch{ |x| between( 1, x, 3) }
+ assert_equal 4, a.bsearch{ |x| between( 3, x, 5) }
+ assert_nil a.bsearch{ |x| between( 5, x, 7) }
+ assert_equal 8, a.bsearch{ |x| between( 7, x, 9) }
+ assert_nil a.bsearch{ |x| between( 9, x, 11) }
+
+ assert_equal 0, a.bsearch{ |x| between( 0, x, 3) }
+ assert_equal 4, a.bsearch{ |x| between( 0, x, 4) }
+ assert_equal 4, a.bsearch{ |x| between( 4, x, 8) }
+ assert_equal 8, a.bsearch{ |x| between( 5, x, 8) }
+
+ # Invalid block result
+ assert_raise TypeError, 'invalid block result (must be numeric, true, false or nil)' do
+ a.bsearch{ 'I like to watch the world burn' }
+ end
+end
+
+assert("Array#bsearch_index") do
+ # tested through Array#bsearch
end
assert("Array#delete_if") do
diff --git a/mrbgems/mruby-bin-debugger/bintest/print.rb b/mrbgems/mruby-bin-debugger/bintest/print.rb
index 403ada8e1..1bc96c478 100644
--- a/mrbgems/mruby-bin-debugger/bintest/print.rb
+++ b/mrbgems/mruby-bin-debugger/bintest/print.rb
@@ -341,8 +341,8 @@ assert('mruby-bin-debugger(print) Literal:Numeric') do
tc << {:cmd=>"p +0100", :exp=>'$3 = 64'}
tc << {:cmd=>"p 0x100", :exp=>'$4 = 256'}
tc << {:cmd=>"p 1_234", :exp=>'$5 = 1234'}
- tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000.to_s}"}
- tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000.to_s}"}
+ tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000}"}
+ tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000}"}
tc << {:cmd=>"p 3.14", :exp=>'$8 = 3.14'}
tc << {:cmd=>"p -12.3", :exp=>'$9 = -12.3'}
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index d633a09b2..fe311d830 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -442,7 +442,7 @@ main(int argc, char **argv)
char_index = 0;
while ((last_char = getchar()) != '\n') {
if (last_char == EOF) break;
- if (char_index > sizeof(last_code_line)-2) {
+ if (char_index >= sizeof(last_code_line)-2) {
fputs("input string too long\n", stderr);
continue;
}
diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake
index 73f971a91..66d6ef80b 100644
--- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake
+++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake
@@ -23,7 +23,7 @@ MRuby.each_target do
FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name
config = Hash[open("#{build_dir}/lib/libmruby.flags.mak").read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}]
IO.write(t.name, File.open(t.name) {|f|
- f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"}
+ f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"}
})
FileUtils.chmod(0755, t.name)
end
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config b/mrbgems/mruby-bin-mruby-config/mruby-config
index fcc3fabe3..57346c03f 100644
--- a/mrbgems/mruby-bin-mruby-config/mruby-config
+++ b/mrbgems/mruby-bin-mruby-config/mruby-config
@@ -6,12 +6,14 @@ while [ $# -gt 0 ]; do
--ldflags) echo MRUBY_LDFLAGS;;
--ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;;
--libs) echo MRUBY_LIBS;;
+ --libmruby-path) echo MRUBY_LIBMRUBY_PATH;;
--help) echo "Usage: mruby-config [switches]"
echo " switches:"
echo " --cflags print flags passed to compiler"
echo " --ldflags print flags passed to linker"
- echo " --ldflags-before-libs print flags passwd to linker before linked libraries"
+ echo " --ldflags-before-libs print flags passed to linker before linked libraries"
echo " --libs print linked libraries"
+ echo " --libmruby-path print libmruby path"
exit 0;;
esac
shift
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/mrbgems/mruby-bin-mruby-config/mruby-config.bat
index 212dbdd77..a1f7bfdd1 100644
--- a/mrbgems/mruby-bin-mruby-config/mruby-config.bat
+++ b/mrbgems/mruby-bin-mruby-config/mruby-config.bat
@@ -7,6 +7,7 @@ if "%0" equ "--cflags" goto cflags
if "%0" equ "--ldflags" goto ldflags
if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs
if "%0" equ "--libs" goto libs
+if "%0" equ "--libmruby-path" goto libmrubypath
if "%0" equ "--help" goto showhelp
echo Invalid Option
goto :eof
@@ -27,10 +28,15 @@ goto top
echo MRUBY_LDFLAGS_BEFORE_LIBS
goto top
+:libmrubypath
+echo MRUBY_LIBMRUBY_PATH
+goto top
+
:showhelp
echo Usage: mruby-config [switches]
echo switches:
echo --cflags print flags passed to compiler
echo --ldflags print flags passed to linker
-echo --ldflags-before-libs print flags passwd to linker before linked libraries
+echo --ldflags-before-libs print flags passed to linker before linked libraries
echo --libs print linked libraries
+echo --libmruby-path print libmruby path
diff --git a/mrbgems/mruby-bin-mruby/mrbgem.rake b/mrbgems/mruby-bin-mruby/mrbgem.rake
index 243b413eb..fbec13847 100644
--- a/mrbgems/mruby-bin-mruby/mrbgem.rake
+++ b/mrbgems/mruby-bin-mruby/mrbgem.rake
@@ -7,7 +7,6 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec|
spec.add_dependency('mruby-error', :core => 'mruby-error')
if build.cxx_exception_enabled?
- @objs << build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
- @objs.delete_if { |v| v == objfile("#{spec.build_dir}/tools/mruby/mruby") }
+ build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
end
end
diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
index d0e5dc8dc..61d4cde94 100644
--- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
+++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
@@ -236,7 +236,10 @@ main(int argc, char **argv)
mrb_gc_arena_restore(mrb, ai);
mrbc_context_free(mrb, c);
if (mrb->exc) {
- if (!mrb_undef_p(v)) {
+ if (mrb_undef_p(v)) {
+ mrb_p(mrb, mrb_obj_value(mrb->exc));
+ }
+ else {
mrb_print_error(mrb);
}
n = -1;
diff --git a/mrbgems/mruby-class-ext/src/class.c b/mrbgems/mruby-class-ext/src/class.c
index 8ca7d66c2..5506c4829 100644
--- a/mrbgems/mruby-class-ext/src/class.c
+++ b/mrbgems/mruby-class-ext/src/class.c
@@ -9,12 +9,19 @@ mrb_mod_name(mrb_state *mrb, mrb_value self)
return mrb_nil_p(name)? name : mrb_str_dup(mrb, name);
}
+static mrb_value
+mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self)
+{
+ return mrb_bool_value(mrb_type(self) == MRB_TT_SCLASS);
+}
+
void
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
{
struct RClass *mod = mrb->module_class;
mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
}
void
diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb
index f721ad0c6..65abde108 100644
--- a/mrbgems/mruby-class-ext/test/module.rb
+++ b/mrbgems/mruby-class-ext/test/module.rb
@@ -1,10 +1,34 @@
assert 'Module#name' do
- module A
- class B
- end
+ module Outer
+ class Inner; end
+ const_set :SetInner, Class.new
end
- assert_nil A::B.singleton_class.name
- assert_equal 'Fixnum', Fixnum.name
- assert_equal 'A::B', A::B.name
+ assert_equal 'Outer', Outer.name
+ assert_equal 'Outer::Inner', Outer::Inner.name
+ assert_equal 'Outer::SetInner', Outer::SetInner.name
+
+ outer = Module.new do
+ const_set :SetInner, Class.new
+ end
+ Object.const_set :SetOuter, outer
+
+ assert_equal 'SetOuter', SetOuter.name
+ assert_equal 'SetOuter::SetInner', SetOuter::SetInner.name
+
+ mod = Module.new
+ cls = Class.new
+
+ assert_nil mod.name
+ assert_nil cls.name
+end
+
+assert 'Module#singleton_class?' do
+ mod = Module.new
+ cls = Class.new
+ scl = cls.singleton_class
+
+ assert_false mod.singleton_class?
+ assert_false cls.singleton_class?
+ assert_true scl.singleton_class?
end
diff --git a/mrbgems/mruby-compiler/bintest/mrbc.rb b/mrbgems/mruby-compiler/bintest/mrbc.rb
index e27365edb..f4d9208b3 100644
--- a/mrbgems/mruby-compiler/bintest/mrbc.rb
+++ b/mrbgems/mruby-compiler/bintest/mrbc.rb
@@ -19,3 +19,12 @@ assert('parsing function with void argument') do
assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp
assert_equal 0, $?.exitstatus
end
+
+assert('embedded document with invalid terminator') do
+ a, out = Tempfile.new('a.rb'), Tempfile.new('out.mrb')
+ a.write("=begin\n=endx\n")
+ a.flush
+ result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} 2>&1`
+ assert_equal "#{a.path}:3:0: embedded document meets end of file", result.chomp
+ assert_equal 1, $?.exitstatus
+end
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 64f4702a7..a1045c38c 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -19,6 +19,10 @@
#include <mruby/re.h>
#include <mruby/throw.h>
+#ifndef MRB_CODEGEN_LEVEL_MAX
+#define MRB_CODEGEN_LEVEL_MAX 1024
+#endif
+
typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
@@ -73,6 +77,8 @@ typedef struct scope {
int debug_start_pos;
uint16_t filename_index;
parser_state* parser;
+
+ int rlev; /* recursion levels */
} codegen_scope;
static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
@@ -956,7 +962,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
int type = (intptr_t)tree->car;
tree = tree->cdr;
- switch ((intptr_t)type) {
+ switch (type) {
case NODE_GVAR:
idx = new_sym(s, sym(tree));
genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
@@ -1006,8 +1012,10 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
break;
case NODE_CALL:
+ case NODE_SCALL:
push();
- gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL, 0);
+ gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL,
+ type == NODE_SCALL);
pop();
if (val) {
genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val);
@@ -1024,7 +1032,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
default:
#ifndef MRB_DISABLE_STDIO
- printf("unknown lhs %d\n", type);
+ fprintf(stderr, "unknown lhs %d\n", type);
#endif
break;
}
@@ -1241,6 +1249,7 @@ static void
codegen(codegen_scope *s, node *tree, int val)
{
int nt;
+ int rlev = s->rlev;
if (!tree) {
if (val) {
@@ -1250,6 +1259,10 @@ codegen(codegen_scope *s, node *tree, int val)
return;
}
+ s->rlev++;
+ if (s->rlev > MRB_CODEGEN_LEVEL_MAX) {
+ codegen_error(s, "too complex expression");
+ }
if (s->irep && s->filename_index != tree->filename_index) {
s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
@@ -1278,7 +1291,7 @@ codegen(codegen_scope *s, node *tree, int val)
int onerr, noexc, exend, pos1, pos2, tmp;
struct loopinfo *lp;
- if (tree->car == NULL) return;
+ if (tree->car == NULL) goto exit;
onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
lp = loop_push(s, LOOP_BEGIN);
lp->pc1 = onerr;
@@ -1383,7 +1396,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_LAMBDA:
- {
+ if (val) {
int idx = lambda_body(s, tree, 1);
genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA));
@@ -1392,7 +1405,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_BLOCK:
- {
+ if (val) {
int idx = lambda_body(s, tree, 1);
genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK));
@@ -1407,18 +1420,18 @@ codegen(codegen_scope *s, node *tree, int val)
if (!tree->car) {
codegen(s, e, val);
- return;
+ goto exit;
}
switch ((intptr_t)tree->car->car) {
case NODE_TRUE:
case NODE_INT:
case NODE_STR:
codegen(s, tree->cdr->car, val);
- return;
+ goto exit;
case NODE_FALSE:
case NODE_NIL:
codegen(s, e, val);
- return;
+ goto exit;
}
codegen(s, tree->car, VAL);
pop();
@@ -1879,7 +1892,7 @@ codegen(codegen_scope *s, node *tree, int val)
gen_assignment(s, tree->car, cursp(), val);
}
dispatch(s, pos);
- return;
+ goto exit;
}
codegen(s, tree->cdr->cdr->car, VAL);
push(); pop();
@@ -1937,9 +1950,19 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_SUPER:
{
+ codegen_scope *s2 = s;
+ int lv = 0;
int n = 0, noop = 0, sendv = 0;
push(); /* room for receiver */
+ while (!s2->mscope) {
+ lv++;
+ s2 = s2->prev;
+ if (!s2) break;
+ }
+ genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf)));
+ push(); push(); /* ARGARY pushes two values */
+ pop(); pop();
if (tree) {
node *args = tree->car;
if (args) {
@@ -2017,7 +2040,6 @@ codegen(codegen_scope *s, node *tree, int val)
if (!s2) break;
}
if (s2) ainfo = s2->ainfo;
- genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
push();
if (tree) {
n = gen_values(s, tree, VAL, 0);
@@ -2027,6 +2049,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
}
pop_n(n+1);
+ genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
if (sendv) n = CALL_MAXARGS;
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
if (val) push();
@@ -2195,11 +2218,11 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_NTH_REF:
if (val) {
mrb_state *mrb = s->mrb;
- char buf[32];
+ mrb_value str;
int sym;
- snprintf(buf, sizeof(buf), "$%" MRB_PRId, (mrb_int)(intptr_t)tree);
- sym = new_sym(s, mrb_intern_cstr(mrb, buf));
+ str = mrb_format(mrb, "$%S", mrb_fixnum_value((mrb_int)(intptr_t)tree));
+ sym = new_sym(s, mrb_intern_str(mrb, str));
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
push();
}
@@ -2377,9 +2400,7 @@ codegen(codegen_scope *s, node *tree, int val)
int ai = mrb_gc_arena_save(s->mrb);
int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
- if (val == NOVAL) { push(); }
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop(s, MKOP_A(OP_LOADSELF, cursp()));
push();
codegen(s, tree->car, VAL);
n = tree->cdr;
@@ -2394,12 +2415,11 @@ codegen(codegen_scope *s, node *tree, int val)
push();
n = n->cdr;
}
- pop();
- pop();
+ push(); /* for block */
+ pop_n(3);
sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
- if (val == NOVAL) { pop(); }
- else { push(); }
+ if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
}
break;
@@ -2409,19 +2429,17 @@ codegen(codegen_scope *s, node *tree, int val)
char *p = (char*)tree->car;
size_t len = (intptr_t)tree->cdr;
int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
int off = new_lit(s, mrb_str_new(s->mrb, p, len));
+ int sym;
- if (val == NOVAL) { push(); }
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop(s, MKOP_A(OP_LOADSELF, cursp()));
push();
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- pop();
+ push(); push();
+ pop_n(3);
sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
- if (val == NOVAL) { pop(); }
- else { push(); }
+ if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
}
break;
@@ -2588,7 +2606,8 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
push();
genop(s, MKOP_A(OP_LOADNIL, cursp()));
- pop_n(3);
+ push();
+ pop_n(4);
genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
if (val) {
push();
@@ -2756,6 +2775,8 @@ codegen(codegen_scope *s, node *tree, int val)
default:
break;
}
+ exit:
+ s->rlev = rlev;
}
static void
@@ -2847,6 +2868,8 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->parser = prev->parser;
p->filename_index = prev->filename_index;
+ p->rlev = prev->rlev+1;
+
return p;
}
@@ -2925,7 +2948,7 @@ loop_break(codegen_scope *s, node *tree)
genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
loop = loop->prev;
}
- while (loop && loop->type == LOOP_RESCUE) {
+ while (loop && (loop->type == LOOP_RESCUE || loop->type == LOOP_BEGIN)) {
loop = loop->prev;
}
if (!loop) {
@@ -2957,10 +2980,10 @@ loop_break(codegen_scope *s, node *tree)
static void
loop_pop(codegen_scope *s, int val)
{
- dispatch_linked(s, s->loop->pc3);
if (val) {
genop(s, MKOP_A(OP_LOADNIL, cursp()));
}
+ dispatch_linked(s, s->loop->pc3);
s->loop = s->loop->prev;
if (val) push();
}
@@ -2970,6 +2993,7 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
{
codegen_scope *scope = scope_new(mrb, 0, 0);
struct RProc *proc;
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
if (!scope) {
return NULL;
@@ -2980,16 +3004,20 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
scope->filename_index = p->current_filename_index;
MRB_TRY(&scope->jmp) {
+ mrb->jmp = &scope->jmp;
/* prepare irep */
codegen(scope, p->tree, NOVAL);
proc = mrb_proc_new(mrb, scope->irep);
mrb_irep_decref(mrb, scope->irep);
mrb_pool_close(scope->mpool);
+ proc->c = NULL;
+ mrb->jmp = prev_jmp;
return proc;
}
MRB_CATCH(&scope->jmp) {
mrb_irep_decref(mrb, scope->irep);
mrb_pool_close(scope->mpool);
+ mrb->jmp = prev_jmp;
return NULL;
}
MRB_END_EXC(&scope->jmp);
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 226701b52..5d5ef297c 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -356,6 +356,7 @@ new_alias(parser_state *p, mrb_sym a, mrb_sym b)
static node*
new_if(parser_state *p, node *a, node *b, node *c)
{
+ void_expr_error(p, a);
return list4((node*)NODE_IF, a, b, c);
}
@@ -363,6 +364,7 @@ new_if(parser_state *p, node *a, node *b, node *c)
static node*
new_unless(parser_state *p, node *a, node *b, node *c)
{
+ void_expr_error(p, a);
return list4((node*)NODE_IF, a, c, b);
}
@@ -370,6 +372,7 @@ new_unless(parser_state *p, node *a, node *b, node *c)
static node*
new_while(parser_state *p, node *a, node *b)
{
+ void_expr_error(p, a);
return cons((node*)NODE_WHILE, cons(a, b));
}
@@ -377,6 +380,7 @@ new_while(parser_state *p, node *a, node *b)
static node*
new_until(parser_state *p, node *a, node *b)
{
+ void_expr_error(p, a);
return cons((node*)NODE_UNTIL, cons(a, b));
}
@@ -384,6 +388,7 @@ new_until(parser_state *p, node *a, node *b)
static node*
new_for(parser_state *p, node *v, node *o, node *b)
{
+ void_expr_error(p, o);
return list4((node*)NODE_FOR, v, o, b);
}
@@ -394,6 +399,7 @@ new_case(parser_state *p, node *a, node *b)
node *n = list2((node*)NODE_CASE, a);
node *n2 = n;
+ void_expr_error(p, a);
while (n2->cdr) {
n2 = n2->cdr;
}
@@ -420,6 +426,7 @@ static node*
new_call(parser_state *p, node *a, mrb_sym b, node *c, int pass)
{
node *n = list4(nint(pass?NODE_CALL:NODE_SCALL), a, nsym(b), c);
+ void_expr_error(p, a);
NODE_LINENO(n, a);
return n;
}
@@ -515,6 +522,7 @@ new_dot3(parser_state *p, node *a, node *b)
static node*
new_colon2(parser_state *p, node *b, mrb_sym c)
{
+ void_expr_error(p, b);
return cons((node*)NODE_COLON2, cons(b, nsym(c)));
}
@@ -622,6 +630,7 @@ new_undef(parser_state *p, mrb_sym sym)
static node*
new_class(parser_state *p, node *c, node *s, node *b)
{
+ void_expr_error(p, s);
return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b));
}
@@ -629,6 +638,7 @@ new_class(parser_state *p, node *c, node *s, node *b)
static node*
new_sclass(parser_state *p, node *o, node *b)
{
+ void_expr_error(p, o);
return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b));
}
@@ -650,6 +660,7 @@ new_def(parser_state *p, mrb_sym m, node *a, node *b)
static node*
new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b)
{
+ void_expr_error(p, o);
return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b);
}
@@ -702,6 +713,7 @@ new_lambda(parser_state *p, node *a, node *b)
static node*
new_asgn(parser_state *p, node *a, node *b)
{
+ void_expr_error(p, b);
return cons((node*)NODE_ASGN, cons(a, b));
}
@@ -709,6 +721,7 @@ new_asgn(parser_state *p, node *a, node *b)
static node*
new_masgn(parser_state *p, node *a, node *b)
{
+ void_expr_error(p, b);
return cons((node*)NODE_MASGN, cons(a, b));
}
@@ -716,6 +729,7 @@ new_masgn(parser_state *p, node *a, node *b)
static node*
new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
{
+ void_expr_error(p, b);
return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
}
@@ -835,6 +849,7 @@ new_symbols(parser_state *p, node *a)
static node*
call_uni_op(parser_state *p, node *recv, const char *m)
{
+ void_expr_error(p, recv);
return new_call(p, recv, intern_cstr(m), 0, 1);
}
@@ -1404,7 +1419,6 @@ expr_value : expr
{
if (!$1) $$ = new_nil(p);
else {
- void_expr_error(p, $1);
$$ = $1;
}
}
@@ -1416,6 +1430,9 @@ command_call : command
block_command : block_call
| block_call call_op2 operation2 command_args
+ {
+ $$ = new_call(p, $1, $3, $4, $2);
+ }
;
cmd_brace_block : tLBRACE_ARG
@@ -1661,6 +1678,7 @@ cpath : tCOLON3 cname
}
| primary_value tCOLON2 cname
{
+ void_expr_error(p, $1);
$$ = cons($1, nsym($3));
}
;
@@ -1931,12 +1949,12 @@ aref_args : none
arg_rhs : arg %prec tOP_ASGN
{
- void_expr_error(p, $1);
$$ = $1;
}
| arg modifier_rescue arg
{
void_expr_error(p, $1);
+ void_expr_error(p, $3);
$$ = new_mod_rescue(p, $1, $3);
}
;
@@ -1972,6 +1990,7 @@ opt_call_args : none
call_args : command
{
+ void_expr_error(p, $1);
$$ = cons(list1($1), 0);
NODE_LINENO($$, $1);
}
@@ -3112,12 +3131,14 @@ f_opt_asgn : tIDENTIFIER '='
f_opt : f_opt_asgn arg
{
+ void_expr_error(p, $2);
$$ = cons(nsym($1), $2);
}
;
f_block_opt : f_opt_asgn primary_value
{
+ void_expr_error(p, $2);
$$ = cons(nsym($1), $2);
}
;
@@ -3230,22 +3251,28 @@ assocs : assoc
assoc : arg tASSOC arg
{
+ void_expr_error(p, $1);
+ void_expr_error(p, $3);
$$ = cons($1, $3);
}
| tLABEL arg
{
+ void_expr_error(p, $2);
$$ = cons(new_sym(p, $1), $2);
}
| tLABEL_END arg
{
+ void_expr_error(p, $2);
$$ = cons(new_sym(p, new_strsym(p, $1)), $2);
}
| tSTRING_BEG tLABEL_END arg
{
+ void_expr_error(p, $3);
$$ = cons(new_sym(p, new_strsym(p, $2)), $3);
}
| tSTRING_BEG string_rep tLABEL_END arg
{
+ void_expr_error(p, $4);
$$ = cons(new_dsym(p, push($2, $3)), $4);
}
;
@@ -3441,6 +3468,19 @@ void_expr_error(parser_state *p, node *n)
case NODE_RETRY:
yyerror(p, "void value expression");
break;
+ case NODE_AND:
+ case NODE_OR:
+ void_expr_error(p, n->cdr->car);
+ void_expr_error(p, n->cdr->cdr);
+ break;
+ case NODE_BEGIN:
+ if (n->cdr) {
+ while (n->cdr) {
+ n = n->cdr;
+ }
+ void_expr_error(p, n->car);
+ }
+ break;
default:
break;
}
@@ -3580,7 +3620,7 @@ skips(parser_state *p, const char *s)
/* skip until first char */
for (;;) {
c = nextc(p);
- if (c < 0) return c;
+ if (c < 0) return FALSE;
if (c == '\n') {
p->lineno++;
p->column = 0;
@@ -5514,10 +5554,11 @@ void mrb_parser_dump(mrb_state *mrb, node *tree, int offset);
MRB_API void
mrb_parser_parse(parser_state *p, mrbc_context *c)
{
- struct mrb_jmpbuf buf;
- p->jmp = &buf;
+ struct mrb_jmpbuf buf1;
+ p->jmp = &buf1;
MRB_TRY(p->jmp) {
+ int n = 1;
p->cmd_start = TRUE;
p->in_def = p->in_single = 0;
@@ -5525,7 +5566,24 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
p->lex_strterm = NULL;
parser_init_cxt(p, c);
- if (yyparse(p) != 0 || p->nerr > 0) {
+
+ if (p->mrb->jmp) {
+ n = yyparse(p);
+ }
+ else {
+ struct mrb_jmpbuf buf2;
+
+ p->mrb->jmp = &buf2;
+ MRB_TRY(p->mrb->jmp) {
+ n = yyparse(p);
+ }
+ MRB_CATCH(p->mrb->jmp) {
+ p->nerr++;
+ }
+ MRB_END_EXC(p->mrb->jmp);
+ p->mrb->jmp = 0;
+ }
+ if (n != 0 || p->nerr > 0) {
p->tree = 0;
return;
}
@@ -5536,7 +5594,6 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
if (c && c->dump_result) {
mrb_parser_dump(p->mrb, p->tree, 0);
}
-
}
MRB_CATCH(p->jmp) {
yyerror(p, "memory allocation error");
@@ -5720,6 +5777,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
return mrb_undef_value();
}
if (!p->tree || p->nerr) {
+ c->parser_nerr = p->nerr;
if (p->capture_errors) {
char buf[256];
int n;
@@ -5731,7 +5789,9 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
return mrb_undef_value();
}
else {
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
+ if (mrb->exc == NULL) {
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
+ }
mrb_parser_free(p);
return mrb_undef_value();
}
@@ -5739,7 +5799,9 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
proc = mrb_generate_code(mrb, p);
mrb_parser_free(p);
if (proc == NULL) {
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
+ if (mrb->exc == NULL) {
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
+ }
return mrb_undef_value();
}
if (c) {
diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index 7e101cf65..7741e515d 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -201,7 +201,7 @@ module Enumerable
ary.push([block.call(e), i])
}
if ary.size > 1
- __sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1) do |a,b|
+ __sort_sub__(ary, 0, ary.size - 1) do |a,b|
a <=> b
end
end
diff --git a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
index b650072e2..8a7ac7fdc 100644
--- a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
+++ b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
@@ -69,7 +69,7 @@ class Enumerator
def reject(&block)
Lazy.new(self){|yielder, val|
- if not block.call(val)
+ unless block.call(val)
yielder << val
end
}
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
index c7b78be5c..a60f19aaf 100644
--- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -612,7 +612,7 @@ module Kernel
def to_enum(meth=:each, *args)
Enumerator.new self, meth, *args
end
- alias :enum_for :to_enum
+ alias enum_for to_enum
end
module Enumerable
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index 5e8952f0d..146c6df08 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -4,6 +4,7 @@
#include <mruby/irep.h>
#include <mruby/proc.h>
#include <mruby/opcode.h>
+#include <mruby/error.h>
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
@@ -30,7 +31,7 @@ get_closure_irep(mrb_state *mrb, int level)
if (!e) return NULL;
if (!MRB_ENV_STACK_SHARED_P(e)) return NULL;
-
+ c = e->cxt.c;
proc = c->cibase[e->cioff].proc;
if (!proc || MRB_PROC_CFUNC_P(proc)) {
@@ -39,6 +40,25 @@ get_closure_irep(mrb_state *mrb, int level)
return proc->body.irep;
}
+/* search for irep lev above the bottom */
+static mrb_irep*
+search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
+{
+ size_t i;
+
+ for (i=0; i<top->rlen; i++) {
+ mrb_irep* tmp = top->reps[i];
+
+ if (tmp == bottom) return top;
+ tmp = search_irep(tmp, bnest-1, lev, bottom);
+ if (tmp) {
+ if (bnest == lev) return top;
+ return tmp;
+ }
+ }
+ return NULL;
+}
+
static inline mrb_code
search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
{
@@ -60,6 +80,20 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
return 0;
}
+static int
+irep_argc(mrb_irep *irep)
+{
+ mrb_code c;
+
+ c = irep->iseq[0];
+ if (GET_OPCODE(c) == OP_ENTER) {
+ mrb_aspec ax = GETARG_Ax(c);
+ /* extra 1 means a slot for block */
+ return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
+ }
+ return 0;
+}
+
static mrb_bool
potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
{
@@ -70,32 +104,24 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
}
static void
-patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
+patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
{
size_t i;
mrb_code c;
- int argc = 0;
+ int argc = irep_argc(irep);
for (i = 0; i < irep->ilen; i++) {
c = irep->iseq[i];
switch(GET_OPCODE(c)){
- case OP_ENTER:
- {
- mrb_aspec ax = GETARG_Ax(c);
- /* extra 1 means a slot for block */
- argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
- }
- break;
-
case OP_EPUSH:
- patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1);
+ patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top);
break;
case OP_LAMBDA:
{
int arg_c = GETARG_c(c);
if (arg_c & OP_L_CAPTURE) {
- patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1);
+ patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top);
}
}
break;
@@ -132,6 +158,34 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
}
break;
+ case OP_GETUPVAR:
+ {
+ int lev = GETARG_C(c)+1;
+ mrb_irep *tmp = search_irep(top, bnest, lev, irep);
+ if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
+ mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
+ if (arg != 0) {
+ /* must replace */
+ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ }
+ }
+ }
+ break;
+
+ case OP_SETUPVAR:
+ {
+ int lev = GETARG_C(c)+1;
+ mrb_irep *tmp = search_irep(top, bnest, lev, irep);
+ if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
+ mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
+ if (arg != 0) {
+ /* must replace */
+ irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ }
+ }
+ }
+ break;
+
case OP_STOP:
if (mrb->c->ci->acc >= 0) {
irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL);
@@ -159,10 +213,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
cxt = mrbc_context_new(mrb);
cxt->lineno = line;
- if (!file) {
- file = "(eval)";
- }
- mrbc_filename(mrb, cxt, file);
+ mrbc_filename(mrb, cxt, file ? file : "(eval)");
cxt->capture_errors = TRUE;
cxt->no_optimize = TRUE;
@@ -175,12 +226,22 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
if (0 < p->nerr) {
/* parse error */
- char buf[256];
- int n;
- n = snprintf(buf, sizeof(buf), "line %d: %s\n", p->error_buffer[0].lineno, p->error_buffer[0].message);
+ mrb_value str;
+
+ if (file) {
+ str = mrb_format(mrb, " file %S line %S: %S",
+ mrb_str_new_cstr(mrb, file),
+ mrb_fixnum_value(p->error_buffer[0].lineno),
+ mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+ }
+ else {
+ str = mrb_format(mrb, " line %S: %S",
+ mrb_fixnum_value(p->error_buffer[0].lineno),
+ mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+ }
mrb_parser_free(p);
mrbc_context_free(mrb, cxt);
- mrb_exc_raise(mrb, mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+ mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str));
}
proc = mrb_generate_code(mrb, p);
@@ -196,14 +257,15 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
e = c->ci[-1].proc->env;
if (!e) e = c->ci[-1].env;
e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e);
- e->mid = c->ci[-1].mid;
- e->cioff = c->ci - c->cibase - 1;
+ e->cxt.c = c;
+ e->cioff = c->ci - c->cibase;
e->stack = c->ci->stackent;
- MRB_SET_ENV_STACK_LEN(e, c->ci[-1].proc->body.irep->nlocals);
+ MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals);
c->ci->target_class = proc->target_class;
c->ci->env = 0;
proc->env = e;
- patch_irep(mrb, proc->body.irep, 0);
+ patch_irep(mrb, proc->body.irep, 0, proc->body.irep);
+ /* mrb_codedump_all(mrb, proc); */
mrb_parser_free(p);
mrbc_context_free(mrb, cxt);
@@ -247,7 +309,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
mrb_value b;
mrb_int argc; mrb_value *argv;
- mrb_get_args(mrb, "*&", &argv, &argc, &b);
+ mrb_get_args(mrb, "*!&", &argv, &argc, &b);
if (mrb_nil_p(b)) {
char *s;
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c
index 232c925d3..9de175f34 100644
--- a/mrbgems/mruby-fiber/src/fiber.c
+++ b/mrbgems/mruby-fiber/src/fiber.c
@@ -74,6 +74,9 @@ fiber_init(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "&", &blk);
+ if (f->cxt) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice");
+ }
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block");
}
@@ -82,9 +85,9 @@ fiber_init(mrb_state *mrb, mrb_value self)
mrb_raise(mrb, E_FIBER_ERROR, "tried to create Fiber from C defined method");
}
- f->cxt = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
- *f->cxt = mrb_context_zero;
- c = f->cxt;
+ c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
+ *c = mrb_context_zero;
+ f->cxt = c;
/* initialize VM stack */
slen = FIBER_STACK_INIT_SIZE;
@@ -122,6 +125,7 @@ fiber_init(mrb_state *mrb, mrb_value self)
ci = c->ci;
ci->target_class = p->target_class;
ci->proc = p;
+ mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p);
ci->pc = p->body.irep->iseq;
ci->nregs = p->body.irep->nregs;
ci[1] = ci[0];
@@ -168,6 +172,16 @@ fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c)
}
}
+static void
+fiber_switch_context(mrb_state *mrb, struct mrb_context *c)
+{
+ if (mrb->c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib);
+ }
+ c->status = MRB_FIBER_RUNNING;
+ mrb->c = c;
+}
+
static mrb_value
fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec)
{
@@ -188,9 +202,13 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
if (c->status == MRB_FIBER_CREATED) {
- mrb_value *b = c->stack+1;
- mrb_value *e = b + len;
+ mrb_value *b, *e;
+ if (len >= c->stend - c->stack) {
+ mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber");
+ }
+ b = c->stack+1;
+ e = b + len;
while (b<e) {
*b++ = *a++;
}
@@ -200,9 +218,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
else {
value = fiber_result(mrb, a, len);
}
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
- c->status = MRB_FIBER_RUNNING;
- mrb->c = c;
+ fiber_switch_context(mrb, c);
if (vmexec) {
c->vmexec = TRUE;
@@ -237,7 +253,7 @@ fiber_resume(mrb_state *mrb, mrb_value self)
mrb_int len;
mrb_bool vmexec = FALSE;
- mrb_get_args(mrb, "*", &a, &len);
+ mrb_get_args(mrb, "*!", &a, &len);
if (mrb->c->ci->acc < 0) {
vmexec = TRUE;
}
@@ -297,14 +313,12 @@ fiber_transfer(mrb_state *mrb, mrb_value self)
mrb_int len;
fiber_check_cfunc(mrb, mrb->c);
- mrb_get_args(mrb, "*", &a, &len);
+ mrb_get_args(mrb, "*!", &a, &len);
if (c == mrb->root_c) {
mrb->c->status = MRB_FIBER_TRANSFERRED;
- mrb->c = c;
- c->status = MRB_FIBER_RUNNING;
+ fiber_switch_context(mrb, c);
MARK_CONTEXT_MODIFY(c);
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
return fiber_result(mrb, a, len);
}
@@ -326,15 +340,15 @@ mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber");
}
+ fiber_check_cfunc(mrb, c);
c->prev->status = MRB_FIBER_RUNNING;
c->status = MRB_FIBER_SUSPENDED;
- mrb->c = c->prev;
+ fiber_switch_context(mrb, c->prev);
c->prev = NULL;
if (c->vmexec) {
c->vmexec = FALSE;
mrb->c->ci->acc = CI_ACC_RESUMED;
}
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
MARK_CONTEXT_MODIFY(mrb->c);
return fiber_result(mrb, a, len);
}
@@ -357,7 +371,7 @@ fiber_yield(mrb_state *mrb, mrb_value self)
mrb_value *a;
mrb_int len;
- mrb_get_args(mrb, "*", &a, &len);
+ mrb_get_args(mrb, "*!", &a, &len);
return mrb_fiber_yield(mrb, len, a);
}
diff --git a/mrbgems/mruby-hash-ext/mrbgem.rake b/mrbgems/mruby-hash-ext/mrbgem.rake
index f01033a6c..103410ab9 100644
--- a/mrbgems/mruby-hash-ext/mrbgem.rake
+++ b/mrbgems/mruby-hash-ext/mrbgem.rake
@@ -2,6 +2,7 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Hash class extension'
- spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
- spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext'
+ spec.add_dependency 'mruby-enum-ext', core: 'mruby-enum-ext'
+ spec.add_dependency 'mruby-array-ext', core: 'mruby-array-ext'
+ spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
end
diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
index 31ff6d685..87817f833 100644
--- a/mrbgems/mruby-hash-ext/mrblib/hash.rb
+++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb
@@ -382,4 +382,80 @@ class Hash
n
end
end
+
+ ##
+ # call-seq:
+ # hsh.transform_keys {|key| block } -> new_hash
+ # hsh.transform_keys -> an_enumerator
+ #
+ # Returns a new hash, with the keys computed from running the block
+ # once for each key in the hash, and the values unchanged.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ def transform_keys(&b)
+ return to_enum :transform_keys unless block_given?
+ hash = {}
+ self.keys.each do |k|
+ new_key = yield(k)
+ hash[new_key] = self[k]
+ end
+ hash
+ end
+ ##
+ # call-seq:
+ # hsh.transform_keys! {|key| block } -> hsh
+ # hsh.transform_keys! -> an_enumerator
+ #
+ # Invokes the given block once for each key in <i>hsh</i>, replacing it
+ # with the new key returned by the block, and then returns <i>hsh</i>.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ def transform_keys!(&b)
+ return to_enum :transform_keys! unless block_given?
+ self.keys.each do |k|
+ value = self[k]
+ new_key = yield(k)
+ self.__delete(k)
+ self[new_key] = value
+ end
+ self
+ end
+ ##
+ # call-seq:
+ # hsh.transform_values {|value| block } -> new_hash
+ # hsh.transform_values -> an_enumerator
+ #
+ # Returns a new hash with the results of running the block once for
+ # every value.
+ # This method does not change the keys.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ def transform_values(&b)
+ return to_enum :transform_values unless block_given?
+ hash = {}
+ self.keys.each do |k|
+ hash[k] = yield(self[k])
+ end
+ hash
+ end
+ ##
+ # call-seq:
+ # hsh.transform_values! {|key| block } -> hsh
+ # hsh.transform_values! -> an_enumerator
+ #
+ # Invokes the given block once for each value in the hash, replacing
+ # with the new value returned by the block, and then returns <i>hsh</i>.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ def transform_values!(&b)
+ return to_enum :transform_values! unless block_given?
+ self.keys.each do |k|
+ self[k] = yield(self[k])
+ end
+ self
+ end
end
diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c
index 9560829b6..61abc080d 100644
--- a/mrbgems/mruby-hash-ext/src/hash-ext.c
+++ b/mrbgems/mruby-hash-ext/src/hash-ext.c
@@ -26,7 +26,7 @@ hash_values_at(mrb_state *mrb, mrb_value hash)
mrb_int argc, i;
int ai;
- mrb_get_args(mrb, "*", &argv, &argc);
+ mrb_get_args(mrb, "*!", &argv, &argc);
result = mrb_ary_new_capa(mrb, argc);
ai = mrb_gc_arena_save(mrb);
for (i = 0; i < argc; i++) {
diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb
index 6e70953f5..2ae88c307 100644
--- a/mrbgems/mruby-hash-ext/test/hash.rb
+++ b/mrbgems/mruby-hash-ext/test/hash.rb
@@ -254,3 +254,27 @@ assert("Hash#dig") do
assert_equal(1, h.dig(:a, :b, :c))
assert_nil(h.dig(:d))
end
+
+assert("Hash#transform_keys") do
+ h = {"1" => 100, "2" => 200}
+ assert_equal(h.transform_keys{|k| k+"!"},
+ {"1!" => 100, "2!" => 200})
+ assert_equal(h.transform_keys{|k|k.to_i},
+ {1 => 100, 2 => 200})
+ assert_equal(h.transform_keys.with_index{|k, i| "#{k}.#{i}"},
+ {"1.0" => 100, "2.1" => 200})
+ assert_equal(h.transform_keys!{|k|k.to_i}, h)
+ assert_equal(h, {1 => 100, 2 => 200})
+end
+
+assert("Hash#transform_values") do
+ h = {a: 1, b: 2, c: 3}
+ assert_equal(h.transform_values{|v| v * v + 1},
+ {a: 2, b: 5, c: 10})
+ assert_equal(h.transform_values{|v|v.to_s},
+ {a: "1", b: "2", c: "3"})
+ assert_equal(h.transform_values.with_index{|v, i| "#{v}.#{i}"},
+ {a: "1.0", b: "2.1", c: "3.2"})
+ assert_equal(h.transform_values!{|v|v.to_s}, h)
+ assert_equal(h, {a: "1", b: "2", c: "3"})
+end
diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb
index 9828538f0..89cedaf27 100644
--- a/mrbgems/mruby-kernel-ext/test/kernel.rb
+++ b/mrbgems/mruby-kernel-ext/test/kernel.rb
@@ -20,13 +20,13 @@ assert('Kernel.caller, Kernel#caller') do
bar(*args)
end
end
- assert_equal "kernel.rb:#{caller_lineno}:in Object#foo", c.new.baz(0)[0][-26..-1]
- assert_equal "#bar", c.new.baz[0][-4..-1]
- assert_equal "#foo", c.new.baz(0)[0][-4..-1]
- assert_equal "#bar", c.new.baz(1)[0][-4..-1]
- assert_equal "#baz", c.new.baz(2)[0][-4..-1]
- assert_equal ["#foo", "#bar"], c.new.baz(0, 2).map { |i| i[-4..-1] }
- assert_equal ["#bar", "#baz"], c.new.baz(1..2).map { |i| i[-4..-1] }
+ assert_equal "kernel.rb:#{caller_lineno}:in foo", c.new.baz(0)[0][-19..-1]
+ assert_equal "bar", c.new.baz[0][-3..-1]
+ assert_equal "foo", c.new.baz(0)[0][-3..-1]
+ assert_equal "bar", c.new.baz(1)[0][-3..-1]
+ assert_equal "baz", c.new.baz(2)[0][-3..-1]
+ assert_equal ["foo", "bar"], c.new.baz(0, 2).map { |i| i[-3..-1] }
+ assert_equal ["bar", "baz"], c.new.baz(1..2).map { |i| i[-3..-1] }
assert_nil c.new.baz(10..20)
assert_raise(ArgumentError) { c.new.baz(-1) }
assert_raise(ArgumentError) { c.new.baz(-1, 1) }
diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c
index 8a2325ef9..35a07b584 100644
--- a/mrbgems/mruby-object-ext/src/object.c
+++ b/mrbgems/mruby-object-ext/src/object.c
@@ -1,6 +1,7 @@
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
+#include <mruby/proc.h>
/*
* call-seq:
@@ -66,7 +67,6 @@ mrb_obj_instance_exec(mrb_state *mrb, mrb_value self)
mrb_int argc;
mrb_value blk;
struct RClass *c;
- mrb_value args;
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
@@ -84,9 +84,8 @@ mrb_obj_instance_exec(mrb_state *mrb, mrb_value self)
c = mrb_class_ptr(mrb_singleton_class(mrb, self));
break;
}
- args = mrb_ary_new_from_values(mrb, argc, argv);
- argv = RARRAY_PTR(args);
- return mrb_yield_with_class(mrb, blk, argc, argv, self, c);
+ mrb->c->ci->target_class = c;
+ return mrb_yield_cont(mrb, blk, self, argc, argv);
}
void
diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
index d0a8effd0..3887091d3 100644
--- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c
+++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
@@ -9,7 +9,7 @@ struct os_count_struct {
mrb_int counts[MRB_TT_MAXDEFINE+1];
};
-static void
+static int
os_count_object_type(mrb_state *mrb, struct RBasic *obj, void *data)
{
struct os_count_struct *obj_count;
@@ -23,6 +23,7 @@ os_count_object_type(mrb_state *mrb, struct RBasic *obj, void *data)
else {
obj_count->counts[obj->tt]++;
}
+ return MRB_EACH_OBJ_OK;
}
/*
@@ -109,35 +110,36 @@ struct os_each_object_data {
mrb_int count;
};
-static void
+static int
os_each_object_cb(mrb_state *mrb, struct RBasic *obj, void *ud)
{
struct os_each_object_data *d = (struct os_each_object_data*)ud;
/* filter dead objects */
if (mrb_object_dead_p(mrb, obj)) {
- return;
+ return MRB_EACH_OBJ_OK;
}
/* filter internal objects */
switch (obj->tt) {
case MRB_TT_ENV:
case MRB_TT_ICLASS:
- return;
+ return MRB_EACH_OBJ_OK;
default:
break;
}
/* filter half baked (or internal) objects */
- if (!obj->c) return;
+ if (!obj->c) return MRB_EACH_OBJ_OK;
/* filter class kind if target module defined */
if (d->target_module && !mrb_obj_is_kind_of(mrb, mrb_obj_value(obj), d->target_module)) {
- return;
+ return MRB_EACH_OBJ_OK;
}
mrb_yield(mrb, d->block, mrb_obj_value(obj));
++d->count;
+ return MRB_EACH_OBJ_OK;
}
/*
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c
index f7f031e7b..b13606f5f 100644
--- a/mrbgems/mruby-proc-ext/src/proc.c
+++ b/mrbgems/mruby-proc-ext/src/proc.c
@@ -52,10 +52,7 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self)
line = mrb_debug_get_line(irep, 0);
if (line != -1) {
- char buf[32];
-
- snprintf(buf, sizeof(buf), "%" PRId32, line);
- mrb_str_cat_cstr(mrb, str, buf);
+ str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line));
}
else {
mrb_str_cat_lit(mrb, str, "-");
diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c
index f81d38fe6..b865244cc 100644
--- a/mrbgems/mruby-random/src/random.c
+++ b/mrbgems/mruby-random/src/random.c
@@ -217,13 +217,15 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
for (i = RARRAY_LEN(ary) - 1; i > 0; i--) {
mrb_int j;
+ mrb_value *ptr = RARRAY_PTR(ary);
mrb_value tmp;
+
j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary))));
- tmp = RARRAY_PTR(ary)[i];
- mrb_ary_ptr(ary)->ptr[i] = RARRAY_PTR(ary)[j];
- mrb_ary_ptr(ary)->ptr[j] = tmp;
+ tmp = ptr[i];
+ ptr[i] = ptr[j];
+ ptr[j] = tmp;
}
}
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c
index 3d96573a7..7b8201736 100644
--- a/mrbgems/mruby-sprintf/src/sprintf.c
+++ b/mrbgems/mruby-sprintf/src/sprintf.c
@@ -116,7 +116,6 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
#define CHECK(l) do {\
/* int cr = ENC_CODERANGE(result);*/\
- if ((l) < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "illegal specifier"); \
while ((l) >= bsiz - blen) {\
bsiz*=2;\
if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \
@@ -529,7 +528,6 @@ mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt)
mrb_int n;
mrb_int width;
mrb_int prec;
- int flags = FNONE;
int nextarg = 1;
int posarg = 0;
mrb_value nextvalue;
@@ -565,6 +563,7 @@ mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt)
for (; p < end; p++) {
const char *t;
mrb_sym id = 0;
+ int flags = FNONE;
for (t = p; t < end && *t != '%'; t++) ;
if (t + 1 == end) ++t;
@@ -702,35 +701,39 @@ retry:
tmp = mrb_check_string_type(mrb, val);
if (!mrb_nil_p(tmp)) {
- if (mrb_fixnum(mrb_funcall(mrb, tmp, "size", 0)) != 1 ) {
+ if (RSTRING_LEN(tmp) != 1) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
}
}
else if (mrb_fixnum_p(val)) {
- tmp = mrb_funcall(mrb, val, "chr", 0);
+ mrb_int n = mrb_fixnum(val);
+
+ if (n < 0x80) {
+ char buf[1];
+
+ buf[0] = (char)n;
+ tmp = mrb_str_new(mrb, buf, 1);
+ }
+ else {
+ tmp = mrb_funcall(mrb, val, "chr", 0);
+ mrb_check_type(mrb, tmp, MRB_TT_STRING);
+ }
}
else {
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
}
- mrb_check_type(mrb, tmp, MRB_TT_STRING);
c = RSTRING_PTR(tmp);
n = RSTRING_LEN(tmp);
if (!(flags & FWIDTH)) {
- CHECK(n);
- memcpy(buf+blen, c, n);
- blen += n;
+ PUSH(c, n);
}
else if ((flags & FMINUS)) {
- CHECK(n);
- memcpy(buf+blen, c, n);
- blen += n;
+ PUSH(c, n);
if (width>0) FILL(' ', width-1);
}
else {
if (width>0) FILL(' ', width-1);
- CHECK(n);
- memcpy(buf+blen, c, n);
- blen += n;
+ PUSH(c, n);
}
}
break;
@@ -768,19 +771,11 @@ retry:
if ((flags&FWIDTH) && (width > slen)) {
width -= (int)slen;
if (!(flags&FMINUS)) {
- CHECK(width);
- while (width-- > 0) {
- buf[blen++] = ' ';
- }
+ FILL(' ', width);
}
- CHECK(len);
- memcpy(&buf[blen], RSTRING_PTR(str), len);
- blen += len;
+ PUSH(RSTRING_PTR(str), len);
if (flags&FMINUS) {
- CHECK(width);
- while (width-- > 0) {
- buf[blen++] = ' ';
- }
+ FILL(' ', width);
}
break;
}
@@ -806,13 +801,6 @@ retry:
int base;
mrb_int len;
- switch (*p) {
- case 'd':
- case 'i':
- sign = 1; break;
- default:
- break;
- }
if (flags & FSHARP) {
switch (*p) {
case 'o': prefix = "0"; break;
@@ -853,21 +841,13 @@ retry:
case 'u':
case 'd':
case 'i':
+ sign = 1;
default:
base = 10; break;
}
- if (base == 2) {
- if (v < 0 && !sign) {
- val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
- dots = 1;
- }
- else {
- val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
- }
- }
if (sign) {
- if (v > 0) {
+ if (v >= 0) {
if (flags & FPLUS) {
sc = '+';
width--;
@@ -877,37 +857,33 @@ retry:
width--;
}
}
- switch (base) {
- case 2:
- strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf));
- break;
- case 8:
- snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIo, v);
- break;
- case 10:
- snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
- break;
- case 16:
- snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIx, v);
- break;
+ else {
+ sc = '-';
+ width--;
}
+ mrb_assert(base == 10);
+ snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
s = nbuf;
+ if (v < 0) s++; /* skip minus sign */
}
else {
s = nbuf;
- if (base != 10 && v < 0) {
+ if (v < 0) {
dots = 1;
}
switch (base) {
case 2:
+ if (v < 0) {
+ val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
+ }
+ else {
+ val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
+ }
strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1);
break;
case 8:
snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v);
break;
- case 10:
- snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRId, v);
- break;
case 16:
snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v);
break;
@@ -935,11 +911,6 @@ retry:
len = (mrb_int)size;
}
- if (dots) {
- prec -= 2;
- width -= 2;
- }
-
if (*p == 'X') {
char *pp = s;
int c;
@@ -986,10 +957,8 @@ retry:
}
if (!(flags&FMINUS) && width > 0) {
- CHECK(width);
- while (width-- > 0) {
- buf[blen++] = ' ';
- }
+ FILL(' ', width);
+ width = 0;
}
if (sc) PUSH(&sc, 1);
@@ -998,28 +967,25 @@ retry:
int plen = (int)strlen(prefix);
PUSH(prefix, plen);
}
- CHECK(prec - len);
- if (dots) PUSH("..", 2);
-
- if (v < 0) {
- char c = sign_bits(base, p);
- while (len < prec--) {
- buf[blen++] = c;
- }
+ if (dots) {
+ prec -= 2;
+ width -= 2;
+ PUSH("..", 2);
}
- else if ((flags & (FMINUS|FPREC)) != FMINUS) {
- char c = '0';
- while (len < prec--) {
- buf[blen++] = c;
+
+ if (prec > len) {
+ CHECK(prec - len);
+ if ((flags & (FMINUS|FPREC)) != FMINUS) {
+ char c = '0';
+ FILL(c, prec - len);
+ } else if (v < 0) {
+ char c = sign_bits(base, p);
+ FILL(c, prec - len);
}
}
-
PUSH(s, len);
if (width > 0) {
- CHECK(width);
- while (width-- > 0) {
- buf[blen++] = ' ';
- }
+ FILL(' ', width);
}
}
break;
@@ -1040,6 +1006,7 @@ retry:
if (!isfinite(fval)) {
const char *expr;
const int elen = 3;
+ char sign = '\0';
if (isnan(fval)) {
expr = "NaN";
@@ -1048,35 +1015,29 @@ retry:
expr = "Inf";
}
need = elen;
- if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS))
- need++;
+ if (!isnan(fval) && fval < 0.0)
+ sign = '-';
+ else if (flags & (FPLUS|FSPACE))
+ sign = (flags & FPLUS) ? '+' : ' ';
+ if (sign)
+ ++need;
if ((flags & FWIDTH) && need < width)
need = width;
- CHECK(need + 1);
- n = snprintf(&buf[blen], need + 1, "%*s", need, "");
- if (n < 0) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error");
+ if (need < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "width too big");
}
+ FILL(' ', need);
if (flags & FMINUS) {
- if (!isnan(fval) && fval < 0.0)
- buf[blen++] = '-';
- else if (flags & FPLUS)
- buf[blen++] = '+';
- else if (flags & FSPACE)
- blen++;
- memcpy(&buf[blen], expr, elen);
+ if (sign)
+ buf[blen - need--] = sign;
+ memcpy(&buf[blen - need], expr, elen);
}
else {
- if (!isnan(fval) && fval < 0.0)
- buf[blen + need - elen - 1] = '-';
- else if (flags & FPLUS)
- buf[blen + need - elen - 1] = '+';
- else if ((flags & FSPACE) && need > width)
- blen++;
- memcpy(&buf[blen + need - elen], expr, elen);
+ if (sign)
+ buf[blen - elen - 1] = sign;
+ memcpy(&buf[blen - elen], expr, elen);
}
- blen += strlen(&buf[blen]);
break;
}
@@ -1092,6 +1053,10 @@ retry:
if ((flags&FWIDTH) && need < width)
need = width;
need += 20;
+ if (need <= 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR,
+ (width > prec ? "width too big" : "prec too big"));
+ }
CHECK(need);
n = snprintf(&buf[blen], need, fbuf, fval);
diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb
index 178904d60..84dba9d19 100644
--- a/mrbgems/mruby-sprintf/test/sprintf.rb
+++ b/mrbgems/mruby-sprintf/test/sprintf.rb
@@ -8,6 +8,62 @@ assert('String#%') do
assert_equal 15, ("%b" % (1<<14)).size
end
+assert('String#% with inf') do
+ inf = Float::INFINITY
+
+ assert_equal "Inf", "%f" % inf
+ assert_equal "Inf", "%2f" % inf
+ assert_equal "Inf", "%3f" % inf
+ assert_equal " Inf", "%4f" % inf
+ assert_equal " Inf", "%5f" % inf
+
+ assert_equal "+Inf", "%+f" % inf
+ assert_equal "+Inf", "%+2f" % inf
+ assert_equal "+Inf", "%+3f" % inf
+ assert_equal "+Inf", "%+4f" % inf
+ assert_equal " +Inf", "%+5f" % inf
+
+ assert_equal "Inf", "%-f" % inf
+ assert_equal "Inf", "%-2f" % inf
+ assert_equal "Inf", "%-3f" % inf
+ assert_equal "Inf ", "%-4f" % inf
+ assert_equal "Inf ", "%-5f" % inf
+
+ assert_equal " Inf", "% f" % inf
+ assert_equal " Inf", "% 2f" % inf
+ assert_equal " Inf", "% 3f" % inf
+ assert_equal " Inf", "% 4f" % inf
+ assert_equal " Inf", "% 5f" % inf
+end
+
+assert('String#% with nan') do
+ nan = Float::NAN
+
+ assert_equal "NaN", "%f" % nan
+ assert_equal "NaN", "%2f" % nan
+ assert_equal "NaN", "%3f" % nan
+ assert_equal " NaN", "%4f" % nan
+ assert_equal " NaN", "%5f" % nan
+
+ assert_equal "+NaN", "%+f" % nan
+ assert_equal "+NaN", "%+2f" % nan
+ assert_equal "+NaN", "%+3f" % nan
+ assert_equal "+NaN", "%+4f" % nan
+ assert_equal " +NaN", "%+5f" % nan
+
+ assert_equal "NaN", "%-f" % nan
+ assert_equal "NaN", "%-2f" % nan
+ assert_equal "NaN", "%-3f" % nan
+ assert_equal "NaN ", "%-4f" % nan
+ assert_equal "NaN ", "%-5f" % nan
+
+ assert_equal " NaN", "% f" % nan
+ assert_equal " NaN", "% 2f" % nan
+ assert_equal " NaN", "% 3f" % nan
+ assert_equal " NaN", "% 4f" % nan
+ assert_equal " NaN", "% 5f" % nan
+end
+
assert("String#% with invalid chr") do
begin
class Fixnum
@@ -19,7 +75,7 @@ assert("String#% with invalid chr") do
end
assert_raise TypeError do
- "%c" % 0
+ "%c" % 0x80
end
ensure
class Fixnum
@@ -31,6 +87,16 @@ assert("String#% with invalid chr") do
end
end
+assert("String#% %b") do
+ assert_equal("..10115", "%0b5" % -5)
+end
+
+assert("String#% %d") do
+ assert_equal(" 10", "%4d" % 10)
+ assert_equal("1000", "%4d" % 1000)
+ assert_equal("100000", "%4d" % 100000)
+end
+
assert("String#% invalid format") do
assert_raise ArgumentError do
"%?" % ""
diff --git a/mrbgems/mruby-string-ext/mrbgem.rake b/mrbgems/mruby-string-ext/mrbgem.rake
index f2df5a783..9812f2cc9 100644
--- a/mrbgems/mruby-string-ext/mrbgem.rake
+++ b/mrbgems/mruby-string-ext/mrbgem.rake
@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-string-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'String class extension'
+ spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
end
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 15f0549f3..c3a7eb380 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -305,50 +305,6 @@ class String
padding + self
end
- # str.upto(other_str, exclusive=false) {|s| block } -> str
- # str.upto(other_str, exclusive=false) -> an_enumerator
- #
- # Iterates through successive values, starting at <i>str</i> and
- # ending at <i>other_str</i> inclusive, passing each value in turn to
- # the block. The <code>String#succ</code> method is used to generate
- # each value. If optional second argument exclusive is omitted or is false,
- # the last value will be included; otherwise it will be excluded.
- #
- # If no block is given, an enumerator is returned instead.
- #
- # "a8".upto("b6") {|s| print s, ' ' }
- # for s in "a8".."b6"
- # print s, ' '
- # end
- #
- # <em>produces:</em>
- #
- # a8 a9 b0 b1 b2 b3 b4 b5 b6
- # a8 a9 b0 b1 b2 b3 b4 b5 b6
- #
- # If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
- # both are recognized as decimal numbers. In addition, the width of
- # string (e.g. leading zeros) is handled appropriately.
- #
- # "9".upto("11").to_a #=> ["9", "10", "11"]
- # "25".upto("5").to_a #=> []
- # "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"]
- #
- def upto(other_str, excl=false, &block)
- return to_enum :upto, other_str, excl unless block
-
- str = self
- n = self.<=>other_str
- return self if n > 0 || (self == other_str && excl)
- while true
- block.call(str)
- return self if !excl && str == other_str
- str = str.succ
- return self if excl && str == other_str
- return self if str.size > other_str.size
- end
- end
-
def chars(&block)
if block_given?
self.split('').each do |i|
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 402dbf987..0d834b6ef 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -134,6 +134,8 @@ mrb_str_swapcase(mrb_state *mrb, mrb_value self)
return str;
}
+static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num);
+
/*
* call-seq:
* str << integer -> str
@@ -153,7 +155,12 @@ static mrb_value
mrb_str_concat2(mrb_state *mrb, mrb_value self)
{
mrb_value str;
- mrb_get_args(mrb, "S", &str);
+
+ mrb_get_args(mrb, "o", &str);
+ if (mrb_fixnum_p(str))
+ str = mrb_fixnum_chr(mrb, str);
+ else
+ str = mrb_string_type(mrb, str);
mrb_str_concat(mrb, self, str);
return self;
}
@@ -367,7 +374,7 @@ mrb_str_succ_bang(mrb_state *mrb, mrb_value self)
unsigned char *p, *e, *b, *t;
const char *prepend;
struct RString *s = mrb_str_ptr(self);
- size_t l;
+ mrb_int l;
if (RSTRING_LEN(self) == 0)
return self;
@@ -514,6 +521,135 @@ mrb_str_ord(mrb_state* mrb, mrb_value str)
}
#endif
+static mrb_bool
+all_digits_p(const char *s, mrb_int len)
+{
+ while (len-- > 0) {
+ if (!ISDIGIT(*s)) return FALSE;
+ s++;
+ }
+ return TRUE;
+}
+
+/*
+ * call-seq:
+ * str.upto(other_str, exclusive=false) {|s| block } -> str
+ * str.upto(other_str, exclusive=false) -> an_enumerator
+ *
+ * Iterates through successive values, starting at <i>str</i> and
+ * ending at <i>other_str</i> inclusive, passing each value in turn to
+ * the block. The <code>String#succ</code> method is used to generate
+ * each value. If optional second argument exclusive is omitted or is false,
+ * the last value will be included; otherwise it will be excluded.
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
+ * "a8".upto("b6") {|s| print s, ' ' }
+ * for s in "a8".."b6"
+ * print s, ' '
+ * end
+ *
+ * <em>produces:</em>
+ *
+ * a8 a9 b0 b1 b2 b3 b4 b5 b6
+ * a8 a9 b0 b1 b2 b3 b4 b5 b6
+ *
+ * If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
+ * both are recognized as decimal numbers. In addition, the width of
+ * string (e.g. leading zeros) is handled appropriately.
+ *
+ * "9".upto("11").to_a #=> ["9", "10", "11"]
+ * "25".upto("5").to_a #=> []
+ * "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"]
+ */
+static mrb_value
+mrb_str_upto(mrb_state *mrb, mrb_value beg)
+{
+ mrb_value end;
+ mrb_value exclusive = mrb_false_value();
+ mrb_value block = mrb_nil_value();
+ mrb_value current, after_end;
+ mrb_int n;
+ mrb_bool excl;
+
+ mrb_get_args(mrb, "o|o&", &end, &exclusive, &block);
+
+ if (mrb_nil_p(block)) {
+ return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive);
+ }
+ end = mrb_string_type(mrb, end);
+ excl = mrb_test(exclusive);
+
+ /* single character */
+ if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
+ ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) {
+ char c = RSTRING_PTR(beg)[0];
+ char e = RSTRING_PTR(end)[0];
+ int ai = mrb_gc_arena_save(mrb);
+
+ if (c > e || (excl && c == e)) return beg;
+ for (;;) {
+ mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1));
+ mrb_gc_arena_restore(mrb, ai);
+ if (!excl && c == e) break;
+ c++;
+ if (excl && c == e) break;
+ }
+ return beg;
+ }
+ /* both edges are all digits */
+ if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
+ all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
+ all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
+ mrb_int min_width = RSTRING_LEN(beg);
+ mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE));
+ mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE));
+ int ai = mrb_gc_arena_save(mrb);
+
+ while (bi <= ei) {
+ mrb_value ns, str;
+
+ if (excl && bi == ei) break;
+ ns = mrb_format(mrb, "%S", mrb_fixnum_value(bi));
+ if (min_width > RSTRING_LEN(ns)) {
+ str = mrb_str_new(mrb, NULL, min_width);
+ memset(RSTRING_PTR(str), '0', min_width-RSTRING_LEN(ns));
+ memcpy(RSTRING_PTR(str)+min_width-RSTRING_LEN(ns),
+ RSTRING_PTR(ns), RSTRING_LEN(ns));
+ }
+ else {
+ str = ns;
+ }
+ mrb_yield(mrb, block, str);
+ mrb_gc_arena_restore(mrb, ai);
+ bi++;
+ }
+
+ return beg;
+ }
+ /* normal case */
+ n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end));
+ if (n > 0 || (excl && n == 0)) return beg;
+
+ after_end = mrb_funcall(mrb, end, "succ", 0);
+ current = mrb_str_dup(mrb, beg);
+ while (!mrb_str_equal(mrb, current, after_end)) {
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_value next = mrb_nil_value();
+ if (excl || !mrb_str_equal(mrb, current, end))
+ next = mrb_funcall(mrb, current, "succ", 0);
+ mrb_yield(mrb, block, current);
+ if (mrb_nil_p(next)) break;
+ current = mrb_str_to_str(mrb, next);
+ if (excl && mrb_str_equal(mrb, current, end)) break;
+ if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
+ break;
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return beg;
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -538,6 +674,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb
index 24bc859d8..2a568c7d6 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -122,12 +122,16 @@ assert('String#swapcase!') do
end
assert('String#concat') do
- s = "Hello "
- s.concat "World!"
- t = "Hello "
- t << "World!"
- assert_equal "Hello World!", t
- assert_equal "Hello World!", s
+ assert_equal "Hello World!", "Hello " << "World" << 33
+ assert_equal "Hello World!", "Hello ".concat("World").concat(33)
+
+ o = Object.new
+ def o.to_str
+ "to_str"
+ end
+ assert_equal "hi to_str", "hi " << o
+
+ assert_raise(TypeError) { "".concat(Object.new) }
end
assert('String#casecmp') do
@@ -491,6 +495,17 @@ assert('String#rjust should raise on zero width padding') do
end
assert('String#upto') do
+ assert_equal %w(a8 a9 b0 b1 b2 b3 b4 b5 b6), "a8".upto("b6").to_a
+ assert_equal ["9", "10", "11"], "9".upto("11").to_a
+ assert_equal [], "25".upto("5").to_a
+ assert_equal ["07", "08", "09", "10", "11"], "07".upto("11").to_a
+
+if UTF8STRING
+ assert_equal ["あ", "ぃ", "い", "ぅ", "う", "ぇ", "え", "ぉ", "お"], "あ".upto("お").to_a
+end
+
+ assert_equal ["9", ":", ";", "<", "=", ">", "?", "@", "A"], "9".upto("A").to_a
+
a = "aa"
start = "aa"
count = 0
@@ -550,6 +565,8 @@ assert('String#upto') do
count += 1
})
assert_equal(2, count)
+
+ assert_raise(TypeError) { "a".upto(:c) {} }
end
assert('String#ord') do
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index 93bd1e2b2..67762a948 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -13,8 +13,8 @@
#include <mruby/hash.h>
#include <mruby/range.h>
-#define RSTRUCT_LEN(st) mrb_ary_ptr(st)->len
-#define RSTRUCT_PTR(st) mrb_ary_ptr(st)->ptr
+#define RSTRUCT_LEN(st) RARRAY_LEN(st)
+#define RSTRUCT_PTR(st) RARRAY_PTR(st)
static struct RClass *
struct_class(mrb_state *mrb)
@@ -84,6 +84,16 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass)
return ary;
}
+static void
+mrb_struct_modify(mrb_state *mrb, mrb_value strct)
+{
+ if (MRB_FROZEN_P(mrb_basic_ptr(strct))) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen struct");
+ }
+
+ mrb_write_barrier(mrb, mrb_basic_ptr(strct));
+}
+
/* 15.2.18.4.6 */
/*
* call-seq:
@@ -266,7 +276,6 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
mrb_int argc;
name = mrb_nil_value();
- rest = mrb_nil_value();
mrb_get_args(mrb, "*&", &argv, &argc, &b);
if (argc == 0) { /* special case to avoid crash */
rest = mrb_ary_new(mrb);
@@ -336,7 +345,7 @@ mrb_struct_initialize(mrb_state *mrb, mrb_value self)
mrb_value *argv;
mrb_int argc;
- mrb_get_args(mrb, "*", &argv, &argc);
+ mrb_get_args(mrb, "*!", &argv, &argc);
return mrb_struct_initialize_withArg(mrb, argc, argv, self);
}
@@ -448,6 +457,7 @@ mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val)
ptr_members = RARRAY_PTR(members);
for (i=0; i<len; i++) {
if (mrb_symbol(ptr_members[i]) == id) {
+ mrb_struct_modify(mrb, s);
ptr[i] = val;
return val;
}
@@ -511,6 +521,7 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s)
"offset %S too large for struct(size:%S)",
mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
}
+ mrb_struct_modify(mrb, s);
return RSTRUCT_PTR(s)[i] = val;
}
@@ -636,7 +647,7 @@ mrb_struct_to_h(mrb_state *mrb, mrb_value self)
mrb_value members, ret;
mrb_int i;
- members = struct_s_members(mrb, mrb_class(mrb, self));
+ members = struct_members(mrb, self);
ret = mrb_hash_new_capa(mrb, RARRAY_LEN(members));
for (i = 0; i < RARRAY_LEN(members); ++i) {
@@ -677,6 +688,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb)
{
struct RClass *st;
st = mrb_define_class(mrb, "Struct", mrb->object_class);
+ MRB_SET_INSTANCE_TT(st, MRB_TT_ARRAY);
mrb_define_class_method(mrb, st, "new", mrb_struct_s_def, MRB_ARGS_ANY()); /* 15.2.18.3.1 */
diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb
index 1c0939e7f..421fe4b5d 100644
--- a/mrbgems/mruby-struct/test/struct.rb
+++ b/mrbgems/mruby-struct/test/struct.rb
@@ -197,3 +197,16 @@ assert("Struct.new generates subclass of Struct") do
Struct = original_struct
end
end
+
+assert 'Struct#freeze' do
+ c = Struct.new :m
+
+ o = c.new
+ o.m = :test
+ assert_equal :test, o.m
+
+ o.freeze
+ assert_raise(RuntimeError) { o.m = :modify }
+ assert_raise(RuntimeError) { o[:m] = :modify }
+ assert_equal :test, o.m
+end
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index ce99a5a65..5e8624830 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -5,22 +5,22 @@
*/
#include <math.h>
-#include <stdio.h>
#include <time.h>
#include <mruby.h>
#include <mruby/class.h>
#include <mruby/data.h>
+#ifndef DISABLE_STDIO
+#include <stdio.h>
+#else
+#include <string.h>
+#endif
+
#define NDIV(x,y) (-(-((x)+1)/(y))-1)
-#if _MSC_VER < 1800
+#if defined(_MSC_VER) && _MSC_VER < 1800
double round(double x) {
- if (x >= 0.0) {
- return (double)((int)(x + 0.5));
- }
- else {
- return (double)((int)(x - 0.5));
- }
+ return floor(x + 0.5);
}
#endif
@@ -55,6 +55,13 @@ double round(double x) {
#endif
#endif
+/* asctime(3) */
+/* mruby usually use its own implementation of struct tm to string conversion */
+/* except when DISABLE_STDIO is set. In that case, it uses asctime() or asctime_r(). */
+/* By default mruby tries to use asctime_r() which is reentrant. */
+/* Undef following macro on platforms that does not have asctime_r(). */
+/* #define NO_ASCTIME_R */
+
/* timegm(3) */
/* mktime() creates tm structure for localtime; timegm() is for UTC time */
/* define following macro to use probably faster timegm() on the platform */
@@ -166,6 +173,7 @@ static const mrb_timezone_name timezone_names[] = {
{ "LOCAL", sizeof("LOCAL") - 1 },
};
+#ifndef DISABLE_STDIO
static const char mon_names[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
@@ -173,6 +181,7 @@ static const char mon_names[12][4] = {
static const char wday_names[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};
+#endif
struct mrb_time {
time_t sec;
@@ -241,12 +250,12 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
tm->sec = tsec;
tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec);
if (tm->usec < 0) {
- long sec2 = NDIV(usec,1000000); /* negative div */
+ long sec2 = (long)NDIV(usec,1000000); /* negative div */
tm->usec -= sec2 * 1000000;
tm->sec += sec2;
}
else if (tm->usec >= 1000000) {
- long sec2 = usec / 1000000;
+ long sec2 = (long)(usec / 1000000);
tm->usec -= sec2 * 1000000;
tm->sec += sec2;
}
@@ -528,18 +537,28 @@ mrb_time_zone(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_time_asctime(mrb_state *mrb, mrb_value self)
{
- struct mrb_time *tm;
- struct tm *d;
- char buf[256];
+ struct mrb_time *tm = time_get_ptr(mrb, self);
+ struct tm *d = &tm->datetime;
int len;
- tm = time_get_ptr(mrb, self);
- d = &tm->datetime;
+#if defined(DISABLE_STDIO)
+ char *s;
+# ifdef NO_ASCTIME_R
+ s = asctime(d);
+# else
+ char buf[32];
+ s = asctime_r(d, buf);
+# endif
+ len = strlen(s)-1; /* truncate the last newline */
+#else
+ char buf[256];
+
len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
d->tm_hour, d->tm_min, d->tm_sec,
tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "",
d->tm_year + 1900);
+#endif
return mrb_str_new(mrb, buf, len);
}
diff --git a/mrblib/00class.rb b/mrblib/00class.rb
index f3762e8d0..1a2d833c8 100644
--- a/mrblib/00class.rb
+++ b/mrblib/00class.rb
@@ -15,6 +15,7 @@ class Module
m.append_features(self)
m.included(self)
end
+ self
end
def prepend(*args)
@@ -22,5 +23,6 @@ class Module
m.prepend_features(self)
m.prepended(self)
end
+ self
end
end
diff --git a/mrblib/10error.rb b/mrblib/10error.rb
index 2674af7a2..22a8d1ad7 100644
--- a/mrblib/10error.rb
+++ b/mrblib/10error.rb
@@ -2,8 +2,8 @@
class ArgumentError < StandardError
end
-# ISO 15.2.25
-class LocalJumpError < StandardError
+# ISO 15.2.25 says "LocalJumpError < StandardError"
+class LocalJumpError < ScriptError
end
# ISO 15.2.26
diff --git a/mrblib/array.rb b/mrblib/array.rb
index d5a2d8405..be98f217e 100644
--- a/mrblib/array.rb
+++ b/mrblib/array.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
##
# Array
#
@@ -193,9 +194,45 @@ class Array
include Enumerable
##
+ # Quick sort
+ # a : the array to sort
+ # left : the beginning of sort region
+ # right : the end of sort region
+ def __sort_sub__(a, left, right, &block)
+ if left < right
+ i = left
+ j = right
+ pivot = a[i + (j - i) / 2]
+ while true
+ while ((block)? block.call(a[i], pivot): (a[i] <=> pivot)) < 0
+ i += 1
+ end
+ while ((block)? block.call(pivot, a[j]): (pivot <=> a[j])) < 0
+ j -= 1
+ end
+ break if (i >= j)
+ tmp = a[i]; a[i] = a[j]; a[j] = tmp;
+ i += 1
+ j -= 1
+ end
+ __sort_sub__(a, left, i-1, &block)
+ __sort_sub__(a, j+1, right, &block)
+ end
+ end
+ # private :__sort_sub__
+
+ ##
# Sort all elements and replace +self+ with these
# elements.
def sort!(&block)
- self.replace(self.sort(&block))
+ size = self.size
+ if size > 1
+ __sort_sub__(self, 0, size - 1, &block)
+ end
+ self
+ end
+
+ def sort(&block)
+ self.dup.sort!(&block)
end
end
diff --git a/mrblib/enum.rb b/mrblib/enum.rb
index fb55efcf8..12bd1d37b 100644
--- a/mrblib/enum.rb
+++ b/mrblib/enum.rb
@@ -316,45 +316,6 @@ module Enumerable
alias select find_all
##
- # TODO
- # Does this OK? Please test it.
- def __sort_sub__(sorted, work, src_ary, head, tail, &block)
- if head == tail
- sorted[head] = work[head] if src_ary == 1
- return
- end
-
- # on current step, which is a src ary?
- if src_ary == 0
- src, dst = sorted, work
- else
- src, dst = work, sorted
- end
-
- key = src[head] # key value for dividing values
- i, j = head, tail # position to store on the dst ary
-
- (head + 1).upto(tail){|idx|
- if ((block)? block.call(src[idx], key): (src[idx] <=> key)) > 0
- # larger than key
- dst[j] = src[idx]
- j -= 1
- else
- dst[i] = src[idx]
- i += 1
- end
- }
-
- sorted[i] = key
-
- # sort each sub-array
- src_ary = (src_ary + 1) % 2 # exchange a src ary
- __sort_sub__(sorted, work, src_ary, head, i - 1, &block) if i > head
- __sort_sub__(sorted, work, src_ary, i + 1, tail, &block) if i < tail
- end
-# private :__sort_sub__
-
- ##
# Return a sorted array of all elements
# which are yield by +each+. If no block
# is given <=> will be invoked on each
@@ -364,12 +325,7 @@ module Enumerable
#
# ISO 15.3.2.2.19
def sort(&block)
- ary = []
- self.each{|*val| ary.push(val.__svalue)}
- if ary.size > 1
- __sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1, &block)
- end
- ary
+ self.map{|*val| val.__svalue}.sort
end
##
diff --git a/mrblib/string.rb b/mrblib/string.rb
index f91b5a23c..4c6114ecb 100644
--- a/mrblib/string.rb
+++ b/mrblib/string.rb
@@ -133,7 +133,7 @@ class String
if args.length == 2 && block
block = nil
end
- if !block
+ unless block
replace = replace.to_str
end
result = []
diff --git a/src/array.c b/src/array.c
index 67cae92eb..9124ff950 100644
--- a/src/array.c
+++ b/src/array.c
@@ -28,9 +28,15 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
blen = capa * sizeof(mrb_value);
a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
- a->ptr = (mrb_value *)mrb_malloc(mrb, blen);
- a->aux.capa = capa;
- a->len = 0;
+ if (capa <= MRB_ARY_EMBED_LEN_MAX) {
+ ARY_SET_EMBED_FLAG(a);
+ /* ARY_SET_EMBED_LEN(a, 0); */
+ }
+ else {
+ a->as.heap.ptr = (mrb_value *)mrb_malloc(mrb, blen);
+ a->as.heap.aux.capa = capa;
+ a->as.heap.len = 0;
+ }
return a;
}
@@ -77,8 +83,8 @@ mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
{
struct RArray *a = ary_new_capa(mrb, size);
- array_copy(a->ptr, vals, size);
- a->len = size;
+ array_copy(ARY_PTR(a), vals, size);
+ ARY_SET_LEN(a, size);
return mrb_obj_value(a);
}
@@ -89,9 +95,9 @@ mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
struct RArray *a;
a = ary_new_capa(mrb, 2);
- a->ptr[0] = car;
- a->ptr[1] = cdr;
- a->len = 2;
+ ARY_PTR(a)[0] = car;
+ ARY_PTR(a)[1] = cdr;
+ ARY_SET_LEN(a, 2);
return mrb_obj_value(a);
}
@@ -106,32 +112,38 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
}
static void
-ary_modify(mrb_state *mrb, struct RArray *a)
+ary_modify_check(mrb_state *mrb, struct RArray *a)
{
if (MRB_FROZEN_P(a)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
}
+}
+
+static void
+ary_modify(mrb_state *mrb, struct RArray *a)
+{
+ ary_modify_check(mrb, a);
if (ARY_SHARED_P(a)) {
- mrb_shared_array *shared = a->aux.shared;
+ mrb_shared_array *shared = a->as.heap.aux.shared;
- if (shared->refcnt == 1 && a->ptr == shared->ptr) {
- a->ptr = shared->ptr;
- a->aux.capa = a->len;
+ if (shared->refcnt == 1 && a->as.heap.ptr == shared->ptr) {
+ a->as.heap.ptr = shared->ptr;
+ a->as.heap.aux.capa = a->as.heap.len;
mrb_free(mrb, shared);
}
else {
mrb_value *ptr, *p;
- size_t len;
+ mrb_int len;
- p = a->ptr;
- len = a->len * sizeof(mrb_value);
+ p = a->as.heap.ptr;
+ len = a->as.heap.len * sizeof(mrb_value);
ptr = (mrb_value *)mrb_malloc(mrb, len);
if (p) {
- array_copy(ptr, p, a->len);
+ array_copy(ptr, p, a->as.heap.len);
}
- a->ptr = ptr;
- a->aux.capa = a->len;
+ a->as.heap.ptr = ptr;
+ a->as.heap.aux.capa = a->as.heap.len;
mrb_ary_decref(mrb, shared);
}
ARY_UNSET_SHARED_FLAG(a);
@@ -148,33 +160,35 @@ mrb_ary_modify(mrb_state *mrb, struct RArray* a)
static void
ary_make_shared(mrb_state *mrb, struct RArray *a)
{
- if (!ARY_SHARED_P(a)) {
+ if (!ARY_SHARED_P(a) && !ARY_EMBED_P(a)) {
mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array));
+ mrb_value *ptr = a->as.heap.ptr;
+ mrb_int len = a->as.heap.len;
shared->refcnt = 1;
- if (a->aux.capa > a->len) {
- a->ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*a->len+1);
+ if (a->as.heap.aux.capa > len) {
+ a->as.heap.ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, ptr, sizeof(mrb_value)*len+1);
}
else {
- shared->ptr = a->ptr;
+ shared->ptr = ptr;
}
- shared->len = a->len;
- a->aux.shared = shared;
+ shared->len = len;
+ a->as.heap.aux.shared = shared;
ARY_SET_SHARED_FLAG(a);
}
}
static void
-ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len)
+ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
{
- size_t capa = a->aux.capa;
+ mrb_int capa = ARY_CAPA(a);
- if (len > ARY_MAX_SIZE) {
+ if (len > ARY_MAX_SIZE || len < 0) {
size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
- if (capa == 0) {
+ if (capa < ARY_DEFAULT_LEN) {
capa = ARY_DEFAULT_LEN;
}
while (capa < len) {
@@ -189,21 +203,36 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len)
goto size_error;
}
- if (capa > (size_t)a->aux.capa) {
- mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
+ if (ARY_EMBED_P(a)) {
+ mrb_value *ptr = ARY_EMBED_PTR(a);
+ mrb_int len = ARY_EMBED_LEN(a);
+ mrb_value *expanded_ptr = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*capa);
- a->aux.capa = capa;
- a->ptr = expanded_ptr;
+ ARY_UNSET_EMBED_FLAG(a);
+ array_copy(expanded_ptr, ptr, len);
+ a->as.heap.len = len;
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = expanded_ptr;
+ }
+ else if (capa > a->as.heap.aux.capa) {
+ mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
+
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = expanded_ptr;
}
}
static void
ary_shrink_capa(mrb_state *mrb, struct RArray *a)
{
- mrb_int capa = a->aux.capa;
+
+ mrb_int capa;
+
+ if (ARY_EMBED_P(a)) return;
+ capa = a->as.heap.aux.capa;
if (capa < ARY_DEFAULT_LEN * 2) return;
- if (capa <= a->len * ARY_SHRINK_RATIO) return;
+ if (capa <= a->as.heap.len * ARY_SHRINK_RATIO) return;
do {
capa /= 2;
@@ -211,11 +240,11 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a)
capa = ARY_DEFAULT_LEN;
break;
}
- } while (capa > a->len * ARY_SHRINK_RATIO);
+ } while (capa > a->as.heap.len * ARY_SHRINK_RATIO);
- if (capa > a->len && capa < a->aux.capa) {
- a->aux.capa = capa;
- a->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
+ if (capa > a->as.heap.len && capa < a->as.heap.aux.capa) {
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
}
}
@@ -228,13 +257,13 @@ mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
ary_modify(mrb, a);
old_len = RARRAY_LEN(ary);
if (old_len != new_len) {
- a->len = new_len;
+ ARY_SET_LEN(a, new_len);
if (new_len < old_len) {
ary_shrink_capa(mrb, a);
}
else {
ary_expand_capa(mrb, a, new_len);
- ary_fill_with_nil(a->ptr + old_len, new_len - old_len);
+ ary_fill_with_nil(ARY_PTR(a) + old_len, new_len - old_len);
}
}
@@ -249,7 +278,7 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
mrb_int len;
struct RArray *a;
- mrb_get_args(mrb, "*", &vals, &len);
+ mrb_get_args(mrb, "*!", &vals, &len);
ary = mrb_ary_new_from_values(mrb, len, vals);
a = mrb_ary_ptr(ary);
a->c = mrb_class_ptr(klass);
@@ -262,18 +291,18 @@ ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
{
mrb_int len;
- if (a2->len > ARY_MAX_SIZE - a->len) {
+ if (ARY_LEN(a2) > ARY_MAX_SIZE - ARY_LEN(a)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
- len = a->len + a2->len;
+ len = ARY_LEN(a) + ARY_LEN(a2);
ary_modify(mrb, a);
- if (a->aux.capa < len) {
+ if (ARY_CAPA(a) < len) {
ary_expand_capa(mrb, a, len);
}
- array_copy(a->ptr+a->len, a2->ptr, a2->len);
+ array_copy(ARY_PTR(a)+ARY_LEN(a), ARY_PTR(a2), ARY_LEN(a2));
mrb_write_barrier(mrb, (struct RBasic*)a);
- a->len = len;
+ ARY_SET_LEN(a, len);
}
MRB_API void
@@ -300,16 +329,17 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
mrb_value *ptr;
- mrb_int blen;
+ mrb_int blen, len1;
mrb_get_args(mrb, "a", &ptr, &blen);
- if (ARY_MAX_SIZE - blen < a1->len) {
+ if (ARY_MAX_SIZE - blen < ARY_LEN(a1)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
- a2 = ary_new_capa(mrb, a1->len + blen);
- array_copy(a2->ptr, a1->ptr, a1->len);
- array_copy(a2->ptr + a1->len, ptr, blen);
- a2->len = a1->len + blen;
+ len1 = ARY_LEN(a1);
+ a2 = ary_new_capa(mrb, len1 + blen);
+ array_copy(ARY_PTR(a2), ARY_PTR(a1), len1);
+ array_copy(ARY_PTR(a2) + len1, ptr, blen);
+ ARY_SET_LEN(a2, len1+blen);
return mrb_obj_value(a2);
}
@@ -318,11 +348,11 @@ static void
ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
{
ary_modify(mrb, a);
- if (a->aux.capa < len)
+ if (ARY_CAPA(a) < len)
ary_expand_capa(mrb, a, len);
- array_copy(a->ptr, argv, len);
+ array_copy(ARY_PTR(a), argv, len);
mrb_write_barrier(mrb, (struct RBasic*)a);
- a->len = len;
+ ARY_SET_LEN(a, len);
}
MRB_API void
@@ -332,7 +362,7 @@ mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
struct RArray *a2 = mrb_ary_ptr(other);
if (a1 != a2) {
- ary_replace(mrb, a1, a2->ptr, a2->len);
+ ary_replace(mrb, a1, ARY_PTR(a2), ARY_LEN(a2));
}
}
@@ -353,22 +383,23 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
mrb_value *ptr;
- mrb_int times;
+ mrb_int times, len1;
mrb_get_args(mrb, "i", &times);
if (times < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
}
if (times == 0) return mrb_ary_new(mrb);
- if (ARY_MAX_SIZE / times < a1->len) {
+ if (ARY_MAX_SIZE / times < ARY_LEN(a1)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
- a2 = ary_new_capa(mrb, a1->len * times);
- ptr = a2->ptr;
+ len1 = ARY_LEN(a1);
+ a2 = ary_new_capa(mrb, len1 * times);
+ ARY_SET_LEN(a2, len1 * times);
+ ptr = ARY_PTR(a2);
while (times--) {
- array_copy(ptr, a1->ptr, a1->len);
- ptr += a1->len;
- a2->len += a1->len;
+ array_copy(ptr, ARY_PTR(a1), len1);
+ ptr += len1;
}
return mrb_obj_value(a2);
@@ -378,13 +409,14 @@ static mrb_value
mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
- if (a->len > 1) {
+ if (len > 1) {
mrb_value *p1, *p2;
ary_modify(mrb, a);
- p1 = a->ptr;
- p2 = a->ptr + a->len - 1;
+ p1 = ARY_PTR(a);
+ p2 = p1 + len - 1;
while (p1 < p2) {
mrb_value tmp = *p1;
@@ -398,18 +430,19 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_ary_reverse(mrb_state *mrb, mrb_value self)
{
- struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len);
+ struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, ARY_LEN(a));
+ mrb_int len = ARY_LEN(a);
- if (a->len > 0) {
+ if (len > 0) {
mrb_value *p1, *p2, *e;
- p1 = a->ptr;
- e = p1 + a->len;
- p2 = b->ptr + a->len - 1;
+ p1 = ARY_PTR(a);
+ e = p1 + len;
+ p2 = ARY_PTR(b) + len - 1;
while (p1 < e) {
*p2-- = *p1++;
}
- b->len = a->len;
+ ARY_SET_LEN(b, len);
}
return mrb_obj_value(b);
}
@@ -418,11 +451,13 @@ MRB_API void
mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
ary_modify(mrb, a);
- if (a->len == a->aux.capa)
- ary_expand_capa(mrb, a, a->len + 1);
- a->ptr[a->len++] = elem;
+ if (len == ARY_CAPA(a))
+ ary_expand_capa(mrb, a, len + 1);
+ ARY_PTR(a)[len] = elem;
+ ARY_SET_LEN(a, len+1);
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem);
}
@@ -432,7 +467,7 @@ mrb_ary_push_m(mrb_state *mrb, mrb_value self)
mrb_value *argv;
mrb_int len;
- mrb_get_args(mrb, "*", &argv, &len);
+ mrb_get_args(mrb, "*!", &argv, &len);
while (len--) {
mrb_ary_push(mrb, self, *argv++);
}
@@ -444,10 +479,12 @@ MRB_API mrb_value
mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
- ary_modify(mrb, a);
- if (a->len == 0) return mrb_nil_value();
- return a->ptr[--a->len];
+ ary_modify_check(mrb, a);
+ if (len == 0) return mrb_nil_value();
+ ARY_SET_LEN(a, len-1);
+ return ARY_PTR(a)[len-1];
}
#define ARY_SHIFT_SHARED_MIN 10
@@ -456,31 +493,32 @@ MRB_API mrb_value
mrb_ary_shift(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
mrb_value val;
- ary_modify(mrb, a);
- if (a->len == 0) return mrb_nil_value();
+ ary_modify_check(mrb, a);
+ if (len == 0) return mrb_nil_value();
if (ARY_SHARED_P(a)) {
L_SHIFT:
- val = a->ptr[0];
- a->ptr++;
- a->len--;
+ val = a->as.heap.ptr[0];
+ a->as.heap.ptr++;
+ a->as.heap.len--;
return val;
}
- if (a->len > ARY_SHIFT_SHARED_MIN) {
+ if (len > ARY_SHIFT_SHARED_MIN) {
ary_make_shared(mrb, a);
goto L_SHIFT;
}
else {
- mrb_value *ptr = a->ptr;
- mrb_int size = a->len;
+ mrb_value *ptr = ARY_PTR(a);
+ mrb_int size = len;
val = *ptr;
while (--size) {
*ptr = *(ptr+1);
++ptr;
}
- --a->len;
+ ARY_SET_LEN(a, len-1);
}
return val;
}
@@ -493,21 +531,25 @@ MRB_API mrb_value
mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
{
struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
if (ARY_SHARED_P(a)
- && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
- && a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ {
- a->ptr--;
- a->ptr[0] = item;
+ && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+ && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= 1) /* there's room for unshifted item */ {
+ a->as.heap.ptr--;
+ a->as.heap.ptr[0] = item;
}
else {
+ mrb_value *ptr;
+
ary_modify(mrb, a);
- if (a->aux.capa < a->len + 1)
- ary_expand_capa(mrb, a, a->len + 1);
- value_move(a->ptr + 1, a->ptr, a->len);
- a->ptr[0] = item;
+ if (ARY_CAPA(a) < len + 1)
+ ary_expand_capa(mrb, a, len + 1);
+ ptr = ARY_PTR(a);
+ value_move(ptr + 1, ptr, len);
+ ptr[0] = item;
}
- a->len++;
+ ARY_SET_LEN(a, len+1);
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item);
return self;
@@ -517,27 +559,31 @@ static mrb_value
mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_value *vals;
- mrb_int len;
+ mrb_value *vals, *ptr;
+ mrb_int alen, len;
- mrb_get_args(mrb, "*", &vals, &len);
- if (len > ARY_MAX_SIZE - a->len) {
+ mrb_get_args(mrb, "*!", &vals, &alen);
+ len = ARY_LEN(a);
+ if (alen > ARY_MAX_SIZE - len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
if (ARY_SHARED_P(a)
- && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
- && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
- a->ptr -= len;
+ && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+ && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= alen) /* there's room for unshifted item */ {
+ ary_modify_check(mrb, a);
+ a->as.heap.ptr -= len;
+ ptr = a->as.heap.ptr;
}
else {
ary_modify(mrb, a);
- if (len == 0) return self;
- if (a->aux.capa < a->len + len)
- ary_expand_capa(mrb, a, a->len + len);
- value_move(a->ptr + len, a->ptr, a->len);
- }
- array_copy(a->ptr, vals, len);
- a->len += len;
+ if (alen == 0) return self;
+ if (ARY_CAPA(a) < len + alen)
+ ary_expand_capa(mrb, a, len + alen);
+ ptr = ARY_PTR(a);
+ value_move(ptr + alen, ptr, len);
+ }
+ array_copy(ptr, vals, alen);
+ ARY_SET_LEN(a, len+alen);
while (len--) {
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[len]);
}
@@ -549,44 +595,47 @@ MRB_API mrb_value
mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
/* range check */
- if (n < 0) n += a->len;
- if (n < 0 || a->len <= n) return mrb_nil_value();
+ if (n < 0) n += len;
+ if (n < 0 || len <= n) return mrb_nil_value();
- return a->ptr[n];
+ return ARY_PTR(a)[n];
}
MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
ary_modify(mrb, a);
/* range check */
if (n < 0) {
- n += a->len;
+ n += len;
if (n < 0) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - a->len));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len));
}
}
- if (a->len <= n) {
- if (a->aux.capa <= n)
+ if (len <= n) {
+ if (ARY_CAPA(a) <= n)
ary_expand_capa(mrb, a, n + 1);
- ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len);
- a->len = n + 1;
+ ary_fill_with_nil(ARY_PTR(a) + len, n + 1 - len);
+ ARY_SET_LEN(a, n+1);
}
- a->ptr[n] = val;
+ ARY_PTR(a)[n] = val;
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
static struct RArray*
ary_dup(mrb_state *mrb, struct RArray *a)
{
- struct RArray *d = ary_new_capa(mrb, a->len);
+ mrb_int len = ARY_LEN(a);
+ struct RArray *d = ary_new_capa(mrb, len);
- ary_replace(mrb, d, a->ptr, a->len);
+ ary_replace(mrb, d, ARY_PTR(a), len);
return d;
}
@@ -594,9 +643,10 @@ MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int alen = ARY_LEN(a);
const mrb_value *argv;
mrb_int argc;
- size_t tail;
+ mrb_int tail;
ary_modify(mrb, a);
@@ -605,61 +655,67 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
/* range check */
if (head < 0) {
- head += a->len;
+ head += alen;
if (head < 0) {
mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
}
}
tail = head + len;
- if (a->len < len || (size_t)a->len < tail) {
- len = a->len - head;
+ if (alen < len || alen < tail) {
+ len = alen - head;
}
/* size check */
if (mrb_array_p(rpl)) {
argc = RARRAY_LEN(rpl);
argv = RARRAY_PTR(rpl);
- if (argv == a->ptr) {
- struct RArray *r = ary_dup(mrb, a);
- argv = r->ptr;
+ if (argv == ARY_PTR(a)) {
+ struct RArray *r;
+
+ if (argc > 32767) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "too big recursive splice");
+ }
+ r = ary_dup(mrb, a);
+ argv = ARY_PTR(r);
}
}
else {
argc = 1;
argv = &rpl;
}
- if (head >= a->len) {
+ if (head >= alen) {
if (head > ARY_MAX_SIZE - argc) {
mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
}
len = head + argc;
- if (len > a->aux.capa) {
+ if (len > ARY_CAPA(a)) {
ary_expand_capa(mrb, a, head + argc);
}
- ary_fill_with_nil(a->ptr + a->len, head - a->len);
+ ary_fill_with_nil(ARY_PTR(a) + alen, head - alen);
if (argc > 0) {
- array_copy(a->ptr + head, argv, argc);
+ array_copy(ARY_PTR(a) + head, argv, argc);
}
- a->len = len;
+ ARY_SET_LEN(a, len);
}
else {
- mrb_int alen;
+ mrb_int newlen;
- if (a->len - len > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len));
+ if (alen - len > ARY_MAX_SIZE - argc) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len));
}
- alen = a->len + argc - len;
- if (alen > a->aux.capa) {
- ary_expand_capa(mrb, a, alen);
+ newlen = alen + argc - len;
+ if (newlen > ARY_CAPA(a)) {
+ ary_expand_capa(mrb, a, newlen);
}
if (len != argc) {
+ mrb_value *ptr = ARY_PTR(a);
tail = head + len;
- value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
- a->len = alen;
+ value_move(ptr + head + argc, ptr + tail, alen - tail);
+ ARY_SET_LEN(a, newlen);
}
if (argc > 0) {
- value_move(a->ptr + head, argv, argc);
+ value_move(ARY_PTR(a) + head, argv, argc);
}
}
mrb_write_barrier(mrb, (struct RBasic*)a);
@@ -681,12 +737,15 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
{
struct RArray *b;
+ if (!ARY_SHARED_P(a) && len <= ARY_SHIFT_SHARED_MIN) {
+ return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg);
+ }
ary_make_shared(mrb, a);
b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
- b->ptr = a->ptr + beg;
- b->len = len;
- b->aux.shared = a->aux.shared;
- b->aux.shared->refcnt++;
+ b->as.heap.ptr = a->as.heap.ptr + beg;
+ b->as.heap.len = len;
+ b->as.heap.aux.shared = a->as.heap.aux.shared;
+ b->as.heap.aux.shared->refcnt++;
ARY_SET_SHARED_FLAG(b);
return mrb_obj_value(b);
@@ -705,7 +764,7 @@ aget_index(mrb_state *mrb, mrb_value index)
mrb_int i, argc;
mrb_value *argv;
- mrb_get_args(mrb, "i*", &i, &argv, &argc);
+ mrb_get_args(mrb, "i*!", &i, &argv, &argc);
return i;
}
}
@@ -741,14 +800,14 @@ static mrb_value
mrb_ary_aget(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int i, len;
+ mrb_int i, len, alen = ARY_LEN(a);
mrb_value index;
if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
switch (mrb_type(index)) {
/* a[n..m] */
case MRB_TT_RANGE:
- if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
+ if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) {
return ary_subseq(mrb, a, i, len);
}
else {
@@ -762,11 +821,11 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self)
}
i = aget_index(mrb, index);
- if (i < 0) i += a->len;
- if (i < 0 || a->len < i) return mrb_nil_value();
+ if (i < 0) i += alen;
+ if (i < 0 || alen < i) return mrb_nil_value();
if (len < 0) return mrb_nil_value();
- if (a->len == i) return mrb_ary_new(mrb);
- if (len > a->len - i) len = a->len - i;
+ if (alen == i) return mrb_ary_new(mrb);
+ if (len > alen - i) len = alen - i;
return ary_subseq(mrb, a, i, len);
}
@@ -841,22 +900,23 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
mrb_int index;
mrb_value val;
mrb_value *ptr;
- mrb_int len;
+ mrb_int len, alen = ARY_LEN(a);
mrb_get_args(mrb, "i", &index);
- if (index < 0) index += a->len;
- if (index < 0 || a->len <= index) return mrb_nil_value();
+ if (index < 0) index += alen;
+ if (index < 0 || alen <= index) return mrb_nil_value();
ary_modify(mrb, a);
- val = a->ptr[index];
+ ptr = ARY_PTR(a);
+ val = ptr[index];
- ptr = a->ptr + index;
- len = a->len - index;
+ ptr += index;
+ len = alen - index;
while (--len) {
*ptr = *(ptr+1);
++ptr;
}
- --a->len;
+ ARY_SET_LEN(a, alen-1);
ary_shrink_capa(mrb, a);
@@ -867,39 +927,39 @@ static mrb_value
mrb_ary_first(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int size;
+ mrb_int size, alen = ARY_LEN(a);
if (mrb_get_args(mrb, "|i", &size) == 0) {
- return (a->len > 0)? a->ptr[0]: mrb_nil_value();
+ return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value();
}
if (size < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
}
- if (size > a->len) size = a->len;
+ if (size > alen) size = alen;
if (ARY_SHARED_P(a)) {
return ary_subseq(mrb, a, 0, size);
}
- return mrb_ary_new_from_values(mrb, size, a->ptr);
+ return mrb_ary_new_from_values(mrb, size, ARY_PTR(a));
}
static mrb_value
mrb_ary_last(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int size;
+ mrb_int size, alen = ARY_LEN(a);
if (mrb_get_args(mrb, "|i", &size) == 0)
- return (a->len > 0)? a->ptr[a->len - 1]: mrb_nil_value();
+ return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value();
if (size < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
}
- if (size > a->len) size = a->len;
+ if (size > alen) size = alen;
if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) {
- return ary_subseq(mrb, a, a->len - size, size);
+ return ary_subseq(mrb, a, alen - size, size);
}
- return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size);
+ return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size);
}
static mrb_value
@@ -972,7 +1032,7 @@ mrb_ary_size(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- return mrb_fixnum_value(a->len);
+ return mrb_fixnum_value(ARY_LEN(a));
}
MRB_API mrb_value
@@ -982,15 +1042,14 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
ary_modify(mrb, a);
if (ARY_SHARED_P(a)) {
- mrb_ary_decref(mrb, a->aux.shared);
+ mrb_ary_decref(mrb, a->as.heap.aux.shared);
ARY_UNSET_SHARED_FLAG(a);
}
- else {
- mrb_free(mrb, a->ptr);
+ else if (!ARY_EMBED_P(a)){
+ mrb_free(mrb, a->as.heap.ptr);
}
- a->len = 0;
- a->aux.capa = 0;
- a->ptr = 0;
+ ARY_SET_EMBED_FLAG(a);
+ ARY_SET_EMBED_LEN(a, 0);
return self;
}
@@ -1000,7 +1059,7 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- return mrb_bool_value(a->len == 0);
+ return mrb_bool_value(ARY_LEN(a) == 0);
}
MRB_API mrb_value
diff --git a/src/backtrace.c b/src/backtrace.c
index d634123b4..f04395597 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -13,101 +13,28 @@
#include <mruby/debug.h>
#include <mruby/error.h>
#include <mruby/numeric.h>
-
-struct backtrace_location_raw {
- int i;
- int lineno;
- const char *filename;
- mrb_sym method_id;
- char sep;
- struct RClass *klass;
-};
+#include <mruby/data.h>
struct backtrace_location {
- int i;
int lineno;
const char *filename;
- const char *method;
- char sep;
- const char *class_name;
+ mrb_sym method_id;
};
-typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location_raw*, void*);
-typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
+typedef void (*each_backtrace_func)(mrb_state*, int i, struct backtrace_location*, void*);
-#ifndef MRB_DISABLE_STDIO
-
-struct print_backtrace_args {
- FILE *stream;
- int tracehead;
-};
-
-static void
-print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
-{
- struct print_backtrace_args *args;
-
- args = (struct print_backtrace_args*)data;
-
- if (args->tracehead) {
- fprintf(args->stream, "trace:\n");
- args->tracehead = FALSE;
- }
-
- fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno);
-
- if (loc->method) {
- if (loc->class_name) {
- fprintf(args->stream, ":in %s%c%s", loc->class_name, loc->sep, loc->method);
- }
- else {
- fprintf(args->stream, ":in %s", loc->method);
- }
- }
-
- fprintf(args->stream, "\n");
-}
-
-#endif
-
-static void
-get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
-{
- mrb_value ary, str;
- char buf[32];
- int ai = mrb_gc_arena_save(mrb);
-
- ary = mrb_obj_value((struct RArray*)data);
-
- str = mrb_str_new_cstr(mrb, loc->filename);
- snprintf(buf, sizeof(buf), ":%d", loc->lineno);
- mrb_str_cat_cstr(mrb, str, buf);
-
- if (loc->method) {
- mrb_str_cat_lit(mrb, str, ":in ");
-
- if (loc->class_name) {
- mrb_str_cat_cstr(mrb, str, loc->class_name);
- mrb_str_cat(mrb, str, &loc->sep, 1);
- }
-
- mrb_str_cat_cstr(mrb, str, loc->method);
- }
-
- mrb_ary_push(mrb, ary, str);
- mrb_gc_arena_restore(mrb, ai);
-}
+static const mrb_data_type bt_type = { "Backtrace", mrb_free };
static void
each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
{
- int i;
+ int i, j;
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
- for (i = ciidx; i >= 0; i--) {
- struct backtrace_location_raw loc;
+ for (i=ciidx, j=0; i >= 0; i--,j++) {
+ struct backtrace_location loc;
mrb_callinfo *ci;
mrb_irep *irep;
mrb_code *pc;
@@ -134,79 +61,15 @@ each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func
if (loc.lineno == -1) continue;
- if (ci->target_class == ci->proc->target_class) {
- loc.sep = '.';
- }
- else {
- loc.sep = '#';
- }
-
if (!loc.filename) {
loc.filename = "(unknown)";
}
loc.method_id = ci->mid;
- loc.klass = ci->proc->target_class;
- loc.i = i;
- func(mrb, &loc, data);
- }
-}
-
-struct output_backtrace_args {
- output_stream_func func;
- void *data;
-};
-
-static void
-output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data)
-{
- struct backtrace_location loc;
- struct output_backtrace_args *args = (struct output_backtrace_args *)data;
-
- loc.i = loc_raw->i;
- loc.lineno = loc_raw->lineno;
- loc.filename = loc_raw->filename;
- loc.method = mrb_sym2name(mrb, loc_raw->method_id);
- loc.sep = loc_raw->sep;
- loc.class_name = mrb_class_name(mrb, loc_raw->klass);
-
- args->func(mrb, &loc, args->data);
-}
-
-static void
-output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
-{
- struct output_backtrace_args args;
- args.func = func;
- args.data = data;
- each_backtrace(mrb, ciidx, pc0, output_backtrace_i, &args);
-}
-
-static void
-exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
-{
- mrb_value lastpc;
- mrb_code *code;
-
- lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"));
- if (mrb_nil_p(lastpc)) {
- code = NULL;
+ func(mrb, j, &loc, data);
}
- else {
- code = (mrb_code*)mrb_cptr(lastpc);
- }
-
- output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))),
- code, func, stream);
}
-/* mrb_print_backtrace/mrb_get_backtrace:
-
- function to retrieve backtrace information from the exception.
- note that if you call method after the exception, call stack will be
- overwritten. So invoke these functions just after detecting exceptions.
-*/
-
#ifndef MRB_DISABLE_STDIO
static void
@@ -215,11 +78,14 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
int i, n;
FILE *stream = stderr;
- fprintf(stream, "trace:\n");
+ if (!mrb_array_p(backtrace)) return;
- n = RARRAY_LEN(backtrace);
- for (i = 0; i < n; i++) {
- mrb_value entry = RARRAY_PTR(backtrace)[i];
+ n = RARRAY_LEN(backtrace) - 1;
+ if (n == 0) return;
+
+ fprintf(stream, "trace:\n");
+ for (i=0; i<n; i++) {
+ mrb_value entry = RARRAY_PTR(backtrace)[n-i-1];
if (mrb_string_p(entry)) {
fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
@@ -227,40 +93,54 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
}
}
+static int
+packed_bt_len(struct backtrace_location *bt, int n)
+{
+ int len = 0;
+ int i;
+
+ for (i=0; i<n; i++) {
+ if (!bt[i].filename && !bt[i].lineno && !bt[i].method_id)
+ continue;
+ len++;
+ }
+ return len;
+}
+
static void
-print_backtrace_saved(mrb_state *mrb)
+print_packed_backtrace(mrb_state *mrb, mrb_value packed)
{
- int i, ai;
FILE *stream = stderr;
+ struct backtrace_location *bt;
+ int n, i;
+ int ai = mrb_gc_arena_save(mrb);
- fprintf(stream, "trace:\n");
- ai = mrb_gc_arena_save(mrb);
- for (i = 0; i < mrb->backtrace.n; i++) {
- mrb_backtrace_entry *entry;
+ bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type);
+ if (bt == NULL) return;
+ n = (mrb_int)RDATA(packed)->flags;
- entry = &(mrb->backtrace.entries[i]);
+ if (packed_bt_len(bt, n) == 0) return;
+ fprintf(stream, "trace:\n");
+ for (i = 0; i<n; i++) {
+ struct backtrace_location *entry = &bt[n-i-1];
+ if (entry->filename == NULL) continue;
fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno);
-
if (entry->method_id != 0) {
const char *method_name;
method_name = mrb_sym2name(mrb, entry->method_id);
- if (entry->klass) {
- fprintf(stream, ":in %s%c%s",
- mrb_class_name(mrb, entry->klass),
- entry->sep,
- method_name);
- }
- else {
- fprintf(stream, ":in %s", method_name);
- }
+ fprintf(stream, ":in %s", method_name);
mrb_gc_arena_restore(mrb, ai);
}
-
fprintf(stream, "\n");
}
}
+/* mrb_print_backtrace
+
+ function to retrieve backtrace information from the last exception.
+*/
+
MRB_API void
mrb_print_backtrace(mrb_state *mrb)
{
@@ -271,20 +151,14 @@ mrb_print_backtrace(mrb_state *mrb)
}
backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
- if (!mrb_nil_p(backtrace)) {
+ if (mrb_nil_p(backtrace)) return;
+ if (mrb_array_p(backtrace)) {
print_backtrace(mrb, backtrace);
}
- else if (mrb->backtrace.n > 0) {
- print_backtrace_saved(mrb);
- }
else {
- struct print_backtrace_args args;
- args.stream = stderr;
- args.tracehead = TRUE;
- exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
+ print_packed_backtrace(mrb, backtrace);
}
}
-
#else
MRB_API void
@@ -294,135 +168,116 @@ mrb_print_backtrace(mrb_state *mrb)
#endif
-MRB_API mrb_value
-mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
+static void
+count_backtrace_i(mrb_state *mrb,
+ int i,
+ struct backtrace_location *loc,
+ void *data)
{
- mrb_value ary;
-
- ary = mrb_ary_new(mrb);
- exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary));
+ int *lenp = (int*)data;
- return ary;
+ if (loc->filename == NULL) return;
+ (*lenp)++;
}
-MRB_API mrb_value
-mrb_get_backtrace(mrb_state *mrb)
+static void
+pack_backtrace_i(mrb_state *mrb,
+ int i,
+ struct backtrace_location *loc,
+ void *data)
{
- mrb_value ary;
- mrb_callinfo *ci = mrb->c->ci;
- mrb_code *pc = ci->pc;
- mrb_int ciidx = (mrb_int)(ci - mrb->c->cibase - 1);
+ struct backtrace_location **pptr = (struct backtrace_location**)data;
+ struct backtrace_location *ptr = *pptr;
- if (ciidx < 0) ciidx = 0;
- ary = mrb_ary_new(mrb);
- output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary));
-
- return ary;
+ if (loc->filename == NULL) return;
+ *ptr = *loc;
+ *pptr = ptr+1;
}
-void
-mrb_free_backtrace(mrb_state *mrb)
+static mrb_value
+packed_backtrace(mrb_state *mrb)
{
- mrb->backtrace.exc = 0;
- mrb->backtrace.n = 0;
- mrb->backtrace.n_allocated = 0;
- mrb_free(mrb, mrb->backtrace.entries);
+ struct RData *backtrace;
+ ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase;
+ int len = 0;
+ int size;
+ void *ptr;
+
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len);
+ size = len * sizeof(struct backtrace_location);
+ ptr = mrb_malloc(mrb, size);
+ memset(ptr, 0, size);
+ backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type);
+ backtrace->flags = (unsigned int)len;
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr);
+ return mrb_obj_value(backtrace);
}
-static void
-save_backtrace_i(mrb_state *mrb,
- struct backtrace_location_raw *loc_raw,
- void *data)
+void
+mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
{
- mrb_backtrace_entry *entry;
-
- if (mrb->backtrace.n >= mrb->backtrace.n_allocated) {
- int new_n_allocated;
- if (mrb->backtrace.n_allocated == 0) {
- new_n_allocated = 8;
- }
- else {
- new_n_allocated = mrb->backtrace.n_allocated * 2;
- }
- mrb->backtrace.entries = (mrb_backtrace_entry *)
- mrb_realloc(mrb,
- mrb->backtrace.entries,
- sizeof(mrb_backtrace_entry) * new_n_allocated);
- mrb->backtrace.n_allocated = new_n_allocated;
- }
-
- entry = &mrb->backtrace.entries[mrb->backtrace.n];
- entry->filename = loc_raw->filename;
- entry->lineno = loc_raw->lineno;
- entry->klass = loc_raw->klass;
- entry->sep = loc_raw->sep;
- entry->method_id = loc_raw->method_id;
+ mrb_value backtrace;
+ int ai = mrb_gc_arena_save(mrb);
- mrb->backtrace.n++;
+ backtrace = packed_backtrace(mrb);
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+ mrb_gc_arena_restore(mrb, ai);
}
-void
-mrb_save_backtrace(mrb_state *mrb)
+mrb_value
+mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
{
- mrb_value lastpc;
- mrb_code *code;
- mrb_int ciidx;
-
- mrb->backtrace.n = 0;
- mrb->backtrace.exc = 0;
-
- if (!mrb->exc)
- return;
-
- mrb->backtrace.exc = mrb->exc;
+ struct backtrace_location *bt;
+ mrb_int n, i;
+ int ai;
- lastpc = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"));
- if (mrb_nil_p(lastpc)) {
- code = NULL;
- }
- else {
- code = (mrb_code*)mrb_cptr(lastpc);
+ if (mrb_nil_p(backtrace)) {
+ empty_backtrace:
+ return mrb_ary_new_capa(mrb, 0);
}
+ if (mrb_array_p(backtrace)) return backtrace;
+ bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type);
+ if (bt == NULL) goto empty_backtrace;
+ n = (mrb_int)RDATA(backtrace)->flags;
+ backtrace = mrb_ary_new_capa(mrb, n);
+ ai = mrb_gc_arena_save(mrb);
+ for (i = 0; i < n; i++) {
+ struct backtrace_location *entry = &bt[i];
+ mrb_value btline;
- ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx")));
+ if (entry->filename == NULL) continue;
+ btline = mrb_format(mrb, "%S:%S",
+ mrb_str_new_cstr(mrb, entry->filename),
+ mrb_fixnum_value(entry->lineno));
+ if (entry->method_id != 0) {
+ mrb_str_cat_lit(mrb, btline, ":in ");
+ mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id));
+ }
+ mrb_ary_push(mrb, backtrace, btline);
+ mrb_gc_arena_restore(mrb, ai);
+ }
- each_backtrace(mrb, ciidx, code, save_backtrace_i, NULL);
+ return backtrace;
}
-mrb_value
-mrb_restore_backtrace(mrb_state *mrb)
+MRB_API mrb_value
+mrb_exc_backtrace(mrb_state *mrb, mrb_value exc)
{
- int i;
+ mrb_sym attr_name;
mrb_value backtrace;
- backtrace = mrb_ary_new(mrb);
- for (i = 0; i < mrb->backtrace.n; i++) {
- int ai;
- mrb_backtrace_entry *entry;
- mrb_value mrb_entry;
- char buf[32];
-
- ai = mrb_gc_arena_save(mrb);
- entry = &(mrb->backtrace.entries[i]);
-
- mrb_entry = mrb_str_new_cstr(mrb, entry->filename);
- snprintf(buf, sizeof(buf), ":%d", entry->lineno);
- mrb_str_cat_cstr(mrb, mrb_entry, buf);
- if (entry->method_id != 0) {
- mrb_str_cat_lit(mrb, mrb_entry, ":in ");
-
- if (entry->klass) {
- mrb_str_cat_cstr(mrb, mrb_entry, mrb_class_name(mrb, entry->klass));
- mrb_str_cat(mrb, mrb_entry, &entry->sep, 1);
- }
-
- mrb_str_cat_cstr(mrb, mrb_entry, mrb_sym2name(mrb, entry->method_id));
- }
-
- mrb_ary_push(mrb, backtrace, mrb_entry);
-
- mrb_gc_arena_restore(mrb, ai);
+ attr_name = mrb_intern_lit(mrb, "backtrace");
+ backtrace = mrb_iv_get(mrb, exc, attr_name);
+ if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) {
+ return backtrace;
}
-
+ backtrace = mrb_unpack_backtrace(mrb, backtrace);
+ mrb_iv_set(mrb, exc, attr_name, backtrace);
return backtrace;
}
+
+MRB_API mrb_value
+mrb_get_backtrace(mrb_state *mrb)
+{
+ return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
+}
diff --git a/src/class.c b/src/class.c
index 7cb544b43..57f64dcc5 100644
--- a/src/class.c
+++ b/src/class.c
@@ -123,25 +123,44 @@ module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
return mrb_class_ptr(c);
}
+static mrb_bool
+class_ptr_p(mrb_value obj)
+{
+ switch (mrb_type(obj)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
MRB_API struct RClass*
mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
{
mrb_value outer;
+ struct RClass *cls;
outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
if (mrb_nil_p(outer)) return NULL;
- return mrb_class_ptr(outer);
+ cls = mrb_class_ptr(outer);
+ if (cls->tt == MRB_TT_SCLASS)
+ {
+ mrb_value klass;
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
+ mrb_intern_lit(mrb, "__attached__"));
+ if (class_ptr_p(klass)) {
+ cls = mrb_class_ptr(klass);
+ }
+ }
+ return cls;
}
static void
check_if_class_or_module(mrb_state *mrb, mrb_value obj)
{
- switch (mrb_type(obj)) {
- case MRB_TT_CLASS:
- case MRB_TT_SCLASS:
- case MRB_TT_MODULE:
- return;
- default:
+ if (!class_ptr_p(obj)) {
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj));
}
}
@@ -412,6 +431,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
if (p) {
+ p->c = NULL;
mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
}
}
@@ -532,9 +552,9 @@ to_sym(mrb_state *mrb, mrb_value ss)
d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
I: Inline struct [void*]
&: Block [mrb_value]
- *: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array.
- |: optional Next argument of '|' and later are optional.
- ?: optional given [mrb_bool] true if preceding argument (optional) is given.
+ *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
+ |: optional Following arguments are optional
+ ?: optional given [mrb_bool] true if preceding argument (optional) is given
*/
MRB_API mrb_int
mrb_get_args(mrb_state *mrb, const char *format, ...)
@@ -544,7 +564,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
va_list ap;
int argc = mrb->c->ci->argc;
int arg_i = 0;
- mrb_bool array_argv;
+ mrb_value *array_argv;
mrb_bool opt = FALSE;
mrb_bool given = TRUE;
@@ -552,15 +572,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (argc < 0) {
struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
- argc = a->len;
- array_argv = TRUE;
+ argc = ARY_LEN(a);
+ array_argv = ARY_PTR(a);
}
else {
- array_argv = FALSE;
+ array_argv = NULL;
}
#define ARGV \
- (array_argv ? mrb_ary_ptr(mrb->c->stack[1])->ptr : (mrb->c->stack + 1))
+ (array_argv ? array_argv : (mrb->c->stack + 1))
while ((c = *format++)) {
switch (c) {
@@ -599,14 +619,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value ss;
ss = ARGV[arg_i++];
- switch (mrb_type(ss)) {
- case MRB_TT_CLASS:
- case MRB_TT_MODULE:
- case MRB_TT_SCLASS:
- break;
- default:
+ if (!class_ptr_p(ss)) {
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
- break;
}
*p = ss;
i++;
@@ -683,7 +697,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc && mrb_nil_p(ARGV[arg_i])) {
*ps = NULL;
*pl = 0;
- i++;
+ i++; arg_i++;
break;
}
}
@@ -737,8 +751,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
aa = to_ary(mrb, ARGV[arg_i++]);
a = mrb_ary_ptr(aa);
- *pb = a->ptr;
- *pl = a->len;
+ *pb = ARY_PTR(a);
+ *pl = ARY_LEN(a);
i++;
}
}
@@ -787,7 +801,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
mrb_float f = mrb_float(ARGV[arg_i]);
- if (!FIXABLE(f)) {
+ if (!FIXABLE_FLOAT(f)) {
mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
}
*p = (mrb_int)f;
@@ -882,13 +896,25 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
mrb_value **var;
mrb_int *pl;
+ mrb_bool nocopy = array_argv ? TRUE : FALSE;
+ if (*format == '!') {
+ format++;
+ nocopy = TRUE;
+ }
var = va_arg(ap, mrb_value**);
pl = va_arg(ap, mrb_int*);
if (argc > i) {
*pl = argc-i;
if (*pl > 0) {
- *var = ARGV + arg_i;
+ if (nocopy) {
+ *var = ARGV+arg_i;
+ }
+ else {
+ mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i);
+ RARRAY(args)->c = NULL;
+ *var = RARRAY_PTR(args);
+ }
}
i = argc;
arg_i += *pl;
@@ -979,7 +1005,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
if (p->tt == MRB_TT_ICLASS) {
if (p->mt == m->mt) {
if (!superclass_seen) {
- ins_pos = p; // move insert point
+ ins_pos = p; /* move insert point */
}
goto skip;
}
@@ -1146,7 +1172,7 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod)
{
mrb_value b;
struct RClass *m = mrb_class_ptr(mod);
- boot_initmod(mrb, m); // bootstrap a newly initialized module
+ boot_initmod(mrb, m); /* bootstrap a newly initialized module */
mrb_get_args(mrb, "|&", &b);
if (!mrb_nil_p(b)) {
mrb_yield_with_class(mrb, b, 1, &mod, mod, m);
@@ -1755,15 +1781,11 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
str = mrb_str_new_lit(mrb, "#<Class:");
- switch (mrb_type(v)) {
- case MRB_TT_CLASS:
- case MRB_TT_MODULE:
- case MRB_TT_SCLASS:
- mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
- break;
- default:
- mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v));
- break;
+ if (class_ptr_p(v)) {
+ mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
+ }
+ else {
+ mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v));
}
return mrb_str_cat_lit(mrb, str, ">");
}
@@ -2139,13 +2161,43 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
}
static mrb_value
+mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+ check_const_name_sym(mrb, id);
+ return mrb_const_get(mrb, mod, id);
+}
+
+static mrb_value
mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
{
+ mrb_value path;
mrb_sym id;
+ char *ptr;
+ mrb_int off, end, len;
- mrb_get_args(mrb, "n", &id);
- check_const_name_sym(mrb, id);
- return mrb_const_get(mrb, mod, id);
+ mrb_get_args(mrb, "o", &path);
+
+ if (mrb_symbol_p(path)) {
+ /* const get with symbol */
+ id = mrb_symbol(path);
+ return mrb_const_get_sym(mrb, mod, id);
+ }
+
+ /* const get with class path string */
+ path = mrb_string_type(mrb, path);
+ ptr = RSTRING_PTR(path);
+ len = RSTRING_LEN(path);
+ off = 0;
+
+ while (off < len) {
+ end = mrb_str_index_lit(mrb, path, "::", off);
+ end = (end == -1) ? len : end;
+ id = mrb_intern(mrb, ptr+off, end-off);
+ mod = mrb_const_get_sym(mrb, mod, id);
+ off = (end == len) ? end : end+2;
+ }
+
+ return mod;
}
static mrb_value
@@ -2156,7 +2208,14 @@ mrb_mod_const_set(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "no", &id, &value);
check_const_name_sym(mrb, id);
- mrb_const_set(mrb, mod, id, value);
+ if ((mrb_type(value) == MRB_TT_CLASS || mrb_type(value) == MRB_TT_MODULE)
+ && !mrb_obj_iv_defined(mrb, mrb_obj_ptr(value), mrb_intern_lit(mrb, "__classid__"))) {
+ /* name unnamed classes/modules */
+ setup_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(value), id);
+ }
+ else {
+ mrb_const_set(mrb, mod, id, value);
+ }
return value;
}
diff --git a/src/codedump.c b/src/codedump.c
index c20afdd00..6b2c43b48 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -239,6 +239,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
printf("OP_RETURN\tR%d", GETARG_A(c));
switch (GETARG_B(c)) {
case OP_R_NORMAL:
+ printf("\tnormal\t"); break;
case OP_R_RETURN:
printf("\treturn\t"); break;
case OP_R_BREAK:
@@ -258,7 +259,15 @@ codedump(mrb_state *mrb, mrb_irep *irep)
break;
case OP_LAMBDA:
- printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c));
+ printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1);
+ switch (GETARG_c(c)) {
+ case OP_L_METHOD:
+ printf("method"); break;
+ case OP_L_BLOCK:
+ printf("block"); break;
+ case OP_L_LAMBDA:
+ printf("lambda"); break;
+ }
print_lv(mrb, irep, c, RA);
break;
case OP_RANGE:
diff --git a/src/error.c b/src/error.c
index 2201fc840..062282719 100644
--- a/src/error.c
+++ b/src/error.c
@@ -47,7 +47,7 @@ exc_initialize(mrb_state *mrb, mrb_value exc)
mrb_int argc;
mrb_value *argv;
- if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) {
+ if (mrb_get_args(mrb, "|o*!", &mesg, &argv, &argc) >= 1) {
mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
}
return exc;
@@ -62,7 +62,7 @@ exc_initialize(mrb_state *mrb, mrb_value exc)
* With no argument, or if the argument is the same as the receiver,
* return the receiver. Otherwise, create a new
* exception object of the same class as the receiver, but with a
- * message equal to <code>string.to_str</code>.
+ * message equal to <code>string</code>.
*
*/
@@ -111,9 +111,7 @@ exc_to_s(mrb_state *mrb, mrb_value exc)
* exception.message -> string
*
* Returns the result of invoking <code>exception.to_s</code>.
- * Normally this returns the exception's message or name. By
- * supplying a to_str method, exceptions are agreeing to
- * be used where Strings are expected.
+ * Normally this returns the exception's message or name.
*/
static mrb_value
@@ -137,6 +135,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
{
mrb_value str, mesg, file, line;
mrb_bool append_mesg;
+ const char *cname;
mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
@@ -148,57 +147,23 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
append_mesg = RSTRING_LEN(mesg) > 0;
}
+ cname = mrb_obj_classname(mrb, exc);
+ str = mrb_str_new_cstr(mrb, cname);
if (mrb_string_p(file) && mrb_fixnum_p(line)) {
- char buf[32];
-
- str = mrb_str_dup(mrb, file);
- snprintf(buf, sizeof(buf), ":%" MRB_PRId ": ", mrb_fixnum(line));
- mrb_str_cat_cstr(mrb, str, buf);
if (append_mesg) {
- mrb_str_cat_str(mrb, str, mesg);
- mrb_str_cat_lit(mrb, str, " (");
+ str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str);
}
- mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
- if (append_mesg) {
- mrb_str_cat_lit(mrb, str, ")");
+ else {
+ str = mrb_format(mrb, "%S:%S: %S", file, line, str);
}
}
- else {
- const char *cname = mrb_obj_classname(mrb, exc);
- str = mrb_str_new_cstr(mrb, cname);
- if (append_mesg) {
- mrb_str_cat_lit(mrb, str, ": ");
- mrb_str_cat_str(mrb, str, mesg);
- }
+ else if (append_mesg) {
+ str = mrb_format(mrb, "%S: %S", str, mesg);
}
return str;
}
-void mrb_save_backtrace(mrb_state *mrb);
-mrb_value mrb_restore_backtrace(mrb_state *mrb);
-
-static mrb_value
-exc_get_backtrace(mrb_state *mrb, mrb_value exc)
-{
- mrb_sym attr_name;
- mrb_value backtrace;
-
- attr_name = mrb_intern_lit(mrb, "backtrace");
- backtrace = mrb_iv_get(mrb, exc, attr_name);
- if (mrb_nil_p(backtrace)) {
- if (mrb_obj_ptr(exc) == mrb->backtrace.exc && mrb->backtrace.n > 0) {
- backtrace = mrb_restore_backtrace(mrb);
- mrb->backtrace.n = 0;
- mrb->backtrace.exc = 0;
- }
- else {
- backtrace = mrb_exc_backtrace(mrb, exc);
- }
- mrb_iv_set(mrb, exc, attr_name, backtrace);
- }
-
- return backtrace;
-}
+void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
static void
set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
@@ -235,7 +200,6 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
mrb_callinfo *ci = mrb->c->ci;
mrb_code *pc = ci->pc;
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase)));
while (ci >= mrb->c->cibase) {
mrb_code *err = ci->err;
@@ -256,41 +220,18 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
}
}
-static mrb_bool
-have_backtrace(mrb_state *mrb, struct RObject *exc)
-{
- return !mrb_nil_p(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "backtrace")));
-}
-
void
mrb_exc_set(mrb_state *mrb, mrb_value exc)
{
- if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) {
- mrb_value target_exc = mrb_nil_value();
- int ai;
-
- ai = mrb_gc_arena_save(mrb);
- if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) {
- target_exc = mrb_obj_value(mrb->exc);
- }
- else if (!mrb_nil_p(exc) && mrb->backtrace.exc) {
- target_exc = mrb_obj_value(mrb->backtrace.exc);
- mrb_gc_protect(mrb, target_exc);
- }
- if (!mrb_nil_p(target_exc)) {
- mrb_value backtrace;
- backtrace = mrb_restore_backtrace(mrb);
- set_backtrace(mrb, target_exc, backtrace);
- }
- mrb_gc_arena_restore(mrb, ai);
- }
-
- mrb->backtrace.n = 0;
if (mrb_nil_p(exc)) {
mrb->exc = 0;
}
else {
mrb->exc = mrb_obj_ptr(exc);
+ if (!mrb->gc.out_of_memory) {
+ exc_debug_info(mrb, mrb->exc);
+ mrb_keep_backtrace(mrb, exc);
+ }
}
}
@@ -301,10 +242,6 @@ mrb_exc_raise(mrb_state *mrb, mrb_value exc)
mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
}
mrb_exc_set(mrb, exc);
- if (!mrb->gc.out_of_memory) {
- exc_debug_info(mrb, mrb->exc);
- mrb_save_backtrace(mrb);
- }
if (!mrb->jmp) {
mrb_p(mrb, exc);
abort();
@@ -535,7 +472,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
void
mrb_init_exception(mrb_state *mrb)
{
- struct RClass *exception, *runtime_error, *script_error, *stack_error;
+ struct RClass *exception, *script_error, *stack_error, *nomem_error;
mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
@@ -545,17 +482,19 @@ mrb_init_exception(mrb_state *mrb)
mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
- mrb_define_method(mrb, exception, "backtrace", exc_get_backtrace, MRB_ARGS_NONE());
+ mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1));
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
- runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
- mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory"));
-#ifdef MRB_GC_FIXED_ARENA
- mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "arena overflow error"));
-#endif
+ mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
stack_error = mrb_define_class(mrb, "SystemStackError", exception);
mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
+
+ nomem_error = mrb_define_class(mrb, "NoMemoryError", exception);
+ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "Out of memory"));
+#ifdef MRB_GC_FIXED_ARENA
+ mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error"));
+#endif
}
diff --git a/src/gc.c b/src/gc.c
index 391da84cb..8cc8feb08 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -17,6 +17,7 @@
#include <mruby/variable.h>
#include <mruby/gc.h>
#include <mruby/error.h>
+#include <mruby/throw.h>
/*
= Tri-color Incremental Garbage Collection
@@ -111,6 +112,7 @@ typedef struct {
struct RProc proc;
struct REnv env;
struct RException exc;
+ struct RBreak brk;
#ifdef MRB_WORD_BOXING
struct RFloat floatv;
struct RCptr cptr;
@@ -214,7 +216,8 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
void *p2;
p2 = mrb_realloc_simple(mrb, p, len);
- if (!p2 && len) {
+ if (len == 0) return p2;
+ if (p2 == NULL) {
if (mrb->gc.out_of_memory) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
/* mrb_panic(mrb); */
@@ -430,7 +433,7 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj)
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
+ arguments. Don't forget to remove the object using
mrb_gc_unregister, otherwise your object will leak.
*/
@@ -463,10 +466,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
}
a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
- for (i = 0; i < a->len; i++) {
- if (mrb_obj_eq(mrb, a->ptr[i], obj)) {
- a->len--;
- memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i]));
+ for (i = 0; i < ARY_LEN(a); i++) {
+ if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) {
+ mrb_int len = ARY_LEN(a)-1;
+ mrb_value *ptr = ARY_PTR(a);
+
+ ARY_SET_LEN(a, len);
+ memmove(&ptr[i], &ptr[i + 1], (len - i) * sizeof(mrb_value));
break;
}
}
@@ -544,22 +550,30 @@ mark_context_stack(mrb_state *mrb, struct mrb_context *c)
{
size_t i;
size_t e;
+ mrb_value nil;
+ int nregs;
+ if (c->stack == NULL) return;
e = c->stack - c->stbase;
- if (c->ci) e += c->ci->nregs;
+ if (c->ci) {
+ nregs = c->ci->argc + 2;
+ if (c->ci->nregs > nregs)
+ nregs = c->ci->nregs;
+ e += nregs;
+ }
if (c->stbase + e > c->stend) e = c->stend - c->stbase;
for (i=0; i<e; i++) {
mrb_value v = c->stbase[i];
if (!mrb_immediate_p(v)) {
- if (mrb_basic_ptr(v)->tt == MRB_TT_FREE) {
- c->stbase[i] = mrb_nil_value();
- }
- else {
- mrb_gc_mark(mrb, mrb_basic_ptr(v));
- }
+ mrb_gc_mark(mrb, mrb_basic_ptr(v));
}
}
+ e = c->stend - c->stbase;
+ nil = mrb_nil_value();
+ for (; i<e; i++) {
+ c->stbase[i] = nil;
+ }
}
static void
@@ -568,10 +582,12 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
int i;
mrb_callinfo *ci;
- /* mark stack */
- mark_context_stack(mrb, c);
+ if (c->status == MRB_FIBER_TERMINATED) return;
/* mark VM stack */
+ mark_context_stack(mrb, c);
+
+ /* mark call stack */
if (c->cibase) {
for (ci = c->cibase; ci <= c->ci; ci++) {
mrb_gc_mark(mrb, (struct RBasic*)ci->env);
@@ -585,8 +601,9 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
}
/* mark fibers */
- if (c->prev && c->prev->fib) {
- mrb_gc_mark(mrb, (struct RBasic*)c->prev->fib);
+ mrb_gc_mark(mrb, (struct RBasic*)c->fib);
+ if (c->prev) {
+ mark_context(mrb, c->prev);
}
}
@@ -638,7 +655,12 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct REnv *e = (struct REnv*)obj;
mrb_int i, len;
- if MRB_ENV_STACK_SHARED_P(e) break;
+ if (MRB_ENV_STACK_SHARED_P(e)) {
+ if (e->cxt.c->fib) {
+ mrb_gc_mark(mrb, (struct RBasic*)e->cxt.c->fib);
+ }
+ break;
+ }
len = MRB_ENV_STACK_LEN(e);
for (i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
@@ -659,8 +681,8 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct RArray *a = (struct RArray*)obj;
size_t i, e;
- for (i=0,e=a->len; i<e; i++) {
- mrb_gc_mark_value(mrb, a->ptr[i]);
+ for (i=0,e=ARY_LEN(a); i<e; i++) {
+ mrb_gc_mark_value(mrb, ARY_PTR(a)[i]);
}
}
break;
@@ -701,7 +723,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
static void
obj_free(mrb_state *mrb, struct RBasic *obj, int end)
{
- DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt));
+ DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt));
switch (obj->tt) {
/* immediate - no mark */
case MRB_TT_TRUE:
@@ -723,8 +745,6 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
case MRB_TT_EXCEPTION:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
- if ((struct RObject*)obj == mrb->backtrace.exc)
- mrb->backtrace.exc = 0;
break;
case MRB_TT_CLASS:
@@ -753,6 +773,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
case MRB_TT_FIBER:
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
+
if (!end && c && c != mrb->root_c) {
mrb_callinfo *ci = c->ci;
mrb_callinfo *ce = c->cibase;
@@ -772,9 +793,9 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
case MRB_TT_ARRAY:
if (ARY_SHARED_P(obj))
- mrb_ary_decref(mrb, ((struct RArray*)obj)->aux.shared);
- else
- mrb_free(mrb, ((struct RArray*)obj)->ptr);
+ mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared);
+ else if (!ARY_EMBED_P(obj))
+ mrb_free(mrb, ((struct RArray*)obj)->as.heap.ptr);
break;
case MRB_TT_HASH:
@@ -819,7 +840,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
static void
root_scan_phase(mrb_state *mrb, mrb_gc *gc)
{
- size_t i, e;
+ int i, e;
if (!is_minor_gc(gc)) {
gc->gray_list = NULL;
@@ -857,12 +878,6 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
/* mark exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
- /* mark backtrace */
- mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc);
- e = (size_t)mrb->backtrace.n;
- for (i=0; i<e; i++) {
- mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.entries[i].klass);
- }
/* mark pre-allocated exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err);
@@ -870,12 +885,9 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err);
#endif
- mark_context(mrb, mrb->root_c);
- if (mrb->root_c->fib) {
- mrb_gc_mark(mrb, (struct RBasic*)mrb->root_c->fib);
- }
+ mark_context(mrb, mrb->c);
if (mrb->root_c != mrb->c) {
- mark_context(mrb, mrb->c);
+ mark_context(mrb, mrb->root_c);
}
}
@@ -927,7 +939,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
children += i;
/* mark ensure stack */
- children += (c->ci) ? c->ci->eidx : 0;
+ children += c->eidx;
/* mark closure */
if (c->cibase) {
@@ -941,7 +953,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_ARRAY:
{
struct RArray *a = (struct RArray*)obj;
- children += a->len;
+ children += ARY_LEN(a);
}
break;
@@ -988,7 +1000,16 @@ incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
static void
final_marking_phase(mrb_state *mrb, mrb_gc *gc)
{
- mark_context_stack(mrb, mrb->root_c);
+ int i, e;
+
+ /* mark arena */
+ for (i=0,e=gc->arena_idx; i<e; i++) {
+ mrb_gc_mark(mrb, gc->arena[i]);
+ }
+ mrb_gc_mark_gv(mrb);
+ mark_context(mrb, mrb->c);
+ mark_context(mrb, mrb->root_c);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
gc_mark_gray_list(mrb, gc);
mrb_assert(gc->gray_list == NULL);
gc->gray_list = gc->atomic_gray_list;
@@ -1153,7 +1174,7 @@ mrb_incremental_gc(mrb_state *mrb)
{
mrb_gc *gc = &mrb->gc;
- if (gc->disabled) return;
+ if (gc->disabled || gc->iterating) return;
GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
GC_TIME_START;
@@ -1193,7 +1214,7 @@ mrb_full_gc(mrb_state *mrb)
{
mrb_gc *gc = &mrb->gc;
- if (gc->disabled) return;
+ if (gc->disabled || gc->iterating) return;
GC_INVOKE_TIME_REPORT("mrb_full_gc()");
GC_TIME_START;
@@ -1225,34 +1246,6 @@ mrb_garbage_collect(mrb_state *mrb)
mrb_full_gc(mrb);
}
-MRB_API int
-mrb_gc_arena_save(mrb_state *mrb)
-{
- 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 = 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 != gc->arena_capa) {
- gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
- gc->arena_capa = capa;
- }
- }
-#endif
- gc->arena_idx = idx;
-}
-
/*
* Field write barrier
* Paint obj(Black) -> value(White) to obj(Black) -> value(Gray).
@@ -1430,6 +1423,10 @@ gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
static void
change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
{
+ if (gc->disabled || gc->iterating) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "generational mode changed when GC disabled");
+ return;
+ }
if (is_generational(gc) && !enable) {
clear_all_old(mrb, gc);
mrb_assert(gc->state == MRB_GC_STATE_ROOT);
@@ -1481,17 +1478,18 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
static void
gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
{
- mrb_heap_page* page = gc->heaps;
+ mrb_heap_page* page;
+ page = gc->heaps;
while (page != NULL) {
- RVALUE *p, *pend;
+ RVALUE *p;
+ int i;
p = objects(page);
- pend = p + MRB_HEAP_PAGE_SIZE;
- for (;p < pend; p++) {
- (*callback)(mrb, &p->as.basic, data);
+ for (i=0; i < MRB_HEAP_PAGE_SIZE; i++) {
+ if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK)
+ return;
}
-
page = page->next;
}
}
@@ -1499,7 +1497,27 @@ gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback,
void
mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
{
- gc_each_objects(mrb, &mrb->gc, callback, data);
+ mrb_bool iterating = mrb->gc.iterating;
+
+ mrb->gc.iterating = TRUE;
+ if (iterating) {
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+ }
+ else {
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
+
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+ mrb->jmp = prev_jmp;
+ mrb->gc.iterating = iterating;
+ } MRB_CATCH(&c_jmp) {
+ mrb->gc.iterating = iterating;
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
+ } MRB_END_EXC(&c_jmp);
+ }
}
#ifdef GC_TEST
diff --git a/src/hash.c b/src/hash.c
index 86dfae996..27d25b384 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -140,7 +140,7 @@ mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
MRB_API mrb_value
-mrb_hash_new_capa(mrb_state *mrb, int capa)
+mrb_hash_new_capa(mrb_state *mrb, mrb_int capa)
{
struct RHash *h;
@@ -238,7 +238,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
ret->ht = kh_init(ht, mrb);
- if (kh_size(h) > 0) {
+ if (h && kh_size(h) > 0) {
ret_h = ret->ht;
for (k = kh_begin(h); k != kh_end(h); k++) {
@@ -759,7 +759,7 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash)
ary = mrb_ary_new_capa(mrb, kh_size(h));
end = kh_size(h)-1;
mrb_ary_set(mrb, ary, end, mrb_nil_value());
- p = mrb_ary_ptr(ary)->ptr;
+ p = RARRAY_PTR(ary);
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
mrb_value kv = kh_key(h, k);
diff --git a/src/init.c b/src/init.c
index 9a6496df1..afd69975a 100644
--- a/src/init.c
+++ b/src/init.c
@@ -13,9 +13,9 @@ void mrb_init_kernel(mrb_state*);
void mrb_init_comparable(mrb_state*);
void mrb_init_enumerable(mrb_state*);
void mrb_init_symbol(mrb_state*);
+void mrb_init_string(mrb_state*);
void mrb_init_exception(mrb_state*);
void mrb_init_proc(mrb_state*);
-void mrb_init_string(mrb_state*);
void mrb_init_array(mrb_state*);
void mrb_init_hash(mrb_state*);
void mrb_init_numeric(mrb_state*);
@@ -38,9 +38,9 @@ mrb_init_core(mrb_state *mrb)
mrb_init_enumerable(mrb); DONE;
mrb_init_symbol(mrb); DONE;
+ mrb_init_string(mrb); DONE;
mrb_init_exception(mrb); DONE;
mrb_init_proc(mrb); DONE;
- mrb_init_string(mrb); DONE;
mrb_init_array(mrb); DONE;
mrb_init_hash(mrb); DONE;
mrb_init_numeric(mrb); DONE;
diff --git a/src/kernel.c b/src/kernel.c
index 8670e0651..bd21ddf53 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -136,38 +136,38 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
{
mrb_callinfo *ci = mrb->c->ci;
mrb_value *bp;
- mrb_bool given_p;
bp = ci->stackent + 1;
ci--;
if (ci <= mrb->c->cibase) {
- given_p = FALSE;
+ return mrb_false_value();
}
- else {
- /* block_given? called within block; check upper scope */
- if (ci->proc->env) {
- struct REnv *e = ci->proc->env;
- mrb_value *sp;
+ /* block_given? called within block; check upper scope */
+ if (ci->proc->env) {
+ struct REnv *e = ci->proc->env;
- while (e->c) {
- e = (struct REnv*)e->c;
- }
- sp = e->stack;
- if (sp) {
- /* top-level does not have block slot (alway false) */
- if (sp == mrb->c->stbase)
- return mrb_false_value();
- ci = mrb->c->cibase + e->cioff;
- bp = ci[1].stackent + 1;
- }
+ while (e->c) {
+ e = (struct REnv*)e->c;
}
- if (ci->argc > 0) {
- bp += ci->argc;
+ /* top-level does not have block slot (always false) */
+ if (e->stack == mrb->c->stbase)
+ return mrb_false_value();
+ if (e->stack && e->cioff < 0) {
+ /* use saved block arg position */
+ bp = &e->stack[-e->cioff];
+ ci = 0; /* no callinfo available */
+ }
+ else {
+ ci = e->cxt.c->cibase + e->cioff;
+ bp = ci[1].stackent + 1;
}
- given_p = !mrb_nil_p(*bp);
}
-
- return mrb_bool_value(given_p);
+ if (ci && ci->argc > 0) {
+ bp += ci->argc;
+ }
+ if (mrb_nil_p(*bp))
+ return mrb_false_value();
+ return mrb_true_value();
}
/* 15.3.1.3.7 */
@@ -199,11 +199,13 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
/* copy singleton(unnamed) class */
struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class);
- if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) {
- clone->c = clone;
- }
- else {
+ switch (mrb_type(obj)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ break;
+ default:
clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass));
+ break;
}
clone->super = klass->super;
if (klass->iv) {
@@ -241,7 +243,12 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0)));
c1->super->flags |= MRB_FLAG_IS_ORIGIN;
}
- dc->mt = kh_copy(mt, mrb, sc->mt);
+ if (sc->mt) {
+ dc->mt = kh_copy(mt, mrb, sc->mt);
+ }
+ else {
+ dc->mt = kh_init(mt, mrb);
+ }
dc->super = sc->super;
MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc));
}
@@ -311,6 +318,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self)
}
p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self));
p->c = mrb_singleton_class_clone(mrb, self);
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c);
clone = mrb_obj_value(p);
init_copy(mrb, clone, self);
@@ -403,11 +411,8 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
mrb_int argc;
- mrb_value args;
mrb_get_args(mrb, "*", &argv, &argc);
- args = mrb_ary_new_from_values(mrb, argc, argv);
- argv = (mrb_value*)RARRAY_PTR(args);
return mrb_obj_extend(mrb, argc, argv, self);
}
@@ -867,7 +872,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
/* fall through */
default:
exc = mrb_make_exception(mrb, argc, a);
- mrb_obj_iv_set(mrb, mrb_obj_ptr(exc), mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, mrb->c->ci->pc));
mrb_exc_raise(mrb, exc);
break;
}
@@ -977,7 +981,7 @@ mrb_obj_missing(mrb_state *mrb, mrb_value mod)
mrb_value *a;
mrb_int alen;
- mrb_get_args(mrb, "n*", &name, &a, &alen);
+ mrb_get_args(mrb, "n*!", &name, &a, &alen);
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
return mrb_nil_value();
@@ -1160,8 +1164,8 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
while (e) {
if (MRB_ENV_STACK_SHARED_P(e) &&
- !MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) {
- irep = mrb->c->cibase[e->cioff].proc->body.irep;
+ !MRB_PROC_CFUNC_P(e->cxt.c->cibase[e->cioff].proc)) {
+ irep = e->cxt.c->cibase[e->cioff].proc->body.irep;
if (irep->lv) {
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
diff --git a/src/numeric.c b/src/numeric.c
index 2117fcc3c..be71f1185 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -52,14 +52,32 @@ static mrb_value
num_pow(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_float d, yv;
+ mrb_float d;
mrb_get_args(mrb, "o", &y);
- yv = mrb_to_flo(mrb, y);
- d = pow(mrb_to_flo(mrb, x), yv);
- if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0 &&
- (d < 0 || (d > 0 && (mrb_int)d > 0)))
- return mrb_fixnum_value((mrb_int)d);
+ if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) {
+ /* try ipow() */
+ mrb_int base = mrb_fixnum(x);
+ mrb_int exp = mrb_fixnum(y);
+ mrb_int result = 1;
+
+ if (exp < 0) goto float_pow;
+ for (;;) {
+ if (exp & 1) {
+ if (mrb_int_mul_overflow(result, base, &result)) {
+ goto float_pow;
+ }
+ }
+ exp >>= 1;
+ if (exp == 0) break;
+ if (mrb_int_mul_overflow(base, base, &base)) {
+ goto float_pow;
+ }
+ }
+ return mrb_fixnum_value(result);
+ }
+ float_pow:
+ d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
return mrb_float_value(mrb, d);
}
@@ -169,7 +187,12 @@ flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *
mrb_float mod;
if (y == 0.0) {
- div = INFINITY;
+ if (x == 0.0) {
+ div = NAN;
+ }
+ else {
+ div = INFINITY;
+ }
mod = NAN;
}
else {
@@ -371,7 +394,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
val *= 2;
}
}
- if (FIXABLE(val)) {
+ if (FIXABLE_FLOAT(val)) {
return mrb_fixnum_value((mrb_int)val);
}
return mrb_float_value(mrb, val);
@@ -408,13 +431,13 @@ flo_hash(mrb_state *mrb, mrb_value num)
mrb_float d;
char *c;
size_t i;
- int hash;
+ mrb_int hash;
d = (mrb_float)mrb_fixnum(num);
/* normalize -0.0 to 0.0 */
if (d == 0) d = 0.0;
c = (char*)&d;
- for (hash=0, i=0; i<sizeof(mrb_float);i++) {
+ for (hash=0,i=0; i<sizeof(mrb_float); i++) {
hash = (hash * 971) ^ (unsigned char)c[i];
}
if (hash < 0) hash = -hash;
@@ -476,6 +499,17 @@ flo_finite_p(mrb_state *mrb, mrb_value num)
return mrb_bool_value(isfinite(mrb_float(num)));
}
+void
+mrb_check_num_exact(mrb_state *mrb, mrb_float num)
+{
+ if (isinf(num)) {
+ mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
+ }
+ if (isnan(num)) {
+ mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
+ }
+}
+
/* 15.2.9.3.10 */
/*
* call-seq:
@@ -494,7 +528,8 @@ flo_floor(mrb_state *mrb, mrb_value num)
{
mrb_float f = floor(mrb_float(num));
- if (!FIXABLE(f)) {
+ mrb_check_num_exact(mrb, f);
+ if (!FIXABLE_FLOAT(f)) {
return mrb_float_value(mrb, f);
}
return mrb_fixnum_value((mrb_int)f);
@@ -519,7 +554,8 @@ flo_ceil(mrb_state *mrb, mrb_value num)
{
mrb_float f = ceil(mrb_float(num));
- if (!FIXABLE(f)) {
+ mrb_check_num_exact(mrb, f);
+ if (!FIXABLE_FLOAT(f)) {
return mrb_float_value(mrb, f);
}
return mrb_fixnum_value((mrb_int)f);
@@ -566,14 +602,10 @@ flo_round(mrb_state *mrb, mrb_value num)
mrb_get_args(mrb, "|i", &ndigits);
number = mrb_float(num);
- if (isinf(number)) {
- if (0 < ndigits) return num;
- else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, number < 0 ? "-Infinity" : "Infinity");
- }
- if (isnan(number)) {
- if (0 < ndigits) return num;
- else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
+ if (0 < ndigits && (isinf(number) || isnan(number))) {
+ return num;
}
+ mrb_check_num_exact(mrb, number);
f = 1.0;
i = ndigits >= 0 ? ndigits : -ndigits;
@@ -610,17 +642,6 @@ flo_round(mrb_state *mrb, mrb_value num)
return mrb_fixnum_value((mrb_int)number);
}
-void
-mrb_check_num_exact(mrb_state *mrb, mrb_float num)
-{
- if (isinf(num)) {
- mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
- }
- if (isnan(num)) {
- mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
- }
-}
-
/* 15.2.9.3.14 */
/* 15.2.9.3.15 */
/*
@@ -640,8 +661,8 @@ flo_truncate(mrb_state *mrb, mrb_value num)
if (f > 0.0) f = floor(f);
if (f < 0.0) f = ceil(f);
- if (!FIXABLE(f)) {
- mrb_check_num_exact(mrb, f);
+ mrb_check_num_exact(mrb, f);
+ if (!FIXABLE_FLOAT(f)) {
return mrb_float_value(mrb, f);
}
return mrb_fixnum_value((mrb_int)f);
@@ -795,8 +816,10 @@ fix_divmod(mrb_state *mrb, mrb_value x)
mrb_int div, mod;
if (mrb_fixnum(y) == 0) {
- return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
- mrb_float_value(mrb, NAN));
+ return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
+ mrb_float_value(mrb, NAN):
+ mrb_float_value(mrb, INFINITY)),
+ mrb_float_value(mrb, NAN));
}
fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
@@ -806,7 +829,7 @@ fix_divmod(mrb_state *mrb, mrb_value x)
mrb_value a, b;
flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
- a = mrb_float_value(mrb, (mrb_int)div);
+ a = mrb_float_value(mrb, div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
}
@@ -822,7 +845,7 @@ flo_divmod(mrb_state *mrb, mrb_value x)
mrb_get_args(mrb, "o", &y);
flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
- a = mrb_float_value(mrb, (mrb_int)div);
+ a = mrb_float_value(mrb, div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
}
@@ -938,22 +961,24 @@ fix_xor(mrb_state *mrb, mrb_value x)
static mrb_value
lshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
- mrb_assert(width > 0);
+ if (width < 0) { /* mrb_int overflow */
+ return mrb_float_value(mrb, INFINITY);
+ }
if (val > 0) {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
(val > (MRB_INT_MAX >> width))) {
goto bit_overflow;
}
+ return mrb_fixnum_value(val << width);
}
else {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
(val < (MRB_INT_MIN >> width))) {
goto bit_overflow;
}
+ return mrb_fixnum_value(val * (1u << width));
}
- return mrb_fixnum_value(val << width);
-
bit_overflow:
{
mrb_float f = (mrb_float)val;
@@ -967,7 +992,9 @@ bit_overflow:
static mrb_value
rshift(mrb_int val, mrb_int width)
{
- mrb_assert(width > 0);
+ if (width < 0) { /* mrb_int overflow */
+ return mrb_fixnum_value(0);
+ }
if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
if (val < 0) {
return mrb_fixnum_value(-1);
@@ -995,6 +1022,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
return x;
}
val = mrb_fixnum(x);
+ if (val == 0) return x;
if (width < 0) {
return rshift(val, -width);
}
@@ -1019,6 +1047,7 @@ fix_rshift(mrb_state *mrb, mrb_value x)
return x;
}
val = mrb_fixnum(x);
+ if (val == 0) return x;
if (width < 0) {
return lshift(mrb, val, -width);
}
@@ -1072,7 +1101,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
if (isnan(d)) {
mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
}
- if (FIXABLE(d)) {
+ if (FIXABLE_FLOAT(d)) {
z = (mrb_int)d;
}
else {
@@ -1276,68 +1305,72 @@ mrb_init_numeric(mrb_state *mrb)
/* Numeric Class */
numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
- mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
- mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
- mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
+ mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
+ mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
+ mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
/* Integer Class */
integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
mrb_undef_class_method(mrb, integer, "new");
- mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
- mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
+ mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
+ mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
+ mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */
+ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */
+ mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 (x) */
+ mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.15 (x) */
/* Fixnum Class */
mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
- mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
- mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
- mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
- mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
- mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
- mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
- mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
- mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
- mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
- mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
- mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
- mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
- mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
- mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
- mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
- mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
- mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
+ mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
+ mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
+ mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
+ mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
+ mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
+ mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
+ mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
+ mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
+ mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
+ mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
+ mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
+ mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
+ mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
+ mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
+ mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
+ mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
/* Float Class */
mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
mrb_undef_class_method(mrb, fl, "new");
- mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
- mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
- mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
- mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
- mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
- mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
- mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
- mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
- mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
- mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
- mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
- mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
- mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
- mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
- mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
- mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
-
- mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
- mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
- mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
+ mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
+ mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
+ mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
+ mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
+ mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
+ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
+ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
+ mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
+ mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
+ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
+ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
+ mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
+ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
+
+ mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
+ mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
#ifdef INFINITY
mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
diff --git a/src/object.c b/src/object.c
index eb2c23e63..a78e9a443 100644
--- a/src/object.c
+++ b/src/object.c
@@ -534,8 +534,11 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
switch (mrb_type(val)) {
case MRB_TT_FLOAT:
if (base != 0) goto arg_error;
- if (FIXABLE(mrb_float(val))) {
- break;
+ else {
+ mrb_float f = mrb_float(val);
+ if (FIXABLE_FLOAT(f)) {
+ break;
+ }
}
return mrb_flo_to_fixnum(mrb, val);
@@ -553,6 +556,7 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
if (base != 0) {
tmp = mrb_check_string_type(mrb, val);
if (!mrb_nil_p(tmp)) {
+ val = tmp;
goto string_conv;
}
arg_error:
diff --git a/src/pool.c b/src/pool.c
index 18f66fc27..db4546abf 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -13,8 +13,12 @@
/* allocated memory address should be multiple of POOL_ALIGNMENT */
/* or undef it if alignment does not matter */
#ifndef POOL_ALIGNMENT
+#if INTPTR_MAX == INT64_MAX
+#define POOL_ALIGNMENT 8
+#else
#define POOL_ALIGNMENT 4
#endif
+#endif
/* page size of memory pool */
#ifndef POOL_PAGE_SIZE
#define POOL_PAGE_SIZE 16000
diff --git a/src/proc.c b/src/proc.c
index ab22bc1fa..ee4a493cd 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -41,7 +41,7 @@ env_new(mrb_state *mrb, int nlocals)
e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
MRB_SET_ENV_STACK_LEN(e, nlocals);
- e->mid = mrb->c->ci->mid;
+ e->cxt.c = mrb->c;
e->cioff = mrb->c->ci - mrb->c->cibase;
e->stack = mrb->c->stack;
@@ -271,6 +271,7 @@ mrb_init_proc(mrb_state *mrb)
call_irep->flags = MRB_ISEQ_NO_FREE;
call_irep->iseq = call_iseq;
call_irep->ilen = 1;
+ call_irep->nregs = 2; /* receiver and block */
mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
diff --git a/src/state.c b/src/state.c
index 2a02debef..0be5a184a 100644
--- a/src/state.c
+++ b/src/state.c
@@ -246,7 +246,6 @@ mrb_close(mrb_state *mrb)
/* free */
mrb_gc_free_gv(mrb);
- mrb_free_backtrace(mrb);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
mrb_alloca_free(mrb);
diff --git a/src/string.c b/src/string.c
index 742046361..6fdb7fe72 100644
--- a/src/string.c
+++ b/src/string.c
@@ -478,15 +478,14 @@ str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
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_API mrb_int
+mrb_str_index(mrb_state *mrb, mrb_value str, const char *sptr, mrb_int slen, mrb_int offset)
{
mrb_int pos;
- char *s, *sptr;
- mrb_int len, slen;
+ char *s;
+ mrb_int len;
len = RSTRING_LEN(str);
- slen = RSTRING_LEN(sub);
if (offset < 0) {
offset += len;
if (offset < 0) return -1;
@@ -498,14 +497,24 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int 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 mrb_int
+str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset)
+{
+ const char *ptr;
+ mrb_int len;
+
+ ptr = RSTRING_PTR(str2);
+ len = RSTRING_LEN(str2);
+
+ return mrb_str_index(mrb, str, ptr, len, offset);
+}
+
static void
check_frozen(mrb_state *mrb, struct RString *s)
{
@@ -520,9 +529,9 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
long len;
check_frozen(mrb, s1);
+ if (s1 == s2) return mrb_obj_value(s1);
s1->flags &= ~MRB_STR_NO_UTF;
s1->flags |= s2->flags&MRB_STR_NO_UTF;
- if (s1 == s2) return mrb_obj_value(s1);
len = RSTR_LEN(s2);
if (RSTR_SHARED_P(s1)) {
str_decref(mrb, s1->as.heap.aux.shared);
@@ -685,13 +694,20 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
p = RSTR_PTR(s);
len = s->as.heap.len;
- ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
+ if (len < RSTRING_EMBED_LEN_MAX) {
+ RSTR_SET_EMBED_FLAG(s);
+ RSTR_SET_EMBED_LEN(s, len);
+ ptr = RSTR_PTR(s);
+ }
+ else {
+ ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
+ s->as.heap.ptr = ptr;
+ s->as.heap.aux.capa = len;
+ }
if (p) {
memcpy(ptr, p, len);
}
ptr[len] = '\0';
- s->as.heap.ptr = ptr;
- s->as.heap.aux.capa = len;
str_decref(mrb, shared);
}
RSTR_UNSET_SHARED_FLAG(s);
@@ -1089,7 +1105,7 @@ num_index:
return str;
case MRB_TT_STRING:
- if (str_index(mrb, str, indx, 0) != -1)
+ if (str_index_str(mrb, str, indx, 0) != -1)
return mrb_str_dup(mrb, indx);
return mrb_nil_value();
@@ -1514,13 +1530,13 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_int len = RSTR_LEN(s);
char *p = RSTR_PTR(s);
- mrb_int key = 0;
+ uint64_t key = 0;
while (len--) {
key = key*65599 + *p;
p++;
}
- return key + (key>>5);
+ return (mrb_int)(key + (key>>5));
}
/* 15.2.10.5.20 */
@@ -1556,7 +1572,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
mrb_value str2;
mrb_get_args(mrb, "S", &str2);
- if (str_index(mrb, self, str2, 0) < 0)
+ if (str_index_str(mrb, self, str2, 0) < 0)
return mrb_bool_value(FALSE);
return mrb_bool_value(TRUE);
}
@@ -1583,14 +1599,14 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
* "hello".index(/[aeiou]/, -3) #=> 4
*/
static mrb_value
-mrb_str_index(mrb_state *mrb, mrb_value str)
+mrb_str_index_m(mrb_state *mrb, mrb_value str)
{
mrb_value *argv;
mrb_int argc;
mrb_value sub;
mrb_int pos, clen;
- mrb_get_args(mrb, "*", &argv, &argc);
+ mrb_get_args(mrb, "*!", &argv, &argc);
if (argc == 2) {
mrb_get_args(mrb, "oi", &sub, &pos);
}
@@ -1624,7 +1640,7 @@ mrb_str_index(mrb_state *mrb, mrb_value str)
}
/* fall through */
case MRB_TT_STRING:
- pos = str_index(mrb, str, sub, pos);
+ pos = str_index_str(mrb, str, sub, pos);
break;
}
@@ -1861,7 +1877,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
mrb_value sub;
mrb_int pos, len = RSTRING_CHAR_LEN(str);
- mrb_get_args(mrb, "*", &argv, &argc);
+ mrb_get_args(mrb, "*!", &argv, &argc);
if (argc == 2) {
mrb_get_args(mrb, "oi", &sub, &pos);
if (pos < 0) {
@@ -1954,10 +1970,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
int argc;
mrb_value spat = mrb_nil_value();
enum {awk, string, regexp} split_type = string;
- long i = 0, lim_p;
+ mrb_int i = 0;
mrb_int beg;
mrb_int end;
mrb_int lim = 0;
+ mrb_bool lim_p;
mrb_value result, tmp;
argc = mrb_get_args(mrb, "|oi", &spat, &lim);
@@ -2744,7 +2761,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, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
+ mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */
mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */
mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */
diff --git a/src/variable.c b/src/variable.c
index f130a968f..86ac32e61 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -12,15 +12,13 @@
typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
-#ifdef MRB_USE_IV_SEGLIST
-
-#ifndef MRB_SEGMENT_SIZE
-#define MRB_SEGMENT_SIZE 4
+#ifndef MRB_IV_SEGMENT_SIZE
+#define MRB_IV_SEGMENT_SIZE 4
#endif
typedef struct segment {
- mrb_sym key[MRB_SEGMENT_SIZE];
- mrb_value val[MRB_SEGMENT_SIZE];
+ mrb_sym key[MRB_IV_SEGMENT_SIZE];
+ mrb_value val[MRB_IV_SEGMENT_SIZE];
struct segment *next;
} segment;
@@ -71,7 +69,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
size_t i;
while (seg) {
- for (i=0; i<MRB_SEGMENT_SIZE; i++) {
+ for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
mrb_sym key = seg->key[i];
/* Found room in last segment after last_len */
if (!seg->next && i >= t->last_len) {
@@ -136,7 +134,7 @@ iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
seg = t->rootseg;
while (seg) {
- for (i=0; i<MRB_SEGMENT_SIZE; i++) {
+ for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
mrb_sym key = seg->key[i];
if (!seg->next && i >= t->last_len) {
@@ -171,7 +169,7 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
seg = t->rootseg;
while (seg) {
- for (i=0; i<MRB_SEGMENT_SIZE; i++) {
+ for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
mrb_sym key = seg->key[i];
if (!seg->next && i >= t->last_len) {
@@ -198,7 +196,7 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
seg = t->rootseg;
while (seg) {
- for (i=0; i<MRB_SEGMENT_SIZE; i++) {
+ for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
mrb_sym key = seg->key[i];
/* no value in last segment after last_len */
@@ -234,7 +232,7 @@ iv_size(mrb_state *mrb, iv_tbl *t)
return size;
}
seg = seg->next;
- size += MRB_SEGMENT_SIZE;
+ size += MRB_IV_SEGMENT_SIZE;
}
/* empty iv_tbl */
return 0;
@@ -252,7 +250,7 @@ iv_copy(mrb_state *mrb, iv_tbl *t)
t2 = iv_new(mrb);
while (seg != NULL) {
- for (i=0; i<MRB_SEGMENT_SIZE; i++) {
+ for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
mrb_sym key = seg->key[i];
mrb_value val = seg->val[i];
@@ -280,115 +278,6 @@ iv_free(mrb_state *mrb, iv_tbl *t)
mrb_free(mrb, t);
}
-#else
-
-#include <mruby/khash.h>
-
-#ifndef MRB_IVHASH_INIT_SIZE
-#define MRB_IVHASH_INIT_SIZE 8
-#endif
-
-KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE)
-KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal)
-
-typedef struct iv_tbl {
- khash_t(iv) h;
-} iv_tbl;
-
-static iv_tbl*
-iv_new(mrb_state *mrb)
-{
- return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE);
-}
-
-static void
-iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
-{
- khash_t(iv) *h = &t->h;
- khiter_t k;
-
- k = kh_put(iv, mrb, h, sym);
- kh_value(h, k) = val;
-}
-
-static mrb_bool
-iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
-{
- khash_t(iv) *h = &t->h;
- khiter_t k;
-
- k = kh_get(iv, mrb, h, sym);
- if (k != kh_end(h)) {
- if (vp) *vp = kh_value(h, k);
- return TRUE;
- }
- return FALSE;
-}
-
-static mrb_bool
-iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
-{
- khash_t(iv) *h = &t->h;
- khiter_t k;
-
- if (h) {
- k = kh_get(iv, mrb, h, sym);
- if (k != kh_end(h)) {
- mrb_value val = kh_value(h, k);
- kh_del(iv, mrb, h, k);
- if (vp) *vp = val;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static mrb_bool
-iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
-{
- khash_t(iv) *h = &t->h;
- khiter_t k;
- int n;
-
- if (h) {
- for (k = kh_begin(h); k != kh_end(h); k++) {
- if (kh_exist(h, k)) {
- n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p);
- if (n > 0) return FALSE;
- if (n < 0) {
- kh_del(iv, mrb, h, k);
- }
- }
- }
- }
- return TRUE;
-}
-
-static size_t
-iv_size(mrb_state *mrb, iv_tbl *t)
-{
- khash_t(iv) *h;
-
- if (t && (h = &t->h)) {
- return kh_size(h);
- }
- return 0;
-}
-
-static iv_tbl*
-iv_copy(mrb_state *mrb, iv_tbl *t)
-{
- return (iv_tbl*)kh_copy(iv, mrb, &t->h);
-}
-
-static void
-iv_free(mrb_state *mrb, iv_tbl *t)
-{
- kh_destroy(iv, mrb, &t->h);
-}
-
-#endif
-
static int
iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
@@ -821,10 +710,19 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
if (cls && cls->tt == MRB_TT_SCLASS) {
mrb_value klass;
- klass = mrb_obj_iv_get(mrb, (struct RObject*)cls,
- mrb_intern_lit(mrb, "__attached__"));
- c = mrb_class_ptr(klass);
+ klass = mrb_obj_iv_get(mrb, (struct RObject*)cls,
+ mrb_intern_lit(mrb, "__attached__"));
+ switch (mrb_type(klass)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ c = mrb_class_ptr(klass);
+ break;
+ default:
+ c = cls;
+ break;
+ }
}
else{
c = cls;
@@ -944,14 +842,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) {
+ c2 = c;
+ while (c2 && c2->tt == MRB_TT_SCLASS) {
mrb_value klass;
- klass = mrb_obj_iv_get(mrb, (struct RObject *)c,
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)c2,
mrb_intern_lit(mrb, "__attached__"));
c2 = mrb_class_ptr(klass);
- if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)
- c = c2;
}
+ if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2;
c2 = c;
for (;;) {
c2 = mrb_class_outer_module(mrb, c2);
diff --git a/src/vm.c b/src/vm.c
index bb4023da2..45f9bf967 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -35,6 +35,14 @@ void abort(void);
#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32
+#ifndef ENSURE_STACK_INIT_SIZE
+#define ENSURE_STACK_INIT_SIZE 16
+#endif
+
+#ifndef RESCUE_STACK_INIT_SIZE
+#define RESCUE_STACK_INIT_SIZE 16
+#endif
+
/* Define amount of linear stack growth. */
#ifndef MRB_STACK_GROWTH
#define MRB_STACK_GROWTH 128
@@ -57,7 +65,28 @@ The value below allows about 60000 recursive calls in the simplest case. */
# define DEBUG(x)
#endif
-#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
+
+#ifndef MRB_GC_FIXED_ARENA
+static void
+mrb_gc_arena_shrink(mrb_state *mrb, int idx)
+{
+ mrb_gc *gc = &mrb->gc;
+ int capa = gc->arena_capa;
+
+ if (idx < capa / 4) {
+ capa >>= 2;
+ if (capa < MRB_GC_ARENA_SIZE) {
+ capa = MRB_GC_ARENA_SIZE;
+ }
+ if (capa != gc->arena_capa) {
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
+ gc->arena_capa = capa;
+ }
+ }
+}
+#else
+#define mrb_gc_arena_shrink(mrb,idx)
+#endif
#define CALL_MAXARGS 127
@@ -107,14 +136,17 @@ stack_init(mrb_state *mrb)
}
static inline void
-envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
+envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size)
{
mrb_callinfo *ci = mrb->c->cibase;
if (newbase == oldbase) return;
while (ci <= mrb->c->ci) {
struct REnv *e = ci->env;
- if (e && MRB_ENV_STACK_SHARED_P(e)) {
+ mrb_value *st;
+
+ if (e && MRB_ENV_STACK_SHARED_P(e) &&
+ (st = e->stack) && oldbase <= st && st < oldbase+size) {
ptrdiff_t off = e->stack - oldbase;
e->stack = newbase + off;
@@ -124,22 +156,15 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
}
}
-static inline void
-init_new_stack_space(mrb_state *mrb, int room, int keep)
-{
- if (room > keep) {
- /* do not leave uninitialized malloc region */
- stack_clear(&(mrb->c->stack[keep]), room - keep);
- }
-}
-
/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */
static void
-stack_extend_alloc(mrb_state *mrb, int room, int keep)
+stack_extend_alloc(mrb_state *mrb, int room)
{
mrb_value *oldbase = mrb->c->stbase;
- size_t size = mrb->c->stend - mrb->c->stbase;
+ mrb_value *newstack;
+ size_t oldsize = mrb->c->stend - mrb->c->stbase;
+ size_t size = oldsize;
size_t off = mrb->c->stack - mrb->c->stbase;
if (off > size) size = off;
@@ -158,29 +183,29 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep)
size += room;
#endif
- mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+ newstack = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+ if (newstack == NULL) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+ }
+ stack_clear(&(newstack[oldsize]), size - oldsize);
+ envadjust(mrb, oldbase, newstack, size);
+ mrb->c->stbase = newstack;
mrb->c->stack = mrb->c->stbase + off;
mrb->c->stend = mrb->c->stbase + size;
- envadjust(mrb, oldbase, mrb->c->stbase);
/* Raise an exception if the new stack size will be too large,
to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
if (size > MRB_STACK_MAX) {
- init_new_stack_space(mrb, room, keep);
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
}
static inline void
-stack_extend(mrb_state *mrb, int room, int keep)
+stack_extend(mrb_state *mrb, int room)
{
- if (room < keep) {
- room = keep;
- }
if (mrb->c->stack + room >= mrb->c->stend) {
- stack_extend_alloc(mrb, room, keep);
+ stack_extend_alloc(mrb, room);
}
- init_new_stack_space(mrb, room, keep);
}
static inline struct REnv*
@@ -200,8 +225,8 @@ is_strict(mrb_state *mrb, struct REnv *e)
{
int cioff = e->cioff;
- if (MRB_ENV_STACK_SHARED_P(e) && mrb->c->cibase[cioff].proc &&
- MRB_PROC_STRICT_P(mrb->c->cibase[cioff].proc)) {
+ if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc &&
+ MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) {
return TRUE;
}
return FALSE;
@@ -224,13 +249,13 @@ top_env(mrb_state *mrb, struct RProc *proc)
#define CI_ACC_DIRECT -2
#define CI_ACC_RESUMED -3
-static mrb_callinfo*
+static inline mrb_callinfo*
cipush(mrb_state *mrb)
{
struct mrb_context *c = mrb->c;
+ static const mrb_callinfo ci_zero = { 0 };
mrb_callinfo *ci = c->ci;
- int eidx = ci->eidx;
int ridx = ci->ridx;
if (ci + 1 == c->ciend) {
@@ -241,13 +266,9 @@ cipush(mrb_state *mrb)
c->ciend = c->cibase + size * 2;
}
ci = ++c->ci;
- ci->eidx = eidx;
+ *ci = ci_zero;
+ ci->epos = mrb->c->eidx;
ci->ridx = ridx;
- ci->env = 0;
- ci->pc = 0;
- ci->err = 0;
- ci->proc = 0;
- ci->acc = 0;
return ci;
}
@@ -255,28 +276,38 @@ cipush(mrb_state *mrb)
MRB_API void
mrb_env_unshare(mrb_state *mrb, struct REnv *e)
{
- size_t len = (size_t)MRB_ENV_STACK_LEN(e);
- mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
-
- MRB_ENV_UNSHARE_STACK(e);
- if (len > 0) {
- stack_copy(p, e->stack, len);
+ if (e == NULL) return;
+ else {
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+ ptrdiff_t cioff = e->cioff;
+ mrb_value *p;
+
+ if (!MRB_ENV_STACK_SHARED_P(e)) return;
+ if (e->cxt.c != mrb->c) return;
+ if (e->cioff == 0 && e->cxt.c == mrb->root_c) return;
+ MRB_ENV_UNSHARE_STACK(e);
+ if (!e->c) {
+ /* save block argument position (negated) */
+ e->cioff = -e->cxt.c->cibase[cioff].argc-1;
+ }
+ e->cxt.mid = e->cxt.c->cibase[cioff].mid;
+ p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
+ if (len > 0) {
+ stack_copy(p, e->stack, len);
+ }
+ e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
}
- e->stack = p;
- mrb_write_barrier(mrb, (struct RBasic *)e);
}
-static void
+static inline void
cipop(mrb_state *mrb)
{
struct mrb_context *c = mrb->c;
struct REnv *env = c->ci->env;
c->ci--;
-
- if (env) {
- mrb_env_unshare(mrb, env);
- }
+ mrb_env_unshare(mrb, env);
}
void mrb_exc_set(mrb_state *mrb, mrb_value exc);
@@ -285,21 +316,20 @@ static void
ecall(mrb_state *mrb, int i)
{
struct RProc *p;
- mrb_callinfo *ci;
+ mrb_callinfo *ci = mrb->c->ci;
mrb_value *self = mrb->c->stack;
struct RObject *exc;
- int cioff;
+ ptrdiff_t cioff;
+ int ai = mrb_gc_arena_save(mrb);
if (i<0) return;
- if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
p = mrb->c->ensure[i];
if (!p) return;
mrb->c->ensure[i] = NULL;
- if (mrb->c->ci->eidx > i)
- mrb->c->ci->eidx = i;
- cioff = mrb->c->ci - mrb->c->cibase;
+ cioff = ci - mrb->c->cibase;
ci = cipush(mrb);
ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
@@ -310,9 +340,13 @@ ecall(mrb_state *mrb, int i)
ci->target_class = p->target_class;
mrb->c->stack = mrb->c->stack + ci[-1].nregs;
exc = mrb->exc; mrb->exc = 0;
+ if (exc) {
+ mrb_gc_protect(mrb, mrb_obj_value(exc));
+ }
mrb_run(mrb, p, *self);
mrb->c->ci = mrb->c->cibase + cioff;
if (!mrb->exc) mrb->exc = exc;
+ mrb_gc_arena_restore(mrb, ai);
}
#ifndef MRB_FUNCALL_ARGC_MAX
@@ -363,11 +397,11 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
val = mrb_obj_value(mrb->exc);
}
MRB_END_EXC(&c_jmp);
+ mrb->jmp = 0;
}
else {
struct RProc *p;
struct RClass *c;
- mrb_sym undef = 0;
mrb_callinfo *ci;
int n;
ptrdiff_t voff = -1;
@@ -383,13 +417,15 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
p = mrb_method_search_vm(mrb, &c, mid);
if (!p) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
p = mrb_method_search_vm(mrb, &c, missing);
if (!p) {
- mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
mrb_method_missing(mrb, mid, self, args);
}
- undef = mid;
- argc++;
+ mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
+ stack_extend(mrb, n+2);
+ mrb->c->stack[n+1] = args;
+ argc = -1;
}
if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
@@ -406,33 +442,25 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
}
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
- stack_extend(mrb, ci->nregs, 0);
+ stack_extend(mrb, ci->nregs);
}
else if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
- stack_extend(mrb, ci->nregs, 0);
+ stack_extend(mrb, ci->nregs);
mrb->c->stack[1] = args;
- if (undef) {
- mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef));
- }
ci->argc = -1;
argc = 1;
}
else {
+ if (argc < 0) argc = 1;
ci->nregs = p->body.irep->nregs + argc;
- stack_extend(mrb, ci->nregs, argc+2);
+ stack_extend(mrb, ci->nregs);
}
if (voff >= 0) {
argv = mrb->c->stbase + voff;
}
mrb->c->stack[0] = self;
- if (undef) {
- mrb->c->stack[1] = mrb_symbol_value(undef);
- if (argc > 1) {
- stack_copy(mrb->c->stack+2, argv, argc-1);
- }
- }
- else if (ci->argc > 0) {
+ if (ci->argc > 0) {
stack_copy(mrb->c->stack+1, argv, argc);
}
mrb->c->stack[argc+1] = blk;
@@ -466,16 +494,17 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
+ mrb->c->stack[0] = self;
ci->proc = p;
ci->target_class = p->target_class;
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
if (ci->argc < 0) {
- stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
+ stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs);
}
else {
- stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
+ stack_extend(mrb, p->body.irep->nregs);
}
ci->nregs = p->body.irep->nregs;
@@ -561,7 +590,8 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
}
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
- return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
+ ci->target_class = c;
+ return mrb_yield_cont(mrb, blk, self, 1, &self);
}
ci->target_class = c;
p = mrb_proc_ptr(blk);
@@ -569,7 +599,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
ci->argc = 1;
ci->mid = ci[-1].mid;
if (MRB_PROC_CFUNC_P(p)) {
- stack_extend(mrb, 3, 0);
+ stack_extend(mrb, 3);
mrb->c->stack[0] = self;
mrb->c->stack[1] = self;
mrb->c->stack[2] = mrb_nil_value();
@@ -577,7 +607,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
}
ci->nregs = p->body.irep->nregs;
if (max < ci->nregs) max = ci->nregs;
- stack_extend(mrb, max, 0);
+ stack_extend(mrb, max);
mrb->c->stack[0] = self;
mrb->c->stack[1] = self;
mrb->c->stack[2] = mrb_nil_value();
@@ -683,11 +713,11 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
mrb->c->stack = mrb->c->stack + n;
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
- stack_extend(mrb, ci->nregs, 0);
+ stack_extend(mrb, ci->nregs);
}
else {
ci->nregs = p->body.irep->nregs;
- stack_extend(mrb, ci->nregs, argc+2);
+ stack_extend(mrb, ci->nregs);
}
mrb->c->stack[0] = self;
@@ -725,6 +755,42 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
}
+mrb_value
+mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ if (mrb_nil_p(b)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ if (mrb_type(b) != MRB_TT_PROC) {
+ mrb_raise(mrb, E_TYPE_ERROR, "not a block");
+ }
+
+ p = mrb_proc_ptr(b);
+ ci = mrb->c->ci;
+
+ stack_extend(mrb, 3);
+ mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
+ mrb->c->stack[2] = mrb_nil_value();
+ ci->argc = -1;
+ return mrb_exec_irep(mrb, self, p);
+}
+
+static struct RBreak*
+break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
+{
+ struct RBreak *brk;
+
+ brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
+ brk->iv = NULL;
+ brk->proc = p;
+ brk->val = val;
+
+ return brk;
+}
+
typedef enum {
LOCALJUMP_ERROR_RETURN = 0,
LOCALJUMP_ERROR_BREAK = 1,
@@ -815,13 +881,30 @@ MRB_API mrb_value
mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
mrb_irep *irep = proc->body.irep;
+ mrb_value result;
+ struct mrb_context *c = mrb->c;
+ int cioff = c->ci - c->cibase;
+ unsigned int nregs = irep->nregs;
- if (!mrb->c->stack) {
+ if (!c->stack) {
stack_init(mrb);
}
- stack_extend(mrb, irep->nregs, stack_keep);
- mrb->c->stack[0] = self;
- return mrb_vm_exec(mrb, proc, irep->iseq);
+ if (stack_keep > nregs)
+ nregs = stack_keep;
+ stack_extend(mrb, nregs);
+ stack_clear(c->stack + stack_keep, nregs - stack_keep);
+ c->stack[0] = self;
+ result = mrb_vm_exec(mrb, proc, irep->iseq);
+ if (c->ci - c->cibase > cioff) {
+ c->ci = c->cibase + cioff;
+ }
+ if (mrb->c != c) {
+ if (mrb->c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib);
+ }
+ mrb->c = c;
+ }
+ return result;
}
MRB_API mrb_value
@@ -868,6 +951,8 @@ RETRY_TRY_BLOCK:
if (exc_catched) {
exc_catched = FALSE;
+ if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK)
+ goto L_BREAK;
goto L_RAISE;
}
mrb->jmp = &c_jmp;
@@ -883,20 +968,24 @@ RETRY_TRY_BLOCK:
CASE(OP_MOVE) {
/* A B R(A) := R(B) */
- regs[GETARG_A(i)] = regs[GETARG_B(i)];
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ regs[a] = regs[b];
NEXT;
}
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
#ifdef MRB_WORD_BOXING
- mrb_value val = pool[GETARG_Bx(i)];
+ mrb_value val = pool[bx];
if (mrb_float_p(val)) {
val = mrb_float_value(mrb, mrb_float(val));
}
- regs[GETARG_A(i)] = val;
+ regs[a] = val;
#else
- regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+ regs[a] = pool[bx];
#endif
NEXT;
}
@@ -909,92 +998,123 @@ RETRY_TRY_BLOCK:
CASE(OP_LOADSYM) {
/* A Bx R(A) := Syms(Bx) */
- SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ SET_SYM_VALUE(regs[a], syms[bx]);
NEXT;
}
CASE(OP_LOADSELF) {
/* A R(A) := self */
- regs[GETARG_A(i)] = regs[0];
+ int a = GETARG_A(i);
+ regs[a] = regs[0];
NEXT;
}
CASE(OP_LOADT) {
/* A R(A) := true */
- SET_TRUE_VALUE(regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+ SET_TRUE_VALUE(regs[a]);
NEXT;
}
CASE(OP_LOADF) {
/* A R(A) := false */
- SET_FALSE_VALUE(regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+ SET_FALSE_VALUE(regs[a]);
NEXT;
}
CASE(OP_GETGLOBAL) {
/* A Bx R(A) := getglobal(Syms(Bx)) */
- regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_gv_get(mrb, syms[bx]);
+ regs[a] = val;
NEXT;
}
CASE(OP_SETGLOBAL) {
- /* setglobal(Syms(Bx), R(A)) */
- mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+ /* A Bx setglobal(Syms(Bx), R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_gv_set(mrb, syms[bx], regs[a]);
NEXT;
}
CASE(OP_GETSPECIAL) {
/* A Bx R(A) := Special[Bx] */
- regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i));
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_vm_special_get(mrb, bx);
+ regs[a] = val;
NEXT;
}
CASE(OP_SETSPECIAL) {
/* A Bx Special[Bx] := R(A) */
- mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_special_set(mrb, bx, regs[a]);
NEXT;
}
CASE(OP_GETIV) {
/* A Bx R(A) := ivget(Bx) */
- regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val = mrb_vm_iv_get(mrb, syms[bx]);
+ regs[a] = val;
NEXT;
}
CASE(OP_SETIV) {
- /* ivset(Syms(Bx),R(A)) */
- mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+ /* A Bx ivset(Syms(Bx),R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_iv_set(mrb, syms[bx], regs[a]);
NEXT;
}
CASE(OP_GETCV) {
/* A Bx R(A) := cvget(Syms(Bx)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_value val;
ERR_PC_SET(mrb, pc);
- regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
+ val = mrb_vm_cv_get(mrb, syms[bx]);
ERR_PC_CLR(mrb);
+ regs[a] = val;
NEXT;
}
CASE(OP_SETCV) {
- /* cvset(Syms(Bx),R(A)) */
- mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+ /* A Bx cvset(Syms(Bx),R(A)) */
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_cv_set(mrb, syms[bx], regs[a]);
NEXT;
}
CASE(OP_GETCONST) {
/* A Bx R(A) := constget(Syms(Bx)) */
mrb_value val;
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_sym sym = syms[bx];
ERR_PC_SET(mrb, pc);
- val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+ val = mrb_vm_const_get(mrb, sym);
ERR_PC_CLR(mrb);
- regs[GETARG_A(i)] = val;
+ regs[a] = val;
NEXT;
}
CASE(OP_SETCONST) {
/* A Bx constset(Syms(Bx),R(A)) */
- mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
+ mrb_vm_const_set(mrb, syms[bx], regs[a]);
NEXT;
}
@@ -1002,9 +1122,10 @@ RETRY_TRY_BLOCK:
/* A Bx R(A) := R(A)::Syms(Bx) */
mrb_value val;
int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
ERR_PC_SET(mrb, pc);
- val = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
+ val = mrb_const_get(mrb, regs[a], syms[bx]);
ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
@@ -1013,53 +1134,60 @@ RETRY_TRY_BLOCK:
CASE(OP_SETMCNST) {
/* A Bx R(A+1)::Syms(Bx) := R(A) */
int a = GETARG_A(i);
-
- mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]);
+ int bx = GETARG_Bx(i);
+ mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]);
NEXT;
}
CASE(OP_GETUPVAR) {
/* A B C R(A) := uvget(B,C) */
- mrb_value *regs_a = regs + GETARG_A(i);
- int up = GETARG_C(i);
-
- struct REnv *e = uvenv(mrb, up);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value *regs_a = regs + a;
+ struct REnv *e = uvenv(mrb, c);
if (!e) {
*regs_a = mrb_nil_value();
}
else {
- int idx = GETARG_B(i);
- *regs_a = e->stack[idx];
+ *regs_a = e->stack[b];
}
NEXT;
}
CASE(OP_SETUPVAR) {
/* A B C uvset(B,C,R(A)) */
- int up = GETARG_C(i);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
- struct REnv *e = uvenv(mrb, up);
+ struct REnv *e = uvenv(mrb, c);
if (e) {
- mrb_value *regs_a = regs + GETARG_A(i);
- int idx = GETARG_B(i);
- e->stack[idx] = *regs_a;
- mrb_write_barrier(mrb, (struct RBasic*)e);
+ mrb_value *regs_a = regs + a;
+
+ if (b < MRB_ENV_STACK_LEN(e)) {
+ e->stack[b] = *regs_a;
+ mrb_write_barrier(mrb, (struct RBasic*)e);
+ }
}
NEXT;
}
CASE(OP_JMP) {
/* sBx pc+=sBx */
- pc += GETARG_sBx(i);
+ int sbx = GETARG_sBx(i);
+ pc += sbx;
JUMP;
}
CASE(OP_JMPIF) {
/* A sBx if R(A) pc+=sBx */
- if (mrb_test(regs[GETARG_A(i)])) {
- pc += GETARG_sBx(i);
+ int a = GETARG_A(i);
+ int sbx = GETARG_sBx(i);
+ if (mrb_test(regs[a])) {
+ pc += sbx;
JUMP;
}
NEXT;
@@ -1067,8 +1195,10 @@ RETRY_TRY_BLOCK:
CASE(OP_JMPNOT) {
/* A sBx if !R(A) pc+=sBx */
- if (!mrb_test(regs[GETARG_A(i)])) {
- pc += GETARG_sBx(i);
+ int a = GETARG_A(i);
+ int sbx = GETARG_sBx(i);
+ if (!mrb_test(regs[a])) {
+ pc += sbx;
JUMP;
}
NEXT;
@@ -1076,12 +1206,13 @@ RETRY_TRY_BLOCK:
CASE(OP_ONERR) {
/* sBx pc+=sBx on exception */
+ int sbx = GETARG_sBx(i);
if (mrb->c->rsize <= mrb->c->ci->ridx) {
- if (mrb->c->rsize == 0) mrb->c->rsize = 16;
+ if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE;
else mrb->c->rsize *= 2;
mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize);
}
- mrb->c->rescue[mrb->c->ci->ridx++] = pc + GETARG_sBx(i);
+ mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx;
NEXT;
}
@@ -1108,8 +1239,14 @@ RETRY_TRY_BLOCK:
case MRB_TT_MODULE:
break;
default:
- mrb_raise(mrb, E_TYPE_ERROR, "class or module required for rescue clause");
- break;
+ {
+ mrb_value exc;
+
+ exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ "class or module required for rescue clause");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
}
ec = mrb_class_ptr(e);
regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec));
@@ -1124,32 +1261,33 @@ RETRY_TRY_BLOCK:
/* A A.times{rescue_pop()} */
int a = GETARG_A(i);
- while (a--) {
- mrb->c->ci->ridx--;
- }
+ mrb->c->ci->ridx -= a;
NEXT;
}
CASE(OP_RAISE) {
/* A raise(R(A)) */
- mrb_exc_set(mrb, regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+
+ mrb_exc_set(mrb, regs[a]);
goto L_RAISE;
}
CASE(OP_EPUSH) {
/* Bx ensure_push(SEQ[Bx]) */
+ int bx = GETARG_Bx(i);
struct RProc *p;
- p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
+ p = mrb_closure_new(mrb, irep->reps[bx]);
/* push ensure_stack */
- if (mrb->c->esize <= mrb->c->ci->eidx+1) {
- if (mrb->c->esize == 0) mrb->c->esize = 16;
+ if (mrb->c->esize <= mrb->c->eidx+1) {
+ if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE;
else mrb->c->esize *= 2;
mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize);
}
- mrb->c->ensure[mrb->c->ci->eidx++] = p;
- mrb->c->ensure[mrb->c->ci->eidx] = NULL;
- ARENA_RESTORE(mrb, ai);
+ mrb->c->ensure[mrb->c->eidx++] = p;
+ mrb->c->ensure[mrb->c->eidx] = NULL;
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -1157,11 +1295,11 @@ RETRY_TRY_BLOCK:
/* A A.times{ensure_pop().call} */
int a = GETARG_A(i);
mrb_callinfo *ci = mrb->c->ci;
- int n, eidx = ci->eidx;
+ int n, epos = ci->epos;
- for (n=0; n<a && (ci == mrb->c->cibase || eidx > ci[-1].eidx); n++) {
- ecall(mrb, --eidx);
- ARENA_RESTORE(mrb, ai);
+ for (n=0; n<a && mrb->c->eidx > epos; n++) {
+ ecall(mrb, --mrb->c->eidx);
+ mrb_gc_arena_restore(mrb, ai);
}
NEXT;
}
@@ -1186,10 +1324,11 @@ RETRY_TRY_BLOCK:
int n = GETARG_C(i);
struct RProc *m;
struct RClass *c;
- mrb_callinfo *ci;
+ mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, result;
mrb_sym mid = syms[GETARG_B(i)];
int bidx;
+ mrb_value blk;
recv = regs[a];
if (n == CALL_MAXARGS) {
@@ -1199,16 +1338,22 @@ RETRY_TRY_BLOCK:
bidx = a+n+1;
}
if (GET_OPCODE(i) != OP_SENDB) {
+ if (bidx >= ci->nregs) {
+ stack_extend(mrb, bidx+1);
+ ci->nregs = bidx+1;
+ }
SET_NIL_VALUE(regs[bidx]);
+ blk = mrb_nil_value();
}
else {
- mrb_value blk = regs[bidx];
+ blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
- if (bidx >= mrb->c->ci->nregs) {
- stack_extend(mrb, bidx+1, mrb->c->ci->nregs);
- mrb->c->ci->nregs = bidx+1;
+ if (bidx >= ci->nregs) {
+ stack_extend(mrb, bidx+1);
+ ci->nregs = bidx+1;
}
- regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ result = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ blk = regs[bidx] = result;
}
}
c = mrb_class(mrb, recv);
@@ -1227,14 +1372,13 @@ RETRY_TRY_BLOCK:
else {
args = mrb_ary_new_from_values(mrb, n, regs+a+1);
}
+ ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
if (n != CALL_MAXARGS) {
- mrb_value blk = regs[bidx];
-
- if (a+2 > irep->nregs) {
- stack_extend(mrb, a+2, a+n+1);
+ if (a+2 >= irep->nregs) {
+ stack_extend(mrb, a+3);
}
regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
regs[a+2] = blk;
@@ -1267,9 +1411,18 @@ RETRY_TRY_BLOCK:
}
result = m->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
+ mrb_gc_arena_shrink(mrb, ai);
if (mrb->exc) goto L_RAISE;
- /* pop stackpos */
ci = mrb->c->ci;
+ if (GET_OPCODE(i) == OP_SENDB) {
+ if (mrb_type(blk) == MRB_TT_PROC) {
+ struct RProc *p = mrb_proc_ptr(blk);
+
+ if (p && !MRB_PROC_STRICT_P(p) && p->env == ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
+ }
+ }
+ }
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
if (ci->acc == CI_ACC_RESUMED) {
mrb->jmp = prev_jmp;
@@ -1284,6 +1437,7 @@ RETRY_TRY_BLOCK:
}
}
mrb->c->stack[0] = result;
+ /* pop stackpos */
mrb->c->stack = ci->stackent;
pc = ci->pc;
cipop(mrb);
@@ -1298,11 +1452,11 @@ RETRY_TRY_BLOCK:
ci->nregs = irep->nregs;
if (n == CALL_MAXARGS) {
ci->argc = -1;
- stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+ stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
}
else {
ci->argc = n;
- stack_extend(mrb, irep->nregs, n+2);
+ stack_extend(mrb, irep->nregs);
}
pc = irep->iseq;
JUMP;
@@ -1311,6 +1465,7 @@ RETRY_TRY_BLOCK:
CASE(OP_FSEND) {
/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
+ /* not implemented yet */
NEXT;
}
@@ -1325,9 +1480,15 @@ RETRY_TRY_BLOCK:
ci->target_class = m->target_class;
ci->proc = m;
if (m->env) {
- if (m->env->mid) {
- ci->mid = m->env->mid;
+ mrb_sym mid;
+
+ if (MRB_ENV_STACK_SHARED_P(m->env)) {
+ mid = m->env->cxt.c->cibase[m->env->cioff].mid;
+ }
+ else {
+ mid = m->env->cxt.mid;
}
+ if (mid) ci->mid = mid;
if (!m->env->stack) {
m->env->stack = mrb->c->stack;
}
@@ -1337,6 +1498,7 @@ RETRY_TRY_BLOCK:
if (MRB_PROC_CFUNC_P(m)) {
recv = m->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
+ mrb_gc_arena_shrink(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
@@ -1360,11 +1522,14 @@ RETRY_TRY_BLOCK:
pool = irep->pool;
syms = irep->syms;
ci->nregs = irep->nregs;
+ stack_extend(mrb, irep->nregs);
if (ci->argc < 0) {
- stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+ if (irep->nregs > 3) {
+ stack_clear(regs+3, irep->nregs-3);
+ }
}
- else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ else if (ci->argc+2 < irep->nregs) {
+ stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2);
}
if (m->env) {
regs[0] = m->env->stack[0];
@@ -1383,6 +1548,8 @@ RETRY_TRY_BLOCK:
mrb_sym mid = ci->mid;
int a = GETARG_A(i);
int n = GETARG_C(i);
+ mrb_value blk;
+ int bidx;
if (mid == 0 || !ci->target_class) {
mrb_value exc;
@@ -1406,6 +1573,7 @@ RETRY_TRY_BLOCK:
else {
args = mrb_ary_new_from_values(mrb, n, regs+a+1);
}
+ ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
@@ -1422,6 +1590,24 @@ RETRY_TRY_BLOCK:
}
}
+ if (n == CALL_MAXARGS) {
+ bidx = a+2;
+ }
+ else {
+ bidx = a+n+1;
+ }
+ blk = regs[bidx];
+ if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+ mrb_value result;
+
+ if (bidx >= ci->nregs) {
+ stack_extend(mrb, bidx+1);
+ ci->nregs = bidx+1;
+ }
+ result = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ regs[bidx] = result;
+ }
+
/* push callinfo */
ci = cipush(mrb);
ci->mid = mid;
@@ -1429,27 +1615,11 @@ RETRY_TRY_BLOCK:
ci->stackent = mrb->c->stack;
ci->target_class = c;
ci->pc = pc + 1;
- {
- int bidx;
- mrb_value blk;
-
- if (n == CALL_MAXARGS) {
- ci->argc = -1;
- bidx = a+2;
- }
- else {
- ci->argc = n;
- bidx = a+n+1;
- }
- blk = regs[bidx];
- if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
- if (bidx >= ci->nregs) {
- stack_extend(mrb, bidx+1, ci->nregs);
- ci->nregs = bidx+1;
- }
- regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
- ci = mrb->c->ci;
- }
+ if (n == CALL_MAXARGS) {
+ ci->argc = -1;
+ }
+ else {
+ ci->argc = n;
}
/* prepare stack */
@@ -1466,13 +1636,28 @@ RETRY_TRY_BLOCK:
ci->nregs = n + 2;
}
v = m->body.func(mrb, recv);
- mrb->c->stack[0] = v;
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
+ ci = mrb->c->ci;
+ if (!ci->target_class) { /* return from context modifying method (resume/yield) */
+ if (ci->acc == CI_ACC_RESUMED) {
+ mrb->jmp = prev_jmp;
+ return v;
+ }
+ else {
+ mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
+ proc = ci[-1].proc;
+ irep = proc->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ }
+ }
+ mrb->c->stack[0] = v;
/* pop stackpos */
- mrb->c->stack = mrb->c->ci->stackent;
+ mrb->c->stack = ci->stackent;
+ pc = ci->pc;
cipop(mrb);
- NEXT;
+ JUMP;
}
else {
/* fill callinfo */
@@ -1485,10 +1670,10 @@ RETRY_TRY_BLOCK:
syms = irep->syms;
ci->nregs = irep->nregs;
if (n == CALL_MAXARGS) {
- stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+ stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ stack_extend(mrb, irep->nregs);
}
pc = irep->iseq;
JUMP;
@@ -1505,16 +1690,20 @@ RETRY_TRY_BLOCK:
int lv = (bx>>0)&0xf;
mrb_value *stack;
+ if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) {
+ mrb_value exc;
+
+ L_NOSUPER:
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
if (lv == 0) stack = regs + 1;
else {
struct REnv *e = uvenv(mrb, lv-1);
- if (!e) {
- mrb_value exc;
-
- exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
- }
+ if (!e) goto L_NOSUPER;
+ if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1)
+ goto L_NOSUPER;
stack = e->stack + 1;
}
if (r == 0) {
@@ -1528,24 +1717,24 @@ RETRY_TRY_BLOCK:
if (mrb_array_p(stack[m1])) {
struct RArray *ary = mrb_ary_ptr(stack[m1]);
- pp = ary->ptr;
- len = ary->len;
+ pp = ARY_PTR(ary);
+ len = ARY_LEN(ary);
}
regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
rest = mrb_ary_ptr(regs[a]);
if (m1 > 0) {
- stack_copy(rest->ptr, stack, m1);
+ stack_copy(ARY_PTR(rest), stack, m1);
}
if (len > 0) {
- stack_copy(rest->ptr+m1, pp, len);
+ stack_copy(ARY_PTR(rest)+m1, pp, len);
}
if (m2 > 0) {
- stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
+ stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2);
}
- rest->len = m1+len+m2;
+ ARY_SET_LEN(rest, m1+len+m2);
}
regs[a+1] = stack[m1+r+m2];
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -1570,8 +1759,8 @@ RETRY_TRY_BLOCK:
if (argc < 0) {
struct RArray *ary = mrb_ary_ptr(regs[1]);
- argv = ary->ptr;
- argc = ary->len;
+ argv = ARY_PTR(ary);
+ argc = ARY_LEN(ary);
mrb_gc_protect(mrb, regs[1]);
}
if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
@@ -1584,10 +1773,9 @@ RETRY_TRY_BLOCK:
}
else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
mrb_gc_protect(mrb, argv[0]);
- argc = mrb_ary_ptr(argv[0])->len;
- argv = mrb_ary_ptr(argv[0])->ptr;
+ argc = RARRAY_LEN(argv[0]);
+ argv = RARRAY_PTR(argv[0]);
}
- mrb->c->ci->argc = len;
if (argc < len) {
int mlen = m2;
if (argc < m1+m2) {
@@ -1601,9 +1789,15 @@ RETRY_TRY_BLOCK:
if (argv0 != argv) {
value_move(&regs[1], argv, argc-mlen); /* m1 + o */
}
+ if (argc < m1) {
+ stack_clear(&regs[argc+1], m1-argc);
+ }
if (mlen) {
value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
}
+ if (mlen < m2) {
+ stack_clear(&regs[len-m2+mlen+1], m2-mlen);
+ }
if (r) {
regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
}
@@ -1631,6 +1825,11 @@ RETRY_TRY_BLOCK:
}
pc += o + 1;
}
+ mrb->c->ci->argc = len;
+ /* clear local (but non-argument) variables */
+ if (irep->nlocals-len-2 > 0) {
+ stack_clear(&regs[len+2], irep->nlocals-len-2);
+ }
JUMP;
}
@@ -1651,18 +1850,36 @@ RETRY_TRY_BLOCK:
/* fall through */
CASE(OP_RETURN) {
/* A B return R(A) (B=normal,in-block return/break) */
+ mrb_callinfo *ci;
+
+ ci = mrb->c->ci;
+ if (ci->mid) {
+ mrb_value blk;
+
+ if (ci->argc < 0) {
+ blk = regs[2];
+ }
+ else {
+ blk = regs[ci->argc+1];
+ }
+ if (mrb_type(blk) == MRB_TT_PROC) {
+ struct RProc *p = mrb_proc_ptr(blk);
+
+ if (!MRB_PROC_STRICT_P(proc) &&
+ ci > mrb->c->cibase && p->env == ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
+ }
+ }
+ }
+
if (mrb->exc) {
- mrb_callinfo *ci, *ci0;
+ mrb_callinfo *ci0;
mrb_value *stk;
- int eidx;
L_RAISE:
ci0 = ci = mrb->c->ci;
- mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, pc));
- mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->c->cibase));
- eidx = ci->eidx;
if (ci == mrb->c->cibase) {
- if (ci->ridx == 0) goto L_STOP;
+ if (ci->ridx == 0) goto L_FTOP;
goto L_RESCUE;
}
stk = mrb->c->stack;
@@ -1677,6 +1894,7 @@ RETRY_TRY_BLOCK:
if (ci == mrb->c->cibase) {
mrb->c->stack = stk;
if (ci->ridx == 0) {
+ L_FTOP: /* fiber top */
if (mrb->c == mrb->root_c) {
mrb->c->stack = mrb->c->stbase;
goto L_STOP;
@@ -1684,6 +1902,9 @@ RETRY_TRY_BLOCK:
else {
struct mrb_context *c = mrb->c;
+ if (c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ }
mrb->c = c->prev;
c->prev = NULL;
goto L_RAISE;
@@ -1693,8 +1914,13 @@ RETRY_TRY_BLOCK:
}
/* call ensure only when we skip this callinfo */
if (ci[0].ridx == ci[-1].ridx) {
- while (eidx > ci[-1].eidx) {
- ecall(mrb, --eidx);
+ mrb_value *org_stbase = mrb->c->stbase;
+ while (mrb->c->eidx > ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
+ ci = mrb->c->ci;
+ if (org_stbase != mrb->c->stbase) {
+ stk = mrb->c->stack;
+ }
}
}
}
@@ -1707,13 +1933,15 @@ RETRY_TRY_BLOCK:
if (ci != ci0) {
mrb->c->stack = ci[1].stackent;
}
+ stack_extend(mrb, irep->nregs);
pc = mrb->c->rescue[--ci->ridx];
}
else {
- mrb_callinfo *ci = mrb->c->ci;
- int acc, eidx = mrb->c->ci->eidx;
- mrb_value v = regs[GETARG_A(i)];
+ int acc;
+ mrb_value v;
+ v = regs[GETARG_A(i)];
+ mrb_gc_protect(mrb, v);
switch (GETARG_B(i)) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
@@ -1721,21 +1949,21 @@ RETRY_TRY_BLOCK:
struct REnv *e = top_env(mrb, proc);
mrb_callinfo *ce;
- if (!MRB_ENV_STACK_SHARED_P(e)) {
+ if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ce = mrb->c->cibase + e->cioff;
- while (--ci > ce) {
- if (ci->env) {
- mrb_env_unshare(mrb, ci->env);
- }
+ while (ci > ce) {
+ mrb_env_unshare(mrb, ci->env);
if (ci->acc < 0) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
+ ci--;
}
+ mrb_env_unshare(mrb, ci->env);
if (ce == mrb->c->cibase) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
@@ -1745,6 +1973,7 @@ RETRY_TRY_BLOCK:
break;
}
case OP_R_NORMAL:
+ NORMAL_RETURN:
if (ci == mrb->c->cibase) {
if (!mrb->c->prev) { /* toplevel return */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
@@ -1755,6 +1984,9 @@ RETRY_TRY_BLOCK:
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
+ while (mrb->c->eidx > 0) {
+ ecall(mrb, --mrb->c->eidx);
+ }
/* automatic yield at the end */
mrb->c->status = MRB_FIBER_TERMINATED;
mrb->c = mrb->c->prev;
@@ -1763,39 +1995,68 @@ RETRY_TRY_BLOCK:
ci = mrb->c->ci;
break;
case OP_R_BREAK:
- if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
- localjump_error(mrb, LOCALJUMP_ERROR_BREAK);
+ if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
+ if (MRB_PROC_ORPHAN_P(proc)) {
+ mrb_value exc;
+
+ L_BREAK_ERROR:
+ exc = mrb_exc_new_str_lit(mrb, E_LOCALJUMP_ERROR,
+ "break from proc-closure");
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
+ if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
+ goto L_BREAK_ERROR;
+ }
+ if (proc->env->cxt.c != mrb->c) {
+ goto L_BREAK_ERROR;
+ }
+ while (mrb->c->eidx > mrb->c->ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
+ }
/* break from fiber block */
if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
struct mrb_context *c = mrb->c;
mrb->c = c->prev;
c->prev = NULL;
+ ci = mrb->c->ci;
+ }
+ if (ci->acc < 0) {
+ mrb_gc_arena_restore(mrb, ai);
+ mrb->c->vmexec = FALSE;
+ mrb->exc = (struct RObject*)break_new(mrb, proc, v);
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
+ }
+ if (FALSE) {
+ L_BREAK:
+ v = ((struct RBreak*)mrb->exc)->val;
+ proc = ((struct RBreak*)mrb->exc)->proc;
+ mrb->exc = NULL;
+ ci = mrb->c->ci;
}
- ci = mrb->c->ci;
mrb->c->stack = ci->stackent;
mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
while (ci > mrb->c->ci) {
+ mrb_env_unshare(mrb, ci->env);
if (ci[-1].acc == CI_ACC_SKIP) {
mrb->c->ci = ci;
- break;
- }
- if (ci->env) {
- mrb_env_unshare(mrb, ci->env);
+ goto L_BREAK_ERROR;
}
ci--;
}
+ mrb_env_unshare(mrb, ci->env);
break;
default:
/* cannot happen */
break;
}
- while (eidx > mrb->c->ci[-1].eidx) {
- ecall(mrb, --eidx);
+ while (mrb->c->eidx > mrb->c->ci->epos) {
+ ecall(mrb, --mrb->c->eidx);
}
if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+ mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
mrb->jmp = prev_jmp;
return v;
@@ -1805,17 +2066,19 @@ RETRY_TRY_BLOCK:
mrb->c->stack = ci->stackent;
cipop(mrb);
if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
+ mrb_gc_arena_restore(mrb, ai);
mrb->jmp = prev_jmp;
return v;
}
pc = ci->pc;
- DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
+ DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid)));
proc = mrb->c->ci->proc;
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
regs[acc] = v;
+ mrb_gc_arena_restore(mrb, ai);
}
JUMP;
}
@@ -1846,6 +2109,7 @@ RETRY_TRY_BLOCK:
else {
args = mrb_ary_new_from_values(mrb, n, regs+a+1);
}
+ ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
@@ -1884,10 +2148,10 @@ RETRY_TRY_BLOCK:
pool = irep->pool;
syms = irep->syms;
if (ci->argc < 0) {
- stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+ stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ stack_extend(mrb, irep->nregs);
}
pc = irep->iseq;
}
@@ -1907,7 +2171,9 @@ RETRY_TRY_BLOCK:
if (lv == 0) stack = regs + 1;
else {
struct REnv *e = uvenv(mrb, lv-1);
- if (!e || e->mid == 0) {
+ if (!e || e->cioff == 0 ||
+ (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0) ||
+ MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) {
localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
goto L_RAISE;
}
@@ -1981,7 +2247,7 @@ RETRY_TRY_BLOCK:
default:
goto L_SEND;
}
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2103,7 +2369,14 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
+ double f;
+ if (y == 0 && x != 0) {
+ f = INFINITY;
+ }
+ else {
+ f = (mrb_float)x / (mrb_float)y;
+ }
+ SET_FLOAT_VALUE(mrb, regs[a], f);
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
@@ -2118,7 +2391,14 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x / y);
+ double f;
+ if (y == 0) {
+ f = INFINITY;
+ }
+ else {
+ f = x / y;
+ }
+ SET_FLOAT_VALUE(mrb, regs[a], f);
}
#else
OP_MATH_BODY(/,mrb_float,mrb_fixnum);
@@ -2140,7 +2420,8 @@ RETRY_TRY_BLOCK:
}
#ifdef MRB_NAN_BOXING
if (isnan(mrb_float(regs[a]))) {
- regs[a] = mrb_float_value(mrb, mrb_float(regs[a]));
+ mrb_value v = mrb_float_value(mrb, mrb_float(regs[a]));
+ regs[a] = v;
}
#endif
NEXT;
@@ -2293,48 +2574,61 @@ RETRY_TRY_BLOCK:
CASE(OP_ARRAY) {
/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
- regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), &regs[GETARG_B(i)]);
- ARENA_RESTORE(mrb, ai);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_value v = mrb_ary_new_from_values(mrb, c, &regs[b]);
+ regs[a] = v;
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
CASE(OP_ARYCAT) {
/* A B mrb_ary_concat(R(A),R(B)) */
- mrb_value splat = mrb_ary_splat(mrb, regs[GETARG_B(i)]);
- mrb_ary_concat(mrb, regs[GETARG_A(i)], splat);
- ARENA_RESTORE(mrb, ai);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ mrb_value splat = mrb_ary_splat(mrb, regs[b]);
+ mrb_ary_concat(mrb, regs[a], splat);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
CASE(OP_ARYPUSH) {
/* A B R(A).push(R(B)) */
- mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ mrb_ary_push(mrb, regs[a], regs[b]);
NEXT;
}
CASE(OP_AREF) {
/* A B C R(A) := R(B)[C] */
int a = GETARG_A(i);
+ int b = GETARG_B(i);
int c = GETARG_C(i);
- mrb_value v = regs[GETARG_B(i)];
+ mrb_value v = regs[b];
if (!mrb_array_p(v)) {
if (c == 0) {
- regs[GETARG_A(i)] = v;
+ regs[a] = v;
}
else {
SET_NIL_VALUE(regs[a]);
}
}
else {
- regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c);
+ v = mrb_ary_ref(mrb, v, c);
+ regs[a] = v;
}
NEXT;
}
CASE(OP_ASET) {
/* A B C R(B)[C] := R(A) */
- mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ mrb_ary_set(mrb, regs[b], c, regs[a]);
NEXT;
}
@@ -2344,7 +2638,6 @@ RETRY_TRY_BLOCK:
mrb_value v = regs[a];
int pre = GETARG_B(i);
int post = GETARG_C(i);
-
struct RArray *ary;
int len, idx;
@@ -2352,31 +2645,34 @@ RETRY_TRY_BLOCK:
v = mrb_ary_new_from_values(mrb, 1, &regs[a]);
}
ary = mrb_ary_ptr(v);
- len = ary->len;
+ len = ARY_LEN(ary);
if (len > pre + post) {
- regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
+ v = mrb_ary_new_from_values(mrb, len - pre - post, ARY_PTR(ary)+pre);
+ regs[a++] = v;
while (post--) {
- regs[a++] = ary->ptr[len-post-1];
+ regs[a++] = ARY_PTR(ary)[len-post-1];
}
}
else {
- regs[a++] = mrb_ary_new_capa(mrb, 0);
+ v = mrb_ary_new_capa(mrb, 0);
+ regs[a++] = v;
for (idx=0; idx+pre<len; idx++) {
- regs[a+idx] = ary->ptr[pre+idx];
+ regs[a+idx] = ARY_PTR(ary)[pre+idx];
}
while (idx < post) {
SET_NIL_VALUE(regs[a+idx]);
idx++;
}
}
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
CASE(OP_STRING) {
/* A Bx R(A) := str_new(Lit(Bx)) */
- regs[GETARG_A(i)] = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
- ARENA_RESTORE(mrb, ai);
+ mrb_value str = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+ regs[GETARG_A(i)] = str;
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2398,7 +2694,7 @@ RETRY_TRY_BLOCK:
b+=2;
}
regs[GETARG_A(i)] = hash;
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2415,7 +2711,7 @@ RETRY_TRY_BLOCK:
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
regs[GETARG_A(i)] = mrb_obj_value(p);
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2442,7 +2738,7 @@ RETRY_TRY_BLOCK:
}
c = mrb_vm_define_class(mrb, base, super, id);
regs[a] = mrb_obj_value(c);
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2462,7 +2758,7 @@ RETRY_TRY_BLOCK:
}
c = mrb_vm_define_module(mrb, base, id);
regs[a] = mrb_obj_value(c);
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2475,6 +2771,7 @@ RETRY_TRY_BLOCK:
/* prepare closure */
p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
+ p->c = NULL;
/* prepare stack */
ci = cipush(mrb);
@@ -2492,25 +2789,14 @@ RETRY_TRY_BLOCK:
p->target_class = ci->target_class;
ci->proc = p;
- if (MRB_PROC_CFUNC_P(p)) {
- ci->nregs = 0;
- mrb->c->stack[0] = p->body.func(mrb, recv);
- mrb_gc_arena_restore(mrb, ai);
- if (mrb->exc) goto L_RAISE;
- /* pop stackpos */
- mrb->c->stack = mrb->c->ci->stackent;
- cipop(mrb);
- NEXT;
- }
- else {
- irep = p->body.irep;
- pool = irep->pool;
- syms = irep->syms;
- stack_extend(mrb, irep->nregs, 1);
- ci->nregs = irep->nregs;
- pc = irep->iseq;
- JUMP;
- }
+ irep = p->body.irep;
+ pool = irep->pool;
+ syms = irep->syms;
+ stack_extend(mrb, irep->nregs);
+ stack_clear(regs+1, irep->nregs-1);
+ ci->nregs = irep->nregs;
+ pc = irep->iseq;
+ JUMP;
}
CASE(OP_METHOD) {
@@ -2520,14 +2806,14 @@ RETRY_TRY_BLOCK:
struct RProc *p = mrb_proc_ptr(regs[a+1]);
mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], p);
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
CASE(OP_SCLASS) {
/* A B R(A) := R(B).singleton_class */
regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2547,7 +2833,7 @@ RETRY_TRY_BLOCK:
int b = GETARG_B(i);
mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
regs[GETARG_A(i)] = val;
- ARENA_RESTORE(mrb, ai);
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2569,10 +2855,10 @@ RETRY_TRY_BLOCK:
/* stop VM */
L_STOP:
{
- int eidx_stop = mrb->c->ci == mrb->c->cibase ? 0 : mrb->c->ci[-1].eidx;
- int eidx = mrb->c->ci->eidx;
- while (eidx > eidx_stop) {
- ecall(mrb, --eidx);
+ int epos = mrb->c->ci->epos;
+
+ while (mrb->c->eidx > epos) {
+ ecall(mrb, --mrb->c->eidx);
}
}
ERR_PC_CLR(mrb);
@@ -2626,7 +2912,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
mrb_callinfo *ci;
mrb_value v;
- if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
+ if (!mrb->c->cibase) {
+ return mrb_vm_run(mrb, proc, self, stack_keep);
+ }
+ if (mrb->c->ci == mrb->c->cibase) {
+ mrb->c->ci->env = NULL;
return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);
diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake
index 23663d0a5..540aa3eb5 100644
--- a/tasks/libmruby.rake
+++ b/tasks/libmruby.rake
@@ -16,6 +16,8 @@ MRuby.each_target do
gem_libraries = gems.map { |g| g.linker.libraries }
f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}"
+
+ f.puts "MRUBY_LIBMRUBY_PATH = #{libfile("#{build_dir}/lib/libmruby")}"
end
end
task :all => "#{build_dir}/lib/libmruby.flags.mak"
diff --git a/tasks/toolchains/android.rake b/tasks/toolchains/android.rake
index e69dbf5a6..c59da7fcb 100644
--- a/tasks/toolchains/android.rake
+++ b/tasks/toolchains/android.rake
@@ -263,7 +263,7 @@ Set ANDROID_PLATFORM environment variable or set :platform parameter
case toolchain
when :gcc
when :clang
- flags += %W(-gcc-toolchain "#{gcc_toolchain_path.to_s}" -Wno-invalid-command-line-argument -Wno-unused-command-line-argument)
+ flags += %W(-gcc-toolchain "#{gcc_toolchain_path}" -Wno-invalid-command-line-argument -Wno-unused-command-line-argument)
end
flags += %W(-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes)
diff --git a/test/assert.rb b/test/assert.rb
index 7efc24e19..8ab9db29e 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -23,8 +23,8 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil)
msg += " => #{e.message}" if e
msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME)
if $mrbtest_assert && $mrbtest_assert.size > 0
- $mrbtest_assert.each do |idx, str, diff|
- msg += "\n - Assertion[#{idx}] Failed: #{str}\n#{diff}"
+ $mrbtest_assert.each do |idx, assert_msg, diff|
+ msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}"
end
end
msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt
@@ -62,7 +62,7 @@ def assert(str = 'Assertion failed', iso = '')
$asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt))
$kill_test += 1
t_print('X')
- end
+ end
ensure
$mrbtest_assert = nil
end
@@ -157,7 +157,7 @@ def assert_raise(*exp)
msg = "#{msg}#{exp.inspect} exception expected, not"
diff = " Class: <#{e.class}>\n" +
" Message: #{e.message}"
- if not exp.any?{|ex| ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class }
+ unless exp.any?{|ex| ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class }
$mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
ret = false
end
diff --git a/test/bintest.rb b/test/bintest.rb
index 8f56cc0ad..12971a9d9 100644
--- a/test/bintest.rb
+++ b/test/bintest.rb
@@ -3,7 +3,7 @@ require 'test/assert.rb'
def cmd(s)
case RbConfig::CONFIG['host_os']
- when /mswin(?!ce)|mingw|cygwin|bccwin/
+ when /mswin(?!ce)|mingw|bccwin/
"bin\\#{s}.exe"
else
"bin/#{s}"
@@ -12,7 +12,7 @@ end
def shellquote(s)
case RbConfig::CONFIG['host_os']
- when /mswin(?!ce)|mingw|cygwin|bccwin/
+ when /mswin(?!ce)|mingw|bccwin/
"\"#{s}\""
else
"'#{s}'"
@@ -21,7 +21,7 @@ end
ARGV.each do |gem|
case RbConfig::CONFIG['host_os']
- when /mswin(?!ce)|mingw|cygwin|bccwin/
+ when /mswin(?!ce)|mingw|bccwin/
gem = gem.gsub('\\', '/')
end
diff --git a/test/t/array.rb b/test/t/array.rb
index 4efc5166a..7c11265a4 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -237,6 +237,8 @@ assert('Array#pop', '15.2.12.5.21') do
assert_nil([].pop)
assert_equal([1,2], a)
assert_equal(3, b)
+
+ assert_raise(RuntimeError) { [].freeze.pop }
end
assert('Array#push', '15.2.12.5.22') do
@@ -284,6 +286,8 @@ assert('Array#shift', '15.2.12.5.27') do
assert_nil([].shift)
assert_equal([2,3], a)
assert_equal(1, b)
+
+ assert_raise(RuntimeError) { [].freeze.shift }
end
assert('Array#size', '15.2.12.5.28') do
diff --git a/test/t/class.rb b/test/t/class.rb
index 54fadc0ca..eb077fce6 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -410,6 +410,20 @@ assert('class variable in module and class << self style class method') do
assert_equal("value", ClassVariableInModuleTest.class_variable)
end
+assert('child class/module defined in singleton class get parent constant') do
+ actual = module GetParentConstantTest
+ EXPECT = "value"
+ class << self
+ class CHILD
+ class << self
+ EXPECT
+ end
+ end
+ end
+ end
+ assert_equal("value", actual)
+end
+
assert('overriding class variable with a module (#3235)') do
module ModuleWithCVar
@@class_variable = 1
diff --git a/test/t/codegen.rb b/test/t/codegen.rb
index 709902741..29f5ad525 100644
--- a/test/t/codegen.rb
+++ b/test/t/codegen.rb
@@ -14,24 +14,6 @@ assert('empty condition in ternary expression parses correctly') do
assert_equal(() ? 1 : 2, 2)
end
-assert('codegen absorbs arguments to redo and retry if they are the argument of a call') do
- assert_nothing_raised do
- a=*"1", case nil
- when 1
- redo |
- 1
- end
- end
-
- assert_nothing_raised do
- a=*"1", case nil
- when 1
- retry |
- 1
- end
- end
-end
-
assert('method call with exactly 127 arguments') do
def args_to_ary(*args)
args
diff --git a/test/t/exception.rb b/test/t/exception.rb
index 9c8b36e44..ce7b5841e 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -398,7 +398,7 @@ assert('GC in rescue') do
end
rescue => exception
GC.start
- assert_equal("#{__FILE__}:#{line}:in Object.call",
+ assert_equal("#{__FILE__}:#{line}:in call",
exception.backtrace.first)
end
end
@@ -416,7 +416,7 @@ assert('Method call in rescue') do
rescue => exception
[3].each do
end
- assert_equal("#{__FILE__}:#{line}:in Object.call",
+ assert_equal("#{__FILE__}:#{line}:in call",
exception.backtrace.first)
end
end
diff --git a/test/t/iterations.rb b/test/t/iterations.rb
new file mode 100644
index 000000000..f227a6037
--- /dev/null
+++ b/test/t/iterations.rb
@@ -0,0 +1,61 @@
+assert('while expression', '11.5.2.3.2') do
+ idx = 10
+ all = []
+ res = while idx > 0
+ all << idx
+ idx -= 1
+ end
+
+ assert_equal nil, res
+ assert_equal [10,9,8,7,6,5,4,3,2,1], all
+end
+
+assert('until expression', '11.5.2.3.3') do
+ idx = 10
+ all = []
+ res = until idx == 0
+ all << idx
+ idx -= 1
+ end
+
+ assert_equal nil, res
+ assert_equal [10,9,8,7,6,5,4,3,2,1], all
+end
+
+assert('break expression', '11.5.2.4.3') do
+ assert_equal :result do
+ while true
+ break :result
+ end
+ end
+
+ assert_equal :result do
+ until false
+ break :result
+ end
+ end
+end
+
+assert('next expression', '11.5.2.4.4') do
+ assert_equal [8,6,4,2,0] do
+ all = []
+ idx = 10
+ while idx > 0
+ idx -= 1
+ next if (idx % 2) == 1
+ all << idx
+ end
+ all
+ end
+
+ assert_equal [8,6,4,2,0] do
+ all = []
+ idx = 10
+ until idx == 0
+ idx -= 1
+ next if (idx % 2) == 1
+ all << idx
+ end
+ all
+ end
+end \ No newline at end of file
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index aff2dd461..40a3482f8 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -387,7 +387,7 @@ assert('Kernel#method_missing', '15.3.1.3.30') do
begin
c.no_method_named_this
rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for #{c.to_s}", e.message
+ assert_equal "undefined method 'no_method_named_this' for #{c}", e.message
end
class NoInspectClass
@@ -397,7 +397,7 @@ assert('Kernel#method_missing', '15.3.1.3.30') do
begin
d.no_method_named_this
rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for #{d.to_s}", e.message
+ assert_equal "undefined method 'no_method_named_this' for #{d}", e.message
end
end
diff --git a/test/t/module.rb b/test/t/module.rb
index cfdca8503..e32cac5f1 100644
--- a/test/t/module.rb
+++ b/test/t/module.rb
@@ -268,6 +268,12 @@ assert('Module#const_get', '15.2.2.4.21') do
end
assert_equal 42, Test4ConstGet.const_get(:Const4Test4ConstGet)
+ assert_equal 42, Test4ConstGet.const_get("Const4Test4ConstGet")
+ assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet")
+
+ assert_raise(TypeError){ Test4ConstGet.const_get(123) }
+ assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) }
+ assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") }
end
assert('Module#const_missing', '15.2.2.4.22') do
@@ -280,7 +286,7 @@ assert('Module#const_missing', '15.2.2.4.22') do
assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist)
end
-assert('Module#const_get', '15.2.2.4.23') do
+assert('Module#const_set', '15.2.2.4.23') do
module Test4ConstSet
Const4Test4ConstSet = 42
end
@@ -309,10 +315,14 @@ assert('Module#include', '15.2.2.4.27') do
Const4Include = 42
end
module Test4Include2
- include Test4Include
+ @include_result = include Test4Include
+ class << self
+ attr_reader :include_result
+ end
end
assert_equal 42, Test4Include2.const_get(:Const4Include)
+ assert_equal Test4Include2, Test4Include2.include_result
end
assert('Module#include?', '15.2.2.4.28') do
@@ -540,6 +550,18 @@ end
assert_equal(expected, obj.m1)
end
+ assert('Module#prepend result') do
+ module TestPrepended; end
+ module TestPrependResult
+ @prepend_result = prepend TestPrepended
+ class << self
+ attr_reader :prepend_result
+ end
+ end
+
+ assert_equal TestPrependResult, TestPrependResult.prepend_result
+ end
+
# mruby shouldn't be affected by this since there is
# no visibility control (yet)
assert('Module#prepend public') do
@@ -787,10 +809,28 @@ end
# @!endgroup prepend
assert('Module#to_s') do
- module Test4to_sModules
+ module Outer
+ class Inner; end
+ const_set :SetInner, Class.new
end
- assert_equal 'Test4to_sModules', Test4to_sModules.to_s
+ assert_equal 'Outer', Outer.to_s
+ assert_equal 'Outer::Inner', Outer::Inner.to_s
+ assert_equal 'Outer::SetInner', Outer::SetInner.to_s
+
+ outer = Module.new do
+ const_set :SetInner, Class.new
+ end
+ Object.const_set :SetOuter, outer
+
+ assert_equal 'SetOuter', SetOuter.to_s
+ assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s
+
+ mod = Module.new
+ cls = Class.new
+
+ assert_equal "#<Module:0x", mod.to_s[0,11]
+ assert_equal "#<Class:0x", cls.to_s[0,10]
end
assert('Module#inspect') do
diff --git a/test/t/superclass.rb b/test/t/superclass.rb
index 9fd8830b3..10b6438d3 100644
--- a/test/t/superclass.rb
+++ b/test/t/superclass.rb
@@ -23,7 +23,8 @@
[:Exception, :Object, '15.2.22.2'],
[:StandardError, :Exception, '15.2.23.2'],
[:ArgumentError, :StandardError, '15.2.24.2'],
- [:LocalJumpError, :StandardError, '15.2.25.2'],
+ # [:LocalJumpError, :StandardError, '15.2.25.2'],
+ [:LocalJumpError, :ScriptError, '15.2.25.2'], # mruby specific
[:RangeError, :StandardError, '12.2.26.2'],
[:RegexpError, :StandardError, '12.2.27.2'],
[:RuntimeError, :StandardError, '12.2.28.2'],
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index 461f5430b..299394557 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -381,7 +381,7 @@ assert('splat in case statement') do
end
assert('External command execution.') do
- class << Kernel
+ module Kernel
sym = '`'.to_sym
alias_method :old_cmd, sym