Issue #12274 has been updated by Koichi Sasada.


Tarui-san suggested another way to optimize and this is my version of that technique (with some refactoring).

evaluation result:
fps: 19.21335880758348
->
fps: 22.16285461090967
(15% improvement)

```
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 54552)
+++ vm_insnhelper.c	(working copy)
@@ -778,45 +778,47 @@
 vm_getivar(VALUE obj, ID id, IC ic, struct rb_call_cache *cc, int is_attr)
 {
 #if USE_IC_FOR_IVAR
-    if (RB_TYPE_P(obj, T_OBJECT)) {
-	VALUE val = Qundef;
-	VALUE klass = RBASIC(obj)->klass;
+    VALUE klass = RBASIC(obj)->klass;
+    VALUE val;
+
+    if (LIKELY(is_attr ? cc->aux.index > 0 : ic->ic_serial == RCLASS_SERIAL(klass))) {
 	const long len = ROBJECT_NUMIV(obj);
 	const VALUE *const ptr = ROBJECT_IVPTR(obj);
+	long index = !is_attr ? (long)ic->ic_value.index : (long)(cc->aux.index - 1);
 
-	if (LIKELY(is_attr ? cc->aux.index > 0 : ic->ic_serial == RCLASS_SERIAL(klass))) {
-	    long index = !is_attr ? (long)ic->ic_value.index : (long)(cc->aux.index - 1);
-
-	    if (index < len) {
-		val = ptr[index];
-	    }
+	if (index < len && (val = ptr[index]) != Qundef) {
+	    return val;
 	}
-	else {
-	    st_data_t index;
-	    struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
+	goto undefined;
+    }
+    else if (RB_TYPE_P(obj, T_OBJECT)) {
+	const long len = ROBJECT_NUMIV(obj);
+	const VALUE *const ptr = ROBJECT_IVPTR(obj);
+	st_data_t index;
+	struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
+	val = Qundef;
 
-	    if (iv_index_tbl) {
-		if (st_lookup(iv_index_tbl, id, &index)) {
-		    if ((long)index < len) {
-			val = ptr[index];
-		    }
-		    if (!is_attr) {
-			ic->ic_value.index = index;
-			ic->ic_serial = RCLASS_SERIAL(klass);
-		    }
-		    else { /* call_info */
-			cc->aux.index = (int)index + 1;
-		    }
+	if (iv_index_tbl) {
+	    if (st_lookup(iv_index_tbl, id, &index)) {
+		if (!is_attr) {
+		    ic->ic_value.index = index;
+		    ic->ic_serial = RCLASS_SERIAL(klass);
 		}
+		else { /* call_info */
+		    cc->aux.index = (int)index + 1;
+		}
+
+		if ((long)index < len && (val = ptr[index]) != Qundef) {
+		    return val;
+		}
 	    }
 	}
 
-	if (UNLIKELY(val == Qundef)) {
-	    if (!is_attr && RTEST(ruby_verbose))
-		rb_warning("instance variable %"PRIsVALUE" not initialized", QUOTE_ID(id));
-	    val = Qnil;
+      undefined:
+	if (!is_attr && RTEST(ruby_verbose)) {
+	    rb_warning("instance variable %"PRIsVALUE" not initialized", QUOTE_ID(id));
 	}
-	return val;
+	return Qnil;
     }
 #endif	/* USE_IC_FOR_IVAR */
     if (is_attr)
```


----------------------------------------
Bug #12274: accessing to instance variable should be fast.
https://bugs.ruby-lang.org/issues/12274#change-58030

* Author: Masaya Tarui
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: ruby 2.4.0dev (2016-04-12 trunk 54553) [x86_64-linux]
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------

Currently, accessing to instance variable is quite slower than accessing to local variable.
I think accessing to instance variable is basic operation and it should be fast, so tried to improve.

patch: https://github.com/tarui/ruby/commit/dd993da80c7ad84340689137bf8b308793595cae

On mame's optcarrot benchmark, (https://github.com/mame/optcarrot/)
it is 10%(!) faster than trunk.
It increases in the maintenance cost a little, but can I commit it?

$ ./ruby -v --disable-gems ../../optcarrot/bin/optcarrot --benchmark ../../optcarrot/examples/Lan_Master.nes
ruby 2.4.0dev (2016-04-12 trunk 54553) [x86_64-linux]
fps: 13.664029283085743
checksum: 59662

$ ./ruby -v --disable-gems ../../optcarrot/bin/optcarrot --benchmark ../../optcarrot/examples/Lan_Master.nes
ruby 2.4.0dev (2016-04-12 fast-ivar-access 54553) [x86_64-linux]
fps: 15.120651593726231
checksum: 59662



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>