diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | doc/limitations.md | 22 | ||||
| -rw-r--r-- | doc/opcode.md | 127 | ||||
| -rw-r--r-- | include/mruby.h | 16 | ||||
| -rw-r--r-- | include/mruby/class.h | 3 | ||||
| -rw-r--r-- | include/mruby/compile.h | 2 | ||||
| -rw-r--r-- | include/mruby/hash.h | 37 | ||||
| -rw-r--r-- | include/mruby/irep.h | 11 | ||||
| -rw-r--r-- | include/mruby/opcode.h | 186 | ||||
| -rw-r--r-- | include/mruby/ops.h | 117 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 1494 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/node.h | 24 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 504 | ||||
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 112 | ||||
| -rw-r--r-- | mrbgems/mruby-method/src/method.c | 6 | ||||
| -rw-r--r-- | mrbgems/mruby-objectspace/src/mruby_objectspace.c | 2 | ||||
| -rw-r--r-- | mrbgems/mruby-proc-ext/src/proc.c | 22 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/src/string.c | 4 | ||||
| -rw-r--r-- | mrblib/hash.rb | 5 | ||||
| -rw-r--r-- | src/class.c | 8 | ||||
| -rw-r--r-- | src/codedump.c | 790 | ||||
| -rw-r--r-- | src/hash.c | 119 | ||||
| -rw-r--r-- | src/kernel.c | 12 | ||||
| -rw-r--r-- | src/load.c | 6 | ||||
| -rw-r--r-- | src/proc.c | 10 | ||||
| -rw-r--r-- | src/vm.c | 1109 | ||||
| -rw-r--r-- | test/t/syntax.rb | 184 |
28 files changed, 2876 insertions, 2065 deletions
diff --git a/.gitignore b/.gitignore index bccfaf218..9c34b5f29 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ .DS_Store .ccmalloc .svn +.vscode /.git cscope.files cscope.out diff --git a/doc/limitations.md b/doc/limitations.md index afcb7b56e..92858cb1f 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -205,3 +205,25 @@ trace (most recent call last): [0] -e:1 -e:1: undefined method 'binding' (NoMethodError) ``` + +## Keyword arguments + +mruby keyword arguments behave slightly different from CRuby 2.5 +to make the behavior simpler and less confusing. Maybe in the +future, the simpler behavior will be adopted to CRuby as well. + +#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)] + +``` +$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' +[[{"a"=>1}], {:b=>2}] +``` + +#### mruby [] + +``` +$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' +trace (most recent call last): + [0] -e:1 +-e:1: keyword argument hash with non symbol keys (ArgumentError) +``` diff --git a/doc/opcode.md b/doc/opcode.md new file mode 100644 index 000000000..fea0afafd --- /dev/null +++ b/doc/opcode.md @@ -0,0 +1,127 @@ +# The new bytecode + +We will reimplement VM to use 8bit instruction code. By +bytecode, we mean real byte code. The whole purpose is +reducing the memory consumption of mruby VM. + +# Instructions + +Instructions are bytes. There can be 256 instructions. Currently we +have 94 instructions. Instructions can take 0 to 3 operands. + +## operands + +The size of operands can be either 8bits, 16bits or 24bits. +In the table.1 below, the second field describes the size (and +sign) of operands. + +* B: 8bit +* sB: signed 8bit +* S: 16bit +* sS: signed 16bit +* W: 24bit + +First two byte operands may be extended to 16bit. When those byte +operands are bigger than 256, the instruction will be prefixed by +`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand +is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). + +For instructions marked by `'`, `OP_EXT1` can be prefixed. For those +with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. + +## table.1 Instruction Table + +|Instruction Name |Operand type |Semantics +|-----------------|-------------|----------------- +|OP_NOP | - | +|OP_MOVE" |BB |R(a) = R(b) +|OP_LOADL" |BB |R(a) = Pool(b) +|OP_LOADI" |BsB |R(a) = mrb_int(b) +|OP_LOADI_0' |B |R(a) = 0 +|OP_LOADI_1' |B |R(a) = 1 +|OP_LOADI_2' |B |R(a) = 2 +|OP_LOADI_3' |B |R(a) = 3 +|OP_LOADSYM" |BB |R(a) = Syms(b) +|OP_LOADNIL' |B |R(a) = nil +|OP_LOADSELF' |B |R(a) = self +|OP_LOADT' |B |R(a) = true +|OP_LOADF' |B |R(a) = false +|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) +|OP_SETGV" |BB |setglobal(Syms(b), R(a)) +|OP_GETSV" |BB |R(a) = Special[b] +|OP_SETSV" |BB |Special[b] = R(a) +|OP_GETIV" |BB |R(a) = ivget(Syms(b)) +|OP_SETIV" |BB |ivset(Syms(b),R(a)) +|OP_GETCV" |BB |R(a) = cvget(Syms(b)) +|OP_SETCV" |BB |cvset(Syms(b),R(a)) +|OP_GETCONST" |BB |R(a) = constget(Syms(b)) +|OP_SETCONST" |BB |constset(Syms(b),R(a)) +|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) +|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) +|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) +|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) +|OP_JMP |S |pc+=a +|OP_JMPIF' |SB |if R(b) pc+=a +|OP_JMPNOT' |SB |if !R(b) pc+=a +|OP_ONERR |sS |rescue_push(pc+a) +|OP_EXCEPT' |B |R(a) = exc +|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) +|OP_POPERR |B |a.times{rescue_pop()} +|OP_RAISE' |B |raise(R(a)) +|OP_EPUSH' |B |ensure_push(SEQ[a]) +|OP_EPOP |B |A.times{ensure_pop().call} +|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) +|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) +|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) +|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) +|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) +|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) +|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) +|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) +|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo +|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo +|OP_RETURN' |B |return R(a) (normal) +|OP_RETURN_BLK' |B |return R(a) (in-block return) +|OP_BREAK' |B |break R(a) +|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) +|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) +|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) +|OP_LT" |BB |R(a) = R(a)<R(a+1) (Syms[b]=:<) +|OP_LE" |BB |R(a) = R(a)<=R(a+1) (Syms[b]=:<=) +|OP_GT" |BB |R(a) = R(a)>R(a+1) (Syms[b]=:>) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) +|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) +|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) +|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) +|OP_AREF' |BB |R(a) = R(a)[b] +|OP_ASET' |BB |R(a)[b] = R(a+1) +|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] +|OP_STRING" |BB |R(a) = str_dup(Lit(b)) +|OP_STRCAT' |B |str_cat(R(a),R(a+1)) +|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) +|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) +|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) +|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) +|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) +|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) +|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) +|OP_OCLASS' |B |R(a) = ::Object +|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) +|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) +|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) +|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) +|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) +|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) +|OP_SCLASS' |B |R(a) = R(a).singleton_class +|OP_TCLASS' |B |R(a) = target_class +|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) +|OP_EXT1 |- |make 1st operand 16bit +|OP_EXT2 |- |make 2nd operand 16bit +|OP_EXT3 |- |make 1st and 2nd operands 16bit +|OP_STOP |- |stop VM diff --git a/include/mruby.h b/include/mruby.h index bc6d72330..872396899 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -93,7 +93,7 @@ */ MRB_BEGIN_DECL -typedef uint32_t mrb_code; +typedef uint8_t mrb_code; /** * Required arguments signature type. @@ -123,8 +123,8 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - int ridx; - int epos; + uint16_t ridx; + uint16_t epos; struct REnv *env; mrb_code *pc; /* return address */ mrb_code *err; /* error position */ @@ -151,10 +151,10 @@ struct mrb_context { mrb_callinfo *ci; mrb_callinfo *cibase, *ciend; - mrb_code **rescue; /* exception handler stack */ + uint16_t *rescue; /* exception handler stack */ int rsize; struct RProc **ensure; /* ensure handler stack */ - int esize, eidx; + uint8_t esize, eidx; enum mrb_fiber_state status; mrb_bool vmexec; @@ -485,9 +485,10 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_ * } * @param [mrb_state*] mrb_state* The mruby state reference. * @param [struct RClass*] RClass* A class the method will be undefined from. - * @param [const char*] constchar* The name of the method to be undefined. + * @param [const char] const char* The name of the method to be undefined. */ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*); +MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); /** * Undefine a class method. @@ -1196,7 +1197,6 @@ typedef enum call_type { CALL_TYPE_MAX } call_type; -MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); @@ -1234,7 +1234,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib); * @mrbgem mruby-fiber */ #define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) -MRB_API void mrb_stack_extend(mrb_state*, int); +MRB_API void mrb_stack_extend(mrb_state*, mrb_int); /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/include/mruby/class.h b/include/mruby/class.h index dfe63999c..96a9f7f95 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -79,7 +79,8 @@ MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t); MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); -MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_define_alias(mrb_state*, struct RClass *c, const char* a, const char* b); MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); diff --git a/include/mruby/compile.h b/include/mruby/compile.h index d7d029616..a85460415 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -33,6 +33,7 @@ typedef struct mrbc_context { mrb_bool no_exec:1; mrb_bool keep_lv:1; mrb_bool no_optimize:1; + mrb_bool on_eval:1; size_t parser_nerr; } mrbc_context; @@ -151,6 +152,7 @@ struct mrb_parser_state { mrb_ast_node *tree; mrb_bool no_optimize:1; + mrb_bool on_eval:1; mrb_bool capture_errors:1; struct mrb_parser_message error_buffer[10]; struct mrb_parser_message warn_buffer[10]; diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 1a870785a..2026c8e0d 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -25,6 +25,7 @@ struct RHash { #define mrb_hash_value(p) mrb_obj_value((void*)(p)) MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); /* * Initializes a new hash. @@ -110,7 +111,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value * @return An array with the keys of the hash. */ MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); -MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); +/* + * Check if the hash has the key. + * + * Equivalent to: + * + * hash.key?(key) + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to check existence. + * @return True if the hash has the key + */ +MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key); /* * Check if the hash is empty @@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); * @param self The target hash. * @return True if the hash is empty, false otherwise. */ -MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self); /* * Gets an array of values. @@ -151,6 +164,26 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +/* + * Copies the hash. + * + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The copy of the hash + */ +MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); + +/* + * Merges two hashes. The first hash will be modified by the + * second hash. + * + * @param mrb The mruby state reference. + * @param hash1 The target hash. + * @param hash2 Updating hash + */ +MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2); + /* declaration of struct kh_ht */ /* be careful when you touch the internal */ typedef struct { diff --git a/include/mruby/irep.h b/include/mruby/irep.h index ad227be5d..7dcf33735 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -44,7 +44,7 @@ typedef struct mrb_irep { uint16_t *lines; struct mrb_irep_debug_info* debug_info; - int ilen, plen, slen, rlen, refcnt; + uint16_t ilen, plen, slen, rlen, refcnt; } mrb_irep; #define MRB_ISEQ_NO_FREE 1 @@ -58,6 +58,15 @@ void mrb_irep_decref(mrb_state*, struct mrb_irep*); void mrb_irep_cutref(mrb_state*, struct mrb_irep*); void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep); +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; + +struct mrb_insn_data mrb_decode_insn(mrb_code *pc); + MRB_END_DECL #endif /* MRUBY_IREP_H */ diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h index a5e3af158..d513ca472 100644 --- a/include/mruby/opcode.h +++ b/include/mruby/opcode.h @@ -7,145 +7,10 @@ #ifndef MRUBY_OPCODE_H #define MRUBY_OPCODE_H -#define MAXARG_Bx (0xffff) -#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ - -/* instructions: packed 32 bit */ -/* ------------------------------- */ -/* A:B:C:OP = 9: 9: 7: 7 */ -/* A:Bx:OP = 9:16: 7 */ -/* Ax:OP = 25: 7 */ -/* A:Bz:Cz:OP = 9:14: 2: 7 */ - -#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) -#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) -#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) -#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) -#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) -#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) -#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) -#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) -#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) -#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) -#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) - -#define MKOPCODE(op) ((op) & 0x7f) -#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) -#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) -#define MKARG_C(c) (((c) & 0x7f) << 7) -#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) -#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) -#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) -#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7)) -#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2) - -#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a)) -#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b)) -#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c)) -#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx)) -#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx)) -#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx)) -#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx)) -#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax)) -#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c)) - -enum { - /*----------------------------------------------------------------------- - operation code operand description - ------------------------------------------------------------------------*/ - OP_NOP=0,/* */ - OP_MOVE,/* A B R(A) := R(B) */ - OP_LOADL,/* A Bx R(A) := Pool(Bx) */ - OP_LOADI,/* A sBx R(A) := sBx */ - OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */ - OP_LOADNIL,/* A R(A) := nil */ - OP_LOADSELF,/* A R(A) := self */ - OP_LOADT,/* A R(A) := true */ - OP_LOADF,/* A R(A) := false */ - - OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */ - OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */ - OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */ - OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */ - OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */ - OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */ - OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */ - OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */ - OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */ - OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */ - OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */ - OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */ - OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */ - OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */ - - OP_JMP,/* sBx pc+=sBx */ - OP_JMPIF,/* A sBx if R(A) pc+=sBx */ - OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */ - OP_ONERR,/* sBx rescue_push(pc+sBx) */ - OP_RESCUE,/* A B C if A (if C exc=R(A) else R(A) := exc); - if B R(B) := exc.isa?(R(B)); clear(exc) */ - OP_POPERR,/* A A.times{rescue_pop()} */ - OP_RAISE,/* A raise(R(A)) */ - OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */ - OP_EPOP,/* A A.times{ensure_pop().call} */ - - OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ - OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */ - OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */ - OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ - OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */ - OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ - OP_KDICT,/* A C R(A) := kdict */ - - OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */ - OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */ - OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */ - - OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */ - OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */ - OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */ - OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */ - OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */ - OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */ - OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */ - OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */ - OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */ - OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */ - OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */ - - OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ - OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ - OP_AREF,/* A B C R(A) := R(B)[C] */ - OP_ASET,/* A B C R(B)[C] := R(A) */ - OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - - OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ - OP_STRCAT,/* A B str_cat(R(A),R(B)) */ - - OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ - OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ - - OP_OCLASS,/* A R(A) := ::Object */ - OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ - OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */ - OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */ - OP_SCLASS,/* A B R(A) := R(B).singleton_class */ - OP_TCLASS,/* A R(A) := target_class */ - - OP_DEBUG,/* A B C print R(A),R(B),R(C) */ - OP_STOP,/* stop VM */ - OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ - - OP_RSVD1,/* reserved instruction #1 */ - OP_RSVD2,/* reserved instruction #2 */ - OP_RSVD3,/* reserved instruction #3 */ - OP_RSVD4,/* reserved instruction #4 */ - OP_RSVD5,/* reserved instruction #5 */ +enum mrb_insn { +#define OPCODE(x,_) OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #define OP_L_STRICT 1 @@ -158,4 +23,47 @@ enum { #define OP_R_BREAK 1 #define OP_R_RETURN 2 +#define PEEK_B(pc) (*(pc)) +#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1]) +#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2]) + +#define READ_B() PEEK_B(pc++) +#define READ_S() (pc+=2, PEEK_S(pc-2)) +#define READ_W() (pc+=3, PEEK_W(pc-3)) + +#define FETCH_Z() /* nothing */ +#define FETCH_B() do {a=READ_B();} while (0) +#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0) +#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_S() do {a=READ_S();} while (0) +#define FETCH_W() do {a=READ_W();} while (0) + +/* with OP_EXT1 (1st 16bit) */ +#define FETCH_Z_1() FETCH_Z() +#define FETCH_B_1() FETCH_S() +#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0) +#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_1() FETCH_S() +#define FETCH_W_1() FETCH_W() + +/* with OP_EXT2 (2nd 16bit) */ +#define FETCH_Z_2() FETCH_Z() +#define FETCH_B_2() FETCH_B() +#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_2() FETCH_BS() +#define FETCH_S_2() FETCH_S() +#define FETCH_W_2() FETCH_W() + +/* with OP_EXT3 (1st & 2nd 16bit) */ +#define FETCH_Z_3() FETCH_Z() +#define FETCH_B_3() FETCH_B() +#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_3() FETCH_S() +#define FETCH_W_3() FETCH_W() + #endif /* MRUBY_OPCODE_H */ diff --git a/include/mruby/ops.h b/include/mruby/ops.h new file mode 100644 index 000000000..f23bb1b0b --- /dev/null +++ b/include/mruby/ops.h @@ -0,0 +1,117 @@ +/* operand types: + + Z: no operand (Z,Z,Z,Z) + + B: 8bit (B,S,B,B) + + BB: 8+8bit (BB,SB,BS,SS) + + BBB: 8+8+8bit (BBB,SBB,BSB,SSB) + + BS: 8+16bit (BS,SS,BS,BS) + + S: 16bit (S,S,S,S) + + W: 24bit (W,W,W,W) +*/ + +/*----------------------------------------------------------------------- +operation code operands semantics +------------------------------------------------------------------------*/ +OPCODE(NOP, Z) /* no operation */ +OPCODE(MOVE, BB) /* R(a) = R(b) */ +OPCODE(LOADL, BB) /* R(a) = Pool(b) */ +OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */ +OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */ +OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */ +OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */ +OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */ +OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */ +OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */ +OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */ +OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */ +OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */ +OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */ +OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */ +OPCODE(LOADNIL, B) /* R(a) = nil */ +OPCODE(LOADSELF, B) /* R(a) = self */ +OPCODE(LOADT, B) /* R(a) = true */ +OPCODE(LOADF, B) /* R(a) = false */ +OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */ +OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */ +OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */ +OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */ +OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */ +OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */ +OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */ +OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */ +OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */ +OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */ +OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */ +OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */ +OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */ +OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */ +OPCODE(JMP, S) /* pc=a */ +OPCODE(JMPIF, BS) /* if R(b) pc=a */ +OPCODE(JMPNOT, BS) /* if !R(b) pc=a */ +OPCODE(JMPNIL, BS) /* if R(b)==nil pc=a */ +OPCODE(ONERR, S) /* rescue_push(a) */ +OPCODE(EXCEPT, B) /* R(a) = exc */ +OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ +OPCODE(POPERR, B) /* a.times{rescue_pop()} */ +OPCODE(RAISE, B) /* raise(R(a)) */ +OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */ +OPCODE(EPOP, B) /* A.times{ensure_pop().call} */ +OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */ +OPCODE(SENDVB, BB) /* R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) */ +OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ +OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */ +OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */ +OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ +OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */ +OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */ +OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */ +OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */ +OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */ +OPCODE(RETURN, B) /* return R(a) (normal) */ +OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ +OPCODE(BREAK, B) /* break R(a) */ +OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */ +OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ +OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ +OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ +OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */ +OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */ +OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */ +OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */ +OPCODE(LT, BB) /* R(a) = R(a)<R(a+1) (Syms[b]=:<) */ +OPCODE(LE, BB) /* R(a) = R(a)<=R(a+1) (Syms[b]=:<=) */ +OPCODE(GT, BB) /* R(a) = R(a)>R(a+1) (Syms[b]=:>) */ +OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */ +OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ +OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ +OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */ +OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */ +OPCODE(AREF, BBB) /* R(a) = R(b)[c] */ +OPCODE(ASET, BBB) /* R(a)[c] = R(b) */ +OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */ +OPCODE(INTERN, B) /* R(a) = intern(R(a)) */ +OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ +OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ +OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */ +OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */ +OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */ +OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */ +OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */ +OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */ +OPCODE(OCLASS, B) /* R(a) = ::Object */ +OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */ +OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */ +OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),SEQ[b]) */ +OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */ +OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */ +OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */ +OPCODE(SCLASS, B) /* R(a) = R(a).singleton_class */ +OPCODE(TCLASS, B) /* R(a) = target_class */ +OPCODE(DEBUG, BBB) /* print a,b,c */ +OPCODE(ERR, B) /* raise(LocalJumpError, Lit(a)) */ +OPCODE(EXT1, Z) /* make 1st operand 16bit */ +OPCODE(EXT2, Z) /* make 2nd operand 16bit */ +OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */ +OPCODE(STOP, Z) /* stop VM */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 0588dfca5..05a6f3622 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -510,6 +510,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value mrb_sym sym; int32_t bpno; mrb_bool isCfunc; + struct mrb_insn_data insn; mrb_debug_context *dbg = mrb_debug_context_get(mrb); @@ -517,11 +518,12 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value bpno = dbg->method_bpno; dbg->method_bpno = 0; - switch(GET_OPCODE(*pc)) { + insn = mrb_decode_insn(pc); + switch(insn.insn) { case OP_SEND: case OP_SENDB: - c = mrb_class(mrb, regs[GETARG_A(*pc)]); - sym = irep->syms[GETARG_B(*pc)]; + c = mrb_class(mrb, regs[insn.a]); + sym = irep->syms[insn.b]; break; case OP_SUPER: c = mrb->c->ci->target_class->super; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 945ddcc1a..a835a563e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -23,6 +23,8 @@ #define MRB_CODEGEN_LEVEL_MAX 1024 #endif +#define MAXARG_S (1<<16) + typedef mrb_ast_node node; typedef struct mrb_parser_state parser_state; @@ -36,7 +38,7 @@ enum looptype { struct loopinfo { enum looptype type; - int pc1, pc2, pc3, acc; + int pc0, pc1, pc2, pc3, acc; int ensure_level; struct loopinfo *prev; }; @@ -50,9 +52,10 @@ typedef struct scope { node *lv; - int sp; - int pc; - int lastlabel; + uint16_t sp; + uint16_t pc; + uint16_t lastpc; + uint16_t lastlabel; int ainfo:15; mrb_bool mscope:1; @@ -63,10 +66,10 @@ typedef struct scope { mrb_code *iseq; uint16_t *lines; - int icapa; + uint32_t icapa; mrb_irep *irep; - int pcapa, scapa, rcapa; + uint32_t pcapa, scapa, rcapa; uint16_t nlocals; uint16_t nregs; @@ -142,38 +145,141 @@ codegen_realloc(codegen_scope *s, void *p, size_t len) static int new_label(codegen_scope *s) { - s->lastlabel = s->pc; - return s->pc; + return s->lastlabel = s->pc; } -static inline int -genop(codegen_scope *s, mrb_code i) +static void +emit_B(codegen_scope *s, uint32_t pc, uint8_t i) { - if (s->pc >= s->icapa) { + if (pc >= s->icapa) { s->icapa *= 2; - if (s->pc >= MAXARG_sBx) { + if (pc >= MAXARG_S) { codegen_error(s, "too big code block"); } - if (s->icapa > MAXARG_sBx) { - s->icapa = MAXARG_sBx; + if (s->icapa > MAXARG_S) { + s->icapa = MAXARG_S; } s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); if (s->lines) { - s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); + s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); s->irep->lines = s->lines; } } - s->iseq[s->pc] = i; if (s->lines) { - s->lines[s->pc] = s->lineno; + s->lines[pc] = s->lineno; } - return s->pc++; + s->iseq[pc] = i; +} + +static void +emit_S(codegen_scope *s, int pc, uint16_t i) +{ + uint8_t hi = i>>8; + uint8_t lo = i&0xff; + + emit_B(s, pc, hi); + emit_B(s, pc+1, lo); +} + +static void +gen_B(codegen_scope *s, uint8_t i) +{ + emit_B(s, s->pc++, i); +} + +static void +gen_S(codegen_scope *s, uint16_t i) +{ + emit_S(s, s->pc, i); + s->pc += 2; +} + +static void +genop_0(codegen_scope *s, mrb_code i) +{ + s->lastpc = s->pc; + gen_B(s, i); +} + +static void +genop_1(codegen_scope *s, mrb_code i, uint16_t a) +{ + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + } +} + +static void +genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + if (a > 0xff && b > 0xff) { + gen_B(s, OP_EXT3); + gen_B(s, i); + gen_S(s, a); + gen_S(s, b); + } + else if (b > 0xff) { + gen_B(s, OP_EXT2); + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_S(s, b); + } + else if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + gen_B(s, (uint8_t)b); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_B(s, (uint8_t)b); + } +} + +static void +genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c) +{ + s->lastpc = s->pc; + genop_2(s, i, a, b); + gen_B(s, c); +} + +static void +genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + genop_1(s, i, a); + gen_S(s, b); +} + +static void +genop_W(codegen_scope *s, mrb_code i, uint32_t a) +{ + uint8_t a1 = (a>>16) & 0xff; + uint8_t a2 = (a>>8) & 0xff; + uint8_t a3 = a & 0xff; + + s->lastpc = s->pc; + gen_B(s, i); + gen_B(s, a1); + gen_B(s, a2); + gen_B(s, a3); } #define NOVAL 0 #define VAL 1 -static mrb_bool +//static +mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) @@ -181,298 +287,270 @@ no_optimize(codegen_scope *s) return FALSE; } -static int -genop_peep(codegen_scope *s, mrb_code i, int val) +static +mrb_bool +on_eval(codegen_scope *s) { - /* peephole optimization */ - if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { - mrb_code i0 = s->iseq[s->pc-1]; - int c1 = GET_OPCODE(i); - int c0 = GET_OPCODE(i0); + if (s && s->parser && s->parser->on_eval) + return TRUE; + return FALSE; +} - switch (c1) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_B(i)) { - /* skip useless OP_MOVE */ - return 0; - } - if (val) break; - switch (c0) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_A(i0)) { - /* skip overridden OP_MOVE */ - s->pc--; - s->iseq[s->pc] = i; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { - /* skip swapping OP_MOVE */ - return 0; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->pc--; - return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); - } - break; - case OP_LOADI: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); - return 0; - } - break; - case OP_ARRAY: - case OP_HASH: - case OP_RANGE: - case OP_AREF: - case OP_GETUPVAR: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); - return 0; - } - break; - case OP_LOADSYM: - case OP_GETGLOBAL: - case OP_GETIV: - case OP_GETCV: - case OP_GETCONST: - case OP_GETSPECIAL: - case OP_LOADL: - case OP_STRING: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); - return 0; - } - break; - case OP_SCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_LOADNIL: - case OP_LOADSELF: - case OP_LOADT: - case OP_LOADF: - case OP_OCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); - return 0; - } - break; - default: - break; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETGLOBAL: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); - return 0; - } - } - break; - case OP_SETUPVAR: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); - return 0; - } - } - break; - case OP_GETUPVAR: - if (c0 == OP_SETUPVAR) { - if (GETARG_B(i) == GETARG_B(i0) && GETARG_C(i) == GETARG_C(i0)) { - if (GETARG_A(i) == GETARG_A(i0)) { - /* just skip OP_SETUPVAR */ - return 0; - } - else { - return genop(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_A(i0))); - } - } - } - break; - case OP_EPOP: - if (c0 == OP_EPOP) { - s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_POPERR: - if (c0 == OP_POPERR) { - s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_RETURN: - switch (c0) { - case OP_RETURN: - return 0; - case OP_MOVE: - if (GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); - return 0; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETUPVAR: - case OP_SETGLOBAL: - s->pc--; - genop_peep(s, i0, NOVAL); - i0 = s->iseq[s->pc-1]; - return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); -#if 0 - case OP_SEND: - if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); - return; - } - break; -#endif - default: - break; - } - break; - case OP_ADD: - case OP_SUB: - if (c0 == OP_LOADI) { - int c = GETARG_sBx(i0); - - if (c1 == OP_SUB) c = -c; - if (c > 127 || c < -127) break; - if (0 <= c) - s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); - else - s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); - return 0; - } - break; - case OP_ARYCAT: - case OP_ARYPUSH: - if (c0 == OP_MOVE && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c1, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_STRCAT: - if (c0 == OP_STRING) { - mrb_value v = s->irep->pool[GETARG_Bx(i0)]; +struct mrb_insn_data +mrb_decode_insn(mrb_code *pc) +{ + struct mrb_insn_data data = { 0 }; + mrb_code insn = READ_B(); + uint16_t a = 0; + uint16_t b = 0; + uint8_t c = 0; + + switch (insn) { +#define FETCH_Z() /* empty */ +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; +#include "mruby/ops.h" +#undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: + break; + } + data.insn = insn; + data.a = a; + data.b = b; + data.c = c; + return data; +} - if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { - s->pc--; - return 0; - } - } - if (c0 == OP_LOADNIL) { - if (GETARG_B(i) == GETARG_A(i0)) { - s->pc--; - return 0; - } - } +static struct mrb_insn_data +mrb_last_insn(codegen_scope *s) +{ + if (s->pc == s->lastpc) { + struct mrb_insn_data data; + + data.insn = OP_NOP; + return data; + } + return mrb_decode_insn(&s->iseq[s->lastpc]); +} + +static mrb_bool +no_peephole(codegen_scope *s) +{ + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; +} + +static uint16_t +genjmp(codegen_scope *s, mrb_code i, uint16_t pc) +{ + uint16_t pos; + + s->lastpc = s->pc; + gen_B(s, i); + pos = s->pc; + gen_S(s, pc); + return pos; +} + +static uint16_t +genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) +{ + uint16_t pos; + + if (!no_peephole(s) && !val) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && data.a == a) { + s->pc = s->lastpc; + a = data.b; + } + } + + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + pos = s->pc; + gen_S(s, pc); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + pos = s->pc; + gen_S(s, pc); + } + return pos; +} + +static void +gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) +{ + if (no_peephole(s)) { + normal: + genop_2(s, OP_MOVE, dst, src); + if (on_eval(s)) { + genop_0(s, OP_NOP); + } + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_MOVE: + if (dst == src) return; /* remove useless MOVE */ + if (data.b == dst && data.a == src) /* skip swapping MOVE */ + return; + goto normal; + case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF: + case OP_LOADI__1: + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_1(s, data.insn, dst); break; - case OP_JMPIF: - case OP_JMPNOT: - if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); - return s->pc-1; - } + case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM: + case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV: + case OP_GETCONST: case OP_STRING: + case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_2(s, data.insn, dst, data.b); break; default: - break; + goto normal; } } - return genop(s, i); } static void -scope_error(codegen_scope *s) +gen_return(codegen_scope *s, uint8_t op, uint16_t src) { - exit(EXIT_FAILURE); + if (no_peephole(s)) { + genop_1(s, op, src); + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && src == data.a) { + s->pc = s->lastpc; + genop_1(s, op, data.b); + } + else { + genop_1(s, op, src); + } + } } static void -distcheck(codegen_scope *s, int diff) +gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) { - if (diff > MAXARG_sBx || diff < -MAXARG_sBx) { - codegen_error(s, "too distant jump address"); + if (no_peephole(s)) { + normal: + genop_2(s, op, dst, idx); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_LOADI__1: + if (op == OP_ADD) op = OP_SUB; + else op = OP_ADD; + data.b = 1; + goto replace; + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + data.b = data.insn - OP_LOADI_0; + /* fall through */ + case OP_LOADI: + replace: + if (data.b >= 128) goto normal; + s->pc = s->lastpc; + if (op == OP_ADD) { + genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b); + } + else { + genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b); + } + break; + default: + goto normal; + } } } -static inline void -dispatch(codegen_scope *s, int pc) +static int +dispatch(codegen_scope *s, uint16_t pos0) { - int diff = s->pc - pc; - mrb_code i = s->iseq[pc]; - int c = GET_OPCODE(i); + uint16_t newpos; s->lastlabel = s->pc; - switch (c) { - case OP_JMP: - case OP_JMPIF: - case OP_JMPNOT: - case OP_ONERR: - break; - default: -#ifndef MRB_DISABLE_STDIO - fprintf(stderr, "bug: dispatch on non JMP op\n"); -#endif - scope_error(s); - break; - } - distcheck(s, diff); - s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); + newpos = PEEK_S(s->iseq+pos0); + emit_S(s, pos0, s->pc); + return newpos; } static void -dispatch_linked(codegen_scope *s, int pc) +dispatch_linked(codegen_scope *s, uint16_t pos) { - mrb_code i; - int pos; - - if (!pc) return; + if (pos==0) return; for (;;) { - i = s->iseq[pc]; - pos = GETARG_sBx(i); - dispatch(s, pc); - if (!pos) break; - pc = pos; + pos = dispatch(s, pos); + if (pos==0) break; } } #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) static void -push_(codegen_scope *s) +push_n_(codegen_scope *s, int n) { - if (s->sp > 511) { + if (s->sp+n >= 0xffff) { codegen_error(s, "too complex expression"); } - s->sp++; + s->sp+=n; nregs_update; } static void -push_n_(codegen_scope *s, int n) +pop_n_(codegen_scope *s, int n) { - if (s->sp+n > 511) { - codegen_error(s, "too complex expression"); + if ((int)s->sp-n < 0) { + codegen_error(s, "stack pointer underflow"); } - s->sp+=n; - nregs_update; + s->sp-=n; } -#define push() push_(s) +#define push() push_n_(s,1) #define push_n(n) push_n_(s,n) -#define pop_(s) ((s)->sp--) -#define pop() pop_(s) -#define pop_n(n) (s->sp-=(n)) +#define pop() pop_n_(s,1) +#define pop_n(n) pop_n_(s,n) #define cursp() (s->sp) static inline int @@ -545,52 +623,23 @@ new_lit(codegen_scope *s, mrb_value val) return i; } -/* method symbols should be fit in 9 bits */ -#define MAXMSYMLEN 512 /* maximum symbol numbers */ -#define MAXSYMLEN 65536 +#define MAXSYMLEN 0x10000 static int -new_msym(codegen_scope *s, mrb_sym sym) +new_sym(codegen_scope *s, mrb_sym sym) { int i, len; mrb_assert(s->irep); len = s->irep->slen; - if (len > MAXMSYMLEN) len = MAXMSYMLEN; for (i=0; i<len; i++) { if (s->irep->syms[i] == sym) return i; - if (s->irep->syms[i] == 0) break; } - if (i == MAXMSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")"); - } - s->irep->syms[i] = sym; - if (i == s->irep->slen) s->irep->slen++; - return i; -} - -static int -new_sym(codegen_scope *s, mrb_sym sym) -{ - int i; - - for (i=0; i<s->irep->slen; i++) { - if (s->irep->syms[i] == sym) return i; - } - if (s->irep->slen == MAXSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")"); - } - - if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) { - s->scapa = MAXSYMLEN; - s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN); - for (i = s->irep->slen; i < MAXMSYMLEN; i++) { - static const mrb_sym mrb_sym_zero = { 0 }; - s->irep->syms[i] = mrb_sym_zero; - } - s->irep->slen = MAXMSYMLEN; + if (s->irep->slen >= s->scapa) { + s->scapa *= 2; + s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa); } s->irep->syms[s->irep->slen] = sym; return s->irep->slen++; @@ -608,8 +657,12 @@ node_len(node *tree) return n; } +#define nint(x) ((int)(intptr_t)(x)) +#define nchar(x) ((char)(intptr_t)(x)) #define nsym(x) ((mrb_sym)(intptr_t)(x)) + #define lv_name(lv) nsym((lv)->car) + static int lv_idx(codegen_scope *s, mrb_sym id) { @@ -631,7 +684,6 @@ for_body(codegen_scope *s, node *tree) int idx; struct loopinfo *lp; node *n2; - mrb_code c; /* generate receiver */ codegen(s, tree->cdr->car, VAL); @@ -645,7 +697,7 @@ for_body(codegen_scope *s, node *tree) /* generate loop variable */ n2 = tree->car; - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); + genop_W(s, OP_ENTER, 0x40000); if (n2->car && !n2->car->cdr && !n2->cdr) { gen_assignment(s, n2->car->car, 1, NOVAL); } @@ -659,25 +711,20 @@ for_body(codegen_scope *s, node *tree) /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } + gen_return(s, OP_RETURN, cursp()); loop_pop(s, NOVAL); scope_finish(s); s = prev; - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1); push();pop(); /* space for a block */ pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); + idx = new_sym(s, mrb_intern_lit(s->mrb, "each")); + genop_3(s, OP_SENDB, cursp(), idx, 0); } static int lambda_body(codegen_scope *s, node *tree, int blk) { - mrb_code c; codegen_scope *parent = s; s = scope_new(s->mrb, s, tree->car); if (s == NULL) { @@ -688,7 +735,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) if (blk) { struct loopinfo *lp = loop_push(s, LOOP_BLOCK); - lp->pc1 = new_label(s); + lp->pc0 = new_label(s); } tree = tree->cdr; if (tree->car) { @@ -696,70 +743,112 @@ lambda_body(codegen_scope *s, node *tree, int blk) int ma, oa, ra, pa, ka, kd, ba; int pos, i; node *n, *opt; + node *tail; + /* mandatory arguments */ ma = node_len(tree->car->car); n = tree->car->car; while (n) { n = n->cdr; } + tail = tree->car->cdr->cdr->cdr->cdr; + + /* optional arguments */ oa = node_len(tree->car->cdr->car); + /* rest argument? */ ra = tree->car->cdr->cdr->car ? 1 : 0; + /* mandatory arugments after rest argument */ pa = node_len(tree->car->cdr->cdr->cdr->car); - ka = kd = 0; - ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; - + /* keyword arguments */ + ka = tail? node_len(tail->cdr->car) : 0; + /* keyword dictionary? */ + kd = tail && tail->cdr->cdr->car? 1 : 0; + /* block argument? */ + ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { codegen_error(s, "too many formal arguments"); } - a = ((mrb_aspec)(ma & 0x1f) << 18) - | ((mrb_aspec)(oa & 0x1f) << 13) - | ((ra & 1) << 12) - | ((pa & 0x1f) << 7) - | ((ka & 0x1f) << 2) - | ((kd & 1)<< 1) - | (ba & 1); - s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ - | ((ra & 1) << 5) - | (pa & 0x1f); - genop(s, MKOP_Ax(OP_ENTER, a)); + a = MRB_ARGS_REQ(ma) + | MRB_ARGS_OPT(oa) + | (ra? MRB_ARGS_REST() : 0) + | MRB_ARGS_POST(pa) + | MRB_ARGS_KEY(ka, kd) + | (ba? MRB_ARGS_BLOCK() : 0); + s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */ + | ((ra & 0x1) << 6) + | ((pa & 0x1f) << 1) + | (kd & 0x1); + genop_W(s, OP_ENTER, a); + /* generate jump table for optional arguments initializer */ pos = new_label(s); for (i=0; i<oa; i++) { new_label(s); - genop(s, MKOP_sBx(OP_JMP, 0)); + genjmp(s, OP_JMP, 0); } if (oa > 0) { - genop(s, MKOP_sBx(OP_JMP, 0)); + genjmp(s, OP_JMP, 0); } opt = tree->car->cdr->car; i = 0; while (opt) { int idx; - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); codegen(s, opt->car->cdr, VAL); - idx = lv_idx(s, nsym(opt->car->car)); pop(); - genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); + idx = lv_idx(s, nsym(opt->car->car)); + gen_move(s, idx, cursp(), 0); i++; opt = opt->cdr; } if (oa > 0) { - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); + } + + if (tail) { + node *kwds = tail->cdr->car; + int kwrest = 0; + + if (tail->cdr->cdr->car) { + kwrest = 1; + } + mrb_assert(nint(tail->car) == NODE_ARGS_TAIL); + mrb_assert(node_len(tail) == 4); + + while (kwds) { + int jmpif_key_p, jmp_def_set = -1; + node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car; + mrb_sym kwd_sym = nsym(kwd->cdr->car); + + mrb_assert(nint(kwd->car) == NODE_KW_ARG); + + if (def_arg) { + genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym)); + jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0); + codegen(s, def_arg, VAL); + pop(); + gen_move(s, lv_idx(s, kwd_sym), cursp(), 0); + jmp_def_set = genjmp(s, OP_JMP, 0); + dispatch(s, jmpif_key_p); + } + genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); + if (jmp_def_set != -1) { + dispatch(s, jmp_def_set); + } + i++; + + kwds = kwds->cdr; + } + if (tail->cdr->car && !kwrest) { + genop_0(s, OP_KEYEND); + } } } codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { - if (s->nregs == 0) { - genop(s, MKOP_A(OP_LOADNIL, 0)); - genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - } + gen_return(s, OP_RETURN, cursp()); } if (blk) { loop_pop(s, NOVAL); @@ -773,24 +862,13 @@ scope_body(codegen_scope *s, node *tree, int val) { codegen_scope *scope = scope_new(s->mrb, s, tree->car); if (scope == NULL) { - raise_error(s, "unexpected scope"); + codegen_error(s, "unexpected scope"); } codegen(scope, tree->cdr, VAL); + gen_return(scope, OP_RETURN, scope->sp-1); if (!s->iseq) { - genop(scope, MKOP_A(OP_STOP, 0)); - } - else if (!val) { - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - if (scope->nregs == 0) { - genop(scope, MKOP_A(OP_LOADNIL, 0)); - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); - } + genop_0(scope, OP_STOP); } scope_finish(scope); if (!s->irep) { @@ -800,9 +878,6 @@ scope_body(codegen_scope *s, node *tree, int val) return s->irep->rlen - 1; } -#define nint(x) ((int)(intptr_t)(x)) -#define nchar(x) ((char)(intptr_t)(x)) - static mrb_bool nosplat(node *t) { @@ -854,15 +929,15 @@ gen_values(codegen_scope *s, node *t, int val, int extra) } else { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); codegen(s, t->car, VAL); pop(); pop(); if (is_splat) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } } t = t->cdr; @@ -871,10 +946,10 @@ gen_values(codegen_scope *s, node *t, int val, int extra) codegen(s, t->car, VAL); pop(); pop(); if (nint(t->car->car) == NODE_SPLAT) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } t = t->cdr; } @@ -905,16 +980,10 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) codegen(s, tree->car, VAL); /* receiver */ if (safe) { int recv = cursp()-1; - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - genop(s, MKOP_AB(OP_MOVE, cursp(), recv)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "==")); - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1)); - skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + gen_move(s, cursp(), recv, 0); + skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - idx = new_msym(s, sym); + idx = new_sym(s, sym); tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -923,14 +992,15 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) push(); } } - if (sp) { + if (sp) { /* last argument pushed (attr=) */ if (sendv) { + gen_move(s, cursp(), sp, 0); pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); + genop_1(s, OP_ARYPUSH, cursp()); push(); } else { - genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); + gen_move(s, cursp(), sp, 0); push(); n++; } @@ -939,9 +1009,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) noop = 1; codegen(s, tree->cdr, VAL); pop(); - } - else { - blk = cursp(); + blk = 1; } push();pop(); pop_n(n+1); @@ -950,39 +1018,38 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); + genop_2(s, OP_MUL, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); + genop_2(s, OP_DIV, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); + genop_2(s, OP_LT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); + genop_2(s, OP_LE, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); + genop_2(s, OP_GT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); + genop_2(s, OP_GE, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); + genop_2(s, OP_EQ, cursp(), idx); } else { - if (sendv) n = CALL_MAXARGS; - if (blk > 0) { /* no block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); + if (sendv) { + genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); + genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n); } } } @@ -1004,13 +1071,14 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) switch (type) { case NODE_GVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); + genop_2(s, OP_SETGV, sp, idx); break; case NODE_LVAR: idx = lv_idx(s, nsym(tree)); if (idx > 0) { if (idx != sp) { - genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); + gen_move(s, idx, sp, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } break; } @@ -1021,7 +1089,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); + genop_3(s, OP_SETUPVAR, sp, idx, lv); break; } lv++; @@ -1031,23 +1099,23 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) break; case NODE_IVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); + genop_2(s, OP_SETIV, sp, idx); break; case NODE_CVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); + genop_2(s, OP_SETCV, sp, idx); break; case NODE_CONST: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); + genop_2(s, OP_SETCONST, sp, idx); break; case NODE_COLON2: - idx = new_sym(s, nsym(tree->cdr)); - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); + gen_move(s, cursp(), sp, 0); push(); codegen(s, tree->car, VAL); pop_n(2); - genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); + idx = new_sym(s, nsym(tree->cdr)); + genop_2(s, OP_SETMCNST, sp, idx); break; case NODE_CALL: @@ -1057,7 +1125,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) type == NODE_SCALL); pop(); if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); + gen_move(s, cursp(), sp, 0); } break; @@ -1090,7 +1158,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) while (t) { int sp = cursp(); - genop(s, MKOP_ABC(OP_AREF, sp, rhs, n)); + genop_3(s, OP_AREF, sp, rhs, n); push(); gen_assignment(s, t->car, sp, NOVAL); pop(); @@ -1107,10 +1175,10 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) p = p->cdr; } } - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, val); push_n(post+1); pop_n(post+1); - genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); + genop_3(s, OP_APOST, cursp(), n, post); n = 1; if (t->car) { /* rest */ gen_assignment(s, t->car, cursp(), NOVAL); @@ -1124,19 +1192,19 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) } } if (val) { - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, 0); } } } static void -gen_send_intern(codegen_scope *s) +gen_intern(codegen_scope *s) { - push();pop(); /* space for a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); + genop_1(s, OP_INTERN, cursp()); push(); } + static void gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) { @@ -1159,25 +1227,25 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) j = 0; ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } break; } - if (j >= 2) { + while (j >= 2) { pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); - j = 1; + j--; } tree = tree->cdr; } if (j > 0) { ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } pop_n(i); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + genop_2(s, OP_ARRAY, cursp(), i); push(); } else { @@ -1196,7 +1264,7 @@ raise_error(codegen_scope *s, const char *msg) { int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); - genop(s, MKOP_ABx(OP_ERR, 1, idx)); + genop_1(s, OP_ERR, idx); } #ifndef MRB_WITHOUT_FLOAT @@ -1274,11 +1342,9 @@ static void gen_retval(codegen_scope *s, node *tree) { if (nint(tree->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0)); - push(); codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + pop(); + genop_1(s, OP_ARYDUP, cursp()); } else { codegen(s, tree, VAL); @@ -1294,7 +1360,7 @@ codegen(codegen_scope *s, node *tree, int val) if (!tree) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } return; @@ -1318,7 +1384,7 @@ codegen(codegen_scope *s, node *tree, int val) switch (nt) { case NODE_BEGIN: if (val && !tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } while (tree) { @@ -1329,18 +1395,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_RESCUE: { - int onerr, noexc, exend, pos1, pos2, tmp; + int noexc, exend, pos1, pos2, tmp; struct loopinfo *lp; if (tree->car == NULL) goto exit; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_ONERR, 0); codegen(s, tree->car, VAL); pop(); lp->type = LOOP_RESCUE; - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); - dispatch(s, onerr); + noexc = genjmp(s, OP_JMP, 0); + dispatch(s, lp->pc1); tree = tree->cdr; exend = 0; pos1 = 0; @@ -1348,7 +1414,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n2 = tree->car; int exc = cursp(); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); + genop_1(s, OP_EXCEPT, exc); push(); while (n2) { node *n3 = n2->car; @@ -1359,30 +1425,29 @@ codegen(codegen_scope *s, node *tree, int val) do { if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { codegen(s, n4->car, VAL); - genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); + gen_move(s, cursp(), exc, 0); push_n(2); pop_n(2); /* space for one arg and a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { if (n4) { codegen(s, n4->car, VAL); } else { - genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); + genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError"))); push(); } pop(); - genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1)); + genop_2(s, OP_RESCUE, exc, cursp()); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); pos2 = tmp; if (n4) { n4 = n4->cdr; } } while (n4); - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); pop(); @@ -1393,21 +1458,20 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, n3->cdr->cdr->car, val); if (val) pop(); } - distcheck(s, exend); - tmp = genop(s, MKOP_sBx(OP_JMP, exend)); + tmp = genjmp(s, OP_JMP, exend); exend = tmp; n2 = n2->cdr; push(); } if (pos1) { dispatch(s, pos1); - genop(s, MKOP_A(OP_RAISE, exc)); + genop_1(s, OP_RAISE, exc); } } pop(); tree = tree->cdr; dispatch(s, noexc); - genop(s, MKOP_A(OP_POPERR, 1)); + genop_1(s, OP_POPERR, 1); if (tree->car) { codegen(s, tree->car, val); } @@ -1424,15 +1488,13 @@ codegen(codegen_scope *s, node *tree, int val) (nint(tree->cdr->cdr->car) == NODE_BEGIN && tree->cdr->cdr->cdr)) { int idx; - int epush = s->pc; - genop(s, MKOP_Bx(OP_EPUSH, 0)); s->ensure_level++; - codegen(s, tree->car, val); idx = scope_body(s, tree->cdr, NOVAL); - s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); + genop_1(s, OP_EPUSH, idx); + codegen(s, tree->car, val); s->ensure_level--; - genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); + genop_1(s, OP_EPOP, 1); } else { /* empty ensure ignored */ codegen(s, tree->car, val); @@ -1443,7 +1505,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); + genop_2(s, OP_LAMBDA, cursp(), idx); push(); } break; @@ -1452,7 +1514,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), idx); push(); } break; @@ -1460,10 +1522,10 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_IF: { int pos1, pos2; - node *e = tree->cdr->cdr->car; + node *elsepart = tree->cdr->cdr->car; if (!tree->car) { - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } switch (nint(tree->car->car)) { @@ -1474,27 +1536,27 @@ codegen(codegen_scope *s, node *tree, int val) goto exit; case NODE_FALSE: case NODE_NIL: - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } codegen(s, tree->car, VAL); pop(); - pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); + pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr->car, val); - if (e) { + if (elsepart) { if (val) pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - codegen(s, e, val); + codegen(s, elsepart, val); dispatch(s, pos2); } else { if (val) { pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); dispatch(s, pos2); push(); } @@ -1511,7 +1573,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1523,7 +1585,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + pos = genjmp2(s, OP_JMPIF, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1533,14 +1595,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1550,14 +1612,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1586,43 +1648,40 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); if (head) { - genop(s, MKOP_AB(OP_MOVE, cursp(), head)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); + gen_move(s, cursp(), head, 0); + push(); push(); pop(); pop(); pop(); if (nint(n->car->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1); } } else { pop(); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL); pos2 = tmp; n = n->cdr; } if (tree->car->car) { - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); } codegen(s, tree->car->cdr, val); if (val) pop(); - distcheck(s, pos3); - tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); + tmp = genjmp(s, OP_JMP, pos3); pos3 = tmp; if (pos1) dispatch(s, pos1); tree = tree->cdr; } if (val) { int pos = cursp(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); if (pos3) dispatch_linked(s, pos3); if (head) pop(); if (cursp() != pos) { - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + gen_move(s, cursp(), pos, 0); } push(); } @@ -1654,7 +1713,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); + genop_1(s, OP_RANGE_INC, cursp()); push(); } break; @@ -1664,7 +1723,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); + genop_1(s, OP_RANGE_EXC, cursp()); push(); } break; @@ -1675,7 +1734,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1684,8 +1743,8 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1698,7 +1757,7 @@ codegen(codegen_scope *s, node *tree, int val) if (n >= 0) { if (val) { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); } } @@ -1709,21 +1768,47 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_HASH: + case NODE_KW_HASH: { int len = 0; mrb_bool update = FALSE; while (tree) { - codegen(s, tree->car->car, val); - codegen(s, tree->car->cdr, val); - len++; + if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) { + if (len > 0) { + pop_n(len*2); + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { + pop(); + genop_2(s, OP_HASHADD, cursp(), len); + } + push(); + } + codegen(s, tree->car->cdr, VAL); + if (len > 0) { + pop(); pop(); + genop_1(s, OP_HASHCAT, cursp()); + push(); + } + update = TRUE; + len = 0; + } + else { + codegen(s, tree->car->car, VAL); + codegen(s, tree->car->cdr, VAL); + len++; + } tree = tree->cdr; - if (val && len == 126) { + if (val && len == 255) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + genop_2(s, OP_HASHADD, cursp(), len); } push(); update = TRUE; @@ -1732,10 +1817,14 @@ codegen(codegen_scope *s, node *tree, int val) } if (val) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + if (len > 0) { + genop_2(s, OP_HASHADD, cursp(), len); + } } push(); } @@ -1776,7 +1865,7 @@ codegen(codegen_scope *s, node *tree, int val) n++; } else { - genop(s, MKOP_A(OP_LOADNIL, rhs+n)); + genop_1(s, OP_LOADNIL, rhs+n); gen_assignment(s, t->car, rhs+n, NOVAL); } t = t->cdr; @@ -1800,7 +1889,7 @@ codegen(codegen_scope *s, node *tree, int val) else { rn = len - post - n; } - genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); + genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); gen_assignment(s, t->car, cursp(), NOVAL); n += rn; } @@ -1815,7 +1904,7 @@ codegen(codegen_scope *s, node *tree, int val) } pop_n(len); if (val) { - genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); + genop_2(s, OP_ARRAY, rhs, len); push(); } } @@ -1843,17 +1932,17 @@ codegen(codegen_scope *s, node *tree, int val) int onerr, noexc, exc; struct loopinfo *lp; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + onerr = genjmp(s, OP_ONERR, 0); lp = loop_push(s, LOOP_BEGIN); lp->pc1 = onerr; exc = cursp(); codegen(s, tree->car, VAL); lp->type = LOOP_RESCUE; - genop(s, MKOP_A(OP_POPERR, 1)); - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + genop_1(s, OP_POPERR, 1); + noexc = genjmp(s, OP_JMP, 0); dispatch(s, onerr); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); - genop(s, MKOP_A(OP_LOADF, exc)); + genop_1(s, OP_EXCEPT, exc); + genop_1(s, OP_LOADF, exc); dispatch(s, noexc); loop_pop(s, NOVAL); } @@ -1867,7 +1956,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); } codegen(s, n->car, VAL); /* receiver */ - idx = new_msym(s, nsym(n->cdr->car)); + idx = new_sym(s, nsym(n->cdr->car)); base = cursp()-1; if (n->cdr->cdr->car) { nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); @@ -1881,12 +1970,12 @@ codegen(codegen_scope *s, node *tree, int val) } } /* copy receiver and arguments */ - genop(s, MKOP_AB(OP_MOVE, cursp(), base)); + gen_move(s, cursp(), base, 0); for (i=0; i<nargs; i++) { - genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1)); + gen_move(s, cursp()+i+1, base+i+1, 0); } push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + genop_3(s, OP_SEND, cursp(), idx, callargs); push(); } else { @@ -1900,30 +1989,30 @@ codegen(codegen_scope *s, node *tree, int val) pop(); if (val) { if (vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } - pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } else { - pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } codegen(s, tree->cdr->cdr->car, VAL); pop(); if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (nint(tree->car->car) == NODE_CALL) { if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } else { gen_assignment(s, tree->car, cursp(), val); @@ -1935,52 +2024,52 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - idx = new_msym(s, sym); + idx = new_sym(s, sym); if (len == 1 && name[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (len == 1 && name[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (len == 1 && name[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); + genop_2(s, OP_MUL, cursp(), idx); } else if (len == 1 && name[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); + genop_2(s, OP_DIV, cursp(), idx); } else if (len == 1 && name[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); + genop_2(s, OP_LT, cursp(), idx); } else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); + genop_2(s, OP_LE, cursp(), idx); } else if (len == 1 && name[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); + genop_2(s, OP_GT, cursp(), idx); } else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); + genop_2(s, OP_GE, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); + genop_3(s, OP_SEND, cursp(), idx, 1); } if (callargs < 0) { gen_assignment(s, tree->car, cursp(), val); } else { if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } } break; @@ -1997,7 +2086,7 @@ codegen(codegen_scope *s, node *tree, int val) s2 = s2->prev; if (!s2) break; } - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf)); push(); push(); /* ARGARY pushes two values */ pop(); pop(); if (tree) { @@ -2015,12 +2104,12 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); pop(); } pop_n(n+1); if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); + genop_2(s, OP_SUPER, cursp(), n); if (val) push(); } break; @@ -2037,14 +2126,14 @@ codegen(codegen_scope *s, node *tree, int val) if (!s2) break; } if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); push(); push(); pop(); /* ARGARY pushes two values */ if (tree && tree->cdr) { codegen(s, tree->cdr, VAL); pop(); } pop(); pop(); - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); + genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS); if (val) push(); } break; @@ -2054,13 +2143,13 @@ codegen(codegen_scope *s, node *tree, int val) gen_retval(s, tree); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } if (s->loop) { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); + gen_return(s, OP_RETURN_BLK, cursp()); } else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2087,9 +2176,9 @@ codegen(codegen_scope *s, node *tree, int val) } push();pop(); /* space for a block */ pop_n(n+1); - genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, 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)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n); if (val) push(); } break; @@ -2105,11 +2194,10 @@ codegen(codegen_scope *s, node *tree, int val) } else if (s->loop->type == LOOP_NORMAL) { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } codegen(s, tree, NOVAL); - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc0); } else { if (tree) { @@ -2117,9 +2205,9 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2130,10 +2218,9 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } - distcheck(s, s->loop->pc2 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc2); } if (val) push(); break; @@ -2160,13 +2247,12 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (s->ensure_level > lp->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level); } - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); + genjmp(s, OP_JMP, lp->pc0); } } if (val) push(); @@ -2178,7 +2264,8 @@ codegen(codegen_scope *s, node *tree, int val) int idx = lv_idx(s, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); + gen_move(s, cursp(), idx, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } else { int lv = 0; @@ -2187,7 +2274,7 @@ codegen(codegen_scope *s, node *tree, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv), VAL); + genop_3(s, OP_GETUPVAR, cursp(), idx, lv); break; } lv++; @@ -2199,29 +2286,29 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_GVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); + genop_2(s, OP_GETGV, cursp(), sym); + if (val) push(); } break; case NODE_IVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); - push(); + genop_2(s, OP_GETIV, cursp(), sym); + if (val) push(); } break; case NODE_CVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); - push(); + genop_2(s, OP_GETCV, cursp(), sym); + if (val) push(); } break; @@ -2229,15 +2316,13 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - if (val) { - push(); - } + genop_2(s, OP_GETCONST, cursp(), sym); + if (val) push(); } break; case NODE_DEFINED: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_BACK_REF: @@ -2249,7 +2334,7 @@ codegen(codegen_scope *s, node *tree, int val) buf[1] = nchar(tree); buf[2] = 0; sym = new_sym(s, mrb_intern_cstr(s->mrb, buf)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2262,7 +2347,7 @@ codegen(codegen_scope *s, node *tree, int val) str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree))); sym = new_sym(s, mrb_intern_str(mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2272,7 +2357,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BLOCK_ARG: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_INT: @@ -2280,7 +2365,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, FALSE, &overflow); @@ -2289,19 +2373,19 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else #endif { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i); + else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp()); + else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i); else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); } push(); } @@ -2314,7 +2398,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2332,7 +2416,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2343,7 +2427,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, TRUE, &overflow); @@ -2352,18 +2435,18 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else { #endif - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i >= -0xffff) { + genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); } else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); #ifndef MRB_WITHOUT_FLOAT } #endif @@ -2373,13 +2456,13 @@ codegen(codegen_scope *s, node *tree, int val) default: if (val) { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "-")); - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); + genop_1(s, OP_LOADI_0, cursp()); push(); codegen(s, tree, VAL); pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + genop_2(s, OP_SUB, cursp(), sym); } else { codegen(s, tree, NOVAL); @@ -2397,7 +2480,7 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); mrb_gc_arena_restore(s->mrb, ai); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); } break; @@ -2410,7 +2493,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n = tree; if (!n) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); break; } @@ -2419,7 +2502,7 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2450,7 +2533,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")); - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); codegen(s, tree->car, VAL); n = tree->cdr; @@ -2461,14 +2544,14 @@ codegen(codegen_scope *s, node *tree, int val) } codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } push(); /* for block */ pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2482,13 +2565,13 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); int sym; - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); push(); pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2504,24 +2587,24 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); int argc = 1; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); if (p2 || p3) { if (p2) { /* opt */ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } push(); argc++; if (p3) { /* enc */ off = new_lit(s, mrb_str_new(s->mrb, p3, 1)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } @@ -2529,7 +2612,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2544,15 +2627,15 @@ codegen(codegen_scope *s, node *tree, int val) int off; char *p; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); codegen(s, n->car, VAL); n = n->cdr; while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2561,29 +2644,29 @@ codegen(codegen_scope *s, node *tree, int val) p = (char*)n->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); codegen(s, tree->car, VAL); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); } if (n->cdr->car) { /* opt */ char *p2 = (char*)n->cdr->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } if (n->cdr->cdr) { /* enc */ char *p2 = (char*)n->cdr->cdr; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2603,7 +2686,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } break; @@ -2611,55 +2694,46 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DSYM: codegen(s, tree, val); if (val) { - gen_send_intern(s); + gen_intern(s); } break; case NODE_SELF: if (val) { - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); } break; case NODE_NIL: if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } break; case NODE_TRUE: if (val) { - genop(s, MKOP_A(OP_LOADT, cursp())); + genop_1(s, OP_LOADT, cursp()); push(); } break; case NODE_FALSE: if (val) { - genop(s, MKOP_A(OP_LOADF, cursp())); + genop_1(s, OP_LOADF, cursp()); push(); } break; case NODE_ALIAS: { - int a = new_msym(s, nsym(tree->car)); - int b = new_msym(s, nsym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); + int a = new_sym(s, nsym(tree->car)); + int b = new_sym(s, nsym(tree->cdr)); - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); - push(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); /* space for a block */ - pop_n(4); - genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); + genop_2(s, OP_ALIAS, a, b); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2667,41 +2741,15 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_UNDEF: { - int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); - int num = 0; node *t = tree; - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); while (t) { - int symbol; - if (num >= CALL_MAXARGS - 1) { - pop_n(num); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num)); - while (t) { - symbol = new_msym(s, nsym(t->car)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - t = t->cdr; - } - num = CALL_MAXARGS; - break; - } - symbol = new_msym(s, nsym(t->car)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - push(); + int symbol = new_sym(s, nsym(t->car)); + genop_1(s, OP_UNDEF, symbol); t = t->cdr; - num++; } - push();pop(); /* space for a block */ - pop(); - if (num < CALL_MAXARGS) { - pop_n(num); - } - genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2710,13 +2758,14 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_CLASS: { int idx; + node *body; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { @@ -2726,14 +2775,17 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr->car, VAL); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } pop(); pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); - idx = scope_body(s, tree->cdr->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_CLASS, cursp(), idx); + body = tree->cdr->cdr->car; + if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) { + idx = scope_body(s, body, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2745,21 +2797,24 @@ codegen(codegen_scope *s, node *tree, int val) int idx; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { codegen(s, tree->car->car, VAL); } pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_MODULE, cursp(), idx); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2772,9 +2827,12 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + genop_1(s, OP_SCLASS, cursp()); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2783,17 +2841,17 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DEF: { - int sym = new_msym(s, nsym(tree->car)); + int sym = new_sym(s, nsym(tree->car)); int idx = lambda_body(s, tree->cdr, 0); - genop(s, MKOP_A(OP_TCLASS, cursp())); + genop_1(s, OP_TCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); push(); pop(); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2802,18 +2860,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_SDEF: { node *recv = tree->car; - int sym = new_msym(s, nsym(tree->cdr->car)); + int sym = new_sym(s, nsym(tree->cdr->car)); int idx = lambda_body(s, tree->cdr->cdr, 0); codegen(s, recv, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + genop_1(s, OP_SCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2875,7 +2933,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); p->irep->plen = 0; - p->scapa = MAXMSYMLEN; + p->scapa = 256; p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); p->irep->slen = 0; @@ -2971,7 +3029,7 @@ loop_push(codegen_scope *s, enum looptype t) struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); p->type = t; - p->pc1 = p->pc2 = p->pc3 = 0; + p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0; p->prev = s->loop; p->ensure_level = s->ensure_level; p->acc = cursp(); @@ -3013,27 +3071,26 @@ loop_break(codegen_scope *s, node *tree) return; } if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (loop->type == LOOP_NORMAL) { int tmp; if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } if (tree) { - genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); + gen_move(s, loop->acc, cursp(), 0); } - distcheck(s, s->loop->pc3); - tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); + tmp = genjmp(s, OP_JMP, loop->pc3); loop->pc3 = tmp; } else { if (!tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); + gen_return(s, OP_BREAK, cursp()); } } } @@ -3042,7 +3099,7 @@ static void loop_pop(codegen_scope *s, int val) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } dispatch_linked(s, s->loop->pc3); s->loop = s->loop->prev; @@ -3107,3 +3164,56 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) mrb_irep_remove_lv(mrb, irep->reps[i]); } } + +#undef OPCODE +#define Z 1 +#define S 3 +#define W 4 +/* instruction sizes */ +uint8_t mrb_insn_size[] = { +#define B 2 +#define BB 3 +#define BBB 4 +#define BS 4 +#define SB 4 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +#undef BB +#undef BS +#undef SB +#undef BBB +}; +/* EXT1 instruction sizes */ +uint8_t mrb_insn_size1[] = { +#define B 3 +#define BB 4 +#define BBB 5 +#define BS 5 +#define SB 5 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +}; +/* EXT2 instruction sizes */ +uint8_t mrb_insn_size2[] = { +#define B 2 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef BB +#undef BBB +#undef BS +#undef SB +}; +/* EXT3 instruction sizes */ +#define BB 5 +#define BBB 6 +#define BS 4 +#define SB 5 +uint8_t mrb_insn_size3[] = { +#define OPCODE(_,x) x, +#include "mruby/ops.h" +}; diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h index 9636dd759..219bddab0 100644 --- a/mrbgems/mruby-compiler/core/node.h +++ b/mrbgems/mruby-compiler/core/node.h @@ -9,14 +9,11 @@ enum node_type { NODE_METHOD, - NODE_FBODY, - NODE_CFUNC, NODE_SCOPE, NODE_BLOCK, NODE_IF, NODE_CASE, NODE_WHEN, - NODE_OPT_N, NODE_WHILE, NODE_UNTIL, NODE_ITER, @@ -40,12 +37,12 @@ enum node_type { NODE_CALL, NODE_SCALL, NODE_FCALL, - NODE_VCALL, NODE_SUPER, NODE_ZSUPER, NODE_ARRAY, NODE_ZARRAY, NODE_HASH, + NODE_KW_HASH, NODE_RETURN, NODE_YIELD, NODE_LVAR, @@ -57,8 +54,6 @@ enum node_type { NODE_NTH_REF, NODE_BACK_REF, NODE_MATCH, - NODE_MATCH2, - NODE_MATCH3, NODE_INT, NODE_FLOAT, NODE_NEGATE, @@ -71,10 +66,10 @@ enum node_type { NODE_REGX, NODE_DREGX, NODE_DREGX_ONCE, - NODE_LIST, NODE_ARG, - NODE_ARGSCAT, - NODE_ARGSPUSH, + NODE_ARGS_TAIL, + NODE_KW_ARG, + NODE_KW_REST_ARGS, NODE_SPLAT, NODE_TO_ARY, NODE_SVALUE, @@ -88,26 +83,15 @@ enum node_type { NODE_SCLASS, NODE_COLON2, NODE_COLON3, - NODE_CREF, NODE_DOT2, NODE_DOT3, - NODE_FLIP2, - NODE_FLIP3, - NODE_ATTRSET, NODE_SELF, NODE_NIL, NODE_TRUE, NODE_FALSE, NODE_DEFINED, - NODE_NEWLINE, NODE_POSTEXE, - NODE_ALLOCA, - NODE_DMETHOD, - NODE_BMETHOD, - NODE_MEMO, - NODE_IFUNC, NODE_DSYM, - NODE_ATTRASGN, NODE_HEREDOC, NODE_LITERAL_DELIM, NODE_WORDS, diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 7f848b4df..5e6cda236 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a) return cons((node*)NODE_HASH, a); } +/* (:kw_hash (k . v) (k . v)...) */ +static node* +new_kw_hash(parser_state *p, node *a) +{ + return cons((node*)NODE_KW_HASH, a); +} + /* (:sym . a) */ static node* new_sym(parser_state *p, mrb_sym sym) @@ -671,23 +678,61 @@ new_arg(parser_state *p, mrb_sym sym) return cons((node*)NODE_ARG, nsym(sym)); } -/* (m o r m2 b) */ +/* (m o r m2 tail) */ /* m: (a b c) */ /* o: ((a . e1) (b . e2)) */ /* r: a */ /* m2: (a b c) */ /* b: a */ static node* -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail) { node *n; - n = cons(m2, nsym(blk)); + n = cons(m2, tail); n = cons(nsym(rest), n); n = cons(opt, n); return cons(m, n); } +/* (:args_tail keywords rest_keywords_sym block_sym) */ +static node* +new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk) +{ + node *k; + + /* allocate register for keywords hash */ + if (kws || kwrest) { + local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**")); + } + + /* allocate register for block */ + local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&")); + + // allocate register for keywords arguments + // order is for Proc#parameters + for (k = kws; k; k = k->cdr) { + if (!k->car->cdr->cdr->car) { // allocate required keywords + local_add_f(p, sym(k->car->cdr->car)); + } + } + for (k = kws; k; k = k->cdr) { + if (k->car->cdr->cdr->car) { // allocate keywords with default + local_add_f(p, sym(k->car->cdr->car)); + } + } + + return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk)); +} + +/* (:kw_arg kw_sym def_arg) */ +static node* +new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg) +{ + mrb_assert(kw); + return list3((node*)NODE_KW_ARG, nsym(kw), def_arg); +} + /* (:block_arg . a) */ static node* new_block_arg(parser_state *p, node *a) @@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p) %type <nd> heredoc words symbols %type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ +%type <nd> args_tail opt_args_tail f_kwarg f_kw f_kwrest +%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail +%type <id> f_label + %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ @@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p) %token tLBRACE /* { */ %token tLBRACE_ARG /* { */ %token tSTAR /* * */ +%token tDSTAR /* ** */ %token tAMPER /* & */ %token tLAMBDA /* -> */ %token tANDDOT /* &. */ @@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); } | '/' { $$ = intern_c('/'); } | '%' { $$ = intern_c('%'); } | tPOW { $$ = intern("**",2); } + | tDSTAR { $$ = intern("**",2); } | '!' { $$ = intern_c('!'); } | '~' { $$ = intern_c('~'); } | tUPLUS { $$ = intern("+@",2); } @@ -1944,11 +1995,11 @@ aref_args : none } | args comma assocs trailer { - $$ = push($1, new_hash(p, $3)); + $$ = push($1, new_kw_hash(p, $3)); } | assocs trailer { - $$ = cons(new_hash(p, $1), 0); + $$ = cons(new_kw_hash(p, $1), 0); NODE_LINENO($$, $1); } ; @@ -1984,12 +2035,12 @@ opt_call_args : none } | args comma assocs ',' { - $$ = cons(push($1, new_hash(p, $3)), 0); + $$ = cons(push($1, new_kw_hash(p, $3)), 0); NODE_LINENO($$, $1); } | assocs ',' { - $$ = cons(list1(new_hash(p, $1)), 0); + $$ = cons(list1(new_kw_hash(p, $1)), 0); NODE_LINENO($$, $1); } ; @@ -2007,12 +2058,12 @@ call_args : command } | assocs opt_block_arg { - $$ = cons(list1(new_hash(p, $1)), $2); + $$ = cons(list1(new_kw_hash(p, $1)), $2); NODE_LINENO($$, $1); } | args comma assocs opt_block_arg { - $$ = cons(push($1, new_hash(p, $3)), $4); + $$ = cons(push($1, new_kw_hash(p, $3)), $4); NODE_LINENO($$, $1); } | block_arg @@ -2451,23 +2502,51 @@ f_margs : f_marg_list } ; -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg +block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_block_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_block_args_tail : ',' block_args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_block_optarg opt_f_block_arg + | f_arg ',' f_block_optarg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } @@ -2475,39 +2554,39 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args(p, $1, 0, 0, 0, 0); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_block_optarg ',' f_rest_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_block_optarg opt_f_block_arg + | f_block_optarg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_block_optarg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | block_args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } @@ -3021,65 +3100,151 @@ f_arglist : '(' f_args rparen } ; -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg +f_label : tIDENTIFIER tLABEL_TAG + ; + +f_kw : f_label arg + { + void_expr_error(p, $2); + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kw : f_label primary_value + { + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kwarg : f_block_kw + { + $$ = list1($1); + } + | f_block_kwarg ',' f_block_kw + { + $$ = push($1, $3); + } + ; + +f_kwarg : f_kw + { + $$ = list1($1); + } + | f_kwarg ',' f_kw + { + $$ = push($1, $3); + } + ; + +kwrest_mark : tPOW + | tDSTAR + ; + +f_kwrest : kwrest_mark tIDENTIFIER + { + $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2)); + } + | kwrest_mark + { + $$ = cons((node*)NODE_KW_REST_ARGS, 0); + } + ; + +args_tail : f_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_args_tail : ',' args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_optarg opt_f_block_arg + | f_arg ',' f_optarg opt_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_optarg ',' f_rest_arg opt_f_block_arg + | f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_optarg opt_f_block_arg + | f_optarg opt_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_optarg ',' f_arg opt_f_block_arg + | f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } | /* none */ { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "&")); $$ = new_args(p, 0, 0, 0, 0, 0); } ; @@ -3189,7 +3354,7 @@ f_rest_arg : restarg_mark tIDENTIFIER } | restarg_mark { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "*")); $$ = -1; } ; @@ -3200,7 +3365,6 @@ blkarg_mark : '&' f_block_arg : blkarg_mark tIDENTIFIER { - local_add_f(p, $2); $$ = $2; } ; @@ -3211,7 +3375,6 @@ opt_f_block_arg : ',' f_block_arg } | none { - local_add_f(p, 0); $$ = 0; } ; @@ -3285,6 +3448,11 @@ assoc : arg tASSOC arg $$ = cons(new_sym(p, new_strsym(p, $1)), $3); } } + | tDSTAR arg + { + void_expr_error(p, $2); + $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2); + } ; operation : tIDENTIFIER @@ -3450,13 +3618,13 @@ backref_error(parser_state *p, node *n) { int c; - c = (int)(intptr_t)n->car; + c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%c", intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -3469,7 +3637,7 @@ void_expr_error(parser_state *p, node *n) int c; if (n == NULL) return; - c = (int)(intptr_t)n->car; + c = intn(n->car); switch (c) { case NODE_BREAK: case NODE_RETURN: @@ -3508,7 +3676,7 @@ nextc(parser_state *p) if (p->pb) { node *tmp; - c = (int)(intptr_t)p->pb->car; + c = intn(p->pb->car); tmp = p->pb; p->pb = p->pb->cdr; cons_free(tmp); @@ -3557,7 +3725,7 @@ pushback(parser_state *p, int c) if (c >= 0) { p->column--; } - p->pb = cons((node*)(intptr_t)c, p->pb); + p->pb = cons(nint(c), p->pb); } static void @@ -3582,7 +3750,7 @@ peekc_n(parser_state *p, int n) c0 = nextc(p); if (c0 == -1) return c0; /* do not skip partial EOF */ if (c0 >= 0) --p->column; - list = push(list, (node*)(intptr_t)c0); + list = push(list, nint(c0)); } while(n--); if (p->pb) { p->pb = append((node*)list, p->pb); @@ -4019,11 +4187,11 @@ parse_string(parser_state *p) } else if (c == beg) { nest_level++; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == end) { nest_level--; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == '\\') { c = nextc(p); @@ -4365,7 +4533,16 @@ parser_yylex(parser_state *p) return tOP_ASGN; } pushback(p, c); - c = tPOW; + if (IS_SPCARG(c)) { + yywarning(p, "`**' interpreted as argument prefix"); + c = tDSTAR; + } + else if (IS_BEG()) { + c = tDSTAR; + } + else { + c = tPOW; /* "**", "argument prefix" */ + } } else { if (c == '=') { @@ -5534,6 +5711,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt) } p->capture_errors = cxt->capture_errors; p->no_optimize = cxt->no_optimize; + p->on_eval = cxt->on_eval; if (cxt->partial_hook) { p->cxt = cxt; } @@ -5546,7 +5724,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) int i = 0; if (!cxt) return; - if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; + if (intn(p->tree->car) != NODE_SCOPE) return; n0 = n = p->tree->cdr->car; while (n) { i++; @@ -5896,6 +6074,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset) } } +static void +dump_args(mrb_state *mrb, node *n, int offset) +{ + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=\n", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, offset+3); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + + n = n->cdr; + if (n) { + mrb_assert(intn(n->car) == NODE_ARGS_TAIL); + mrb_parser_dump(mrb, n, offset); + } +} + #endif void @@ -5907,7 +6127,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) if (!tree) return; again: dump_prefix(tree, offset); - nodetype = (int)(intptr_t)tree->car; + nodetype = intn(tree->car); tree = tree->cdr; switch (nodetype) { case NODE_BEGIN: @@ -5967,7 +6187,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_LAMBDA: - printf("NODE_BLOCK:\n"); + printf("NODE_LAMBDA:\n"); + dump_prefix(tree, offset); goto block; case NODE_BLOCK: @@ -5975,43 +6196,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_BLOCK:\n"); tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset+1); } dump_prefix(tree, offset+1); printf("body:\n"); @@ -6163,7 +6348,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_prefix(tree, offset+1); printf("method='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); + intn(tree->cdr->car)); tree = tree->cdr->cdr->car; if (tree) { dump_prefix(tree, offset+1); @@ -6218,6 +6403,19 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } break; + case NODE_KW_HASH: + printf("NODE_KW_HASH:\n"); + while (tree) { + dump_prefix(tree, offset+1); + printf("key:\n"); + mrb_parser_dump(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("value:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + case NODE_SPLAT: printf("NODE_SPLAT:\n"); mrb_parser_dump(mrb, tree, offset+1); @@ -6280,7 +6478,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(tree, offset+1); - printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); + printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), intn(tree->car)); tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); break; @@ -6362,11 +6560,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_BACK_REF: - printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); + printf("NODE_BACK_REF: $%c\n", intn(tree)); break; case NODE_NTH_REF: - printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree); + printf("NODE_NTH_REF: $%d\n", intn(tree)); break; case NODE_ARG: @@ -6379,7 +6577,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_INT: - printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); + printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car)); break; case NODE_FLOAT: @@ -6392,7 +6590,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_STR: - printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DSTR: @@ -6401,7 +6599,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_XSTR: - printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DXSTR: @@ -6430,7 +6628,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_SYM: printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)), - (int)(intptr_t)tree); + intn(tree)); break; case NODE_SELF: @@ -6546,43 +6744,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset); } mrb_parser_dump(mrb, tree->cdr->car, offset+1); break; @@ -6595,44 +6757,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); tree = tree->cdr->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } + dump_args(mrb, tree->car, offset+1); } tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); @@ -6648,6 +6773,37 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; + case NODE_ARGS_TAIL: + printf("NODE_ARGS_TAIL:\n"); + { + node *kws = tree->car; + + while (kws) { + mrb_parser_dump(mrb, kws->car, offset+1); + kws = kws->cdr; + } + } + tree = tree->cdr; + if (tree->car) { + mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS); + mrb_parser_dump(mrb, tree->car, offset+1); + } + tree = tree->cdr; + if (tree->car) { + dump_prefix(tree, offset+1); + printf("block='%s'\n", mrb_sym2name(mrb, sym(tree->car))); + } + break; + + case NODE_KW_ARG: + printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car))); + mrb_parser_dump(mrb, tree->cdr->car, offset + 1); + break; + + case NODE_KW_REST_ARGS: + printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree))); + break; + default: printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); break; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 47d029a98..b9c87f6d1 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -44,7 +44,7 @@ search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom) return NULL; } -static inline mrb_code +static uint16_t search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) { mrb_irep *virep; @@ -57,7 +57,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) } for (pos = 0; pos < virep->nlocals - 1; pos++) { if (vsym == virep->lv[pos].name) { - return (MKARG_B(pos + 1) | MKARG_C(level + bnest)); + return (pos+1)<<8 | (level+bnest); } } } @@ -71,8 +71,8 @@ irep_argc(mrb_irep *irep) mrb_code c; c = irep->iseq[0]; - if (GET_OPCODE(c) == OP_ENTER) { - mrb_aspec ax = GETARG_Ax(c); + if (c == OP_ENTER) { + mrb_aspec ax = PEEK_W(irep->iseq+1); /* 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; } @@ -88,95 +88,132 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) return TRUE; } +extern uint8_t mrb_insn_size[]; +extern uint8_t mrb_insn_size1[]; +extern uint8_t mrb_insn_size2[]; +extern uint8_t mrb_insn_size3[]; + static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) { int i; - mrb_code c; + uint32_t a; + uint16_t b; + uint8_t c; + mrb_code insn; int argc = irep_argc(irep); - for (i = 0; i < irep->ilen; i++) { - c = irep->iseq[i]; - switch(GET_OPCODE(c)){ + for (i = 0; i < irep->ilen; ) { + insn = irep->iseq[i]; + switch(insn){ case OP_EPUSH: - patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); + b = PEEK_S(irep->iseq+i+1); + patch_irep(mrb, irep->reps[b], 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, top); - } - } + case OP_BLOCK: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + patch_irep(mrb, irep->reps[b], bnest + 1, top); break; case OP_SEND: - if (GETARG_C(c) != 0) { + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); + if (c != 0) { break; } else { - mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); + uint16_t arg = search_variable(mrb, irep->syms[b], bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_MOVE: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); /* src part */ - if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = insn = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } /* dst part */ - if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; + irep->iseq[i] = insn = OP_SETUPVAR; + irep->iseq[i+1] = (mrb_code)b; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_GETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = 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 (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; case OP_SETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = 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 (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_SETUPVAR; + irep->iseq[i+1] = a; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; - case OP_STOP: - if (mrb->c->ci->acc >= 0) { - irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); - } - break; + case OP_EXT1: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size1[insn]; + continue; + case OP_EXT2: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size2[insn]; + continue; + case OP_EXT3: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size3[insn]; + continue; } + i+=mrb_insn_size[insn]; } } @@ -203,6 +240,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; cxt->no_optimize = TRUE; + cxt->on_eval = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index e445b34c8..600567cac 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -387,7 +387,7 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1)); mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, unbound_method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, unbound_method, "eql?", "=="); mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE()); @@ -396,11 +396,11 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_undef_class_method(mrb, method, "new"); mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, method, "eql?", "=="); mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY()); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "[]"), mrb_intern_lit(mrb, "call")); + mrb_define_alias(mrb, method, "[]", "call"); mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index 3887091d3..b31dee04c 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self) hash = mrb_hash_new(mrb); } - if (!mrb_test(mrb_hash_empty_p(mrb, hash))) { + if (!mrb_hash_empty_p(mrb, hash)) { mrb_hash_clear(mrb, hash); } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index b13606f5f..9ce6c1831 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -109,6 +109,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) mrb_aspec aspec; mrb_value sname, parameters; int i, j; + int max = -1; if (MRB_PROC_CFUNC_P(proc)) { // TODO cfunc aspec is not implemented yet @@ -120,7 +121,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) if (!irep->lv) { return mrb_ary_new(mrb); } - if (GET_OPCODE(*irep->iseq) != OP_ENTER) { + if (*irep->iseq != OP_ENTER) { return mrb_ary_new(mrb); } @@ -129,7 +130,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters_list[3].name = "opt"; } - aspec = GETARG_Ax(*irep->iseq); + aspec = PEEK_W(irep->iseq+1); parameters_list[0].size = MRB_ASPEC_REQ(aspec); parameters_list[1].size = MRB_ASPEC_OPT(aspec); parameters_list[2].size = MRB_ASPEC_REST(aspec); @@ -138,14 +139,25 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters = mrb_ary_new_capa(mrb, irep->nlocals-1); + max = irep->nlocals-1; for (i = 0, p = parameters_list; p->name; p++) { if (p->size <= 0) continue; sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); for (j = 0; j < p->size; i++, j++) { - mrb_value a = mrb_ary_new(mrb); + mrb_value a; + + a = mrb_ary_new(mrb); mrb_ary_push(mrb, a, sname); - if (irep->lv[i].name) { - mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); + if (i < max && irep->lv[i].name) { + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_ary_push(mrb, a, mrb_symbol_value(sym)); + break; + } } mrb_ary_push(mrb, parameters, a); } diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 4cab49094..142d449f4 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -627,8 +627,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); - 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_alias(mrb, s, "next", "succ"); + mrb_define_alias(mrb, s, "next!", "succ!"); mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1)); diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 7e1db905f..96029a230 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -341,11 +341,6 @@ class Hash } self.replace(h) end - - def __update(h) - h.each_key{|k| self[k] = h[k]} - self - end end ## diff --git a/src/class.c b/src/class.c index d3a1e2fb2..37bc39c75 100644 --- a/src/class.c +++ b/src/class.c @@ -1953,8 +1953,8 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static void -undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +void +mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); @@ -1970,7 +1970,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - undef_method(mrb, c, mrb_intern_cstr(mrb, name)); + mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1988,7 +1988,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, to_sym(mrb, *argv)); + mrb_undef_method_id(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); diff --git a/src/codedump.c b/src/codedump.c index d79a65a70..80802778f 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -6,451 +6,521 @@ #include <mruby/proc.h> #ifndef MRB_DISABLE_STDIO -static int -print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +static void +print_r(mrb_state *mrb, mrb_irep *irep, size_t n) { size_t i; - if (n == 0) return 0; + if (n == 0) return; for (i=0; i+1<irep->nlocals; i++) { if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; - if (pre) printf(" "); - printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); - return 1; + printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); } } - return 0; } -#define RA 1 -#define RB 2 -#define RAB 3 - static void -print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a) { - int pre = 0; - - if (!irep->lv - || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) - && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { + if (!irep->lv || a >= irep->nlocals || a == 0) { printf("\n"); return; } - printf("\t; "); - if (r & RA) { - pre = print_r(mrb, irep, GETARG_A(c), 0); - } - if (r & RB) { - print_r(mrb, irep, GETARG_B(c), pre); + printf("\t;"); + print_r(mrb, irep, a); + printf("\n"); +} + +static void +print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) +{ + if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) { + printf("\n"); + return; } + printf("\t;"); + if (a > 0) print_r(mrb, irep, a); + if (b > 0) print_r(mrb, irep, b); printf("\n"); } #endif static void +print_header(mrb_irep *irep, ptrdiff_t i) +{ + int32_t line; + + line = mrb_debug_get_line(irep, i); + if (line < 0) { + printf(" "); + } + else { + printf("%5d ", line); + } + + printf("%03d ", (int)i); +} + +#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn + +static void codedump(mrb_state *mrb, mrb_irep *irep) { #ifndef MRB_DISABLE_STDIO - int i; int ai; - mrb_code c; + mrb_code *pc, *pcend; + mrb_code ins; const char *file = NULL, *next_file; - int32_t line; if (!irep) return; printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); - for (i = 0; i < (int)irep->ilen; i++) { + if (irep->lv) { + int i; + + printf("local variable names:\n"); + for (i = 1; i < irep->nlocals; ++i) { + char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name); + printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : ""); + } + } + + pc = irep->iseq; + pcend = pc + irep->ilen; + while (pc < pcend) { + ptrdiff_t i; + uint32_t a; + uint16_t b; + uint8_t c; + ai = mrb_gc_arena_save(mrb); + i = pc - irep->iseq; next_file = mrb_debug_get_filename(irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - line = mrb_debug_get_line(irep, i); - if (line < 0) { - printf(" "); - } - else { - printf("%5d ", line); - } - - printf("%03d ", i); - c = irep->iseq[i]; - switch (GET_OPCODE(c)) { - case OP_NOP: + print_header(irep, i); + ins = READ_B(); + switch (ins) { + CASE(OP_NOP, Z): printf("OP_NOP\n"); break; - case OP_MOVE: - printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_MOVE, BB): + printf("OP_MOVE\tR%d\tR%d\t", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_LOADL: + CASE(OP_LOADL, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); - break; - case OP_LOADI: - printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSYM: - printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADNIL: - printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSELF: - printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADT: - printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADF: - printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETGLOBAL: - printf("OP_SETGLOBAL\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCONST: - printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCONST: - printf("OP_SETCONST\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETMCNST: - printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RAB); - break; - case OP_SETMCNST: - printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETIV: - printf("OP_GETIV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETIV: - printf("OP_SETIV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETUPVAR: - printf("OP_GETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_SETUPVAR: - printf("OP_SETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCV: - printf("OP_GETCV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCV: - printf("OP_SETCV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_JMP: - printf("OP_JMP\t%03d (%d)\n", i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPIF: - printf("OP_JMPIF\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPNOT: - printf("OP_JMPNOT\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_SEND: - printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SENDB: - printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_CALL: - printf("OP_CALL\tR%d\n", GETARG_A(c)); - break; - case OP_TAILCALL: - printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUPER: - printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), - GETARG_C(c)); - break; - case OP_ARGARY: - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI, BB): + printf("OP_LOADI\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADINEG, BB): + printf("OP_LOADI\tR%d\t-%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI__1, B): + printf("OP_LOADI__1\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI_0, B): goto L_LOADI; + CASE(OP_LOADI_1, B): goto L_LOADI; + CASE(OP_LOADI_2, B): goto L_LOADI; + CASE(OP_LOADI_3, B): goto L_LOADI; + CASE(OP_LOADI_4, B): goto L_LOADI; + CASE(OP_LOADI_5, B): goto L_LOADI; + CASE(OP_LOADI_6, B): goto L_LOADI; + CASE(OP_LOADI_7, B): + L_LOADI: + printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a); + print_lv_a(mrb, irep, a); break; - - case OP_ENTER: + CASE(OP_LOADSYM, BB): + printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADNIL, B): + printf("OP_LOADNIL\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADSELF, B): + printf("OP_LOADSELF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADT, B): + printf("OP_LOADT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADF, B): + printf("OP_LOADF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETGV, BB): + printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETGV, BB): + printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETSV, BB): + printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETSV, BB): + printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCONST, BB): + printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCONST, BB): + printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETMCNST, BB): + printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETMCNST, BB): + printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETIV, BB): + printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETIV, BB): + printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETUPVAR, BBB): + printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETUPVAR, BBB): + printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCV, BB): + printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCV, BB): + printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMP, S): + printf("OP_JMP\t\t%03d\n", a); + break; + CASE(OP_JMPIF, BS): + printf("OP_JMPIF\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNOT, BS): + printf("OP_JMPNOT\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNIL, BS): + printf("OP_JMPNIL\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SENDV, BB): + printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SENDVB, BB): + printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SEND, BBB): + printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SENDB, BBB): + printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_CALL, Z): + printf("OP_CALL\n"); + break; + CASE(OP_SUPER, BB): + printf("OP_SUPER\tR%d\t%d\n", a, b); + break; + CASE(OP_ARGARY, BS): + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (GETARG_Ax(c)>>18)&0x1f, - (GETARG_Ax(c)>>13)&0x1f, - (GETARG_Ax(c)>>12)&0x1, - (GETARG_Ax(c)>>7)&0x1f, - (GETARG_Ax(c)>>2)&0x1f, - (GETARG_Ax(c)>>1)&0x1, - GETARG_Ax(c) & 0x1); - break; - case OP_RETURN: - printf("OP_RETURN\tR%d", GETARG_A(c)); - switch (GETARG_B(c)) { - case OP_R_NORMAL: - printf("\tnormal\t"); break; - case OP_R_RETURN: - printf("\treturn\t"); break; - case OP_R_BREAK: - printf("\tbreak\t"); break; - default: - printf("\tbroken\t"); break; - } - print_lv(mrb, irep, c, RA); + (a>>18)&0x1f, + (a>>13)&0x1f, + (a>>12)&0x1, + (a>>7)&0x1f, + (a>>2)&0x1f, + (a>>1)&0x1, + a & 0x1); break; - case OP_BLKPUSH: - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + CASE(OP_KEY_P, BB): + printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - - case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1); - switch (GETARG_c(c)) { - case OP_L_METHOD: - printf("method"); break; - case OP_L_BLOCK: - printf("block"); break; - case OP_L_LAMBDA: - printf("lambda"); break; - } - print_lv(mrb, irep, c, RA); + CASE(OP_KEYEND, Z): + printf("OP_KEYEND\n"); break; - case OP_RANGE: - printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_KARG, BB): + printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_METHOD: - printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_RETURN, B): + printf("OP_RETURN\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_ADD: - printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_ADDI: - printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUB: - printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUBI: - printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_MUL: - printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_DIV: - printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LT: - printf("OP_LT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LE: - printf("OP_LE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GT: - printf("OP_GT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GE: - printf("OP_GE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_EQ: - printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); + CASE(OP_RETURN_BLK, B): + printf("OP_RETURN_BLK\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_STOP: - printf("OP_STOP\n"); + CASE(OP_BREAK, B): + printf("OP_BREAK\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - - case OP_ARRAY: - printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_BLKPUSH, BS): + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LAMBDA, BB): + printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_BLOCK, BB): + printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_METHOD, BB): + printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_RANGE_INC, B): + printf("OP_RANGE_INC\tR%d\n", a); + break; + CASE(OP_RANGE_EXC, B): + printf("OP_RANGE_EXC\tR%d\n", a); + break; + CASE(OP_DEF, BB): + printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_UNDEF, B): + printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); + break; + CASE(OP_ALIAS, BB): + printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADD, BB): + printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADDI, BBB): + printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SUB, BB): + printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SUBI, BBB): + printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_MUL, BB): + printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_DIV, BB): + printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LT, BB): + printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LE, BB): + printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GT, BB): + printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GE, BB): + printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_EQ, BB): + printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); break; - case OP_ARYCAT: - printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY, BB): + printf("OP_ARRAY\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_ARYPUSH: - printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY2, BBB): + printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); + print_lv_ab(mrb, irep, a, b); break; - case OP_AREF: - printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYCAT, B): + printf("OP_ARYCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_APOST: - printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_ARYPUSH, B): + printf("OP_ARYPUSH\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRING: + CASE(OP_ARYDUP, B): + printf("OP_ARYDUP\tR%d\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_AREF, BBB): + printf("OP_AREF\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_ASET, BBB): + printf("OP_ASET\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_APOST, BBB): + printf("OP_APOST\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_INTERN, B): + printf("OP_INTERN\tR%d", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRING, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRCAT, B): + printf("OP_STRCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRCAT: - printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASH, BB): + printf("OP_HASH\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_HASH: - printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASHADD, BB): + printf("OP_HASHADD\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_HASHCAT, B): + printf("OP_HASHCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_OCLASS: - printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_OCLASS, B): + printf("OP_OCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_CLASS: - printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_CLASS, BB): + printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_MODULE: - printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_MODULE, BB): + printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); - print_lv(mrb, irep, c, RA); + CASE(OP_EXEC, BB): + printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]); + print_lv_a(mrb, irep, a); break; - case OP_SCLASS: - printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_SCLASS, B): + printf("OP_SCLASS\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_TCLASS: - printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_TCLASS, B): + printf("OP_TCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_ERR: + CASE(OP_ERR, B): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[a]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; - case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + CASE(OP_EPUSH, B): + printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]); break; - case OP_ONERR: - printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + CASE(OP_ONERR, S): + printf("OP_ONERR\t%03d\n", a); break; - case OP_RESCUE: - { - int a = GETARG_A(c); - int b = GETARG_B(c); - int cnt = GETARG_C(c); - - if (b == 0) { - printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RA); - break; - } - else { - printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RAB); - break; - } - } + CASE(OP_EXCEPT, B): + printf("OP_EXCEPT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_RESCUE, BB): + printf("OP_RESCUE\tR%d\tR%d", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_RAISE: - printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_RAISE, B): + printf("OP_RAISE\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_POPERR: - printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); + CASE(OP_POPERR, B): + printf("OP_POPERR\t%d\t\t\n", a); break; - case OP_EPOP: - printf("OP_EPOP\t%d\n", GETARG_A(c)); + CASE(OP_EPOP, B): + printf("OP_EPOP\t%d\n", a); break; + CASE(OP_DEBUG, BBB): + printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); + break; + + CASE(OP_STOP, Z): + printf("OP_STOP\n"); + break; + + CASE(OP_EXT1, Z): + ins = READ_B(); + printf("OP_EXT1\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT2, Z): + ins = READ_B(); + printf("OP_EXT2\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT3, Z): + ins = READ_B(); + printf("OP_EXT3\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: - printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), - GETARG_A(c), GETARG_B(c), GETARG_C(c)); + printf("OP_unknown (0x%x)\n", ins); break; } mrb_gc_arena_restore(mrb, ai); diff --git a/src/hash.c b/src/hash.c index db9d1d9c8..122f5b5d5 100644 --- a/src/hash.c +++ b/src/hash.c @@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +void +mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) +{ + khash_t(ht) *orig_h; + khiter_t k; + int nosym = FALSE; + + orig_h = RHASH_TBL(self); + if (!orig_h || kh_size(orig_h) == 0) return; + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + mrb_value key = kh_key(orig_h, k); + + if (!mrb_symbol_p(key)) nosym = TRUE; + } + } + if (nosym) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } +} + +MRB_API mrb_value +mrb_hash_dup(mrb_state *mrb, mrb_value self) +{ + struct RHash* copy; + khash_t(ht) *orig_h; + + orig_h = RHASH_TBL(self); + copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + copy->ht = kh_init(ht, mrb); + + if (orig_h && kh_size(orig_h) > 0) { + int ai = mrb_gc_arena_save(mrb); + khash_t(ht) *copy_h = copy->ht; + khiter_t k, copy_k; + + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); + mrb_gc_arena_restore(mrb, ai); + kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; + kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; + } + } + } + return mrb_obj_value(copy); +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -716,13 +764,21 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_value +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { khash_t(ht) *h = RHASH_TBL(self); - if (h) return mrb_bool_value(kh_size(h) == 0); - return mrb_true_value(); + if (h) return kh_size(h) == 0; + return TRUE; +} + +static mrb_value +mrb_hash_empty_m(mrb_state *mrb, mrb_value self) +{ + if (mrb_hash_empty_p(mrb, self)) + return mrb_true_value(); + return mrb_false_value(); } /* 15.2.13.4.29 (x)*/ @@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) * */ -static mrb_value -mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +MRB_API mrb_bool +mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - mrb_value key; khash_t(ht) *h; khiter_t k; - mrb_get_args(mrb, "o", &key); - h = RHASH_TBL(hash); if (h) { k = kh_get(ht, mrb, h, key); - return mrb_bool_value(k != kh_end(h)); + return k != kh_end(h); } - return mrb_false_value(); + return FALSE; +} + +static mrb_value +mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +{ + mrb_value key; + mrb_bool key_p; + + mrb_get_args(mrb, "o", &key); + key_p = mrb_hash_key_p(mrb, hash, key); + return mrb_bool_value(key_p); } /* 15.2.13.4.14 */ @@ -887,6 +951,39 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) return mrb_false_value(); } +MRB_API void +mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) +{ + khash_t(ht) *h1; + khash_t(ht) *h2; + khiter_t k; + + mrb_hash_modify(mrb, hash1); + hash2 = mrb_check_hash_type(mrb, hash2); + h1 = RHASH_TBL(hash1); + h2 = RHASH_TBL(hash2); + + if (!h1) { + RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); + return; + } + for (k = kh_begin(h2); k != kh_end(h2); k++) { + khiter_t k1; + int r; + + if (!kh_exist(h2, k)) continue; + k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r); + kh_value(h1, k1).v = kh_value(h2,k).v; + if (r != 0) { + /* expand */ + kh_key(h1, k1) = kh_key(h2, k); + kh_value(h1, k1).n = kh_size(h1)-1; + } + } + mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); + return; +} + void mrb_init_hash(mrb_state *mrb) { @@ -904,7 +1001,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */ - mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ + mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */ mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */ mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */ diff --git a/src/kernel.c b/src/kernel.c index 50ad50f00..fed64e9b0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (!irep->lv) break; for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } } } if (!MRB_PROC_ENV_P(proc)) break; @@ -1266,5 +1274,5 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); + mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/src/load.c b/src/load.c index ddf3cdfbf..54b50b14d 100644 --- a/src/load.c +++ b/src/load.c @@ -68,7 +68,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag /* Binary Data Section */ /* ISEQ BLOCK */ - irep->ilen = (size_t)bin_to_uint32(src); + irep->ilen = (uint16_t)bin_to_uint32(src); src += sizeof(uint32_t); src += skip_padding(src); @@ -79,7 +79,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag if ((flags & FLAG_SRC_MALLOC) == 0 && (flags & FLAG_BYTEORDER_NATIVE)) { irep->iseq = (mrb_code*)src; - src += sizeof(uint32_t) * irep->ilen; + src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; } else { @@ -157,7 +157,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } /* SYMS BLOCK */ - irep->slen = (size_t)bin_to_uint32(src); /* syms length */ + irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */ src += sizeof(uint32_t); if (irep->slen > 0) { if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { diff --git a/src/proc.c b/src/proc.c index c6e9be433..05b897480 100644 --- a/src/proc.c +++ b/src/proc.c @@ -10,7 +10,7 @@ #include <mruby/opcode.h> static mrb_code call_iseq[] = { - MKOP_A(OP_CALL, 0), + OP_CALL, }; struct RProc* @@ -223,7 +223,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); struct mrb_irep *irep; - mrb_code *iseq; + mrb_code *pc; mrb_aspec aspec; int ma, op, ra, pa, arity; @@ -237,13 +237,13 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(0); } - iseq = irep->iseq; + pc = irep->iseq; /* arity is depend on OP_ENTER */ - if (GET_OPCODE(*iseq) != OP_ENTER) { + if (*pc != OP_ENTER) { return mrb_fixnum_value(0); } - aspec = GETARG_Ax(*iseq); + aspec = PEEK_W(pc+1); ma = MRB_ASPEC_REQ(aspec); op = MRB_ASPEC_OPT(aspec); ra = MRB_ASPEC_REST(aspec); @@ -218,7 +218,7 @@ stack_extend_alloc(mrb_state *mrb, int room) } MRB_API void -mrb_stack_extend(mrb_state *mrb, int room) +mrb_stack_extend(mrb_state *mrb, mrb_int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); @@ -333,7 +333,7 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - int i = --c->eidx; + uint8_t i = --c->eidx; int nregs; if (i<0) return; @@ -934,18 +934,18 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) { -#define CASE(op) case op: -#define NEXT pc++; break -#define JUMP break +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define NEXT break +#define JUMP NEXT #define END_DISPATCH }} #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(op) L_ ## op: -#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] -#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] +#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] +#define JUMP NEXT #define END_DISPATCH @@ -981,6 +981,19 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac return result; } +static mrb_bool +check_target_class(mrb_state *mrb) +{ + if (!mrb->c->ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); + mrb_exc_set(mrb, exc); + return FALSE; + } + return TRUE; +} + +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { @@ -988,33 +1001,19 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; - mrb_code i; + mrb_code insn; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; + uint32_t a; + uint16_t b; + uint8_t c; #ifdef DIRECT_THREADED static void *optable[] = { - &&L_OP_NOP, &&L_OP_MOVE, - &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, - &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, - &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, - &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, - &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, - &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, - &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, - &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, - &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, - &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, - &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, - &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, - &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, - &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, - &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, - &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, - &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, - &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, - &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, +#define OPCODE(x,_) &&L_OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #endif @@ -1035,25 +1034,19 @@ RETRY_TRY_BLOCK: #define regs (mrb->c->stack) INIT_DISPATCH { - CASE(OP_NOP) { + CASE(OP_NOP, Z) { /* do nothing */ NEXT; } - CASE(OP_MOVE) { - /* A B R(A) := R(B) */ - int a = GETARG_A(i); - int b = GETARG_B(i); + CASE(OP_MOVE, BB) { regs[a] = regs[b]; NEXT; } - CASE(OP_LOADL) { - /* A Bx R(A) := Pool(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_LOADL, BB) { #ifdef MRB_WORD_BOXING - mrb_value val = pool[bx]; + mrb_value val = pool[b]; #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { val = mrb_float_value(mrb, mrb_float(val)); @@ -1061,125 +1054,109 @@ RETRY_TRY_BLOCK: #endif regs[a] = val; #else - regs[a] = pool[bx]; + regs[a] = pool[b]; #endif NEXT; } - CASE(OP_LOADI) { - /* A sBx R(A) := sBx */ - int a = GETARG_A(i); - mrb_int bx = GETARG_sBx(i); - SET_INT_VALUE(regs[a], bx); + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + + CASE(OP_LOADI__1,B) goto L_LOADI; + CASE(OP_LOADI_0,B) goto L_LOADI; + CASE(OP_LOADI_1,B) goto L_LOADI; + CASE(OP_LOADI_2,B) goto L_LOADI; + CASE(OP_LOADI_3,B) goto L_LOADI; + CASE(OP_LOADI_4,B) goto L_LOADI; + CASE(OP_LOADI_5,B) goto L_LOADI; + CASE(OP_LOADI_6,B) goto L_LOADI; + CASE(OP_LOADI_7, B) { + L_LOADI: + SET_INT_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0); + NEXT; + } + + CASE(OP_LOADSYM, BB) { + SET_SYM_VALUE(regs[a], syms[b]); NEXT; } - CASE(OP_LOADSYM) { - /* A Bx R(A) := Syms(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - SET_SYM_VALUE(regs[a], syms[bx]); + CASE(OP_LOADNIL, B) { + SET_NIL_VALUE(regs[a]); NEXT; } - CASE(OP_LOADSELF) { - /* A R(A) := self */ - int a = GETARG_A(i); + CASE(OP_LOADSELF, B) { regs[a] = regs[0]; NEXT; } - CASE(OP_LOADT) { - /* A R(A) := true */ - int a = GETARG_A(i); + CASE(OP_LOADT, B) { SET_TRUE_VALUE(regs[a]); NEXT; } - CASE(OP_LOADF) { - /* A R(A) := false */ - int a = GETARG_A(i); + CASE(OP_LOADF, B) { SET_FALSE_VALUE(regs[a]); NEXT; } - CASE(OP_GETGLOBAL) { - /* A Bx R(A) := getglobal(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_gv_get(mrb, syms[bx]); + CASE(OP_GETGV, BB) { + mrb_value val = mrb_gv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETGLOBAL) { - /* A Bx setglobal(Syms(Bx), R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_gv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETGV, BB) { + mrb_gv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETSPECIAL) { - /* A Bx R(A) := Special[Bx] */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_special_get(mrb, bx); + CASE(OP_GETSV, BB) { + mrb_value val = mrb_vm_special_get(mrb, b); regs[a] = val; NEXT; } - CASE(OP_SETSPECIAL) { - /* A Bx Special[Bx] := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_special_set(mrb, bx, regs[a]); + CASE(OP_SETSV, BB) { + mrb_vm_special_set(mrb, b, regs[a]); NEXT; } - CASE(OP_GETIV) { - /* A Bx R(A) := ivget(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_iv_get(mrb, regs[0], syms[bx]); - regs[a] = val; + CASE(OP_GETIV, BB) { + regs[a] = mrb_iv_get(mrb, regs[0], syms[b]); NEXT; } - CASE(OP_SETIV) { - /* A Bx ivset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_iv_set(mrb, regs[0], syms[bx], regs[a]); + CASE(OP_SETIV, BB) { + mrb_iv_set(mrb, regs[0], syms[b], regs[a]); NEXT; } - CASE(OP_GETCV) { - /* A Bx R(A) := cvget(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_GETCV, BB) { mrb_value val; ERR_PC_SET(mrb, pc); - val = mrb_vm_cv_get(mrb, syms[bx]); + val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETCV) { - /* A Bx cvset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_cv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCV, BB) { + mrb_vm_cv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCONST) { - /* A Bx R(A) := constget(Syms(Bx)) */ + CASE(OP_GETCONST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_sym sym = syms[bx]; + mrb_sym sym = syms[b]; ERR_PC_SET(mrb, pc); val = mrb_vm_const_get(mrb, sym); @@ -1188,40 +1165,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETCONST) { - /* A Bx constset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_const_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCONST, BB) { + mrb_vm_const_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETMCNST) { - /* A Bx R(A) := R(A)::Syms(Bx) */ + CASE(OP_GETMCNST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); ERR_PC_SET(mrb, pc); - val = mrb_const_get(mrb, regs[a], syms[bx]); + val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETMCNST) { - /* A Bx R(A+1)::Syms(Bx) := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]); + CASE(OP_SETMCNST, BB) { + mrb_const_set(mrb, regs[a+1], syms[b], regs[a]); NEXT; } - CASE(OP_GETUPVAR) { - /* A B C R(A) := uvget(B,C) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_GETUPVAR, BBB) { mrb_value *regs_a = regs + a; struct REnv *e = uvenv(mrb, c); @@ -1234,12 +1198,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETUPVAR) { - /* A B C uvset(B,C,R(A)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - + CASE(OP_SETUPVAR, BBB) { struct REnv *e = uvenv(mrb, c); if (e) { @@ -1253,110 +1212,86 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_JMP) { - /* sBx pc+=sBx */ - int sbx = GETARG_sBx(i); - pc += sbx; + CASE(OP_JMP, S) { + pc = irep->iseq+a; JUMP; } - - CASE(OP_JMPIF) { - /* A sBx if R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPIF, BS) { if (mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; JUMP; } NEXT; } - - CASE(OP_JMPNOT) { - /* A sBx if !R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPNOT, BS) { if (!mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; + JUMP; + } + NEXT; + } + CASE(OP_JMPNIL, BS) { + if (mrb_nil_p(regs[a])) { + pc = irep->iseq+b; JUMP; } NEXT; } - CASE(OP_ONERR) { - /* sBx pc+=sBx on exception */ - int sbx = GETARG_sBx(i); + CASE(OP_ONERR, S) { if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; else mrb->c->rsize *= 2; - mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize); + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize); } - mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx; + mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } - CASE(OP_RESCUE) { - /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - mrb_value exc; - - if (c == 0) { - exc = mrb_obj_value(mrb->exc); - mrb->exc = 0; - } - else { /* continued; exc taken from R(A) */ - exc = regs[a]; - } - if (b != 0) { - mrb_value e = regs[b]; - struct RClass *ec; + CASE(OP_EXCEPT, B) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = 0; + regs[a] = exc; + NEXT; + } + CASE(OP_RESCUE, BB) { + mrb_value exc = regs[a]; /* exc on stack */ + mrb_value e = regs[b]; + struct RClass *ec; - switch (mrb_type(e)) { - case MRB_TT_CLASS: - case MRB_TT_MODULE: - break; - default: - { - mrb_value exc; + switch (mrb_type(e)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + break; + default: + { + mrb_value exc; - exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, - "class or module required for rescue clause"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } + exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, + "class or module required for rescue clause"); + mrb_exc_set(mrb, exc); + goto L_RAISE; } - ec = mrb_class_ptr(e); - regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); - } - if (a != 0 && c == 0) { - regs[a] = exc; } + ec = mrb_class_ptr(e); + regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); NEXT; } - CASE(OP_POPERR) { - /* A A.times{rescue_pop()} */ - int a = GETARG_A(i); - + CASE(OP_POPERR, B) { mrb->c->ci->ridx -= a; NEXT; } - CASE(OP_RAISE) { - /* A raise(R(A)) */ - int a = GETARG_A(i); - + CASE(OP_RAISE, B) { mrb_exc_set(mrb, regs[a]); goto L_RAISE; } - CASE(OP_EPUSH) { - /* Bx ensure_push(SEQ[Bx]) */ - int bx = GETARG_Bx(i); + CASE(OP_EPUSH, B) { struct RProc *p; - p = mrb_closure_new(mrb, irep->reps[bx]); + p = mrb_closure_new(mrb, irep->reps[a]); /* push ensure_stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; @@ -1369,11 +1304,9 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_EPOP) { - /* A A.times{ensure_pop().call} */ - int a = GETARG_A(i); + CASE(OP_EPOP, B) { mrb_callinfo *ci = mrb->c->ci; - int n, epos = ci->epos; + unsigned int n, epos = ci->epos; mrb_value self = regs[0]; struct RClass *target_class = ci->target_class; @@ -1381,9 +1314,8 @@ RETRY_TRY_BLOCK: NEXT; } - if (a > mrb->c->eidx - epos) + if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; - pc = pc + 1; for (n=0; n<a; n++) { int nregs = irep->nregs; @@ -1410,29 +1342,32 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_LOADNIL) { - /* A R(A) := nil */ - int a = GETARG_A(i); + CASE(OP_SENDV, BB) { + c = CALL_MAXARGS; + goto L_SEND; + }; - SET_NIL_VALUE(regs[a]); - NEXT; - } + CASE(OP_SENDVB, BB) { + c = CALL_MAXARGS; + goto L_SENDB; + }; - CASE(OP_SENDB) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - /* fall through */ + CASE(OP_SEND, BBB) + L_SEND: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB; }; - L_SEND: - CASE(OP_SEND) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SENDB, BBB) + L_SENDB: + { + int argc = (c == CALL_MAXARGS) ? -1 : c; + int bidx = (argc < 0) ? a+2 : a+c+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = syms[b]; @@ -1440,26 +1375,20 @@ RETRY_TRY_BLOCK: mrb_assert(bidx < irep->nregs); recv = regs[a]; - if (GET_OPCODE(i) != OP_SENDB) { - SET_NIL_VALUE(regs[bidx]); - blk = regs[bidx]; - } - else { - blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { - blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); - /* The stack might have been reallocated during mrb_convert_type(), - see #3622 */ - regs[bidx] = blk; - } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack might have been reallocated during mrb_convert_type(), + see #3622 */ + regs[bidx] = blk; } - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); + cls = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1467,7 +1396,7 @@ RETRY_TRY_BLOCK: if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, c, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1479,10 +1408,10 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; + ci->target_class = cls; ci->argc = argc; - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; /* prepare stack */ @@ -1502,12 +1431,10 @@ RETRY_TRY_BLOCK: mrb_gc_arena_shrink(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; - if (GET_OPCODE(i) == OP_SENDB) { - if (mrb_type(blk) == MRB_TT_PROC) { - struct RProc *p = mrb_proc_ptr(blk); - if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { - p->flags |= MRB_PROC_ORPHAN; - } + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; } } if (!ci->target_class) { /* return from context modifying method (resume/yield) */ @@ -1542,14 +1469,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; - } - - CASE(OP_CALL) { - /* A R(A) := self.call(frame.argc, frame.argv) */ + CASE(OP_CALL, Z) { mrb_callinfo *ci; mrb_value recv = mrb->c->stack[0]; struct RProc *m = mrb_proc_ptr(recv); @@ -1592,7 +1512,9 @@ RETRY_TRY_BLOCK: irep = m->body.irep; if (!irep) { mrb->c->stack[0] = mrb_nil_value(); - goto L_RETURN; + a = 0; + c = OP_R_NORMAL; + goto L_OP_RETURN_BODY; } pool = irep->pool; syms = irep->syms; @@ -1613,14 +1535,11 @@ RETRY_TRY_BLOCK: } } - CASE(OP_SUPER) { - /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SUPER, BB) { + int argc = (b == CALL_MAXARGS) ? -1 : b; + int bidx = (argc < 0) ? a+2 : a+b+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = ci->mid; @@ -1656,17 +1575,17 @@ RETRY_TRY_BLOCK: regs[bidx] = blk; ci = mrb->c->ci; } - c = target_class->super; - m = mrb_method_search_vm(mrb, &c, mid); + cls = target_class->super; + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); if (mid != missing) { - c = mrb_class(mrb, recv); + cls = mrb_class(mrb, recv); } - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1675,7 +1594,7 @@ RETRY_TRY_BLOCK: if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1686,8 +1605,8 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; - ci->pc = pc + 1; + ci->target_class = cls; + ci->pc = pc; ci->argc = argc; /* prepare stack */ @@ -1739,14 +1658,12 @@ RETRY_TRY_BLOCK: } } - CASE(OP_ARGARY) { - /* A Bx R(A) := argument array (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_ARGARY, BS) { + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; + int lv = (b>>0)&0xf; mrb_value *stack; if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) { @@ -1761,12 +1678,12 @@ RETRY_TRY_BLOCK: else { struct REnv *e = uvenv(mrb, lv-1); if (!e) goto L_NOSUPER; - if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) + if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+kd+1) goto L_NOSUPER; stack = e->stack + 1; } if (r == 0) { - regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack); + regs[a] = mrb_ary_new_from_values(mrb, m1+m2+kd, stack); } else { mrb_value *pp = NULL; @@ -1779,7 +1696,7 @@ RETRY_TRY_BLOCK: pp = ARY_PTR(ary); len = (int)ARY_LEN(ary); } - regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); + regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd); rest = mrb_ary_ptr(regs[a]); if (m1 > 0) { stack_copy(ARY_PTR(rest), stack, m1); @@ -1790,89 +1707,130 @@ RETRY_TRY_BLOCK: if (m2 > 0) { stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); } - ARY_SET_LEN(rest, m1+len+m2); + if (kd) { + stack_copy(ARY_PTR(rest)+m1+len+m2, stack+m1+m2+1, kd); + } + ARY_SET_LEN(rest, m1+len+m2+kd); } regs[a+1] = stack[m1+r+m2]; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ENTER) { - /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - /* number of optional arguments times OP_JMP should follow */ - mrb_aspec ax = GETARG_Ax(i); - int m1 = MRB_ASPEC_REQ(ax); - int o = MRB_ASPEC_OPT(ax); - int r = MRB_ASPEC_REST(ax); - int m2 = MRB_ASPEC_POST(ax); + CASE(OP_ENTER, W) { + int m1 = MRB_ASPEC_REQ(a); + int o = MRB_ASPEC_OPT(a); + int r = MRB_ASPEC_REST(a); + int m2 = MRB_ASPEC_POST(a); + int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0; /* unused - int k = MRB_ASPEC_KEY(ax); - int kd = MRB_ASPEC_KDICT(ax); - int b = MRB_ASPEC_BLOCK(ax); + int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; - mrb_value *argv0 = argv; - int len = m1 + o + r + m2; + mrb_value * const argv0 = argv; + int const len = m1 + o + r + m2; + int const blk_pos = len + kd + 1; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + mrb_value kdict; + int kargs = kd; + /* arguments is passed with Array */ if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ARY_PTR(ary); argc = (int)ARY_LEN(ary); mrb_gc_protect(mrb, regs[1]); } + + /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0) { - if (argc < m1 + m2 || (r == 0 && argc > len)) { + if (argc >= 0 && !(argc <= 1 && kd)) { + if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) { argnum_error(mrb, m1+m2); goto L_RAISE; } } } + /* extract first argument array to arguments */ else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { mrb_gc_protect(mrb, argv[0]); argc = (int)RARRAY_LEN(argv[0]); argv = RARRAY_PTR(argv[0]); } - if (argc < len) { + + if (kd) { + /* check last arguments is hash if method takes keyword arguments */ + if (argc == m1+m2) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + if (!mrb_hash_p(argv[argc - 1])) { + if (r) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + } + else { + kdict = argv[argc-1]; + } + mrb_hash_check_kdict(mrb, kdict); + if (MRB_ASPEC_KEY(a) > 0) { + kdict = mrb_hash_dup(mrb, kdict); + } + } + } + + /* no rest arguments */ + if (argc-kargs < len) { int mlen = m2; if (argc < m1+m2) { - if (m1 < argc) - mlen = argc - m1; - else - mlen = 0; + mlen = m1 < argc ? argc - m1 : 0; } - regs[len+1] = *blk; /* move block */ - SET_NIL_VALUE(regs[argc+1]); + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; + + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ } if (argc < m1) { stack_clear(®s[argc+1], m1-argc); } + /* copy post mandatory arguments */ if (mlen) { value_move(®s[len-m2+1], &argv[argc-mlen], mlen); } if (mlen < m2) { stack_clear(®s[len-m2+mlen+1], m2-mlen); } + /* initalize rest arguments with empty Array */ if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o == 0 || argc < m1+m2) pc++; - else - pc += argc - m1 - m2 + 1; + /* skip initailizer of passed arguments */ + if (o > 0 && argc-kargs > m1+m2) + pc += (argc - kargs - m1 - m2)*3; } else { int rnum = 0; if (argv0 != argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; value_move(®s[1], argv, m1+o); } if (r) { - rnum = argc-m1-o-m2; - regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + mrb_value ary; + + rnum = argc-m1-o-m2-kargs; + ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + regs[m1+o+1] = ary; } if (m2) { if (argc-m2 > m1) { @@ -1880,36 +1838,71 @@ RETRY_TRY_BLOCK: } } if (argv0 == argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; } - pc += o + 1; + pc += o*3; } - mrb->c->ci->argc = len; + + /* format arguments for generated code */ + mrb->c->ci->argc = len + kd; + /* clear local (but non-argument) variables */ - if (irep->nlocals-len-2 > 0) { - stack_clear(®s[len+2], irep->nlocals-len-2); + if (irep->nlocals-blk_pos-1 > 0) { + stack_clear(®s[blk_pos+1], irep->nlocals-blk_pos-1); } JUMP; } - CASE(OP_KARG) { - /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ - /* if C == 2; raise unless kdict.empty? */ - /* OP_JMP should follow to skip init code */ + CASE(OP_KARG, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (!mrb_hash_key_p(mrb, kdict, k)) { + mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + regs[a] = mrb_hash_get(mrb, kdict, k); + mrb_hash_delete_key(mrb, kdict, k); + NEXT; + } + + CASE(OP_KEY_P, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k); + + regs[a] = mrb_bool_value(key_p); NEXT; } - CASE(OP_KDICT) { - /* A C R(A) := kdict */ + CASE(OP_KEYEND, Z) { + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { + mrb_value keys = mrb_hash_keys(mrb, kdict); + mrb_value key1 = RARRAY_PTR(keys)[0]; + mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } NEXT; } + CASE(OP_BREAK, B) { + c = OP_R_BREAK; + goto L_RETURN; + } + CASE(OP_RETURN_BLK, B) { + c = OP_R_RETURN; + goto L_RETURN; + } + CASE(OP_RETURN, B) + c = OP_R_NORMAL; L_RETURN: - i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); - /* fall through */ - CASE(OP_RETURN) { - /* A B return R(A) (B=normal,in-block return/break) */ - mrb_callinfo *ci; + { + mrb_callinfo *ci; #define ecall_adjust() do {\ ptrdiff_t cioff = ci - mrb->c->cibase;\ @@ -1995,7 +1988,7 @@ RETRY_TRY_BLOCK: mrb->c->stack = ci[1].stackent; } mrb_stack_extend(mrb, irep->nregs); - pc = mrb->c->rescue[--ci->ridx]; + pc = irep->iseq+mrb->c->rescue[--ci->ridx]; } else { int acc; @@ -2003,9 +1996,9 @@ RETRY_TRY_BLOCK: struct RProc *dst; ci = mrb->c->ci; - v = regs[GETARG_A(i)]; + v = regs[a]; mrb_gc_protect(mrb, v); - switch (GETARG_B(i)) { + switch (c) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { @@ -2040,8 +2033,7 @@ RETRY_TRY_BLOCK: struct mrb_context *c; if (!mrb->c->prev) { /* toplevel return */ - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; + goto L_STOP; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); @@ -2160,91 +2152,12 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_TAILCALL) { - /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - mrb_method_t m; - struct RClass *c; - mrb_callinfo *ci; - mrb_value recv; - mrb_sym mid = syms[b]; - - recv = regs[a]; - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value sym = mrb_symbol_value(mid); - mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args; - - if (n == CALL_MAXARGS) { - args = regs[a+1]; - } - else { - args = mrb_ary_new_from_values(mrb, n, regs+a+1); - } - ERR_PC_SET(mrb, pc); - mrb_method_missing(mrb, mid, recv, args); - } - mid = missing; - if (n == CALL_MAXARGS) { - mrb_ary_unshift(mrb, regs[a+1], sym); - } - else { - value_move(regs+a+2, regs+a+1, ++n); - regs[a+1] = sym; - } - } - - /* replace callinfo */ - ci = mrb->c->ci; - ci->mid = mid; - ci->target_class = c; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; - } - - /* move stack */ - value_move(mrb->c->stack, ®s[a], ci->argc+1); - - if (MRB_METHOD_CFUNC_P(m)) { - mrb_value v = MRB_METHOD_CFUNC(m)(mrb, recv); - mrb->c->stack[0] = v; - mrb_gc_arena_restore(mrb, ai); - goto L_RETURN; - } - else { - /* setup environment for calling method */ - struct RProc *p = MRB_METHOD_PROC(m); - irep = p->body.irep; - pool = irep->pool; - syms = irep->syms; - if (ci->argc < 0) { - mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); - } - else { - mrb_stack_extend(mrb, irep->nregs); - } - pc = irep->iseq; - } - JUMP; - } - - CASE(OP_BLKPUSH) { - /* A Bx R(A) := block (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_BLKPUSH, BS) { + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; + int lv = (b>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; @@ -2261,7 +2174,7 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_YIELD); goto L_RAISE; } - regs[a] = stack[m1+r+m2]; + regs[a] = stack[m1+r+m2+kd]; NEXT; } @@ -2270,10 +2183,7 @@ RETRY_TRY_BLOCK: v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ } while(0) - CASE(OP_ADD) { - /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_ADD, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2327,16 +2237,14 @@ RETRY_TRY_BLOCK: regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break; default: + c = 1; goto L_SEND; } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SUB) { - /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_SUB, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2386,15 +2294,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_MUL) { - /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_MUL, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2444,14 +2350,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_DIV) { - /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ - int a = GETARG_A(i); + CASE(OP_DIV, BB) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2484,6 +2389,7 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } @@ -2501,16 +2407,13 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI) { - /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ - int a = GETARG_A(i); - + CASE(OP_ADDI, BBB) { /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_add_overflow(x, y, &z)) { @@ -2527,24 +2430,22 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], x + c); } #else - mrb_float(regs[a]) += GETARG_C(i); + mrb_float(regs[a]) += c; #endif break; #endif default: - SET_INT_VALUE(regs[a+1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs[a+1], c); + c = 1; goto L_SEND; } NEXT; } - CASE(OP_SUBI) { - /* A B C R(A) := R(A)-C (Syms[B]=:-)*/ - int a = GETARG_A(i); + CASE(OP_SUBI, BBB) { mrb_value *regs_a = regs + a; /* need to check if + is overridden */ @@ -2552,7 +2453,7 @@ RETRY_TRY_BLOCK: case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_sub_overflow(x, y, &z)) { @@ -2569,16 +2470,16 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c); } #else - mrb_float(regs_a[0]) -= GETARG_C(i); + mrb_float(regs_a[0]) -= c; #endif break; #endif default: - SET_INT_VALUE(regs_a[1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs_a[1], c); + c = 1; goto L_SEND; } NEXT; @@ -2595,6 +2496,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2622,6 +2524,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_float,mrb_float);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2633,9 +2536,7 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ) { - /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ - int a = GETARG_A(i); + CASE(OP_EQ, BB) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } @@ -2645,68 +2546,59 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LT) { - /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ - int a = GETARG_A(i); + CASE(OP_LT, BB) { OP_CMP(<); NEXT; } - CASE(OP_LE) { - /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_LE, BB) { OP_CMP(<=); NEXT; } - CASE(OP_GT) { - /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GT, BB) { OP_CMP(>); NEXT; } - CASE(OP_GE) { - /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GE, BB) { OP_CMP(>=); NEXT; } - CASE(OP_ARRAY) { - /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARRAY, BB) { + mrb_value v = mrb_ary_new_from_values(mrb, b, ®s[a]); + regs[a] = v; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_ARRAY2, BBB) { mrb_value v = mrb_ary_new_from_values(mrb, c, ®s[b]); regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYCAT) { - /* A B mrb_ary_concat(R(A),R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_value splat = mrb_ary_splat(mrb, regs[b]); + CASE(OP_ARYCAT, B) { + mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); mrb_ary_concat(mrb, regs[a], splat); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYPUSH) { - /* A B R(A).push(R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_ary_push(mrb, regs[a], regs[b]); + CASE(OP_ARYPUSH, B) { + mrb_ary_push(mrb, regs[a], regs[a+1]); 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); + CASE(OP_ARYDUP, B) { + mrb_value ary = regs[a]; + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + regs[a] = ary; + NEXT; + } + + CASE(OP_AREF, BBB) { mrb_value v = regs[b]; if (!mrb_array_p(v)) { @@ -2724,21 +2616,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ASET) { - /* A B C R(B)[C] := R(A) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ASET, BBB) { mrb_ary_set(mrb, regs[b], c, regs[a]); NEXT; } - CASE(OP_APOST) { - /* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - int a = GETARG_A(i); + CASE(OP_APOST, BBB) { mrb_value v = regs[a]; - int pre = GETARG_B(i); - int post = GETARG_C(i); + int pre = b; + int post = c; struct RArray *ary; int len, idx; @@ -2769,48 +2655,62 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STRING) { - /* A Bx R(A) := str_new(Lit(Bx)) */ - mrb_int a = GETARG_A(i); - mrb_int bx = GETARG_Bx(i); - mrb_value str = mrb_str_dup(mrb, pool[bx]); + CASE(OP_INTERN, B) { + mrb_sym sym = mrb_intern_str(mrb, regs[a]); + + regs[a] = mrb_symbol_value(sym); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRING, BB) { + mrb_value str = mrb_str_dup(mrb, pool[b]); regs[a] = str; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_STRCAT) { - /* A B R(A).concat(R(B)) */ - mrb_int a = GETARG_A(i); - mrb_int b = GETARG_B(i); + CASE(OP_STRCAT, B) { + mrb_str_concat(mrb, regs[a], regs[a+1]); + NEXT; + } + + CASE(OP_HASH, BB) { + mrb_value hash = mrb_hash_new_capa(mrb, b); + int i; + int lim = a+b*2; - mrb_str_concat(mrb, regs[a], regs[b]); + for (i=a; i<lim; i+=2) { + mrb_hash_set(mrb, hash, regs[i], regs[i+1]); + } + regs[a] = hash; + mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_HASH) { - /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - int b = GETARG_B(i); - int c = GETARG_C(i); - int lim = b+c*2; - mrb_value hash = mrb_hash_new_capa(mrb, c); + CASE(OP_HASHADD, BB) { + mrb_value hash = regs[a]; + int i; + int lim = a+b*2+1; - while (b < lim) { - mrb_hash_set(mrb, hash, regs[b], regs[b+1]); - b+=2; + for (i=a+1; i<lim; i+=2) { + mrb_hash_set(mrb, hash, regs[i], regs[i+1]); } - regs[GETARG_A(i)] = hash; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_HASHCAT, B) { + mrb_hash_merge(mrb, regs[a], regs[a+1]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_LAMBDA) { - /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */ + CASE(OP_LAMBDA, BB) + c = OP_L_LAMBDA; + L_MAKE_LAMBDA: + { struct RProc *p; - int a = GETARG_A(i); - int b = GETARG_b(i); - int c = GETARG_c(i); mrb_irep *nirep = irep->reps[b]; if (c & OP_L_CAPTURE) { @@ -2825,19 +2725,38 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_BLOCK, BB) { + c = OP_L_BLOCK; + goto L_MAKE_LAMBDA; + } + CASE(OP_METHOD, BB) { + c = OP_L_METHOD; + goto L_MAKE_LAMBDA; + } + + CASE(OP_RANGE_INC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_RANGE_EXC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], TRUE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } - CASE(OP_OCLASS) { - /* A R(A) := ::Object */ - regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); + CASE(OP_OCLASS, B) { + regs[a] = mrb_obj_value(mrb->object_class); NEXT; } - CASE(OP_CLASS) { - /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + CASE(OP_CLASS, BB) { struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); mrb_value base, super; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; super = regs[a+1]; @@ -2851,32 +2770,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_MODULE) { - /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); + CASE(OP_MODULE, BB) { + struct RClass *cls = 0, *baseclass; mrb_value base; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; if (mrb_nil_p(base)) { baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); base = mrb_obj_value(baseclass); } - c = mrb_vm_define_module(mrb, base, id); - regs[a] = mrb_obj_value(c); + cls = mrb_vm_define_module(mrb, base, id); + regs[a] = mrb_obj_value(cls); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_EXEC) { - /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_EXEC, BB) { mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; - mrb_irep *nirep = irep->reps[bx]; + mrb_irep *nirep = irep->reps[b]; /* prepare closure */ p = mrb_proc_new(mrb, nirep); @@ -2887,7 +2801,7 @@ RETRY_TRY_BLOCK: /* prepare call stack */ ci = cipush(mrb); - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; ci->mid = 0; ci->stackent = mrb->c->stack; @@ -2909,56 +2823,53 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_METHOD) { - /* A B R(A).newmethod(Syms(B),R(A+1)) */ - int a = GETARG_A(i); - struct RClass *c = mrb_class_ptr(regs[a]); + CASE(OP_DEF, BB) { + struct RClass *target = mrb_class_ptr(regs[a]); struct RProc *p = mrb_proc_ptr(regs[a+1]); mrb_method_t m; MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], m); + mrb_define_method_raw(mrb, target, syms[b], m); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SCLASS) { - /* A B R(A) := R(B).singleton_class */ - int a = GETARG_A(i); - int b = GETARG_B(i); - - regs[a] = mrb_singleton_class(mrb, regs[b]); + CASE(OP_SCLASS, B) { + regs[a] = mrb_singleton_class(mrb, regs[a]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_TCLASS) { - /* A R(A) := target_class */ - if (!mrb->c->ci->target_class) { - mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } - regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class); + CASE(OP_TCLASS, B) { + if (!check_target_class(mrb)) goto L_RAISE; + regs[a] = mrb_obj_value(mrb->c->ci->target_class); NEXT; } - CASE(OP_RANGE) { - /* A B C R(A) := range_new(R(B),R(B+1),C) */ - int b = GETARG_B(i); - mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); - regs[GETARG_A(i)] = val; - mrb_gc_arena_restore(mrb, ai); + CASE(OP_ALIAS, BB) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_alias_method(mrb, target, syms[a], syms[b]); + NEXT; + } + CASE(OP_UNDEF, B) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_undef_method_id(mrb, target, syms[a]); NEXT; } - CASE(OP_DEBUG) { - /* A B C debug print R(A),R(B),R(C) */ + CASE(OP_DEBUG, Z) { + FETCH_BBB(); #ifdef MRB_ENABLE_DEBUG_HOOK mrb->debug_op_hook(mrb, irep, pc, regs); #else #ifndef MRB_DISABLE_STDIO - printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); + printf("OP_DEBUG %d %d %d\n", a, b, c); #else abort(); #endif @@ -2966,7 +2877,48 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STOP) { + CASE(OP_ERR, B) { + mrb_value msg = mrb_str_dup(mrb, pool[a]); + mrb_value exc; + + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + ERR_PC_SET(mrb, pc); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + + CASE(OP_EXT1, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT2, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT3, Z) { + uint8_t insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + + CASE(OP_STOP, Z) { /* stop VM */ L_STOP: while (mrb->c->eidx > 0) { @@ -2979,26 +2931,9 @@ RETRY_TRY_BLOCK: } return regs[irep->nlocals]; } - - CASE(OP_ERR) { - /* Bx raise RuntimeError with message Lit(Bx) */ - mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); - mrb_value exc; - - if (GETARG_A(i) == 0) { - exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg); - } - else { - exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - } - ERR_PC_SET(mrb, pc); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } } END_DISPATCH; #undef regs - } MRB_CATCH(&c_jmp) { exc_catched = TRUE; diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 299394557..c5405aa9c 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -403,6 +403,9 @@ assert('External command execution.') do assert_equal 'test dynamic `', t assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results + results = [] + assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test` + alias_method sym, :old_cmd end true @@ -466,3 +469,184 @@ this is a comment that has extra after =begin and =end with tabs after it =end xxxxxxxxxxxxxxxxxxxxxxxxxx assert_equal(line + 4, __LINE__) end + +assert 'keyword arguments' do + def m(a, b:) [a, b] end + assert_equal [1, 2], m(1, b: 2) + assert_raise(ArgumentError) { m b: 1 } + assert_raise(ArgumentError) { m 1 } + + def m(a:) a end + assert_equal 1, m(a: 1) + assert_raise(ArgumentError) { m } + assert_raise(ArgumentError) { m 'a' => 1, a: 1 } + h = { a: 1 } + assert_equal 1, m(h) + assert_equal({ a: 1 }, h) + + def m(a: 1) a end + assert_equal 1, m + assert_equal 2, m(a: 2) + assert_raise(ArgumentError) { m 1 } + + def m(**) end + assert_nil m + assert_nil m a: 1, b: 2 + assert_raise(ArgumentError) { m 2 } + + def m(a, **) a end + assert_equal 1, m(1) + assert_equal 1, m(1, a: 2, b: 3) + assert_equal({ 'a' => 1, b: 2 }, m('a' => 1, b: 2)) + + def m(a, **k) [a, k] end + assert_equal [1, {}], m(1) + assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3) + assert_equal [{'a' => 1, b: 2}, {}], m('a' => 1, b: 2) + + def m(a=1, **) a end + assert_equal 1, m + assert_equal 2, m(2, a: 1, b: 0) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(a=1, **k) [a, k] end + assert_equal [1, {}], m + assert_equal [1, {a: 1}], m(a: 1) + assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2) + assert_equal [{a: 1}, {b: 2}], m({a: 1}, {b: 2}) + + def m(*, a:) a end + assert_equal 1, m(a: 1) + assert_equal 3, m(1, 2, a: 3) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(*a, b:) [a, b] end + assert_equal [[], 1], m(b: 1) + assert_equal [[1, 2], 3], m(1, 2, b: 3) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*a, b: 1) [a, b] end + assert_equal [[], 1], m + assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*, **) end + assert_nil m() + assert_nil m(a: 1, b: 2) + assert_nil m(1, 2, 3, a: 4, b: 5) + + def m(*a, **) a end + assert_equal [], m() + assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal [1], m(1, **{a: 2}) + + def m(*, **k) k end + assert_equal({}, m()) + assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + + def m(a = nil, b = nil, **k) [a, k] end + assert_equal [nil, {}], m() + assert_equal([nil, {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([{a: 1}, {}], m({a: 1}, {})) + assert_equal([nil, {}], m({})) + + def m(*a, **k) [a, k] end + assert_equal([[], {}], m()) + assert_equal([[1], {}], m(1)) + assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2)) + assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_raise(ArgumentError) { m("a" => 1) } + assert_equal([[], {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([[{a: 1}], {}], m({a: 1}, {})) + assert_raise(ArgumentError) { m({a: 1}, {"a" => 1}) } + + def m(a:, b:) [a, b] end + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, b: 1) [a, b] end + assert_equal([1, 1], m(a: 1)) + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **) a end + assert_equal(1, m(a: 1)) + assert_equal(1, m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **k) [a, k] end + assert_equal([1, {}], m(a: 1)) + assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + +=begin + def m(a:, &b) [a, b] end + assert_equal([1, nil], m(a: 1)) + assert_equal([1, l], m(a: 1, &(l = ->{}))) +=end + + def m(a: 1, b:) [a, b] end + assert_equal([1, 0], m(b: 0)) + assert_equal([3, 2], m(b: 2, a: 3)) + assert_raise(ArgumentError) { m a: 1 } + + def m(a: def m(a: 1) a end, b:) + [a, b] + end + assert_equal([2, 3], m(a: 2, b: 3)) + assert_equal([:m, 1], m(b: 1)) + # Note the default value of a: in the original method. + assert_equal(1, m()) + + def m(a: 1, b: 2) [a, b] end + assert_equal([1, 2], m()) + assert_equal([4, 3], m(b: 3, a: 4)) + + def m(a: 1, **) a end + assert_equal(1, m()) + assert_equal(2, m(a: 2, b: 1)) + + def m(a: 1, **k) [a, k] end + assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3)) + + def m(a:, **) yield end + assert_raise(ArgumentError) { m { :blk } } + assert_equal :blk, m(a: 1){ :blk } + + def m(a:, **k, &b) [b.call, k] end + assert_raise(ArgumentError) { m { :blk } } + assert_equal [:blk, {b: 2}], m(a: 1, b: 2){ :blk } + + def m(**k, &b) [k, b] end + assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2)) + assert_equal :blk, m{ :blk }[1].call + + def m(hsh = {}) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + + def m(hsh) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + +=begin + def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l) + [a, b, c, d, e, f, g, h, k, l] + end + result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{})) + assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result) + + def m a, b=1, *c, d, e:, f: 2, g:, **k, &l + [a, b, c, d, e, f, g, k, l] + end + result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{})) + assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result) +=end +end |
