# HG changeset patch # User Thomas Wuerthinger # Date 1373291664 -7200 # Node ID 192a3b3c7292b46319fab496341acf7bb082c359 # Parent b6e46324233f3f64682b91ae024607fdccddd149# Parent 87c441b324e9152b946e68c869f17cfe34fdef9a Merge. diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Mon Jul 08 15:54:24 2013 +0200 @@ -24,9 +24,10 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public abstract class UnsafeAccessNode extends FixedWithNextNode { +public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable { @Input private ValueNode object; @Input private ValueNode offset; @@ -57,4 +58,38 @@ public Kind accessKind() { return accessKind; } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (offset().isConstant()) { + long constantOffset = offset().asConstant().asLong(); + + // Try to canonicalize to a field access. + if (object().stamp() instanceof ObjectStamp) { + // TODO (gd) remove that once UnsafeAccess only have an object base + ObjectStamp receiverStamp = object().objectStamp(); + ResolvedJavaType receiverType = receiverStamp.type(); + ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement() + constantOffset); + + // No need for checking that the receiver is non-null. The field access includes the + // null check and if a field is found, the offset is so small that this is never a + // valid access of an arbitrary address. + if (field != null && field.getKind() == this.accessKind()) { + return cloneAsFieldAccess(field); + } + } + + if (constantOffset != 0 && Integer.MAX_VALUE - displacement() >= constantOffset) { + int intDisplacement = (int) (constantOffset + displacement()); + if (constantOffset == intDisplacement) { + return cloneWithZeroOffset(intDisplacement); + } + } + } + return this; + } + + protected abstract ValueNode cloneAsFieldAccess(ResolvedJavaField field); + + protected abstract ValueNode cloneWithZeroOffset(int intDisplacement); } diff -r 87c441b324e9 -r 192a3b3c7292 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 Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Mon Jul 08 15:54:24 2013 +0200 @@ -25,7 +25,6 @@ import static com.oracle.graal.graph.UnsafeAccess.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @@ -35,7 +34,7 @@ * 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 UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable { +public class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable { public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, boolean nonNull) { this(nonNull ? StampFactory.objectNonNull() : StampFactory.object(), object, displacement, offset, Kind.Object); @@ -70,29 +69,13 @@ } @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (offset().isConstant()) { - long constantOffset = offset().asConstant().asLong(); - if (constantOffset != 0) { - int intDisplacement = (int) (constantOffset + displacement()); - if (constantOffset == intDisplacement) { - Graph graph = this.graph(); - return graph.add(new UnsafeLoadNode(this.stamp(), object(), intDisplacement, graph.unique(ConstantNode.forInt(0, graph)), accessKind())); - } - } else if (object().stamp() instanceof ObjectStamp) { // TODO (gd) remove that once - // UnsafeAccess only have an - // object base - ObjectStamp receiverStamp = object().objectStamp(); - ResolvedJavaType receiverType = receiverStamp.type(); - if (receiverStamp.nonNull() && receiverType != null) { - ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement()); - if (field != null) { - return this.graph().add(new LoadFieldNode(object(), field)); - } - } - } - } - return this; + protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) { + return this.graph().add(new LoadFieldNode(object(), field)); + } + + @Override + protected ValueNode cloneWithZeroOffset(int intDisplacement) { + return graph().add(new UnsafeLoadNode(this.stamp(), object(), intDisplacement, graph().unique(ConstantNode.forInt(0, graph())), accessKind())); } @SuppressWarnings("unchecked") diff -r 87c441b324e9 -r 192a3b3c7292 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 Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Mon Jul 08 15:54:24 2013 +0200 @@ -34,7 +34,7 @@ * 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 UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable, MemoryCheckpoint.Single { +public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -94,32 +94,17 @@ } @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (offset().isConstant()) { - long constantOffset = offset().asConstant().asLong(); - if (constantOffset != 0) { - int intDisplacement = (int) (constantOffset + displacement()); - if (constantOffset == intDisplacement) { - UnsafeStoreNode unsafeStoreNode = graph().add(new UnsafeStoreNode(stamp(), object(), intDisplacement, ConstantNode.forInt(0, graph()), value(), accessKind())); - unsafeStoreNode.setStateAfter(stateAfter()); - return unsafeStoreNode; - } - } else if (object().stamp() instanceof ObjectStamp) { // TODO (gd) remove that once - // UnsafeAccess only have an - // object base - ObjectStamp receiverStamp = object().objectStamp(); - if (receiverStamp.nonNull()) { - ResolvedJavaType receiverType = receiverStamp.type(); - ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement()); - if (field != null) { - StoreFieldNode storeFieldNode = graph().add(new StoreFieldNode(object(), field, value())); - storeFieldNode.setStateAfter(stateAfter()); - return storeFieldNode; - } - } - } - } - return this; + protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) { + StoreFieldNode storeFieldNode = graph().add(new StoreFieldNode(object(), field, value())); + storeFieldNode.setStateAfter(stateAfter()); + return storeFieldNode; + } + + @Override + protected ValueNode cloneWithZeroOffset(int intDisplacement) { + UnsafeStoreNode unsafeStoreNode = graph().add(new UnsafeStoreNode(stamp(), object(), intDisplacement, ConstantNode.forInt(0, graph()), value(), accessKind())); + unsafeStoreNode.setStateAfter(stateAfter()); + return unsafeStoreNode; } // specialized on value type until boxing/unboxing is sorted out in intrinsification diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Jul 08 15:54:24 2013 +0200 @@ -331,27 +331,7 @@ assert inlineable instanceof InlineableMacroNode; Class macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass(); - if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) { - assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static; - InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); - } - - FixedWithNextNode macroNode; - try { - macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke); - } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { - throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass); - } - - CallTargetNode callTarget = invoke.callTarget(); - if (invoke instanceof InvokeNode) { - graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode)); - } else { - InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - invokeWithException.killExceptionEdge(); - graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next()); - } - GraphUtil.killWithUnusedFloatingInputs(callTarget); + inlineMacroNode(invoke, concrete, graph, macroNodeClass); } InlinedBytecodes.add(concrete.getCodeSize()); @@ -1480,4 +1460,29 @@ public static Class getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) { return replacements.getMacroSubstitution(target); } + + public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, StructuredGraph graph, Class macroNodeClass) throws GraalInternalError { + if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) { + assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static; + InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); + } + + FixedWithNextNode macroNode; + try { + macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke); + } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { + throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass); + } + + CallTargetNode callTarget = invoke.callTarget(); + if (invoke instanceof InvokeNode) { + graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode)); + } else { + InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; + invokeWithException.killExceptionEdge(); + graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next()); + } + GraphUtil.killWithUnusedFloatingInputs(callTarget); + return macroNode; + } } diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 08 15:54:24 2013 +0200 @@ -260,7 +260,7 @@ @Override public boolean visit(Node node) { - if (node instanceof RootNode && node != root) { + if (node instanceof RootNode && visitedCount > 0) { return false; } diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Mon Jul 08 15:54:24 2013 +0200 @@ -26,7 +26,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.common.*; @@ -68,41 +67,8 @@ return ConstantNode.forObject(value, metaAccessProvider, node.graph()); } } - } else if (node instanceof UnsafeLoadNode) { - UnsafeLoadNode unsafeLoadNode = (UnsafeLoadNode) node; - if (unsafeLoadNode.offset().isConstant()) { - long offset = unsafeLoadNode.offset().asConstant().asLong() + unsafeLoadNode.displacement(); - ResolvedJavaType type = unsafeLoadNode.object().objectStamp().type(); - ResolvedJavaField field = recursiveFindFieldWithOffset(type, offset); - if (field != null) { - return node.graph().add(new LoadFieldNode(unsafeLoadNode.object(), field)); - } - } - } else if (node instanceof UnsafeStoreNode) { - UnsafeStoreNode unsafeStoreNode = (UnsafeStoreNode) node; - if (unsafeStoreNode.offset().isConstant()) { - long offset = unsafeStoreNode.offset().asConstant().asLong() + unsafeStoreNode.displacement(); - ResolvedJavaType type = unsafeStoreNode.object().objectStamp().type(); - ResolvedJavaField field = recursiveFindFieldWithOffset(type, offset); - if (field != null) { - StoreFieldNode storeFieldNode = node.graph().add(new StoreFieldNode(unsafeStoreNode.object(), field, unsafeStoreNode.value())); - storeFieldNode.setStateAfter(unsafeStoreNode.stateAfter()); - return storeFieldNode; - } - } } return node; } - - private ResolvedJavaField recursiveFindFieldWithOffset(ResolvedJavaType type, long offset) { - if (type != null) { - ResolvedJavaField field = type.findInstanceFieldWithOffset(offset); - if (field != null) { - return field; - } - return recursiveFindFieldWithOffset(type.getSuperclass(), offset); - } - return null; - } } diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Mon Jul 08 15:54:24 2013 +0200 @@ -216,25 +216,25 @@ if (invoke.callTarget() instanceof MethodCallTargetNode) { final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget(); if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && - !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) { - if (methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) != null) { - // Do not inline explode loop methods, they need canonicalization and forced - // unrolling. - return invoke.asNode(); - } - StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable() { + !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null) { + Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); + if (macroSubstitution != null) { + return InliningUtil.inlineMacroNode(invoke, methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution); + } else { + StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable() { - public StructuredGraph call() { - StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); - if (inlineGraph == null) { - inlineGraph = parseGraph(methodCallTargetNode.targetMethod()); + public StructuredGraph call() { + StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null) { + inlineGraph = parseGraph(methodCallTargetNode.targetMethod()); + } + return inlineGraph; } - return inlineGraph; - } - }); - FixedNode fixedNode = (FixedNode) invoke.predecessor(); - InliningUtil.inline(invoke, inlinedGraph, true); - return fixedNode; + }); + FixedNode fixedNode = (FixedNode) invoke.predecessor(); + InliningUtil.inline(invoke, inlinedGraph, true); + return fixedNode; + } } } return invoke.asNode(); diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/UnsafeCastMacroNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/UnsafeCastMacroNode.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/UnsafeCastMacroNode.java Mon Jul 08 15:54:24 2013 +0200 @@ -41,7 +41,10 @@ Class c = (Class) arguments.get(1).asConstant().asObject(); ResolvedJavaType lookupJavaType = tool.runtime().lookupJavaType(c); Stamp s = StampFactory.declaredNonNull(lookupJavaType); - return graph().unique(new UnsafeCastNode(arguments.get(0), s)); + ValueAnchorNode valueAnchorNode = graph().add(new ValueAnchorNode()); + UnsafeCastNode unsafeCast = graph().unique(new UnsafeCastNode(arguments.get(0), s, (GuardingNode) valueAnchorNode)); + this.replaceAtUsages(unsafeCast); + return valueAnchorNode; } return this; } diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Mon Jul 08 15:54:24 2013 +0200 @@ -57,4 +57,7 @@ @MacroSubstitution(macro = BailoutNode.class, isStatic = true) public static native void bailout(String reason); + + @MacroSubstitution(macro = UnsafeCastMacroNode.class, isStatic = true) + public static native Object unsafeCast(Object value, Class clazz); } diff -r 87c441b324e9 -r 192a3b3c7292 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Mon Jul 08 14:34:45 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Mon Jul 08 15:54:24 2013 +0200 @@ -126,4 +126,17 @@ @Target({ElementType.METHOD}) public @interface Unsafe { } + + /** + * Treats the given value as a value of the given class. The class must evaluate to a constant. + * + * @param value the value that is known to have the specified type + * @param clazz the specified type of the value + * @return the value + */ + @SuppressWarnings("unchecked") + @Unsafe + public static T unsafeCast(Object value, Class clazz) { + return (T) value; + } }