# HG changeset patch # User Thomas Wuerthinger # Date 1429709813 -7200 # Node ID 056f90577ed1e529fca8c369045bca36da312b1e # Parent 0a3bc68fc3a75a71e2c9c68116fc4d7b226af02b# Parent 8f67ddf0dd3b73ddba47c33812fac32bd88b9731 Merge. diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Wed Apr 22 15:36:53 2015 +0200 @@ -132,10 +132,31 @@ public static final int INVALID_FRAMESTATE_BCI = -6; /** - * Determines if a given BCI matches one of the synthetic BCI contants defined in this class. + * Determines if a given BCI matches one of the placeholder BCI constants defined in this class. + */ + public static boolean isPlaceholderBci(int bci) { + return bci < 0; + } + + /** + * Gets the name of a given placeholder BCI. */ - public static boolean isSyntheticBci(int bci) { - return bci < 0; + public static String getPlaceholderBciName(int bci) { + assert isPlaceholderBci(bci); + if (bci == BytecodeFrame.AFTER_BCI) { + return "AFTER_BCI"; + } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + return "AFTER_EXCEPTION_BCI"; + } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + return "INVALID_FRAMESTATE_BCI"; + } else if (bci == BytecodeFrame.BEFORE_BCI) { + return "BEFORE_BCI"; + } else if (bci == BytecodeFrame.UNKNOWN_BCI) { + return "UNKNOWN_BCI"; + } else { + assert bci == BytecodeFrame.UNWIND_BCI; + return "UNWIND_BCI"; + } } /** diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java Wed Apr 22 15:36:53 2015 +0200 @@ -41,9 +41,22 @@ public final class MethodSubstitutionPlugin implements InvocationPlugin { private ResolvedJavaMethod cachedSubstitute; + + /** + * The class in which the substitute method is declared. + */ private final Class declaringClass; + + /** + * The name of the original and substitute method. + */ private final String name; + + /** + * The parameter types of the substitute method. + */ private final Class[] parameters; + private final boolean originalIsStatic; /** @@ -62,6 +75,20 @@ this.originalIsStatic = parameters.length == 0 || parameters[0] != Receiver.class; } + /** + * Creates a method substitution plugin. + * + * @param declaringClass the class in which the substitute method is declared + * @param name the name of the substitute method + * @param parameters the parameter types of the substitute method + */ + public MethodSubstitutionPlugin(boolean originalIsStatic, Class declaringClass, String name, Class... parameters) { + this.declaringClass = declaringClass; + this.name = name; + this.parameters = parameters; + this.originalIsStatic = originalIsStatic; + } + public boolean inlineOnly() { // Conservatively assume MacroNodes may be used in a substitution return true; diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Apr 22 15:36:53 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.api.code.BytecodeFrame.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; @@ -60,7 +62,7 @@ @Override protected BytecodeFrame computeFrameForState(FrameState state) { - assert state.bci >= 0 || state.bci == BytecodeFrame.BEFORE_BCI : state.bci; + assert !isPlaceholderBci(state.bci) || state.bci == BytecodeFrame.BEFORE_BCI : state.bci; return super.computeFrameForState(state); } } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Apr 22 15:36:53 2015 +0200 @@ -38,7 +38,6 @@ import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.nodes.ClassQueryNode.Query; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.replacements.arraycopy.*; import com.oracle.graal.hotspot.word.*; @@ -79,7 +78,7 @@ plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin)); registerObjectPlugins(invocationPlugins); - registerClassPlugins(invocationPlugins); + registerClassPlugins(plugins); registerSystemPlugins(invocationPlugins, foreignCalls); registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config); registerCallSitePlugins(invocationPlugins); @@ -107,27 +106,16 @@ r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class); } - private static void registerClassPlugins(InvocationPlugins plugins) { - Registration r = new Registration(plugins, Class.class); + private static void registerClassPlugins(Plugins plugins) { + Registration r = new Registration(plugins.getInvocationPlugins(), Class.class); - for (Query query : Query.values()) { - r.register1(query.name(), Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - ValueNode javaClass = receiver.get(); - ValueNode folded = ClassQueryNode.tryFold(GraphUtil.originalValue(javaClass), query, b.getMetaAccess(), b.getConstantReflection()); - if (folded != null) { - b.addPush(query.returnKind, folded); - } else { - b.addPush(query.returnKind, new ClassQueryNode(b.getInvokeKind(), targetMethod, query, b.bci(), b.getInvokeReturnType(), javaClass)); - } - return true; - } + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class); - public boolean inlineOnly() { - return true; - } - }); - } r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { ValueNode javaClass = receiver.get(); diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Wed Apr 22 15:36:53 2015 +0200 @@ -39,6 +39,7 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin; import com.oracle.graal.replacements.nodes.*; @@ -149,12 +150,21 @@ for (Node node : newNodes) { if (node.hasUsages() && node instanceof ConstantNode) { ConstantNode c = (ConstantNode) node; - if (c.getKind() == Kind.Object && !AheadOfTimeVerificationPhase.isLegalObjectConstant(c)) { - throw new AssertionError("illegal constant node in AOT: " + node); + if (c.getKind() == Kind.Object && AheadOfTimeVerificationPhase.isIllegalObjectConstant(c)) { + if (isClass(c)) { + // This will be handled later by LoadJavaMirrorWithKlassPhase + } else { + throw new AssertionError("illegal constant node in AOT: " + node); + } } } } } super.checkNewNodes(b, plugin, newNodes); } + + private static boolean isClass(ConstantNode node) { + ResolvedJavaType typeOrNull = StampTool.typeOrNull(node); + return typeOrNull != null && "Ljava/lang/Class;".equals(typeOrNull.getName()); + } } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassQueryNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassQueryNode.java Wed Apr 22 15:36:38 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * {@link MacroNode Macro node} for some basic query methods in {@link Class}. - */ -@NodeInfo -public final class ClassQueryNode extends MacroStateSplitNode implements Canonicalizable { - - /** - * The query methods in {@link Class} supported by {@link ClassQueryNode}. - */ - public enum Query { - getClassLoader0(Kind.Object), - getComponentType(Kind.Object), - getSuperclass(Kind.Object), - getModifiers(Kind.Int), - isArray(Kind.Boolean), - isInterface(Kind.Boolean), - isPrimitive(Kind.Boolean); - - private Query(Kind returnKind) { - this.returnKind = returnKind; - } - - public final Kind returnKind; - } - - public static final NodeClass TYPE = NodeClass.create(ClassQueryNode.class); - - protected final Query query; - - public ClassQueryNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, Query query, int bci, JavaType returnType, ValueNode receiver) { - super(TYPE, invokeKind, targetMethod, bci, returnType, receiver); - this.query = query; - assert query.returnKind == targetMethod.getSignature().getReturnKind(); - } - - private ValueNode getJavaClass() { - return arguments.get(0); - } - - @Override - public Node canonical(CanonicalizerTool tool) { - ValueNode value = tryFold(getJavaClass(), query, tool.getMetaAccess(), tool.getConstantReflection()); - return value == null ? this : value; - } - - public static ValueNode tryFold(ValueNode javaClass, Query query, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { - if (javaClass != null && javaClass.isConstant()) { - if (query.returnKind == Kind.Object) { - if (GraalOptions.ImmutableCode.getValue()) { - return null; - } - HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant(); - JavaConstant answer; - switch (query) { - case getClassLoader0: - answer = c.getClassLoader(); - break; - case getComponentType: - answer = c.getComponentType(); - break; - case getSuperclass: - answer = c.getSuperclass(); - break; - default: - GraalInternalError.shouldNotReachHere(); - answer = null; - } - if (answer != null) { - return ConstantNode.forConstant(answer, metaAccess); - } - } else { - ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant()); - if (type != null) { - switch (query) { - case isArray: - return ConstantNode.forBoolean(type.isArray()); - case isPrimitive: - return ConstantNode.forBoolean(type.isPrimitive()); - case isInterface: - return ConstantNode.forBoolean(type.isInterface()); - case getModifiers: - return ConstantNode.forInt(type.getModifiers()); - default: - GraalInternalError.shouldNotReachHere(); - } - } - } - } - return null; - } -} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java Wed Apr 22 15:36:53 2015 +0200 @@ -22,13 +22,14 @@ */ package com.oracle.graal.hotspot.nodes; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @NodeInfo -public class G1PostWriteBarrier extends WriteBarrier { +public class G1PostWriteBarrier extends WriteBarrier implements MemoryCheckpoint.Single { public static final NodeClass TYPE = NodeClass.create(G1PostWriteBarrier.class); protected final boolean alwaysNull; @@ -45,4 +46,8 @@ public boolean alwaysNull() { return alwaysNull; } + + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Wed Apr 22 15:36:53 2015 +0200 @@ -32,7 +32,7 @@ import com.oracle.graal.phases.tiers.*; /** - * Checks for {@link #isLegalObjectConstant(ConstantNode) illegal} object constants in a graph + * Checks for {@link #isIllegalObjectConstant(ConstantNode) illegal} object constants in a graph * processed for AOT compilation. * * @see LoadJavaMirrorWithKlassPhase @@ -42,14 +42,14 @@ @Override protected boolean verify(StructuredGraph graph, PhaseContext context) { for (ConstantNode node : getConstantNodes(graph)) { - if (isLegalObjectConstant(node)) { + if (isIllegalObjectConstant(node)) { throw new VerificationError("illegal object constant: " + node); } } return true; } - public static boolean isLegalObjectConstant(ConstantNode node) { + public static boolean isIllegalObjectConstant(ConstantNode node) { return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node); } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java Wed Apr 22 15:36:53 2015 +0200 @@ -26,7 +26,6 @@ import java.lang.reflect.*; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.nodes.*; import com.oracle.graal.word.*; @@ -34,10 +33,8 @@ /** * Substitutions for {@link java.lang.Class} methods. */ -@ClassSubstitution(java.lang.Class.class) public class HotSpotClassSubstitutions { - @MethodSubstitution(isStatic = false, forced = true) public static int getModifiers(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (klass.isNull()) { @@ -48,7 +45,6 @@ } } - @MethodSubstitution(isStatic = false, forced = true) public static boolean isInterface(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (klass.isNull()) { @@ -59,7 +55,6 @@ } } - @MethodSubstitution(isStatic = false, forced = true) public static boolean isArray(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (klass.isNull()) { @@ -69,15 +64,11 @@ } } - @MethodSubstitution(isStatic = false, forced = true) public static boolean isPrimitive(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); return klass.isNull(); } - public static native ClassLoader getClassLoader0(Class thisObj); - - @MethodSubstitution(isStatic = false) public static Class getSuperclass(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (!klass.isNull()) { @@ -102,7 +93,6 @@ return PiNode.asNonNullClass(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION)); } - @MethodSubstitution(isStatic = false) public static Class getComponentType(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (!klass.isNull()) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Wed Apr 22 15:36:53 2015 +0200 @@ -43,7 +43,6 @@ replacements.registerSubstitutions(System.class, SystemSubstitutions.class); replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class); replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class); - replacements.registerSubstitutions(Class.class, HotSpotClassSubstitutions.class); replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Apr 22 15:36:53 2015 +0200 @@ -124,7 +124,7 @@ frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); parser.build(graph.start(), frameState); - connectLoopEndToBegin(graph); + GraphUtil.normalizeLoops(graph); // Remove dead parameters. for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { @@ -2428,27 +2428,4 @@ assert assertionsEnabled = true; return assertionsEnabled; } - - /** - * Remove loop header without loop ends. This can happen with degenerated loops like this one: - * - *
-     * for (;;) {
-     *     try {
-     *         break;
-     *     } catch (UnresolvedException iioe) {
-     *     }
-     * }
-     * 
- */ - public static void connectLoopEndToBegin(StructuredGraph graph) { - for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) { - if (begin.loopEnds().isEmpty()) { - assert begin.forwardEndCount() == 1; - graph.reduceDegenerateLoopBegin(begin); - } else { - GraphUtil.normalizeLoopBegin(begin); - } - } - } } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Apr 22 15:36:53 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import static com.oracle.graal.api.code.BytecodeFrame.*; + import java.util.*; import com.oracle.graal.api.code.*; @@ -293,7 +295,7 @@ * is that a stateAfter is being transformed into a stateDuring, so the stack depth may change. */ private boolean checkStackDepth(int oldBci, int oldStackSize, boolean oldDuringCall, boolean oldRethrowException, int newBci, int newStackSize, boolean newDuringCall, boolean newRethrowException) { - if (BytecodeFrame.isSyntheticBci(oldBci)) { + if (BytecodeFrame.isPlaceholderBci(oldBci)) { return true; } /* @@ -449,18 +451,8 @@ properties.put("sourceLine", ste.getLineNumber()); } } - if (bci == BytecodeFrame.AFTER_BCI) { - properties.put("bci", "AFTER_BCI"); - } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { - properties.put("bci", "AFTER_EXCEPTION_BCI"); - } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { - properties.put("bci", "INVALID_FRAMESTATE_BCI"); - } else if (bci == BytecodeFrame.BEFORE_BCI) { - properties.put("bci", "BEFORE_BCI"); - } else if (bci == BytecodeFrame.UNKNOWN_BCI) { - properties.put("bci", "UNKNOWN_BCI"); - } else if (bci == BytecodeFrame.UNWIND_BCI) { - properties.put("bci", "UNWIND_BCI"); + if (isPlaceholderBci(bci)) { + properties.put("bci", getPlaceholderBciName(bci)); } properties.put("locksSize", values.size() - stackSize - localsSize); return properties; diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Wed Apr 22 15:36:53 2015 +0200 @@ -257,10 +257,14 @@ } public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) { - MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE); - decode(methodScope, null); - cleanupGraph(methodScope, null); - methodScope.graph.verify(); + try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) { + MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE); + decode(methodScope, null); + cleanupGraph(methodScope, null); + methodScope.graph.verify(); + } catch (Throwable ex) { + Debug.handle(ex); + } } protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) { @@ -287,6 +291,7 @@ assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1; loopScope = loopScope.nextIterations.removeFirst(); } else { + propagateCreatedNodes(loopScope); loopScope = loopScope.outer; } } @@ -303,6 +308,19 @@ } } + private static void propagateCreatedNodes(LoopScope loopScope) { + if (loopScope.outer == null) { + return; + } + + /* Register nodes that were created while decoding the loop to the outside scope. */ + for (int i = 0; i < loopScope.createdNodes.length; i++) { + if (loopScope.outer.createdNodes[i] == null) { + loopScope.outer.createdNodes[i] = loopScope.createdNodes[i]; + } + } + } + protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) { int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0); loopScope.nodesToProcess.clear(nodeOrderId); diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java Wed Apr 22 15:36:53 2015 +0200 @@ -442,9 +442,6 @@ } } - for (Node expectedNode : expectedGraph.getNodes()) { - assert nodeMapping.get(expectedNode) != null || (expectedNode.hasNoUsages() && !(expectedNode instanceof FixedNode)) : "expectedNode"; - } return true; } @@ -486,7 +483,19 @@ assert !actualIter.hasNext(); } - protected static void verifyNodeEqual(Node expectedNode, Node actualNode, NodeMap nodeMapping, Deque> workList, boolean ignoreEndNode) { + protected static void verifyNodeEqual(Node e, Node actualNode, NodeMap nodeMapping, Deque> workList, boolean ignoreEndNode) { + Node expectedNode = e; + if (expectedNode instanceof PhiNode) { + /* + * The input graph can contain unnecessary (eliminatable) phi functions. Such phis are + * not re-created during decoding, so we need to simplify the expected node too. + */ + Node singleValue = ((PhiNode) expectedNode).singleValue(); + if (singleValue != null && singleValue != PhiNode.MULTIPLE_VALUES) { + expectedNode = singleValue; + } + } + assert expectedNode.getClass() == actualNode.getClass(); if (ignoreEndNode && expectedNode instanceof EndNode) { return; diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Wed Apr 22 15:36:53 2015 +0200 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; + +/** + * Graph decoder that simplifies nodes during decoding. The standard + * {@link Canonicalizable#canonical node canonicalization} interface is used to canonicalize nodes + * during decoding. Additionally, {@link IfNode branches} and {@link IntegerSwitchNode switches} + * with constant conditions are simplified. + */ +public class SimplifyingGraphDecoder extends GraphDecoder { + + protected final MetaAccessProvider metaAccess; + protected final ConstantReflectionProvider constantReflection; + protected final StampProvider stampProvider; + protected final boolean canonicalizeReads; + + protected class PECanonicalizerTool implements CanonicalizerTool { + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public boolean canonicalizeReads() { + return canonicalizeReads; + } + + @Override + public boolean allUsagesAvailable() { + return false; + } + } + + public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, boolean canonicalizeReads, Architecture architecture) { + super(architecture); + this.metaAccess = metaAccess; + this.constantReflection = constantReflection; + this.stampProvider = stampProvider; + this.canonicalizeReads = canonicalizeReads; + } + + @Override + protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { + GraphUtil.normalizeLoops(methodScope.graph); + super.cleanupGraph(methodScope, start); + } + + @Override + protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { + if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + if (ifNode.condition() instanceof LogicNegationNode) { + ifNode.eliminateNegation(); + } + if (ifNode.condition() instanceof LogicConstantNode) { + boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); + AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); + AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); + + methodScope.graph.removeSplit(ifNode, survivingSuccessor); + assert deadSuccessor.next() == null : "must not be parsed yet"; + deadSuccessor.safeDelete(); + } + + } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { + IntegerSwitchNode switchNode = (IntegerSwitchNode) node; + int value = switchNode.value().asJavaConstant().asInt(); + AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value); + List allSuccessors = switchNode.successors().snapshot(); + + methodScope.graph.removeSplit(switchNode, survivingSuccessor); + for (Node successor : allSuccessors) { + if (successor != survivingSuccessor) { + assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet"; + successor.safeDelete(); + } + } + + } else if (node instanceof Canonicalizable) { + Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); + if (canonical == null) { + /* + * This is a possible return value of canonicalization. However, we might need to + * add additional usages later on for which we need a node. Therefore, we just do + * nothing and leave the node in place. + */ + } else if (canonical != node) { + if (!canonical.isAlive()) { + assert !canonical.isDeleted(); + canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + if (canonical instanceof FixedWithNextNode) { + methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical); + } else if (canonical instanceof ControlSinkNode) { + FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor(); + predecessor.setNext((ControlSinkNode) canonical); + node.safeDelete(); + for (Node successor : node.successors()) { + successor.safeDelete(); + } + + } else { + assert !(canonical instanceof FixedNode); + } + } + if (!node.isDeleted()) { + GraphUtil.unlinkFixedNode((FixedWithNextNode) node); + node.replaceAtUsages(canonical); + node.safeDelete(); + } + assert lookupNode(loopScope, nodeOrderId) == node; + registerNode(loopScope, nodeOrderId, canonical, true, false); + } + } + } + + @Override + protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) { + if (node instanceof Canonicalizable) { + Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); + if (canonical == null) { + /* + * This is a possible return value of canonicalization. However, we might need to + * add additional usages later on for which we need a node. Therefore, we just do + * nothing and leave the node in place. + */ + } else if (canonical != node) { + if (!canonical.isAlive()) { + assert !canonical.isDeleted(); + canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + } + assert node.hasNoUsages(); + // methodScope.graph.replaceFloating((FloatingNode) node, canonical); + return canonical; + } + } + return node; + } +} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Wed Apr 22 15:36:53 2015 +0200 @@ -80,7 +80,7 @@ ResolvedJavaType exactType = null; if (objectStamp.isExactType()) { exactType = objectStamp.type(); - } else if (objectStamp.type() != null && graph().getAssumptions() != null) { + } else if (objectStamp.type() != null && graph() != null && graph().getAssumptions() != null) { AssumptionResult leafConcreteSubtype = objectStamp.type().findLeafConcreteSubtype(); if (leafConcreteSubtype != null) { exactType = leafConcreteSubtype.getResult(); diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed Apr 22 15:36:53 2015 +0200 @@ -79,7 +79,7 @@ if (result != null) { return result; } - Assumptions assumptions = graph().getAssumptions(); + Assumptions assumptions = graph() == null ? null : graph().getAssumptions(); if (assumptions != null) { AssumptionResult leafConcreteSubtype = stampType.findLeafConcreteSubtype(); if (leafConcreteSubtype != null) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Wed Apr 22 15:36:53 2015 +0200 @@ -225,7 +225,30 @@ } } - public static void normalizeLoopBegin(LoopBeginNode begin) { + /** + * Remove loop header without loop ends. This can happen with degenerated loops like this one: + * + *
+     * for (;;) {
+     *     try {
+     *         break;
+     *     } catch (UnresolvedException iioe) {
+     *     }
+     * }
+     * 
+ */ + public static void normalizeLoops(StructuredGraph graph) { + for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) { + if (begin.loopEnds().isEmpty()) { + assert begin.forwardEndCount() == 1; + graph.reduceDegenerateLoopBegin(begin); + } else { + normalizeLoopBegin(begin); + } + } + } + + private static void normalizeLoopBegin(LoopBeginNode begin) { // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either // the same or the phi itself. for (PhiNode phi : begin.phis().snapshot()) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java Wed Apr 22 15:36:53 2015 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; + +/** + * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and + * encoding the graphs). + */ +public class CachingPEGraphDecoder extends PEGraphDecoder { + + private final Providers providers; + private final GraphBuilderConfiguration graphBuilderConfig; + private final OptimisticOptimizations optimisticOpts; + private final AllowAssumptions allowAssumptions; + private final Map graphCache; + + public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, Architecture architecture) { + super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture); + + this.providers = providers; + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; + this.allowAssumptions = allowAssumptions; + this.graphCache = new HashMap<>(); + } + + private EncodedGraph createGraph(ResolvedJavaMethod method) { + StructuredGraph graph = new StructuredGraph(method, allowAssumptions); + try (Debug.Scope scope = Debug.scope("createGraph", graph)) { + + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, optimisticOpts, null).apply(graph); + + PhaseContext context = new PhaseContext(providers); + new CanonicalizerPhase().apply(graph, context); + + EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture); + graphCache.put(method, encodedGraph); + return encodedGraph; + + } catch (Throwable ex) { + throw Debug.handle(ex); + } + } + + @Override + protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) { + EncodedGraph result = graphCache.get(method); + if (result == null && method.hasBytecodes()) { + result = createGraph(method); + } + return result; + } +} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Wed Apr 22 15:36:53 2015 +0200 @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.compiler.common.GraalInternalError.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; +import com.oracle.graal.java.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.inlining.*; + +/** + * A graph decoder that performs partial evaluation, i.e., that performs method inlining and + * canonicalization/simplification of nodes during decoding. + * + * Inlining and loop explosion are configured via the plugin mechanism also used by the + * {@link GraphBuilderPhase}. However, not all callback methods defined in + * {@link GraphBuilderContext} are available since decoding is more limited than graph building. + * + * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to + * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and + * {@link IntegerSwitchNode switches} with constant conditions are simplified. + */ +public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { + + protected class PEMethodScope extends MethodScope { + /** The state of the caller method. Only non-null during method inlining. */ + protected final PEMethodScope caller; + protected final LoopScope callerLoopScope; + protected final ResolvedJavaMethod method; + protected final InvokeData invokeData; + protected final int inliningDepth; + + protected final LoopExplosionPlugin loopExplosionPlugin; + protected final InvocationPlugins invocationPlugins; + protected final InlineInvokePlugin inlineInvokePlugin; + protected final ParameterPlugin parameterPlugin; + protected final ValueNode[] arguments; + + protected FrameState outerState; + protected FrameState exceptionState; + protected ExceptionPlaceholderNode exceptionPlaceholderNode; + protected BytecodePosition bytecodePosition; + + protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, + int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, + ValueNode[] arguments) { + super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); + + this.caller = caller; + this.callerLoopScope = callerLoopScope; + this.method = method; + this.invokeData = invokeData; + this.inliningDepth = inliningDepth; + this.loopExplosionPlugin = loopExplosionPlugin; + this.invocationPlugins = invocationPlugins; + this.inlineInvokePlugin = inlineInvokePlugin; + this.parameterPlugin = parameterPlugin; + this.arguments = arguments; + } + + public boolean isInlinedMethod() { + return caller != null; + } + } + + protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { + protected final PEMethodScope methodScope; + protected final Invoke invoke; + + public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { + this.methodScope = methodScope; + this.invoke = invoke; + } + + @Override + public BailoutException bailout(String string) { + throw new BailoutException(string); + } + + @Override + public StampProvider getStampProvider() { + return stampProvider; + } + + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public StructuredGraph getGraph() { + return methodScope.graph; + } + + @Override + public int getDepth() { + return methodScope.inliningDepth; + } + + @Override + public Replacement getReplacement() { + return null; + } + + @Override + public T append(T value) { + throw unimplemented(); + } + + @Override + public T recursiveAppend(T value) { + throw unimplemented(); + } + + @Override + public void push(Kind kind, ValueNode value) { + throw unimplemented(); + } + + @Override + public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { + throw unimplemented(); + } + + @Override + public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) { + throw unimplemented(); + } + + @Override + public FrameState createStateAfter() { + throw unimplemented(); + } + + @Override + public GraphBuilderContext getParent() { + throw unimplemented(); + } + + @Override + public ResolvedJavaMethod getMethod() { + throw unimplemented(); + } + + @Override + public int bci() { + return invoke.bci(); + } + + @Override + public InvokeKind getInvokeKind() { + throw unimplemented(); + } + + @Override + public JavaType getInvokeReturnType() { + throw unimplemented(); + } + } + + protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { + protected FixedWithNextNode lastInstr; + protected ValueNode pushedNode; + + public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { + super(inlineScope, inlineScope.invokeData.invoke); + this.lastInstr = lastInstr; + } + + @Override + public void push(Kind kind, ValueNode value) { + if (pushedNode != null) { + throw unimplemented("Only one push is supported"); + } + pushedNode = value; + } + + @Override + public FrameState createStateAfter() { + Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + getGraph().add(stateAfter); + return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + } + + @Override + public T append(T v) { + if (v.graph() != null) { + return v; + } + T added = getGraph().addOrUnique(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + @Override + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = getGraph().addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + private void updateLastInstruction(T v) { + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + } else { + lastInstr = null; + } + } + } + } + + @NodeInfo + static class ExceptionPlaceholderNode extends ValueNode { + public static final NodeClass TYPE = NodeClass.create(ExceptionPlaceholderNode.class); + + public ExceptionPlaceholderNode() { + super(TYPE, StampFactory.object()); + } + } + + public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) { + super(metaAccess, constantReflection, stampProvider, true, architecture); + } + + protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { + if (loopExplosionPlugin == null) { + return LoopExplosionKind.NONE; + } else if (loopExplosionPlugin.shouldMergeExplosions(method)) { + return LoopExplosionKind.MERGE_EXPLODE; + } else if (loopExplosionPlugin.shouldExplodeLoops(method)) { + return LoopExplosionKind.FULL_EXPLODE; + } else { + return LoopExplosionKind.NONE; + } + } + + public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, + ParameterPlugin parameterPlugin) { + PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, + parameterPlugin, null); + decode(methodScope, null); + cleanupGraph(methodScope, null); + methodScope.graph.verify(); + } + + @Override + protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) { + String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; + if (FailedLoopExplosionIsFatal.getValue()) { + throw new RuntimeException(message); + } else { + throw new BailoutException(message); + } + } + } + + @Override + protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { + PEMethodScope methodScope = (PEMethodScope) s; + + /* + * Decode the call target, but do not add it to the graph yet. This avoids adding usages for + * all the arguments, which are expensive to remove again when we can inline the method. + */ + assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; + CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); + if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) { + + /* We know that we need an invoke, so now we can add the call target to the graph. */ + methodScope.graph.add(callTarget); + registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); + super.handleInvoke(methodScope, loopScope, invokeData); + } + } + + protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + // attempt to devirtualize the call + ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType); + if (specialCallTarget != null) { + callTarget.setTargetMethod(specialCallTarget); + callTarget.setInvokeKind(InvokeKind.Special); + } + + if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { + return true; + } + if (tryInline(methodScope, loopScope, invokeData, callTarget)) { + return true; + } + + if (methodScope.inlineInvokePlugin != null) { + methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); + } + return false; + } + + protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + if (methodScope.invocationPlugins == null) { + return false; + } + + Invoke invoke = invokeData.invoke; + + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); + if (invocationPlugin == null) { + return false; + } + + ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); + FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); + + /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */ + invoke.asNode().replaceAtPredecessor(null); + + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, + methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); + InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); + + if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { + + if (graphBuilderContext.lastInstr != null) { + registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); + invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); + graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); + } else { + assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; + invoke.asNode().replaceAtUsages(null); + } + + deleteInvoke(invoke); + return true; + + } else { + /* Intrinsification failed, restore original state: invoke is in Graph. */ + invokePredecessor.setNext(invoke.asNode()); + return false; + } + } + + protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { + if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) { + return false; + } + + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + if (!targetMethod.canBeInlined()) { + return false; + } + + ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); + GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); + InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType()); + if (inlineInfo == null) { + return false; + } + assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported"; + + ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline; + EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod); + if (graphToInline == null) { + return false; + } + + Invoke invoke = invokeData.invoke; + FixedNode invokeNode = invoke.asNode(); + FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); + invokeNode.replaceAtPredecessor(null); + + PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, + methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); + /* Do the actual inlining by decoding the inlineMethod */ + decode(inlineScope, predecessor); + + ValueNode exceptionValue = null; + if (inlineScope.unwindNode != null) { + exceptionValue = inlineScope.unwindNode.exception(); + } + UnwindNode unwindNode = inlineScope.unwindNode; + + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); + assert invokeWithException.next() == null; + assert invokeWithException.exceptionEdge() == null; + + if (unwindNode != null) { + assert unwindNode.predecessor() != null; + Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); + unwindNode.replaceAndDelete(n); + } + + } else { + if (unwindNode != null && !unwindNode.isDeleted()) { + DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + unwindNode.replaceAndDelete(deoptimizeNode); + } + } + + assert invoke.next() == null; + + ValueNode returnValue; + List returnNodes = inlineScope.returnNodes; + if (!returnNodes.isEmpty()) { + FixedNode n; + n = nodeAfterInvoke(methodScope, loopScope, invokeData); + if (returnNodes.size() == 1) { + ReturnNode returnNode = returnNodes.get(0); + returnValue = returnNode.result(); + returnNode.replaceAndDelete(n); + } else { + AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); + merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); + returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); + merge.setNext(n); + } + } else { + returnValue = null; + } + invokeNode.replaceAtUsages(returnValue); + + /* + * Usage the handles that we have on the return value and the exception to update the + * orderId->Node table. + */ + registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); + if (invoke instanceof InvokeWithExceptionNode) { + registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); + } + if (inlineScope.exceptionPlaceholderNode != null) { + inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); + } + deleteInvoke(invoke); + + methodScope.inlineInvokePlugin.postInline(inlineMethod); + return true; + } + + public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + FixedNode n; + if (invokeData.invoke instanceof InvokeWithExceptionNode) { + n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); + } else { + n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); + } + return n; + } + + private static void deleteInvoke(Invoke invoke) { + /* + * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can + * kill too much: nodes that are decoded later can use values that appear unused by now. + */ + FrameState frameState = invoke.stateAfter(); + invoke.asNode().safeDelete(); + assert invoke.callTarget() == null : "must not have been added to the graph yet"; + if (frameState != null && frameState.hasNoUsages()) { + frameState.safeDelete(); + } + } + + protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method); + + @Override + protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (node instanceof ParameterNode) { + if (methodScope.arguments != null) { + Node result = methodScope.arguments[((ParameterNode) node).index()]; + assert result != null; + return result; + + } else if (methodScope.parameterPlugin != null) { + GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); + Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp()); + if (result != null) { + return result; + } + } + + } + + return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node); + } + + protected void ensureOuterStateDecoded(PEMethodScope methodScope) { + if (methodScope.outerState == null && methodScope.caller != null) { + FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); + if (stateAtReturn == null) { + stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); + } + + Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind(); + FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind); + + /* + * When the encoded graph has methods inlining, we can already have a proper caller + * state. If not, we set the caller state here. + */ + if (outerState.outerFrameState() == null && methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + outerState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.outerState = outerState; + } + } + + protected void ensureStateAfterDecoded(PEMethodScope methodScope) { + if (methodScope.invokeData.invoke.stateAfter() == null) { + methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); + } + } + + protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { + if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { + ensureStateAfterDecoded(methodScope); + + assert methodScope.exceptionPlaceholderNode == null; + methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); + registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); + FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); + + if (exceptionState.outerFrameState() == null && methodScope.caller != null) { + ensureOuterStateDecoded(methodScope.caller); + exceptionState.setOuterFrameState(methodScope.caller.outerState); + } + methodScope.exceptionState = exceptionState; + } + } + + @Override + protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { + PEMethodScope methodScope = (PEMethodScope) s; + + if (methodScope.isInlinedMethod()) { + if (node instanceof SimpleInfopointNode) { + methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); + return node; + + } else if (node instanceof FrameState) { + FrameState frameState = (FrameState) node; + + ensureOuterStateDecoded(methodScope); + if (frameState.bci < 0) { + ensureExceptionStateDecoded(methodScope); + } + return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true); + + } else if (node instanceof MonitorIdNode) { + ensureOuterStateDecoded(methodScope); + InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); + return node; + } + } + + return node; + } +} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Apr 22 15:36:53 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.replacements.nodes; +import static com.oracle.graal.api.code.BytecodeFrame.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; @@ -74,7 +76,7 @@ this.targetMethod = targetMethod; this.returnType = returnType; this.invokeKind = invokeKind; - assert bci >= 0; + assert !isPlaceholderBci(bci); } public int getBci() { @@ -171,8 +173,8 @@ InliningUtil.inline(invoke, replacementGraph, false, null); Debug.dump(graph(), "After inlining replacement %s", replacementGraph); } else { - if (invoke.bci() < 0) { - throw new GraalInternalError("%s: cannot lower to invoke with invalid BCI: %s", graph(), this); + if (isPlaceholderBci(invoke.bci())) { + throw new GraalInternalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this); } if (invoke.stateAfter() == null) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java Wed Apr 22 15:36:38 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; - -/** - * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and - * encoding the graphs). - */ -public class CachingPEGraphDecoder extends PEGraphDecoder { - - private final Providers providers; - private final GraphBuilderConfiguration graphBuilderConfig; - private final AllowAssumptions allowAssumptions; - private final Map graphCache; - - public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, AllowAssumptions allowAssumptions, Architecture architecture) { - super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture); - - this.providers = providers; - this.graphBuilderConfig = graphBuilderConfig; - this.allowAssumptions = allowAssumptions; - this.graphCache = new HashMap<>(); - } - - private EncodedGraph createGraph(ResolvedJavaMethod method) { - StructuredGraph graph = new StructuredGraph(method, allowAssumptions); - try (Debug.Scope scope = Debug.scope("createGraph", graph)) { - - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, TruffleCompilerImpl.Optimizations, null).apply(graph); - - PhaseContext context = new PhaseContext(providers); - new CanonicalizerPhase().apply(graph, context); - - EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture); - graphCache.put(method, encodedGraph); - return encodedGraph; - - } catch (Throwable ex) { - throw Debug.handle(ex); - } - } - - @Override - protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) { - EncodedGraph result = graphCache.get(method); - if (result == null && method.hasBytecodes()) { - result = createGraph(method); - } - return result; - } -} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java Wed Apr 22 15:36:38 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,725 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle; - -import static com.oracle.graal.compiler.common.GraalInternalError.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; -import com.oracle.graal.java.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.common.inlining.*; - -/** - * A graph decoder that performs partial evaluation, i.e., that performs method inlining and - * canonicalization/simplification of nodes during decoding. - * - * Inlining and loop explosion are configured via the plugin mechanism also used by the - * {@link GraphBuilderPhase}. However, not all callback methods defined in - * {@link GraphBuilderContext} are available since decoding is more limited than graph building. - * - * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to - * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and - * {@link IntegerSwitchNode switches} with constant conditions are simplified. - */ -public abstract class PEGraphDecoder extends GraphDecoder { - - protected final MetaAccessProvider metaAccess; - protected final ConstantReflectionProvider constantReflection; - protected final StampProvider stampProvider; - - protected class PEMethodScope extends MethodScope { - /** The state of the caller method. Only non-null during method inlining. */ - protected final PEMethodScope caller; - protected final LoopScope callerLoopScope; - protected final ResolvedJavaMethod method; - protected final InvokeData invokeData; - protected final int inliningDepth; - - protected final LoopExplosionPlugin loopExplosionPlugin; - protected final InvocationPlugins invocationPlugins; - protected final InlineInvokePlugin inlineInvokePlugin; - protected final ParameterPlugin parameterPlugin; - protected final ValueNode[] arguments; - - protected FrameState outerState; - protected FrameState exceptionState; - protected ExceptionPlaceholderNode exceptionPlaceholderNode; - protected BytecodePosition bytecodePosition; - - protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, - int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin, - ValueNode[] arguments) { - super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); - - this.caller = caller; - this.callerLoopScope = callerLoopScope; - this.method = method; - this.invokeData = invokeData; - this.inliningDepth = inliningDepth; - this.loopExplosionPlugin = loopExplosionPlugin; - this.invocationPlugins = invocationPlugins; - this.inlineInvokePlugin = inlineInvokePlugin; - this.parameterPlugin = parameterPlugin; - this.arguments = arguments; - } - - public boolean isInlinedMethod() { - return caller != null; - } - } - - protected class PECanonicalizerTool implements CanonicalizerTool { - @Override - public MetaAccessProvider getMetaAccess() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflection() { - return constantReflection; - } - - @Override - public boolean canonicalizeReads() { - return true; - } - - @Override - public boolean allUsagesAvailable() { - return false; - } - } - - protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { - protected final PEMethodScope methodScope; - protected final Invoke invoke; - - public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { - this.methodScope = methodScope; - this.invoke = invoke; - } - - @Override - public BailoutException bailout(String string) { - throw new BailoutException(string); - } - - @Override - public StampProvider getStampProvider() { - return stampProvider; - } - - @Override - public MetaAccessProvider getMetaAccess() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflection() { - return constantReflection; - } - - @Override - public StructuredGraph getGraph() { - return methodScope.graph; - } - - @Override - public int getDepth() { - return methodScope.inliningDepth; - } - - @Override - public Replacement getReplacement() { - return null; - } - - @Override - public T append(T value) { - throw unimplemented(); - } - - @Override - public T recursiveAppend(T value) { - throw unimplemented(); - } - - @Override - public void push(Kind kind, ValueNode value) { - throw unimplemented(); - } - - @Override - public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { - throw unimplemented(); - } - - @Override - public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) { - throw unimplemented(); - } - - @Override - public FrameState createStateAfter() { - throw unimplemented(); - } - - @Override - public GraphBuilderContext getParent() { - throw unimplemented(); - } - - @Override - public ResolvedJavaMethod getMethod() { - throw unimplemented(); - } - - @Override - public int bci() { - return invoke.bci(); - } - - @Override - public InvokeKind getInvokeKind() { - throw unimplemented(); - } - - @Override - public JavaType getInvokeReturnType() { - throw unimplemented(); - } - } - - protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { - protected FixedWithNextNode lastInstr; - protected ValueNode pushedNode; - - public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { - super(inlineScope, inlineScope.invokeData.invoke); - this.lastInstr = lastInstr; - } - - @Override - public void push(Kind kind, ValueNode value) { - if (pushedNode != null) { - throw unimplemented("Only one push is supported"); - } - pushedNode = value; - } - - @Override - public FrameState createStateAfter() { - Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); - getGraph().add(stateAfter); - return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); - } - - @Override - public T append(T v) { - if (v.graph() != null) { - return v; - } - T added = getGraph().addOrUnique(v); - if (added == v) { - updateLastInstruction(v); - } - return added; - } - - @Override - public T recursiveAppend(T v) { - if (v.graph() != null) { - return v; - } - T added = getGraph().addOrUniqueWithInputs(v); - if (added == v) { - updateLastInstruction(v); - } - return added; - } - - private void updateLastInstruction(T v) { - if (v instanceof FixedNode) { - FixedNode fixedNode = (FixedNode) v; - lastInstr.setNext(fixedNode); - if (fixedNode instanceof FixedWithNextNode) { - FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; - assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; - lastInstr = fixedWithNextNode; - } else { - lastInstr = null; - } - } - } - } - - @NodeInfo - static class ExceptionPlaceholderNode extends ValueNode { - public static final NodeClass TYPE = NodeClass.create(ExceptionPlaceholderNode.class); - - public ExceptionPlaceholderNode() { - super(TYPE, StampFactory.object()); - } - } - - public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) { - super(architecture); - this.metaAccess = metaAccess; - this.constantReflection = constantReflection; - this.stampProvider = stampProvider; - } - - protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { - if (loopExplosionPlugin == null) { - return LoopExplosionKind.NONE; - } else if (loopExplosionPlugin.shouldMergeExplosions(method)) { - return LoopExplosionKind.MERGE_EXPLODE; - } else if (loopExplosionPlugin.shouldExplodeLoops(method)) { - return LoopExplosionKind.FULL_EXPLODE; - } else { - return LoopExplosionKind.NONE; - } - } - - public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, - ParameterPlugin parameterPlugin) { - PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin, - parameterPlugin, null); - decode(methodScope, null); - cleanupGraph(methodScope, null); - methodScope.graph.verify(); - } - - @Override - protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { - GraphBuilderPhase.connectLoopEndToBegin(methodScope.graph); - super.cleanupGraph(methodScope, start); - } - - @Override - protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) { - String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; - if (FailedLoopExplosionIsFatal.getValue()) { - throw new RuntimeException(message); - } else { - throw new BailoutException(message); - } - } - } - - @Override - protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { - PEMethodScope methodScope = (PEMethodScope) s; - - /* - * Decode the call target, but do not add it to the graph yet. This avoids adding usages for - * all the arguments, which are expensive to remove again when we can inline the method. - */ - assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; - CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); - if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) { - - /* We know that we need an invoke, so now we can add the call target to the graph. */ - methodScope.graph.add(callTarget); - registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); - super.handleInvoke(methodScope, loopScope, invokeData); - } - } - - protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - // attempt to devirtualize the call - ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType); - if (specialCallTarget != null) { - callTarget.setTargetMethod(specialCallTarget); - callTarget.setInvokeKind(InvokeKind.Special); - } - - if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { - return true; - } - if (tryInline(methodScope, loopScope, invokeData, callTarget)) { - return true; - } - - if (methodScope.inlineInvokePlugin != null) { - methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); - } - return false; - } - - protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - if (methodScope.invocationPlugins == null) { - return false; - } - - Invoke invoke = invokeData.invoke; - - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); - if (invocationPlugin == null) { - return false; - } - - ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); - FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); - - /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */ - invoke.asNode().replaceAtPredecessor(null); - - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, - methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); - PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); - InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); - - if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { - - if (graphBuilderContext.lastInstr != null) { - registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); - invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); - graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); - } else { - assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; - invoke.asNode().replaceAtUsages(null); - } - - deleteInvoke(invoke); - return true; - - } else { - /* Intrinsification failed, restore original state: invoke is in Graph. */ - invokePredecessor.setNext(invoke.asNode()); - return false; - } - } - - protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) { - return false; - } - - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (!targetMethod.canBeInlined()) { - return false; - } - - ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); - GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); - InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType()); - if (inlineInfo == null) { - return false; - } - assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported"; - - ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline; - EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod); - if (graphToInline == null) { - return false; - } - - Invoke invoke = invokeData.invoke; - FixedNode invokeNode = invoke.asNode(); - FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); - invokeNode.replaceAtPredecessor(null); - - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, - methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments); - /* Do the actual inlining by decoding the inlineMethod */ - decode(inlineScope, predecessor); - - ValueNode exceptionValue = null; - if (inlineScope.unwindNode != null) { - exceptionValue = inlineScope.unwindNode.exception(); - } - UnwindNode unwindNode = inlineScope.unwindNode; - - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); - assert invokeWithException.next() == null; - assert invokeWithException.exceptionEdge() == null; - - if (unwindNode != null) { - assert unwindNode.predecessor() != null; - Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); - unwindNode.replaceAndDelete(n); - } - - } else { - if (unwindNode != null && !unwindNode.isDeleted()) { - DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); - unwindNode.replaceAndDelete(deoptimizeNode); - } - } - - assert invoke.next() == null; - - ValueNode returnValue; - List returnNodes = inlineScope.returnNodes; - if (!returnNodes.isEmpty()) { - FixedNode n; - n = nodeAfterInvoke(methodScope, loopScope, invokeData); - if (returnNodes.size() == 1) { - ReturnNode returnNode = returnNodes.get(0); - returnValue = returnNode.result(); - returnNode.replaceAndDelete(n); - } else { - AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); - merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); - returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); - merge.setNext(n); - } - } else { - returnValue = null; - } - invokeNode.replaceAtUsages(returnValue); - - /* - * Usage the handles that we have on the return value and the exception to update the - * orderId->Node table. - */ - registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); - if (invoke instanceof InvokeWithExceptionNode) { - registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); - } - if (inlineScope.exceptionPlaceholderNode != null) { - inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); - } - deleteInvoke(invoke); - - methodScope.inlineInvokePlugin.postInline(inlineMethod); - return true; - } - - public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { - FixedNode n; - if (invokeData.invoke instanceof InvokeWithExceptionNode) { - n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); - } else { - n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); - } - return n; - } - - private static void deleteInvoke(Invoke invoke) { - /* - * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can - * kill too much: nodes that are decoded later can use values that appear unused by now. - */ - FrameState frameState = invoke.stateAfter(); - invoke.asNode().safeDelete(); - assert invoke.callTarget() == null : "must not have been added to the graph yet"; - if (frameState != null && frameState.hasNoUsages()) { - frameState.safeDelete(); - } - } - - protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method); - - @Override - protected void simplifyFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - if (ifNode.condition() instanceof LogicNegationNode) { - ifNode.eliminateNegation(); - } - if (ifNode.condition() instanceof LogicConstantNode) { - boolean condition = ((LogicConstantNode) ifNode.condition()).getValue(); - AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); - AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); - - methodScope.graph.removeSplit(ifNode, survivingSuccessor); - assert deadSuccessor.next() == null : "must not be parsed yet"; - deadSuccessor.safeDelete(); - } - - } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { - IntegerSwitchNode switchNode = (IntegerSwitchNode) node; - int value = switchNode.value().asJavaConstant().asInt(); - AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value); - List allSuccessors = switchNode.successors().snapshot(); - - methodScope.graph.removeSplit(switchNode, survivingSuccessor); - for (Node successor : allSuccessors) { - if (successor != survivingSuccessor) { - assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet"; - successor.safeDelete(); - } - } - - } else if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); - if (canonical == null) { - /* - * This is a possible return value of canonicalization. However, we might need to - * add additional usages later on for which we need a node. Therefore, we just do - * nothing and leave the node in place. - */ - } else if (canonical != node) { - if (!canonical.isAlive()) { - assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); - if (canonical instanceof FixedWithNextNode) { - methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical); - } - } - GraphUtil.unlinkFixedNode((FixedWithNextNode) node); - node.replaceAtUsages(canonical); - node.safeDelete(); - assert lookupNode(loopScope, nodeOrderId) == node; - registerNode(loopScope, nodeOrderId, canonical, true, false); - } - } - } - - @Override - protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (node instanceof ParameterNode) { - if (methodScope.arguments != null) { - Node result = methodScope.arguments[((ParameterNode) node).index()]; - assert result != null; - return result; - - } else if (methodScope.parameterPlugin != null) { - GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); - Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp()); - if (result != null) { - return result; - } - } - - } else if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool()); - if (canonical == null) { - /* - * This is a possible return value of canonicalization. However, we might need to - * add additional usages later on for which we need a node. Therefore, we just do - * nothing and leave the node in place. - */ - } else if (canonical != node) { - if (!canonical.isAlive()) { - assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); - } - assert node.hasNoUsages(); - // methodScope.graph.replaceFloating((FloatingNode) node, canonical); - return canonical; - } - } - return node; - } - - protected void ensureOuterStateDecoded(PEMethodScope methodScope) { - if (methodScope.outerState == null && methodScope.caller != null) { - FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); - if (stateAtReturn == null) { - stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); - } - - Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind(); - FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind); - - /* - * When the encoded graph has methods inlining, we can already have a proper caller - * state. If not, we set the caller state here. - */ - if (outerState.outerFrameState() == null && methodScope.caller != null) { - ensureOuterStateDecoded(methodScope.caller); - outerState.setOuterFrameState(methodScope.caller.outerState); - } - methodScope.outerState = outerState; - } - } - - protected void ensureStateAfterDecoded(PEMethodScope methodScope) { - if (methodScope.invokeData.invoke.stateAfter() == null) { - methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); - } - } - - protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { - if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { - ensureStateAfterDecoded(methodScope); - - assert methodScope.exceptionPlaceholderNode == null; - methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); - registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); - FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); - - if (exceptionState.outerFrameState() == null && methodScope.caller != null) { - ensureOuterStateDecoded(methodScope.caller); - exceptionState.setOuterFrameState(methodScope.caller.outerState); - } - methodScope.exceptionState = exceptionState; - } - } - - @Override - protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { - PEMethodScope methodScope = (PEMethodScope) s; - - if (methodScope.isInlinedMethod()) { - if (node instanceof SimpleInfopointNode) { - methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); - return node; - - } else if (node instanceof FrameState) { - FrameState frameState = (FrameState) node; - - ensureOuterStateDecoded(methodScope); - if (frameState.bci < 0) { - ensureExceptionStateDecoded(methodScope); - } - return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true); - - } else if (node instanceof MonitorIdNode) { - ensureOuterStateDecoded(methodScope); - InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); - return node; - } - } - - return node; - } -} diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Apr 22 15:36:53 2015 +0200 @@ -340,7 +340,7 @@ plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue())); - CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget); diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Wed Apr 22 15:36:53 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.graph.*; @@ -158,11 +159,11 @@ if (node instanceof LoopExitNode) { LoopExitNode loopExit = (LoopExitNode) node; for (ProxyNode proxy : loopExit.proxies()) { - changed |= processNode(proxy, state, effects, lastFixedNode); + changed |= processNode(proxy, state, effects, lastFixedNode) && isSignificantNode(node); } processLoopExit(loopExit, loopEntryStates.get(loopExit.loopBegin()), state, blockEffects.get(block)); } - changed |= processNode(node, state, effects, lastFixedNode); + changed |= processNode(node, state, effects, lastFixedNode) && isSignificantNode(node); if (node instanceof FixedWithNextNode) { lastFixedNode = (FixedWithNextNode) node; } @@ -175,6 +176,15 @@ return state; } + private static boolean isSignificantNode(Node node) { + return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode || node instanceof BoxNode); + } + + /** + * Collects the effects of virtualizing the given node. + * + * @return {@code true} if the effects include removing the node, {@code false} otherwise. + */ protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode); @Override diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Apr 22 15:36:53 2015 +0200 @@ -34,7 +34,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; @@ -134,32 +133,30 @@ private boolean processNodeInternal(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) { FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next(); - boolean significantChange = false; VirtualUtil.trace("%s", node); if (node instanceof VirtualizableAllocation) { - significantChange |= processVirtualizable((ValueNode) node, nextFixedNode, state, effects); - if (tool.isDeleted()) { + if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) { VirtualUtil.trace("deleted virtualizable allocation %s", node); - return significantChange; + return true; } } - if (hasVirtualInputs.isMarked(node) && node instanceof ValueNode) { if (node instanceof Virtualizable) { - significantChange |= processVirtualizable((ValueNode) node, nextFixedNode, state, effects); - if (tool.isDeleted()) { + if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) { VirtualUtil.trace("deleted virtualizable node %s", node); - return significantChange; + return true; } } processNodeInputs((ValueNode) node, nextFixedNode, state, effects); } if (hasScalarReplacedInputs(node) && node instanceof ValueNode) { - significantChange |= processNodeWithScalarReplacedInputs((ValueNode) node, nextFixedNode, state, effects); + if (processNodeWithScalarReplacedInputs((ValueNode) node, nextFixedNode, state, effects)) { + return true; + } } - return significantChange; + return false; } private boolean processNodeWithScalarReplacedInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) { @@ -268,10 +265,7 @@ private boolean processVirtualizable(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) { tool.reset(state, node, insertBefore, effects); ((Virtualizable) node).virtualize(tool); - if (tool.isDeleted()) { - return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode || node instanceof BoxNode); - } - return false; + return tool.isDeleted(); } private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Wed Apr 22 15:36:53 2015 +0200 @@ -63,7 +63,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (getUsageCount() == 0) { + if (tool.allUsagesAvailable() && hasNoUsages()) { /* If the cast is unused, it can be eliminated. */ return input; } diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Wed Apr 22 15:36:53 2015 +0200 @@ -504,7 +504,15 @@ if (merged == generated) { // new node if (start.count() == 2) { - insertAt(start, start.createPolymorphic(), "insert polymorphic"); + SpecializationNode polymorphic = start.createPolymorphic(); + /* + * For nodes with all parameters evaluated in the execute method we do not need a + * polymorphic node. the generated code returns null in createPolymorphic in this + * case. + */ + if (polymorphic != null) { + insertAt(start, polymorphic, "insert polymorphic"); + } } SpecializationNode current = start; while (current != null && current.index < generated.index) { diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 22 15:36:53 2015 +0200 @@ -420,6 +420,17 @@ } private boolean needsPolymorphic() { + int signatureSize = node.getSignatureSize(); + boolean allEvaluated = true; + for (ExecutableTypeData type : usedTypes) { + if (type.getEvaluatedCount() != signatureSize) { + allEvaluated = false; + } + } + if (allEvaluated) { + return false; + } + if (reachableSpecializations.size() != 1) { return true; } @@ -2345,6 +2356,7 @@ final CodeTreeBuilder polyChainBuilder = builder.create(); final String profileField = polymorphicTypeProfileFieldName(execution); final String valueFieldName = "_value"; + final String typeFieldName = "_type"; builder.declaration(getType(Class.class), profileField, accessParent(profileField)); @@ -2367,6 +2379,8 @@ polyChainBuilder.startElseIf().string(profileField).string(" == null").end(); polyChainBuilder.startBlock(); polyChainBuilder.tree(createTransferToInterpreterAndInvalidate()); + polyChainBuilder.declaration(context.getType(Class.class), typeFieldName, polyChainBuilder.create().typeLiteral(genericType).build()); + polyChainBuilder.startTryBlock(); polyChainBuilder.declaration(genericExecutableType.getReturnType(), valueFieldName, executeGeneric); hasSpecializedTypes = false; @@ -2375,14 +2389,17 @@ polyChainBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, executableType.getReturnType(), CodeTreeBuilder.singleString(valueFieldName))); polyChainBuilder.end(); polyChainBuilder.startBlock(); - polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getReturnType()).end(); + polyChainBuilder.startStatement().string(typeFieldName).string(" = ").typeLiteral(executableType.getReturnType()).end(); polyChainBuilder.end(); } - polyChainBuilder.startElseBlock(); - polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end(); + polyChainBuilder.startStatement().string(typeFieldName).string(" = ").typeLiteral(genericType).end(); polyChainBuilder.end(); polyChainBuilder.startReturn().string(valueFieldName).end(); + + polyChainBuilder.end().startFinallyBlock(); + polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").string(typeFieldName).end(); + polyChainBuilder.end(); polyChainBuilder.end(); // else -> execute generic diff -r 0a3bc68fc3a7 -r 056f90577ed1 graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/messages/MessageUtil.java --- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/messages/MessageUtil.java Wed Apr 22 15:36:38 2015 +0200 +++ b/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/messages/MessageUtil.java Wed Apr 22 15:36:53 2015 +0200 @@ -34,6 +34,6 @@ } else if (o1 instanceof Receiver && o2 instanceof Receiver) { return true; } - throw new IllegalStateException(); + return false; } } diff -r 0a3bc68fc3a7 -r 056f90577ed1 make/Makefile --- a/make/Makefile Wed Apr 22 15:36:38 2015 +0200 +++ b/make/Makefile Wed Apr 22 15:36:53 2015 +0200 @@ -632,6 +632,9 @@ $(EXPORT_JRE_LIB_EXT_DIR)/%.jar: $(SHARED_DIR)/%.jar $(install-file) +$(EXPORT_JRE_LIB_GRAAL_DIR)/%.jar: $(SHARED_DIR)/%.jar + $(install-file) + $(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/code/% $(install-file) diff -r 0a3bc68fc3a7 -r 056f90577ed1 mx/mx_graal.py --- a/mx/mx_graal.py Wed Apr 22 15:36:38 2015 +0200 +++ b/mx/mx_graal.py Wed Apr 22 15:36:53 2015 +0200 @@ -594,6 +594,35 @@ shutil.move(tmp, dstLib) os.chmod(dstLib, permissions) +def _updateGraalServiceFiles(jdkDir): + jreGraalDir = join(jdkDir, 'jre', 'lib', 'graal') + graalJars = [join(jreGraalDir, e) for e in os.listdir(jreGraalDir) if e.startswith('graal') and e.endswith('.jar')] + jreGraalServicesDir = join(jreGraalDir, 'services') + if exists(jreGraalServicesDir): + shutil.rmtree(jreGraalServicesDir) + os.makedirs(jreGraalServicesDir) + for jar in graalJars: + if os.path.isfile(jar): + with zipfile.ZipFile(jar) as zf: + for member in zf.namelist(): + if not member.startswith('META-INF/services'): + continue + serviceName = basename(member) + # we don't handle directories + assert serviceName + target = join(jreGraalServicesDir, serviceName) + lines = [] + with zf.open(member) as serviceFile: + lines.extend(serviceFile.readlines()) + if exists(target): + with open(target) as targetFile: + lines.extend(targetFile.readlines()) + with open(target, "w+") as targetFile: + for line in lines: + targetFile.write(line.rstrip() + os.linesep) + + + def _installDistInJdks(deployableDist): """ Installs the jar(s) for a given Distribution into all existing Graal JDKs @@ -613,7 +642,8 @@ if exists(jdks): for e in os.listdir(jdks): - jreLibDir = join(jdks, e, 'jre', 'lib') + jdkDir = join(jdks, e) + jreLibDir = join(jdkDir, 'jre', 'lib') if exists(jreLibDir): if deployableDist.isExtension: targetDir = join(jreLibDir, 'ext') @@ -625,23 +655,10 @@ os.makedirs(targetDir) _copyToJdk(dist.path, targetDir) if dist.sourcesPath: - _copyToJdk(dist.sourcesPath, join(jdks, e)) - # deploy service files + _copyToJdk(dist.sourcesPath, jdkDir) if deployableDist.isGraalClassLoader: - # deploy services files - jreGraalServicesDir = join(jreLibDir, 'graal', 'services') - if not exists(jreGraalServicesDir): - os.makedirs(jreGraalServicesDir) - with zipfile.ZipFile(dist.path) as zf: - for member in zf.namelist(): - if not member.startswith('META-INF/services'): - continue - serviceName = basename(member) - # we don't handle directories - assert serviceName - target = join(jreGraalServicesDir, serviceName) - with zf.open(member) as serviceFile, open(target, "w+") as targetFile: - shutil.copyfileobj(serviceFile, targetFile) + # deploy service files + _updateGraalServiceFiles(jdkDir) # run a command in the windows SDK Debug Shell def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo=None): diff -r 0a3bc68fc3a7 -r 056f90577ed1 mxtool/mx.py --- a/mxtool/mx.py Wed Apr 22 15:36:38 2015 +0200 +++ b/mxtool/mx.py Wed Apr 22 15:36:53 2015 +0200 @@ -2798,7 +2798,7 @@ archive(['@' + dist.name]) if args.check_distributions and not dist.isProcessorDistribution: with zipfile.ZipFile(dist.path, 'r') as zf: - files.extend([member for member in zf.namelist() if not member.startswith('META-INF/services')]) + files.extend([member for member in zf.namelist() if not member.startswith('META-INF')]) dups = set([x for x in files if files.count(x) > 1]) if len(dups) > 0: abort('Distributions overlap! duplicates: ' + str(dups)) diff -r 0a3bc68fc3a7 -r 056f90577ed1 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Apr 22 15:36:38 2015 +0200 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Apr 22 15:36:53 2015 +0200 @@ -186,9 +186,7 @@ __ subptr(rsp, 256); // Save upper half of YMM registers if (save_vectors) { assert(UseAVX > 0, "256bit vectors are supported only with AVX"); -#ifdef COMPILER2 assert(MaxVectorSize == 32, "only 256bit vectors are supported now"); -#endif // Save upper half of YMM registers __ vextractf128h(Address(rsp, ymm_hi0_off * BytesPerInt), xmm0); __ vextractf128h(Address(rsp, ymm_hi1_off * BytesPerInt), xmm1); @@ -327,9 +325,7 @@ if (restore_vectors) { // Restore upper half of YMM registes. assert(UseAVX > 0, "256bit vectors are supported only with AVX"); -#if defined(COMPILER2) assert(MaxVectorSize == 32, "only 256bit vectors are supported now"); -#endif __ vinsertf128h(xmm0, Address(rsp, ymm_hi0_off * BytesPerInt)); __ vinsertf128h(xmm1, Address(rsp, ymm_hi1_off * BytesPerInt)); __ vinsertf128h(xmm2, Address(rsp, ymm_hi2_off * BytesPerInt)); diff -r 0a3bc68fc3a7 -r 056f90577ed1 src/cpu/x86/vm/vm_version_x86.cpp --- a/src/cpu/x86/vm/vm_version_x86.cpp Wed Apr 22 15:36:38 2015 +0200 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Wed Apr 22 15:36:53 2015 +0200 @@ -667,6 +667,8 @@ FLAG_SET_DEFAULT(UseFPUForSpilling, false); } } +#endif +#if defined(COMPILER2) || defined(GRAAL) if (MaxVectorSize > 0) { if (!is_power_of_2(MaxVectorSize)) { warning("MaxVectorSize must be a power of 2"); @@ -684,7 +686,7 @@ FLAG_SET_DEFAULT(MaxVectorSize, 0); } #ifdef ASSERT - if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { + if (supports_avx() && PrintMiscellaneous && Verbose) { tty->print_cr("State of YMM registers after signal handle:"); int nreg = 2 LP64_ONLY(+2); const char* ymm_name[4] = {"0", "7", "8", "15"}; @@ -698,7 +700,9 @@ } #endif } +#endif +#ifdef COMPILER2 #ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; diff -r 0a3bc68fc3a7 -r 056f90577ed1 src/share/vm/graal/graalEnv.cpp --- a/src/share/vm/graal/graalEnv.cpp Wed Apr 22 15:36:38 2015 +0200 +++ b/src/share/vm/graal/graalEnv.cpp Wed Apr 22 15:36:53 2015 +0200 @@ -550,7 +550,7 @@ // It might be preferable to set this only for methods which // use vector instructions but we currently don't track this // and it probably wouldn't make much difference. - nm->set_has_wide_vectors(UseAVX >= 2); + nm->set_has_wide_vectors(MaxVectorSize > 16); #endif // Record successful registration. diff -r 0a3bc68fc3a7 -r 056f90577ed1 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Wed Apr 22 15:36:38 2015 +0200 +++ b/src/share/vm/graal/graalGlobals.hpp Wed Apr 22 15:36:53 2015 +0200 @@ -67,6 +67,10 @@ GRAAL_ONLY(product(bool, CodeInstallSafepointChecks, true, \ "Perform explicit safepoint checks while installing code")) \ \ + NOT_COMPILER2(product(intx, MaxVectorSize, 32, \ + "Max vector size in bytes, " \ + "actual size could be less depending on elements type")) \ + \ product(intx, TraceGraal, 0, \ "Trace level for Graal") \ \ diff -r 0a3bc68fc3a7 -r 056f90577ed1 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Apr 22 15:36:38 2015 +0200 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Apr 22 15:36:53 2015 +0200 @@ -113,11 +113,7 @@ #if defined(COMPILER2) || defined(GRAAL) // Vectors are generated only by C2 and Graal. -#ifdef COMPILER2 - bool support_wide = is_wide_vector(MaxVectorSize) || IS_GRAAL_DEFINED; -#else - bool support_wide = true; -#endif + bool support_wide = is_wide_vector(MaxVectorSize); if (support_wide) { _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); }