# HG changeset patch # User Lukas Stadler # Date 1354033960 -3600 # Node ID ccade022ec83b49f38d5b199dfef3dccdbb585d4 # Parent 2a1ec8b0bfe0eec1c788b33710bcf81d794e17cf virtualization of unsafeload and unsafestore diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Tue Nov 27 17:32:40 2012 +0100 @@ -234,4 +234,12 @@ * Returns the {@link java.lang.Class} object representing this type. */ Class< ? > toJava(); + + /** + * Returns the instance field of this class (or one of its super classes) at the given offset, or {@code null} if there is no such field. + * + * @param offset the offset of the field to look for + * @return the field with the given offset, or {@code null} if there is no such field. + */ + ResolvedJavaField findFieldWithOffset(long offset); } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java Tue Nov 27 17:32:40 2012 +0100 @@ -466,4 +466,15 @@ public long prototypeMarkWord() { return HotSpotGraalRuntime.getInstance().getCompilerToVM().getPrototypeMarkWord(this); } + + @Override + public ResolvedJavaField findFieldWithOffset(long offset) { + ResolvedJavaField[] declaredFields = getInstanceFields(true); + for (ResolvedJavaField field : declaredFields) { + if (((HotSpotResolvedJavaField) field).offset() == offset) { + return field; + } + } + return null; + } } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java Tue Nov 27 17:32:40 2012 +0100 @@ -182,4 +182,9 @@ @Override public void initialize() { } + + @Override + public ResolvedJavaField findFieldWithOffset(long offset) { + return null; + } } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -26,12 +26,13 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * Load of a value from a location specified as an offset relative to an object. * No null check is performed before the load. */ -public class UnsafeLoadNode extends FixedWithNextNode implements Lowerable { +public class UnsafeLoadNode extends FixedWithNextNode implements Lowerable, Virtualizable { @Input private ValueNode object; @Input private ValueNode offset; @@ -75,6 +76,26 @@ tool.getRuntime().lower(this, tool); } + @Override + public void virtualize(VirtualizerTool tool) { + VirtualObjectNode virtual = tool.getVirtualState(object()); + if (virtual != null) { + ValueNode indexValue = tool.getReplacedValue(offset()); + if (indexValue.isConstant()) { + int fieldIndex = virtual.fieldIndexForOffset(indexValue.asConstant().asLong()); + if (fieldIndex != -1) { + ValueNode result = tool.getVirtualEntry(virtual, fieldIndex); + VirtualObjectNode virtualResult = tool.getVirtualState(result); + if (virtualResult != null) { + tool.replaceWithVirtual(virtualResult); + } else { + tool.replaceWithValue(result); + } + } + } + } + } + @NodeIntrinsic public static native T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind kind); diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -26,12 +26,13 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * Store of a value at a location specified as an offset relative to an object. * No null check is performed before the store. */ -public class UnsafeStoreNode extends FixedWithNextNode implements StateSplit, Lowerable { +public class UnsafeStoreNode extends FixedWithNextNode implements StateSplit, Lowerable, Virtualizable { @Input private ValueNode object; @Input private ValueNode offset; @@ -96,6 +97,21 @@ tool.getRuntime().lower(this, tool); } + @Override + public void virtualize(VirtualizerTool tool) { + VirtualObjectNode virtual = tool.getVirtualState(object()); + if (virtual != null) { + ValueNode indexValue = tool.getReplacedValue(offset()); + if (indexValue.isConstant()) { + int fieldIndex = virtual.fieldIndexForOffset(indexValue.asConstant().asLong()); + if (fieldIndex != -1) { + tool.setVirtualEntry(virtual, fieldIndex, value()); + tool.delete(); + } + } + } + } + // specialized on value type until boxing/unboxing is sorted out in intrinsification @NodeIntrinsic public static native void store(Object object, @ConstantNodeParameter int displacement, long offset, Object value, @ConstantNodeParameter Kind kind); diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -58,4 +58,10 @@ assert index == 0; return "value"; } + + @Override + public int fieldIndexForOffset(long constantOffset) { + // (lstadler) unsafe access to a newly created boxing object should only ever touch the value field + return 0; + } } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.virtual; +import sun.misc.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; @@ -70,4 +72,59 @@ public String fieldName(int index) { return "[" + index + "]"; } + + @Override + public int fieldIndexForOffset(long constantOffset) { + int baseOffset; + int indexScale; + switch (componentType.getKind()) { + case Boolean: + baseOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + indexScale = Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + break; + case Byte: + baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET; + indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE; + break; + case Short: + baseOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET; + indexScale = Unsafe.ARRAY_SHORT_INDEX_SCALE; + break; + case Char: + baseOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET; + indexScale = Unsafe.ARRAY_CHAR_INDEX_SCALE; + break; + case Int: + baseOffset = Unsafe.ARRAY_INT_BASE_OFFSET; + indexScale = Unsafe.ARRAY_INT_INDEX_SCALE; + break; + case Long: + baseOffset = Unsafe.ARRAY_LONG_BASE_OFFSET; + indexScale = Unsafe.ARRAY_LONG_INDEX_SCALE; + break; + case Float: + baseOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET; + indexScale = Unsafe.ARRAY_FLOAT_INDEX_SCALE; + break; + case Double: + baseOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + indexScale = Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + break; + case Object: + baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET; + indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE; + break; + default: + return -1; + } + long index = constantOffset - baseOffset; + if (index % indexScale != 0) { + return -1; + } + long elementIndex = index / indexScale; + if (elementIndex < 0 || elementIndex >= length) { + return -1; + } + return (int) elementIndex; + } } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -75,4 +75,9 @@ Integer index = fieldMap.get(field); return index == null ? -1 : index; } + + @Override + public int fieldIndexForOffset(long constantOffset) { + return fieldIndex(type.findFieldWithOffset(constantOffset)); + } } diff -r 2a1ec8b0bfe0 -r ccade022ec83 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Tue Nov 27 17:29:42 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Tue Nov 27 17:32:40 2012 +0100 @@ -57,4 +57,6 @@ public void materializeAt(@SuppressWarnings("unused") FixedNode fixed) { // nothing to do in here - this method allows subclasses to respond to materialization } + + public abstract int fieldIndexForOffset(long constantOffset); }