Created
December 17, 2011 18:04
-
-
Save headius/1490893 to your computer and use it in GitHub Desktop.
Two attempts to make instance vars volatile. The ARA version is 10-15% slower, and Unsafe version is 5-10% slower.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/org/jruby/RubyBasicObject.java b/src/org/jruby/RubyBasicObject.java | |
index 3bdc916..952c400 100644 | |
--- a/src/org/jruby/RubyBasicObject.java | |
+++ b/src/org/jruby/RubyBasicObject.java | |
@@ -37,6 +37,7 @@ import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.concurrent.atomic.AtomicBoolean; | |
+import java.util.concurrent.atomic.AtomicReferenceArray; | |
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; | |
import org.jruby.anno.JRubyMethod; | |
@@ -112,7 +113,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
protected int flags; | |
// variable table, lazily allocated as needed (if needed) | |
- private transient volatile Object[] varTable; | |
+ private transient volatile AtomicReferenceArray<Object> varTable; | |
/** | |
* The error message used when some one tries to modify an | |
@@ -1215,27 +1216,27 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
/** | |
* Get variable table for read purposes. May return null if uninitialized. | |
*/ | |
- protected final Object[] getVariableTableForRead() { | |
+ protected final AtomicReferenceArray<Object> getVariableTableForRead() { | |
return varTable; | |
} | |
private static final AtomicReferenceFieldUpdater VARTABLE_UPDATER = | |
- AtomicReferenceFieldUpdater.newUpdater(RubyBasicObject.class, Object[].class, "varTable"); | |
+ AtomicReferenceFieldUpdater.newUpdater(RubyBasicObject.class, AtomicReferenceArray.class, "varTable"); | |
/** | |
* Get variable table for write purposes. Initializes if uninitialized, and | |
* resizes if necessary. | |
*/ | |
- protected final Object[] getVariableTableForWrite(int index) { | |
+ protected final AtomicReferenceArray<Object> getVariableTableForWrite(int index) { | |
while (true) { | |
- Object[] myVarTable = varTable; | |
- Object[] newTable; | |
+ AtomicReferenceArray<Object> myVarTable = varTable; | |
+ AtomicReferenceArray<Object> newTable; | |
if (myVarTable == null) { | |
- newTable = new Object[getMetaClass().getRealClass().getVariableTableSizeWithExtras()]; | |
- } else if (myVarTable.length <= index) { | |
- newTable = new Object[getMetaClass().getRealClass().getVariableTableSizeWithExtras()]; | |
- System.arraycopy(myVarTable, 0, newTable, 0, myVarTable.length); | |
+ newTable = new AtomicReferenceArray<Object>(getMetaClass().getRealClass().getVariableTableSizeWithExtras()); | |
+ } else if (myVarTable.length() <= index) { | |
+ newTable = new AtomicReferenceArray<Object>(getMetaClass().getRealClass().getVariableTableSizeWithExtras()); | |
+ for (int i = 0; i < myVarTable.length(); i++) newTable.set(i, myVarTable.get(i)); | |
} else { | |
return myVarTable; | |
} | |
@@ -1248,23 +1249,23 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
} | |
public Object getVariable(int index) { | |
- Object[] ivarTable; | |
+ AtomicReferenceArray<Object> ivarTable; | |
if (index < 0 || (ivarTable = getVariableTableForRead()) == null) return null; | |
- if (ivarTable.length > index) return ivarTable[index]; | |
+ if (ivarTable.length() > index) return ivarTable.get(index); | |
return null; | |
} | |
public void setVariable(int index, Object value) { | |
ensureInstanceVariablesSettable(); | |
if (index < 0) return; | |
- Object[] ivarTable = getVariableTableForWrite(index); | |
- ivarTable[index] = value; | |
+ AtomicReferenceArray<Object> ivarTable = getVariableTableForWrite(index); | |
+ ivarTable.set(index, value); | |
} | |
private void setObjectId(int index, long value) { | |
if (index < 0) return; | |
- Object[] ivarTable = getVariableTableForWrite(index); | |
- ivarTable[index] = value; | |
+ AtomicReferenceArray<Object> ivarTable = getVariableTableForWrite(index); | |
+ ivarTable.set(index, value); | |
} | |
public final Object getNativeHandle() { | |
@@ -1273,8 +1274,8 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
public final void setNativeHandle(Object value) { | |
int index = getMetaClass().getRealClass().getNativeHandleAccessorForWrite().getIndex(); | |
- Object[] ivarTable = getVariableTableForWrite(index); | |
- ivarTable[index] = value; | |
+ AtomicReferenceArray<Object> ivarTable = getVariableTableForWrite(index); | |
+ ivarTable.set(index, value); | |
} | |
// | |
@@ -1293,7 +1294,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
*/ | |
public boolean hasVariables() { | |
// we check both to exclude object_id | |
- return getMetaClass().getRealClass().getVariableTableSize() > 0 && varTable != null && varTable.length > 0; | |
+ return getMetaClass().getRealClass().getVariableTableSize() > 0 && varTable != null && varTable.length() > 0; | |
} | |
/** | |
@@ -1303,7 +1304,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
@Deprecated | |
public int getVariableCount() { | |
// we use min to exclude object_id | |
- return varTable == null ? 0 : Math.min(varTable.length, getMetaClass().getRealClass().getVariableTableSize()); | |
+ return varTable == null ? 0 : Math.min(varTable.length(), getMetaClass().getRealClass().getVariableTableSize()); | |
} | |
/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/org/jruby/RubyBasicObject.java b/src/org/jruby/RubyBasicObject.java | |
index 3bdc916..d5607c7 100644 | |
--- a/src/org/jruby/RubyBasicObject.java | |
+++ b/src/org/jruby/RubyBasicObject.java | |
@@ -66,6 +66,7 @@ import org.jruby.util.IdUtil; | |
import org.jruby.util.TypeConverter; | |
import org.jruby.util.log.Logger; | |
import org.jruby.util.log.LoggerFactory; | |
+import org.jruby.util.unsafe.UnsafeGetter; | |
import static org.jruby.javasupport.util.RuntimeHelpers.invokedynamic; | |
import static org.jruby.runtime.MethodIndex.OP_EQUAL; | |
@@ -114,6 +115,38 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
// variable table, lazily allocated as needed (if needed) | |
private transient volatile Object[] varTable; | |
+ // unsafe logic for volatile updates to var table | |
+ private static final sun.misc.Unsafe unsafe; | |
+ static { | |
+ sun.misc.Unsafe _unsafe; | |
+ try { | |
+ _unsafe = UnsafeGetter.getUnsafe(); | |
+ } catch (UnsafeGetter.UnsafeInaccessibleException x) { | |
+ _unsafe = null; | |
+ } | |
+ unsafe = _unsafe; | |
+ } | |
+ private static final int base = unsafe.arrayBaseOffset(Object[].class); | |
+ private static final int shift; | |
+ | |
+ static { | |
+ int scale = unsafe.arrayIndexScale(Object[].class); | |
+ if ((scale & (scale - 1)) != 0) | |
+ throw new Error("data type scale not a power of two"); | |
+ shift = 31 - Integer.numberOfLeadingZeros(scale); | |
+ } | |
+ | |
+ private long checkedByteOffset(int i) { | |
+ if (i < 0 || i >= varTable.length) | |
+ throw new IndexOutOfBoundsException("index " + i); | |
+ | |
+ return byteOffset(i); | |
+ } | |
+ | |
+ private static long byteOffset(int i) { | |
+ return ((long) i << shift) + base; | |
+ } | |
+ | |
/** | |
* The error message used when some one tries to modify an | |
* instance variable in a high security setting. | |
@@ -1250,7 +1283,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
public Object getVariable(int index) { | |
Object[] ivarTable; | |
if (index < 0 || (ivarTable = getVariableTableForRead()) == null) return null; | |
- if (ivarTable.length > index) return ivarTable[index]; | |
+ if (ivarTable.length > index) return unsafe.getObjectVolatile(varTable, checkedByteOffset(index)); | |
return null; | |
} | |
@@ -1258,7 +1291,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co | |
ensureInstanceVariablesSettable(); | |
if (index < 0) return; | |
Object[] ivarTable = getVariableTableForWrite(index); | |
- ivarTable[index] = value; | |
+ unsafe.putObjectVolatile(varTable, checkedByteOffset(index), value); | |
} | |
private void setObjectId(int index, long value) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment