diff --git a/insns.def b/insns.def index a4f2526bef..2fcb1b0c48 100644 --- a/insns.def +++ b/insns.def @@ -57,14 +57,7 @@ getlocal () (VALUE val) { - int i, lev = (int)level; - const VALUE *ep = GET_EP(); - - /* optimized insns generated for level == (0|1) in defs/opt_operand.def */ - for (i = 0; i < lev; i++) { - ep = GET_PREV_EP(ep); - } - val = *(ep - idx); + val = *(vm_get_ep(GET_EP(), level) - idx); } /** @@ -80,14 +73,7 @@ setlocal (VALUE val) () { - int i, lev = (int)level; - const VALUE *ep = GET_EP(); - - /* optimized insns generated for level == (0|1) in defs/opt_operand.def */ - for (i = 0; i < lev; i++) { - ep = GET_PREV_EP(ep); - } - vm_env_write(ep, -(int)idx, val); + vm_env_write(vm_get_ep(GET_EP(), level), -(int)idx, val); } /** @@ -311,21 +297,10 @@ putspecialobject () (VALUE val) { - enum vm_special_object_type type = (enum vm_special_object_type)value_type; + enum vm_special_object_type type; - switch (type) { - case VM_SPECIAL_OBJECT_VMCORE: - val = rb_mRubyVMFrozenCore; - break; - case VM_SPECIAL_OBJECT_CBASE: - val = vm_get_cbase(GET_EP()); - break; - case VM_SPECIAL_OBJECT_CONST_BASE: - val = vm_get_const_base(GET_EP()); - break; - default: - rb_bug("putspecialobject insn: unknown value_type"); - } + type = (enum vm_special_object_type)value_type; + val = vm_get_special_object(GET_EP(), type); } /** @@ -367,7 +342,7 @@ concatstrings (...) (VALUE val) // inc += 1 - num; { - val = rb_str_concat_literals(num, &TOPN(num-1)); + val = rb_str_concat_literals(num, STACK_ADDR_FROM_TOP(num)); POPN(num); } @@ -396,10 +371,7 @@ freezestring (VALUE str) (VALUE str) { - if (!NIL_P(debug_info)) { - rb_ivar_set(str, id_debug_created_info, debug_info); - } - rb_str_freeze(str); + vm_freezestring(str, debug_info); } /** @@ -437,7 +409,7 @@ newarray (...) (VALUE val) // inc += 1 - num; { - val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num)); + val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num)); POPN(num); } @@ -491,25 +463,10 @@ expandarray DEFINE_INSN concatarray () -(VALUE ary1, VALUE ary2st) +(VALUE ary1, VALUE ary2) (VALUE ary) { - const VALUE ary2 = ary2st; - VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, "Array", "to_a"); - VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, "Array", "to_a"); - - if (NIL_P(tmp1)) { - tmp1 = rb_ary_new3(1, ary1); - } - - if (NIL_P(tmp2)) { - tmp2 = rb_ary_new3(1, ary2); - } - - if (tmp1 == ary1) { - tmp1 = rb_ary_dup(ary1); - } - ary = rb_ary_concat(tmp1, tmp2); + ary = vm_concat_array(ary1, ary2); } /** @@ -523,14 +480,7 @@ splatarray (VALUE ary) (VALUE obj) { - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); - if (NIL_P(tmp)) { - tmp = rb_ary_new3(1, ary); - } - else if (RTEST(flag)) { - tmp = rb_ary_dup(tmp); - } - obj = tmp; + obj = vm_splat_array(flag, ary); } /** @@ -617,12 +567,11 @@ dupn (...) (...) // inc += n; { - rb_num_t i; - VALUE *sp = STACK_ADDR_FROM_TOP(n); - for (i = 0; i < n; i++) { - GET_SP()[i] = sp[i]; - } - INC_SP(n); + void *dst = GET_SP(); + void *src = STACK_ADDR_FROM_TOP(n); + + INC_SP(n); /* alloca */ + MEMCPY(dst, src, VALUE, n); } @@ -753,24 +702,7 @@ checkmatch (VALUE target, VALUE pattern) (VALUE result) { - enum vm_check_match_type checkmatch_type = - (enum vm_check_match_type)(flag & VM_CHECKMATCH_TYPE_MASK); - result = Qfalse; - - if (flag & VM_CHECKMATCH_ARRAY) { - long i; - for (i = 0; i < RARRAY_LEN(pattern); i++) { - if (RTEST(check_match(RARRAY_AREF(pattern, i), target, checkmatch_type))) { - result = Qtrue; - break; - } - } - } - else { - if (RTEST(check_match(pattern, target, checkmatch_type))) { - result = Qtrue; - } - } + result = vm_check_match(target, pattern, flag) } /** @@ -784,17 +716,7 @@ checkkeyword () (VALUE ret) { - const VALUE *ep = GET_EP(); - const VALUE kw_bits = *(ep - kw_bits_index); - - if (FIXNUM_P(kw_bits)) { - int bits = FIX2INT(kw_bits); - ret = (bits & (0x01 << keyword_index)) ? Qfalse : Qtrue; - } - else { - VM_ASSERT(RB_TYPE_P(kw_bits, T_HASH)); - ret = rb_hash_has_key(kw_bits, INT2FIX(keyword_index)) ? Qfalse : Qtrue; - } + ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP()); } /** @@ -810,27 +732,7 @@ trace { rb_event_flag_t flag = (rb_event_flag_t)nf; - if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() || - RUBY_DTRACE_METHOD_RETURN_ENABLED() || - RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() || - RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) { - - switch (flag) { - case RUBY_EVENT_CALL: - RUBY_DTRACE_METHOD_ENTRY_HOOK(th, 0, 0); - break; - case RUBY_EVENT_C_CALL: - RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, 0, 0); - break; - case RUBY_EVENT_RETURN: - RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0); - break; - case RUBY_EVENT_C_RETURN: - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, 0, 0); - break; - } - } - + vm_dtrace(nf, th); EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0, 0 /* id and klass are resolved at callee */, (flag & (RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN)) ? TOPN(0) : Qundef); } @@ -854,82 +756,7 @@ defineclass (VALUE cbase, VALUE super) (VALUE val) { - VALUE klass; - rb_vm_defineclass_type_t type = VM_DEFINECLASS_TYPE(flags); - - switch (type) { - case VM_DEFINECLASS_TYPE_CLASS: - /* val is dummy. classdef returns class scope value */ - - if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) && - !RB_TYPE_P(super, T_CLASS)) { - rb_raise(rb_eTypeError, "superclass must be a Class (%"PRIsVALUE" given)", - rb_obj_class(super)); - } - - vm_check_if_namespace(cbase); - - /* find klass */ - rb_autoload_load(cbase, id); - if ((klass = vm_search_const_defined_class(cbase, id)) != 0) { - /* already exist */ - klass = VM_DEFINECLASS_SCOPED_P(flags) ? - rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id); - if (!RB_TYPE_P(klass, T_CLASS)) { - rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a class", rb_id2str(id)); - } - - if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) { - VALUE tmp; - tmp = rb_class_real(RCLASS_SUPER(klass)); - - if (tmp != super) { - rb_raise(rb_eTypeError, "superclass mismatch for class %"PRIsVALUE"", - rb_id2str(id)); - } - } - } - else { - if (!VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) { - super = rb_cObject; - } - /* new class declaration */ - klass = rb_define_class_id(id, super); - rb_set_class_path_string(klass, cbase, rb_id2str(id)); - rb_const_set(cbase, id, klass); - rb_class_inherited(super, klass); - } - break; - case VM_DEFINECLASS_TYPE_SINGLETON_CLASS: - /* val is dummy. classdef returns class scope value */ - /* super is dummy */ - klass = rb_singleton_class(cbase); - break; - case VM_DEFINECLASS_TYPE_MODULE: - /* val is dummy. classdef returns class scope value */ - /* super is dummy */ - - vm_check_if_namespace(cbase); - - /* find klass */ - if ((klass = vm_search_const_defined_class(cbase, id)) != 0) { - klass = VM_DEFINECLASS_SCOPED_P(flags) ? - rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id); - /* already exist */ - if (!RB_TYPE_P(klass, T_MODULE)) { - rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a module", rb_id2str(id)); - } - } - else { - /* new module declaration */ - klass = rb_define_module_id(id); - rb_set_class_path_string(klass, cbase, rb_id2str(id)); - rb_const_set(cbase, id, klass); - } - break; - default: - rb_bug("unknown defineclass type: %d", (int)type); - } + VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super); rb_iseq_check(class_iseq); @@ -1001,32 +828,8 @@ opt_newarray_max (...) (VALUE val) // inc += 1 - num; { -#define id_cmp idCmp - if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) { - if (num == 0) { - val = Qnil; - } - else { - struct cmp_opt_data cmp_opt = { 0, 0 }; - VALUE result = Qundef; - rb_num_t i = num - 1; - result = TOPN(i); - while (i-- > 0) { - const VALUE v = TOPN(i); - if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) { - result = v; - } - } - val = result == Qundef ? Qnil : result; - } - POPN(num); - } - else { - VALUE ary = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num)); - val = rb_funcall(ary, idMax, 0); - POPN(num); - } -#undef id_cmp + val = vm_opt_newarray_max(num, STACK_ADDR_FROM_TOP(num)); + POPN(num); } DEFINE_INSN @@ -1035,32 +838,8 @@ opt_newarray_min (...) (VALUE val) // inc += 1 - num; { -#define id_cmp idCmp - if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) { - if (num == 0) { - val = Qnil; - } - else { - struct cmp_opt_data cmp_opt = { 0, 0 }; - VALUE result = Qundef; - rb_num_t i = num - 1; - result = TOPN(i); - while (i-- > 0) { - const VALUE v = TOPN(i); - if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) { - result = v; - } - } - val = result == Qundef ? Qnil : result; - } - POPN(num); - } - else { - VALUE ary = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num)); - val = rb_funcall(ary, idMin, 0); - POPN(num); - } -#undef id_cmp + val = vm_opt_newarray_min(num, STACK_ADDR_FROM_TOP(num)); + POPN(num); } /** @@ -1264,15 +1043,10 @@ getinlinecache () (VALUE val) { - if (ic->ic_serial == GET_GLOBAL_CONSTANT_STATE() && - (ic->ic_cref == NULL || ic->ic_cref == rb_vm_get_cref(GET_EP()))) { - val = ic->ic_value.value; + val = vm_ic_hit_p(ic, GET_EP()); + if (val != Qnil) { JUMP(dst); } - else { - /* none */ - val = Qnil; - } } /** @@ -1286,11 +1060,7 @@ setinlinecache (VALUE val) (VALUE val) { - VM_ASSERT(ic->ic_value.value != Qundef); - ic->ic_value.value = val; - ic->ic_serial = GET_GLOBAL_CONSTANT_STATE() - ruby_vm_const_missing_count; - ic->ic_cref = vm_get_const_key_cref(GET_EP()); - ruby_vm_const_missing_count = 0; + vm_ic_update(ic, val, GET_EP()); } /** @@ -1304,30 +1074,7 @@ once () (VALUE val) { - union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)ic; - -#define RUNNING_THREAD_ONCE_DONE ((rb_thread_t *)(0x1)) - retry: - if (is->once.running_thread == RUNNING_THREAD_ONCE_DONE) { - val = is->once.value; - } - else if (is->once.running_thread == NULL) { - is->once.running_thread = th; - val = is->once.value = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is); - /* is->once.running_thread is cleared by vm_once_clear() */ - is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */ - rb_iseq_add_mark_object(GET_ISEQ(), val); - } - else if (is->once.running_thread == th) { - /* recursive once */ - val = vm_once_exec((VALUE)iseq); - } - else { - /* waiting for finish */ - RUBY_VM_CHECK_INTS(th); - rb_thread_schedule(); - goto retry; - } + val = vm_once_dispatch(iseq, ic, th); } /** @@ -1341,34 +1088,10 @@ opt_case_dispatch (..., VALUE key) () // inc += -1; { - switch (OBJ_BUILTIN_TYPE(key)) { - case -1: - case T_FLOAT: - case T_SYMBOL: - case T_BIGNUM: - case T_STRING: - if (BASIC_OP_UNREDEFINED_P(BOP_EQQ, - SYMBOL_REDEFINED_OP_FLAG | - INTEGER_REDEFINED_OP_FLAG | - FLOAT_REDEFINED_OP_FLAG | - NIL_REDEFINED_OP_FLAG | - TRUE_REDEFINED_OP_FLAG | - FALSE_REDEFINED_OP_FLAG | - STRING_REDEFINED_OP_FLAG)) { - st_data_t val; - if (RB_FLOAT_TYPE_P(key)) { - double kval = RFLOAT_VALUE(key); - if (!isinf(kval) && modf(kval, &kval) == 0.0) { - key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval); - } - } - if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) { - JUMP(FIX2INT((VALUE)val)); - } - else { - JUMP(else_offset); - } - } + OFFSET dst = vm_case_dispatch(hash, else_offset, key); + + if (dst) { + JUMP(dst); } } @@ -1385,33 +1108,10 @@ opt_plus (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS,INTEGER_REDEFINED_OP_FLAG)) { - val = rb_fix_plus_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); - } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); - } - else if (RBASIC_CLASS(recv) == rb_cString && RBASIC_CLASS(obj) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) { - val = rb_str_plus(recv, obj); - } - else if (RBASIC_CLASS(recv) == rb_cArray && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) { - val = rb_ary_plus(recv, obj); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_plus(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1429,26 +1129,10 @@ opt_minus (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, INTEGER_REDEFINED_OP_FLAG)) { - val = rb_fix_minus_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); - } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { + val = vm_opt_minus(recv, obj); + + if (val == Qundef) { /* other */ - INSN_LABEL(normal_dispatch): PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1466,25 +1150,10 @@ opt_mult (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MULT, INTEGER_REDEFINED_OP_FLAG)) { - val = rb_fix_mul_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); - } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_mult(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1502,26 +1171,10 @@ opt_div (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_DIV, INTEGER_REDEFINED_OP_FLAG)) { - if (FIX2LONG(obj) == 0) goto INSN_LABEL(normal_dispatch); - val = rb_fix_div_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); - } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_div(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1539,26 +1192,10 @@ opt_mod (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MOD, INTEGER_REDEFINED_OP_FLAG )) { - if (FIX2LONG(obj) == 0) goto INSN_LABEL(normal_dispatch); - val = rb_fix_mod_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); - } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { - val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_mod(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1597,18 +1234,7 @@ opt_neq (VALUE recv, VALUE obj) (VALUE val) { - extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); - vm_search_method(ci, cc, recv); - - val = Qundef; - - if (check_cfunc(cc->me, rb_obj_not_equal)) { - val = opt_eq_func(recv, obj, ci_eq, cc_eq); - - if (val != Qundef) { - val = RTEST(val) ? Qfalse : Qtrue; - } - } + val = vm_opt_neq(ci, cc, ci_eq, cc_eq, recv, obj); if (val == Qundef) { /* other */ @@ -1629,27 +1255,10 @@ opt_lt (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; + val = vm_opt_lt(recv, obj); - if (a < b) { - val = Qtrue; - } - else { - val = Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - /* flonum is not NaN */ - val = RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - val = double_cmp_lt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1667,27 +1276,9 @@ opt_le (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LE, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; + val = vm_opt_le(recv, obj); - if (a <= b) { - val = Qtrue; - } - else { - val = Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) { - /* flonum is not NaN */ - val = RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - val = double_cmp_le(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + if (val == Qundef) { /* other */ PUSH(recv); PUSH(obj); @@ -1706,27 +1297,10 @@ opt_gt (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; + val = vm_opt_gt(recv, obj); - if (a > b) { - val = Qtrue; - } - else { - val = Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { - /* flonum is not NaN */ - val = RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - val = double_cmp_gt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1744,27 +1318,10 @@ opt_ge (VALUE recv, VALUE obj) (VALUE val) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GE, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; + val = vm_opt_ge(recv, obj); - if (a >= b) { - val = Qtrue; - } - else { - val = Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) { - /* flonum is not NaN */ - val = RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - val = double_cmp_ge(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1782,21 +1339,10 @@ opt_ltlt (VALUE recv, VALUE obj) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) { - val = rb_str_concat(recv, obj); - } - else if (RBASIC_CLASS(recv) == rb_cArray && - BASIC_OP_UNREDEFINED_P(BOP_LTLT, ARRAY_REDEFINED_OP_FLAG)) { - val = rb_ary_push(recv, obj); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_ltlt(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1814,19 +1360,10 @@ opt_aref (VALUE recv, VALUE obj) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_AREF, ARRAY_REDEFINED_OP_FLAG) && FIXNUM_P(obj)) { - val = rb_ary_entry(recv, FIX2LONG(obj)); - } - else if (RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG)) { - val = rb_hash_aref(recv, obj); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_aref(recv, obj); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); @@ -1844,21 +1381,10 @@ opt_aset (VALUE recv, VALUE obj, VALUE set) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_ASET, ARRAY_REDEFINED_OP_FLAG) && FIXNUM_P(obj)) { - rb_ary_store(recv, FIX2LONG(obj), set); - val = set; - } - else if (RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG)) { - rb_hash_aset(recv, obj, set); - val = set; - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_aset(recv, obj, set); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(obj); PUSH(set); @@ -1877,12 +1403,13 @@ opt_aset_with (VALUE recv, VALUE val) (VALUE val) { - if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && - BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG) && - rb_hash_compare_by_id_p(recv) == Qfalse) { - rb_hash_aset(recv, key, val); + VALUE tmp = vm_opt_aset_with(recv, key, val); + + if (tmp != Qundef) { + val = tmp; } else { + /* other */ PUSH(recv); PUSH(rb_str_resurrect(key)); PUSH(val); @@ -1901,12 +1428,10 @@ opt_aref_with (VALUE recv) (VALUE val) { - if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && - BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG) && - rb_hash_compare_by_id_p(recv) == Qfalse) { - val = rb_hash_aref(recv, key); - } - else { + val = vm_opt_aref_with(recv, key); + + if (val == Qundef) { + /* other */ PUSH(recv); PUSH(rb_str_resurrect(key)); CALL_SIMPLE_METHOD(recv); @@ -1924,25 +1449,10 @@ opt_length (VALUE recv) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_LENGTH, STRING_REDEFINED_OP_FLAG)) { - val = rb_str_length(recv); - } - else if (RBASIC_CLASS(recv) == rb_cArray && - BASIC_OP_UNREDEFINED_P(BOP_LENGTH, ARRAY_REDEFINED_OP_FLAG)) { - val = LONG2NUM(RARRAY_LEN(recv)); - } - else if (RBASIC_CLASS(recv) == rb_cHash && - BASIC_OP_UNREDEFINED_P(BOP_LENGTH, HASH_REDEFINED_OP_FLAG)) { - val = INT2FIX(RHASH_SIZE(recv)); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_length(recv, BOP_LENGTH); + + if (val == Qundef) { + /* other */ PUSH(recv); CALL_SIMPLE_METHOD(recv); } @@ -1959,25 +1469,10 @@ opt_size (VALUE recv) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_SIZE, STRING_REDEFINED_OP_FLAG)) { - val = rb_str_length(recv); - } - else if (RBASIC_CLASS(recv) == rb_cArray && - BASIC_OP_UNREDEFINED_P(BOP_SIZE, ARRAY_REDEFINED_OP_FLAG)) { - val = LONG2NUM(RARRAY_LEN(recv)); - } - else if (RBASIC_CLASS(recv) == rb_cHash && - BASIC_OP_UNREDEFINED_P(BOP_SIZE, HASH_REDEFINED_OP_FLAG)) { - val = INT2FIX(RHASH_SIZE(recv)); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_length(recv, BOP_SIZE); + + if (val == Qundef) { + /* other */ PUSH(recv); CALL_SIMPLE_METHOD(recv); } @@ -1994,28 +1489,10 @@ opt_empty_p (VALUE recv) (VALUE val) { - if (!SPECIAL_CONST_P(recv)) { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, STRING_REDEFINED_OP_FLAG)) { - if (RSTRING_LEN(recv) == 0) val = Qtrue; - else val = Qfalse; - } - else if (RBASIC_CLASS(recv) == rb_cArray && - BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, ARRAY_REDEFINED_OP_FLAG)) { - if (RARRAY_LEN(recv) == 0) val = Qtrue; - else val = Qfalse; - } - else if (RBASIC_CLASS(recv) == rb_cHash && - BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, HASH_REDEFINED_OP_FLAG)) { - if (RHASH_EMPTY_P(recv)) val = Qtrue; - else val = Qfalse; - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - INSN_LABEL(normal_dispatch): + val = vm_opt_empty_p(recv); + + if (val == Qundef) { + /* other */ PUSH(recv); CALL_SIMPLE_METHOD(recv); } @@ -2032,32 +1509,10 @@ opt_succ (VALUE recv) (VALUE val) { - if (SPECIAL_CONST_P(recv)) { - if (FIXNUM_P(recv) && - BASIC_OP_UNREDEFINED_P(BOP_SUCC, INTEGER_REDEFINED_OP_FLAG)) { - /* fixnum + INT2FIX(1) */ - if (recv != LONG2FIX(FIXNUM_MAX)) { - val = recv - 1 + INT2FIX(1); - } - else { - val = LONG2NUM(FIXNUM_MAX + 1); - } - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - else { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_SUCC, STRING_REDEFINED_OP_FLAG)) { - val = rb_str_succ(recv); - } - else { - goto INSN_LABEL(normal_dispatch); - } - } - if (0) { - INSN_LABEL(normal_dispatch): + val = vm_opt_succ(recv); + + if (val == Qundef) { + /* other */ PUSH(recv); CALL_SIMPLE_METHOD(recv); } @@ -2074,12 +1529,10 @@ opt_not (VALUE recv) (VALUE val) { - vm_search_method(ci, cc, recv); + val = vm_opt_not(ci, cc, recv); - if (check_cfunc(cc->me, rb_obj_not)) { - val = RTEST(recv) ? Qfalse : Qtrue; - } - else { + if (val == Qundef) { + /* other */ PUSH(recv); CALL_SIMPLE_METHOD(recv); } @@ -2093,16 +1546,11 @@ opt_not */ DEFINE_INSN opt_regexpmatch1 -(VALUE r) +(VALUE recv) (VALUE obj) (VALUE val) { - if (BASIC_OP_UNREDEFINED_P(BOP_MATCH, REGEXP_REDEFINED_OP_FLAG)) { - val = rb_reg_match(r, obj); - } - else { - val = rb_funcall(r, idEqTilde, 1, obj); - } + val = vm_opt_regexpmatch1(recv, obj); } /** @@ -2116,11 +1564,10 @@ opt_regexpmatch2 (VALUE obj2, VALUE obj1) (VALUE val) { - if (CLASS_OF(obj2) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_MATCH, STRING_REDEFINED_OP_FLAG)) { - val = rb_reg_match(obj1, obj2); - } - else { + val = vm_opt_regexpmatch2(obj2, obj1); + + if (val == Qundef) { + /* other */ PUSH(obj2); PUSH(obj1); CALL_SIMPLE_METHOD(obj2); diff --git a/internal.h b/internal.h index a6f7ef87f8..afea318376 100644 --- a/internal.h +++ b/internal.h @@ -1421,6 +1421,7 @@ NORETURN(void rb_undefined_alloc(VALUE klass)); double rb_num_to_dbl(VALUE val); VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound); VALUE rb_immutable_obj_clone(int, VALUE *, VALUE); +VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); struct RBasicRaw { VALUE flags; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index fd259fd428..a2367876dc 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2880,3 +2880,869 @@ vm_defined(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE return Qnil; } } + +static const VALUE * +vm_get_ep(const VALUE *const reg_ep, rb_num_t lv) +{ + rb_num_t i; + const VALUE *ep = reg_ep; + for (i = 0; i < lv; i++) { + ep = GET_PREV_EP(ep); + } + return ep; +} + +static VALUE +vm_get_special_object(const VALUE *const reg_ep, + enum vm_special_object_type type) +{ + switch (type) { + case VM_SPECIAL_OBJECT_VMCORE: + return rb_mRubyVMFrozenCore; + case VM_SPECIAL_OBJECT_CBASE: + return vm_get_cbase(reg_ep); + case VM_SPECIAL_OBJECT_CONST_BASE: + return vm_get_const_base(reg_ep); + default: + rb_bug("putspecialobject insn: unknown value_type %d", type); + } +} + +static void +vm_freezestring(VALUE str, VALUE debug) +{ + if (!NIL_P(debug)) { + rb_ivar_set(str, id_debug_created_info, debug); + } + rb_str_freeze(str); +} + +static VALUE +vm_concat_array(VALUE ary1, VALUE ary2st) +{ + const VALUE ary2 = ary2st; + VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, "Array", "to_a"); + VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, "Array", "to_a"); + + if (NIL_P(tmp1)) { + tmp1 = rb_ary_new3(1, ary1); + } + + if (NIL_P(tmp2)) { + tmp2 = rb_ary_new3(1, ary2); + } + + if (tmp1 == ary1) { + tmp1 = rb_ary_dup(ary1); + } + return rb_ary_concat(tmp1, tmp2); +} + +static VALUE +vm_splat_array(VALUE flag, VALUE ary) +{ + VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); + if (NIL_P(tmp)) { + return rb_ary_new3(1, ary); + } + else if (RTEST(flag)) { + return rb_ary_dup(tmp); + } + else { + return tmp; + } +} + +static VALUE +vm_check_match(VALUE target, VALUE pattern, rb_num_t flag) +{ + enum vm_check_match_type type = ((int)flag) & VM_CHECKMATCH_TYPE_MASK; + + if (flag & VM_CHECKMATCH_ARRAY) { + long i; + const long n = RARRAY_LEN(pattern); + + for (i = 0; i < n; i++) { + VALUE v = RARRAY_AREF(pattern, i); + VALUE c = check_match(v, target, type); + + if (RTEST(c)) { + return c; + } + } + return Qfalse; + } + else { + return check_match(pattern, target, type); + } +} + +static VALUE +vm_check_keyword(lindex_t bits, lindex_t idx, const VALUE *ep) +{ + const VALUE kw_bits = *(ep - bits); + + if (FIXNUM_P(kw_bits)) { + int b = FIX2INT(kw_bits); + return (b & (0x01 << idx)) ? Qfalse : Qtrue; + } + else { + VM_ASSERT(RB_TYPE_P(kw_bits, T_HASH)); + return rb_hash_has_key(kw_bits, INT2FIX(idx)); + } +} + +static void +vm_dtrace(rb_event_flag_t flag, rb_thread_t *th) +{ + if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() || + RUBY_DTRACE_METHOD_RETURN_ENABLED() || + RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() || + RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) { + + switch (flag) { + case RUBY_EVENT_CALL: + RUBY_DTRACE_METHOD_ENTRY_HOOK(th, 0, 0); + return; + case RUBY_EVENT_C_CALL: + RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, 0, 0); + return; + case RUBY_EVENT_RETURN: + RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0); + return; + case RUBY_EVENT_C_RETURN: + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, 0, 0); + return; + } + } +} + +static VALUE +vm_const_get_under(ID id, rb_num_t flags, VALUE cbase) +{ + VALUE ns; + + if ((ns = vm_search_const_defined_class(cbase, id)) == 0) { + return ns; + } + else if (VM_DEFINECLASS_SCOPED_P(flags)) { + return rb_public_const_get_at(ns, id); + } + else { + return rb_const_get_at(ns, id); + } +} + +static VALUE +vm_check_if_class(ID id, rb_num_t flags, VALUE super, VALUE klass) +{ + if (!RB_TYPE_P(klass, T_CLASS)) { + rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a class", rb_id2str(id)); + } + else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) { + VALUE tmp = rb_class_real(RCLASS_SUPER(klass)); + + if (tmp != super) { + rb_raise(rb_eTypeError, + "superclass mismatch for class %"PRIsVALUE"", + rb_id2str(id)); + } + else { + return klass; + } + } + else { + return klass; + } +} + +static VALUE +vm_check_if_module(ID id, VALUE mod) +{ + if (!RB_TYPE_P(mod, T_MODULE)) { + rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a module", rb_id2str(id)); + } + else { + return mod; + } +} + +static VALUE +vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super) +{ + /* new class declaration */ + VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject; + VALUE c = rb_define_class_id(id, s); + + rb_set_class_path_string(c, cbase, rb_id2str(id)); + rb_const_set(cbase, id, c); + rb_class_inherited(s, c); + return c; +} + +static VALUE +vm_declare_module(ID id, VALUE cbase) +{ + /* new module declaration */ + VALUE mod = rb_define_module_id(id); + rb_set_class_path_string(mod, cbase, rb_id2str(id)); + rb_const_set(cbase, id, mod); + return mod; +} + +static VALUE +vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super) +{ + VALUE klass; + + if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) && !RB_TYPE_P(super, T_CLASS)) { + rb_raise(rb_eTypeError, + "superclass must be a Class (%"PRIsVALUE" given)", + rb_obj_class(super)); + } + + vm_check_if_namespace(cbase); + + /* find klass */ + rb_autoload_load(cbase, id); + if ((klass = vm_const_get_under(id, flags, cbase)) != 0) { + return vm_check_if_class(id, flags, super, klass); + } + else { + return vm_declare_class(id, flags, cbase, super); + } +} + +static VALUE +vm_define_module(ID id, rb_num_t flags, VALUE cbase) +{ + VALUE mod; + + vm_check_if_namespace(cbase); + if ((mod = vm_const_get_under(id, flags, cbase)) != 0) { + return vm_check_if_module(id, mod); + } + else { + return vm_declare_module(id, cbase); + } +} + +static VALUE +vm_find_or_create_class_by_id(ID id, + rb_num_t flags, + VALUE cbase, + VALUE super) +{ + rb_vm_defineclass_type_t type = VM_DEFINECLASS_TYPE(flags); + + switch (type) { + case VM_DEFINECLASS_TYPE_CLASS: + /* classdef returns class scope value */ + return vm_define_class(id, flags, cbase, super); + + case VM_DEFINECLASS_TYPE_SINGLETON_CLASS: + /* classdef returns class scope value */ + return rb_singleton_class(cbase); + + case VM_DEFINECLASS_TYPE_MODULE: + /* classdef returns class scope value */ + return vm_define_module(id, flags, cbase); + + default: + rb_bug("unknown defineclass type: %d", (int)type); + } +} + +/* this macro is mandatory to use OPTIMIZED_CMP. What a design! */ +#define id_cmp idCmp + +static VALUE +vm_opt_newarray_max(rb_num_t num, const VALUE *ptr) +{ + if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) { + if (num == 0) { + return Qnil; + } + else { + struct cmp_opt_data cmp_opt = { 0, 0 }; + VALUE result = Qundef; + rb_num_t i = num - 1; + result = ptr[i]; + while (i-- > 0) { + const VALUE v = ptr[i]; + if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) { + result = v; + } + } + return result == Qundef ? Qnil : result; + } + } + else { + VALUE ary = rb_ary_new4(num, ptr); + return rb_funcall(ary, idMax, 0); + } +} + +static VALUE +vm_opt_newarray_min(rb_num_t num, const VALUE *ptr) +{ + if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) { + if (num == 0) { + return Qnil; + } + else { + struct cmp_opt_data cmp_opt = { 0, 0 }; + VALUE result = Qundef; + rb_num_t i = num - 1; + result = ptr[i]; + while (i-- > 0) { + const VALUE v = ptr[i]; + if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) { + result = v; + } + } + return result == Qundef ? Qnil : result; + } + } + else { + VALUE ary = rb_ary_new4(num, ptr); + return rb_funcall(ary, idMin, 0); + } +} + +#undef id_cmp + +static VALUE +vm_ic_hit_p(IC ic, const VALUE *reg_ep) +{ + if (ic->ic_serial == GET_GLOBAL_CONSTANT_STATE() && + (ic->ic_cref == NULL || ic->ic_cref == rb_vm_get_cref(reg_ep))) { + return ic->ic_value.value; + } + else { + return Qnil; + } +} + +static void +vm_ic_update(IC ic, VALUE val, const VALUE *reg_ep) +{ + VM_ASSERT(ic->ic_value.value != Qundef); + ic->ic_value.value = val; + ic->ic_serial = GET_GLOBAL_CONSTANT_STATE() - ruby_vm_const_missing_count; + ic->ic_cref = vm_get_const_key_cref(reg_ep); + ruby_vm_const_missing_count = 0; +} + +static VALUE +vm_once_dispatch(ISEQ iseq, IC ic, rb_thread_t *th) +{ + rb_thread_t *const RUNNING_THREAD_ONCE_DONE = (rb_thread_t *)(0x1); + union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)ic; + + if (is->once.running_thread == RUNNING_THREAD_ONCE_DONE) { + return is->once.value; + } + else if (is->once.running_thread == NULL) { + VALUE val; + is->once.running_thread = th; + val = is->once.value = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is); + /* is->once.running_thread is cleared by vm_once_clear() */ + is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */ + rb_iseq_add_mark_object(th->cfp->iseq, val); + return val; + } + else if (is->once.running_thread == th) { + /* recursive once */ + return vm_once_exec((VALUE)iseq); + } + else { + /* waiting for finish */ + RUBY_VM_CHECK_INTS(th); + rb_thread_schedule(); + return vm_once_dispatch(iseq, ic, th); + } +} + +static OFFSET +vm_case_dispatch(CDHASH hash, OFFSET else_offset, VALUE key) +{ + switch (OBJ_BUILTIN_TYPE(key)) { + case -1: + case T_FLOAT: + case T_SYMBOL: + case T_BIGNUM: + case T_STRING: + if (BASIC_OP_UNREDEFINED_P(BOP_EQQ, + SYMBOL_REDEFINED_OP_FLAG | + INTEGER_REDEFINED_OP_FLAG | + FLOAT_REDEFINED_OP_FLAG | + NIL_REDEFINED_OP_FLAG | + TRUE_REDEFINED_OP_FLAG | + FALSE_REDEFINED_OP_FLAG | + STRING_REDEFINED_OP_FLAG)) { + st_data_t val; + if (RB_FLOAT_TYPE_P(key)) { + double kval = RFLOAT_VALUE(key); + if (!isinf(kval) && modf(kval, &kval) == 0.0) { + key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval); + } + } + if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) { + return FIX2INT((VALUE)val); + } + else { + return else_offset; + } + } + } + return 0; +} + +static VALUE +vm_opt_plus(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_PLUS,INTEGER_REDEFINED_OP_FLAG)) { + return rb_fix_plus_fix(recv, obj); + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + } + else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { + if (RBASIC_CLASS(recv) == rb_cString && RBASIC_CLASS(obj) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) { + return rb_str_plus(recv, obj); + } + else if (RBASIC_CLASS(recv) == rb_cArray && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) { + return rb_ary_plus(recv, obj); + } + else { + return Qundef; + } + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_minus(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MINUS, INTEGER_REDEFINED_OP_FLAG)) { + return rb_fix_minus_fix(recv, obj); + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_mult(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MULT, INTEGER_REDEFINED_OP_FLAG)) { + return rb_fix_mul_fix(recv, obj); + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_div(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_DIV, INTEGER_REDEFINED_OP_FLAG)) { + if (FIX2LONG(obj) == 0) { + return Qundef; + } + else { + return rb_fix_div_fix(recv, obj); + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_mod(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MOD, INTEGER_REDEFINED_OP_FLAG )) { + if (FIX2LONG(obj) == 0) { + return Qundef; + } + else { + return rb_fix_mod_fix(recv, obj); + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { + return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); + } + else { + return Qundef; + } +} + +static inline int +vm_method_cfunc_is(CALL_INFO ci, CALL_CACHE cc, + VALUE recv, VALUE (*func)()) +{ + vm_search_method(ci, cc, recv); + return check_cfunc(cc->me, func); +} + +static VALUE +vm_opt_neq(CALL_INFO ci, CALL_CACHE cc, + CALL_INFO ci_eq, CALL_CACHE cc_eq, + VALUE recv, VALUE obj) +{ + if (vm_method_cfunc_is(ci, cc, recv, rb_obj_not_equal)) { + VALUE val = opt_eq_func(recv, obj, ci_eq, cc_eq); + + if (val != Qundef) { + return RTEST(val) ? Qfalse : Qtrue; + } + } + + return Qundef; +} + +static VALUE +vm_opt_lt(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LT, INTEGER_REDEFINED_OP_FLAG)) { + SIGNED_VALUE a = recv, b = obj; + + if (a < b) { + return Qtrue; + } + else { + return Qfalse; + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + return RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + return double_cmp_lt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_le(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LE, INTEGER_REDEFINED_OP_FLAG)) { + SIGNED_VALUE a = recv, b = obj; + + if (a <= b) { + return Qtrue; + } + else { + return Qfalse; + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + return RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + return double_cmp_le(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_gt(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT, INTEGER_REDEFINED_OP_FLAG)) { + SIGNED_VALUE a = recv, b = obj; + + if (a > b) { + return Qtrue; + } + else { + return Qfalse; + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + return RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + return double_cmp_gt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_ge(VALUE recv, VALUE obj) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GE, INTEGER_REDEFINED_OP_FLAG)) { + SIGNED_VALUE a = recv, b = obj; + + if (a >= b) { + return Qtrue; + } + else { + return Qfalse; + } + } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + return RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } + else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + return double_cmp_ge(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_ltlt(VALUE recv, VALUE obj) +{ + if (SPECIAL_CONST_P(recv)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) { + return rb_str_concat(recv, obj); + } + else if (RBASIC_CLASS(recv) == rb_cArray && + BASIC_OP_UNREDEFINED_P(BOP_LTLT, ARRAY_REDEFINED_OP_FLAG)) { + return rb_ary_push(recv, obj); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_aref(VALUE recv, VALUE obj) +{ + if (SPECIAL_CONST_P(recv)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cArray && + BASIC_OP_UNREDEFINED_P(BOP_AREF, ARRAY_REDEFINED_OP_FLAG) && + FIXNUM_P(obj)) { + return rb_ary_entry(recv, FIX2LONG(obj)); + } + else if (RBASIC_CLASS(recv) == rb_cHash && + BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG)) { + return rb_hash_aref(recv, obj); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_aset(VALUE recv, VALUE obj, VALUE set) +{ + if (SPECIAL_CONST_P(recv)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cArray && + BASIC_OP_UNREDEFINED_P(BOP_ASET, ARRAY_REDEFINED_OP_FLAG) && + FIXNUM_P(obj)) { + rb_ary_store(recv, FIX2LONG(obj), set); + return set; + } + else if (RBASIC_CLASS(recv) == rb_cHash && + BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG)) { + rb_hash_aset(recv, obj, set); + return set; + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_aref_with(VALUE recv, VALUE key) +{ + if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && + BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG) && + rb_hash_compare_by_id_p(recv) == Qfalse) { + return rb_hash_aref(recv, key); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_aset_with(VALUE recv, VALUE key, VALUE val) +{ + if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && + BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG) && + rb_hash_compare_by_id_p(recv) == Qfalse) { + return rb_hash_aset(recv, key, val); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_length(VALUE recv, int bop) +{ + if (SPECIAL_CONST_P(recv)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cString && + BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) { + if (bop == BOP_EMPTY_P) { + return LONG2NUM(RSTRING_LEN(recv)); + } + else { + return rb_str_length(recv); + } + } + else if (RBASIC_CLASS(recv) == rb_cArray && + BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) { + return LONG2NUM(RARRAY_LEN(recv)); + } + else if (RBASIC_CLASS(recv) == rb_cHash && + BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) { + return INT2FIX(RHASH_SIZE(recv)); + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_empty_p(VALUE recv) +{ + switch (vm_opt_length(recv, BOP_EMPTY_P)) { + case Qundef: return Qundef; + case INT2FIX(0): return Qtrue; + default: return Qfalse; + } +} + +static VALUE +vm_opt_succ(VALUE recv) +{ + if (SPECIAL_CONST_P(recv)) { + if (FIXNUM_P(recv) && + BASIC_OP_UNREDEFINED_P(BOP_SUCC, INTEGER_REDEFINED_OP_FLAG)) { + /* fixnum + INT2FIX(1) */ + if (recv == LONG2FIX(FIXNUM_MAX)) { + return LONG2NUM(FIXNUM_MAX + 1); + } + else { + return recv - 1 + INT2FIX(1); + } + } + else { + return Qundef; + } + } + else { + if (RBASIC_CLASS(recv) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_SUCC, STRING_REDEFINED_OP_FLAG)) { + return rb_str_succ(recv); + } + else { + return Qundef; + } + } +} + +static VALUE +vm_opt_not(CALL_INFO ci, CALL_CACHE cc, VALUE recv) +{ + if (vm_method_cfunc_is(ci, cc, recv, rb_obj_not)) { + return RTEST(recv) ? Qfalse : Qtrue; + } + else { + return Qundef; + } +} + +static VALUE +vm_opt_regexpmatch1(VALUE recv, VALUE obj) +{ + if (BASIC_OP_UNREDEFINED_P(BOP_MATCH, REGEXP_REDEFINED_OP_FLAG)) { + return rb_reg_match(recv, obj); + } + else { + return rb_funcall(recv, idEqTilde, 1, obj); + } +} + +static VALUE +vm_opt_regexpmatch2(VALUE recv, VALUE obj) +{ + if (CLASS_OF(obj) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_MATCH, STRING_REDEFINED_OP_FLAG)) { + return rb_reg_match(recv, obj); + } + else { + return Qundef; + } +} +