[前][次][番号順一覧][スレッド一覧]

ruby-changes:46277

From: shyouhei <ko1@a...>
Date: Tue, 18 Apr 2017 19:58:54 +0900 (JST)
Subject: [ruby-changes:46277] shyouhei:r58390 (trunk): split insns.def into functions

shyouhei	2017-04-18 19:58:49 +0900 (Tue, 18 Apr 2017)

  New Revision: 58390

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58390

  Log:
    split insns.def into functions
    
    Contemporary C compilers are good at function inlining.  They fold
    multiple functions into one.  However they are not yet smart enough to
    unfold a function into several ones.  So generally speaking, it is
    wiser for a C programmer to manually split C functions whenever
    possible.  That should make rooms for compilers to optimize at will.
    
    Before this changeset insns.def was converted into single HUGE
    function called vm_exec_core().  By moving each instruction's core
    into individual functions, generated C source code is reduced from
    3,428 lines to 2,847 lines.  Looking at the generated assembly
    however, it seems my compiler (gcc 6.2) is extraordinary smart so that
    it inlines almost all functions I introduced in this changeset back
    into that vm_exec_core.  On my machine compiled machine binary of the
    function does not shrink very much in size (28,432 bytes to 26,816
    bytes, according to nm(1)).
    
    I believe this change is zero-cost.  Several benchmarks I exercised
    showed no significant difference beyond error mergin.  For instance
    3 repeated runs of optcarrot benchmark on my machine resulted in:
    
       before this: 28.330329285707490, 27.513378371065920, 29.40420215754537
       after  this: 27.107195867280414, 25.549324021385907, 30.31581919050884
    
    in fps (greater==faster).
    
    ----
    
    * internal.h (rb_obj_not_equal): used from vm_insnhelper.c
    * insns.def: move vast majority of lines into vm_insnhelper.c
    * vm_insnhelper.c: moved here.

  Modified files:
    trunk/insns.def
    trunk/internal.h
    trunk/vm_insnhelper.c
Index: internal.h
===================================================================
--- internal.h	(revision 58389)
+++ internal.h	(revision 58390)
@@ -1421,6 +1421,7 @@ NORETURN(void rb_undefined_alloc(VALUE k https://github.com/ruby/ruby/blob/trunk/internal.h#L1421
 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;
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 58389)
+++ vm_insnhelper.c	(revision 58390)
@@ -2880,3 +2880,869 @@ vm_defined(rb_thread_t *th, rb_control_f https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2880
 	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) &&
 (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]