# HG changeset patch # User Doug Simon # Date 1427040243 -3600 # Node ID aaf5039e56d7d1ffc4e849bfeea79357dd05320c # Parent bca124e6ad581274edf1c3ee1863d6c58fc429d5 made partial intrinsification work (i.e., intrinsics that call the original method to handle slow/uncommon paths) diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Sun Mar 22 17:04:03 2015 +0100 @@ -100,16 +100,12 @@ public void testCipherBlockChainingIntrinsics() throws Exception { if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) { ByteArrayOutputStream actual = new ByteArrayOutputStream(); - System.out.println("testCipherBlockChainingIntrinsics: 1"); actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); - System.out.println("testCipherBlockChainingIntrinsics: 2"); actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); actual.reset(); - System.out.println("testCipherBlockChainingIntrinsics: 3"); actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); - System.out.println("testCipherBlockChainingIntrinsics: 4"); actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray()); } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Sun Mar 22 17:04:03 2015 +0100 @@ -33,17 +33,14 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** * HotSpot implementation of {@link ConstantReflectionProvider}. */ -@SuppressWarnings("unused") public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { private static final String SystemClassName = "Ljava/lang/System;"; @@ -317,7 +314,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Sun Mar 22 17:04:03 2015 +0100 @@ -27,6 +27,7 @@ import static java.lang.String.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; @@ -44,6 +45,8 @@ this.replacements = replacements; } + private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method); if (subst != null) { @@ -56,6 +59,13 @@ assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null && !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); + assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + + if (method.getName().startsWith("$jacoco")) { + throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + + b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this."); + } + // Force inlining when parsing replacements return new InlineInfo(method, true, true); } else { diff -r bca124e6ad58 -r aaf5039e56d7 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 Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Sun Mar 22 17:04:03 2015 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.nodes.spi.Replacements.*; - import java.lang.reflect.*; import java.util.zip.*; @@ -64,9 +62,7 @@ replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); - if (SELF_RECURSIVE_INTRINSICS_ENABLED) { - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); - } + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); } } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Sun Mar 22 17:04:03 2015 +0100 @@ -192,7 +192,7 @@ StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO); graph.disableInlinedMethodRecording(); - GraphKit kit = new GraphKit(graph, providers, wordTypes); + GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); ParameterNode[] params = createParameters(kit, args); ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Sun Mar 22 17:04:03 2015 +0100 @@ -29,9 +29,10 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; @@ -94,7 +95,8 @@ assert SnippetGraphUnderConstruction.get() == null; SnippetGraphUnderConstruction.set(graph); - new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph); + ReplacementContext initialReplacementContext = new ReplacementContext(method, method); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); SnippetGraphUnderConstruction.set(null); graph.setGuardsStage(GuardsStage.FLOATING_GUARDS); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Sun Mar 22 17:04:03 2015 +0100 @@ -27,6 +27,7 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.HIRFrameStateBuilder.*; import java.util.*; @@ -42,6 +43,7 @@ import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -82,7 +84,7 @@ * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation * is a {@link MethodSubstitution} or a snippet. */ - static class ReplacementContext implements Replacement { + public static class ReplacementContext implements Replacement { /** * The method being replaced. */ @@ -121,6 +123,11 @@ IntrinsicContext asIntrinsic() { return null; } + + @Override + public String toString() { + return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}"; + } } /** @@ -129,25 +136,37 @@ * information required to build a frame state denoting the JVM state just before the * intrinsified call. */ - static class IntrinsicContext extends ReplacementContext { + public static class IntrinsicContext extends ReplacementContext { /** - * The arguments to the intrinsified invocation. + * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed. */ - private final ValueNode[] invokeArgs; + public static final int POST_PARSE_INLINE_BCI = -1; + + /** + * BCI denoting an intrinsic is the compilation root. + */ + public static final int ROOT_COMPILATION_BCI = -2; /** - * The BCI of the intrinsified invocation. + * The arguments to the intrinsic. */ - private final int invokeBci; + ValueNode[] args; - private FrameState invokeStateBefore; - private FrameState invokeStateDuring; + /** + * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or + * {@link #ROOT_COMPILATION_BCI}. + */ + final int bci; - public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] invokeArgs, int invokeBci) { + private FrameState stateBeforeCache; + + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) { super(method, substitute); - this.invokeArgs = invokeArgs; - this.invokeBci = invokeBci; + assert bci != POST_PARSE_INLINE_BCI || args == null; + this.args = args; + this.bci = bci; + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)"); } @Override @@ -155,34 +174,56 @@ return true; } - /** - * Gets the frame state that will restart the interpreter just before the intrinsified - * invocation. - */ - public FrameState getInvokeStateBefore(BytecodeParser parent) { - assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; - if (invokeStateDuring == null) { - assert invokeStateBefore == null; - // Find the ancestor calling the replaced method - BytecodeParser ancestor = parent; - while (ancestor.parsingReplacement()) { - ancestor = ancestor.getParent(); - } - invokeStateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); - invokeStateBefore = invokeStateDuring.duplicateModifiedBeforeCall(invokeBci, Kind.Void, invokeArgs); - } - return invokeStateBefore; + public boolean isPostParseInlined() { + return bci == POST_PARSE_INLINE_BCI; + } + + public boolean isCompilationRoot() { + return bci == ROOT_COMPILATION_BCI; } - public FrameState getInvokeStateDuring() { - assert invokeStateDuring != null : "must only be called after getInvokeStateBefore()"; - return invokeStateDuring; + public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) { + if (isCompilationRoot()) { + int maxLocals = method.getMaxLocals(); + // The 'args' were initialized based on the intrinsic method but a + // frame state's 'locals' needs to have the same length as the frame + // state method's 'max_locals'. + ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals); + ValueNode[] stack = EMPTY_ARRAY; + int stackSize = 0; + ValueNode[] locks = EMPTY_ARRAY; + List monitorIds = Collections.emptyList(); + return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } else if (isPostParseInlined()) { + return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; + if (stateBeforeCache == null) { + assert stateBeforeCache == null; + + // Find the non-intrinsic ancestor calling the intrinsified method + BytecodeParser ancestor = parent; + while (ancestor.parsingReplacement()) { + assert ancestor.replacementContext instanceof IntrinsicContext; + ancestor = ancestor.getParent(); + } + FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); + stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args); + } + return stateBeforeCache; + } } @Override IntrinsicContext asIntrinsic() { return this; } + + @Override + public String toString() { + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + + (args == null ? "" : ", args: " + Arrays.toString(args)) + (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}"; + } } /** @@ -1104,214 +1145,214 @@ // Checkstyle: stop // @formatter:off - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; - case ICONST_M1 : // fall through - case ICONST_0 : // fall through - case ICONST_1 : // fall through - case ICONST_2 : // fall through - case ICONST_3 : // fall through - case ICONST_4 : // fall through - case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; - case LCONST_0 : // fall through - case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; - case FCONST_0 : // fall through - case FCONST_1 : // fall through - case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; - case DCONST_0 : // fall through - case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; - case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; - case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; - case IALOAD : genLoadIndexed(Kind.Int ); break; - case LALOAD : genLoadIndexed(Kind.Long ); break; - case FALOAD : genLoadIndexed(Kind.Float ); break; - case DALOAD : genLoadIndexed(Kind.Double); break; - case AALOAD : genLoadIndexed(Kind.Object); break; - case BALOAD : genLoadIndexed(Kind.Byte ); break; - case CALOAD : genLoadIndexed(Kind.Char ); break; - case SALOAD : genLoadIndexed(Kind.Short ); break; - case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(Kind.Int ); break; - case LASTORE : genStoreIndexed(Kind.Long ); break; - case FASTORE : genStoreIndexed(Kind.Float ); break; - case DASTORE : genStoreIndexed(Kind.Double); break; - case AASTORE : genStoreIndexed(Kind.Object); break; - case BASTORE : genStoreIndexed(Kind.Byte ); break; - case CASTORE : genStoreIndexed(Kind.Char ); break; - case SASTORE : genStoreIndexed(Kind.Short ); break; - case POP : frameState.xpop(); break; - case POP2 : frameState.xpop(); frameState.xpop(); break; - case DUP : frameState.xpush(frameState.xpeek()); break; - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(Kind.Int, opcode); break; - case IDIV : // fall through - case IREM : genIntegerDivOp(Kind.Int, opcode); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(Kind.Long, opcode); break; - case LDIV : // fall through - case LREM : genIntegerDivOp(Kind.Long, opcode); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(Kind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(Kind.Double, opcode); break; - case INEG : genNegateOp(Kind.Int); break; - case LNEG : genNegateOp(Kind.Long); break; - case FNEG : genNegateOp(Kind.Float); break; - case DNEG : genNegateOp(Kind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(Kind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(Kind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(Kind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(Kind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; - case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; - case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; - case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; - case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; - case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; - case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; - case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; - case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; - case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; - case L2I : genNarrow(Kind.Long, Kind.Int); break; - case I2L : genSignExtend(Kind.Int, Kind.Long); break; - case I2B : genSignExtend(Kind.Byte, Kind.Int); break; - case I2S : genSignExtend(Kind.Short, Kind.Int); break; - case I2C : genZeroExtend(Kind.Char, Kind.Int); break; - case LCMP : genCompareOp(Kind.Long, false); break; - case FCMPL : genCompareOp(Kind.Float, true); break; - case FCMPG : genCompareOp(Kind.Float, false); break; - case DCMPL : genCompareOp(Kind.Double, true); break; - case DCMPG : genCompareOp(Kind.Double, false); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; - case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; - case GOTO : genGoto(); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; - case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; - case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; - case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; - case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; - case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; - case ARETURN : genReturn(frameState.apop(), Kind.Object); break; - case RETURN : genReturn(null, Kind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(); break; - case JSR_W : genJsr(stream.readBranchDest()); break; - case BREAKPOINT: - throw new BailoutException("concurrent setting of breakpoint"); - default: - throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); - } - // @formatter:on + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : frameState.xpop(); break; + case POP2 : frameState.xpop(); frameState.xpop(); break; + case DUP : frameState.xpush(frameState.xpeek()); break; + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; + case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; + case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; + case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; + case ARETURN : genReturn(frameState.apop(), Kind.Object); break; + case RETURN : genReturn(null, Kind.Void); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on // Checkstyle: resume } diff -r bca124e6ad58 -r aaf5039e56d7 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 Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sun Mar 22 17:04:03 2015 +0100 @@ -100,7 +100,9 @@ * Furthermore, if it is non-null and not equal to {@link #rootMethod} then this is the * original method for which a snippet exists (e.g., System.arraycopy()). */ - private final ResolvedJavaMethod rootMethodIsReplacement; + // private final ResolvedJavaMethod rootMethodIsReplacement; + + private final ReplacementContext initialReplacementContext; private final GraphBuilderConfiguration graphBuilderConfig; private final OptimisticOptimizations optimisticOpts; @@ -109,20 +111,21 @@ private final SnippetReflectionProvider snippetReflectionProvider; public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; this.stampProvider = stampProvider; this.constantReflection = constantReflection; this.snippetReflectionProvider = snippetReflectionProvider; - this.rootMethodIsReplacement = rootMethodIsReplacement; + this.initialReplacementContext = initialReplacementContext; + assert metaAccess != null; } public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { - this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { + this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } @Override @@ -134,10 +137,10 @@ this.currentGraph = graph; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { - ReplacementContext replacementContext = rootMethodIsReplacement != null ? new ReplacementContext(rootMethodIsReplacement, rootMethod) : null; + ReplacementContext replacementContext = initialReplacementContext; BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext); HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); - frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || rootMethodIsReplacement != null, graphBuilderConfig.getPlugins().getParameterPlugin()); + frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); parser.build(graph.start(), frameState); parser.connectLoopEndToBegin(); @@ -1316,13 +1319,30 @@ } ReplacementContext context = this.replacementContext; if (context != null && context.isCallToOriginal(targetMethod)) { - assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying"; - // Self recursive replacement means the original - // method should be called. - if (context.method.hasBytecodes()) { - parseAndInlineCallee(context.method, args, null); + IntrinsicContext intrinsic = context.asIntrinsic(); + if (intrinsic != null) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + deopt.setStateBefore(intrinsic.getInvokeStateBefore(currentGraph, null)); + return true; + } else { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + parseAndInlineCallee(context.method, args, null); + return true; + } } else { - return false; + // Self recursive replacement means the original + // method should be called. + if (context.method.hasBytecodes()) { + parseAndInlineCallee(context.method, args, null); + return true; + } else { + return false; + } } } else { if (context == null && inlineInfo.isReplacement) { @@ -2451,7 +2471,8 @@ if (bp != this) { fmt.format("%n%s", indent); } - fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bci(), bp.parsingReplacement()); + fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement()); + fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10)); bp = bp.parent; indent += " "; } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Sun Mar 22 17:04:03 2015 +0100 @@ -43,8 +43,8 @@ public final class HIRFrameStateBuilder { - private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; protected final BytecodeParser parser; protected final ResolvedJavaMethod method; @@ -145,6 +145,14 @@ javaIndex += kind.getSlotCount(); index++; } + + if (parser.replacementContext instanceof IntrinsicContext) { + IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; + if (intrinsic.isCompilationRoot()) { + // Records the parameters to an root compiled intrinsic + intrinsic.args = locals.clone(); + } + } } private HIRFrameStateBuilder(HIRFrameStateBuilder other) { @@ -200,28 +208,20 @@ if (parser.parsingReplacement()) { IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); if (intrinsic != null) { - assert parent != null : "intrinsics can only be processed in context of a caller"; - - // We're somewhere in an intrinsic. In this case, we want a frame state - // that will restart the interpreter just before the intrinsified - // invocation. - return intrinsic.getInvokeStateBefore(parent); + return intrinsic.getInvokeStateBefore(parser.getGraph(), parent); } } + // If this is the recursive call in a partial intrinsification + // the frame(s) of the intrinsic method are omitted + while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) { + parent = parent.getParent(); + } return create(bci, parent, false); } public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { if (outerFrameState == null && parent != null) { outerFrameState = parent.getFrameState().create(parent.bci()); - if (parser.parsingReplacement()) { - IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); - if (intrinsic != null) { - // A side-effect of creating the frame state in a replacing - // parent is that the 'during' frame state is created as well - outerFrameState = intrinsic.getInvokeStateDuring(); - } - } } if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Sun Mar 22 17:04:03 2015 +0100 @@ -35,7 +35,7 @@ } public static double test(double arg) throws NaN { - double v = Math.sin(arg); + double v = Math.sin(arg) * Math.sin(arg * 5); if (Double.isNaN(v)) { // NaN can't be tested against itself throw new NaN(); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Sun Mar 22 17:04:03 2015 +0100 @@ -33,8 +33,6 @@ * Interface for managing replacements. */ public interface Replacements { - // Disabled until bug in support for this is fixed. - boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false; /** * Gets the snippet graph derived from a given method. diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Sun Mar 22 17:04:03 2015 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; @@ -432,14 +433,18 @@ frameState.replaceAndDelete(stateAfterException); } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { handleMissingAfterExceptionFrameState(frameState); + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { + // This is an intrinsic. Deoptimizing within an intrinsic + // must re-execute the intrinsified invocation + assert frameState.outerFrameState() == null; + NodeInputList invokeArgsList = invoke.callTarget().arguments(); + ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]); + FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeArgs); + frameState.replaceAndDelete(stateBeforeCall); } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { - assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; - assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; - assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState; + assert checkInlineeFrameState(invoke, inlineGraph, frameState); if (outerFrameState == null) { outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind); } @@ -450,6 +455,32 @@ } } + static boolean checkInlineeFrameState(Invoke invoke, StructuredGraph inlineGraph, FrameState frameState) { + assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; + assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; + if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) { + if (frameState.method().equals(inlineGraph.method())) { + // Normal inlining expects all outermost inlinee frame states to + // denote the inlinee method + } else if (frameState.method().equals(invoke.callTarget().targetMethod())) { + // This occurs when an intrinsic calls back to the original + // method to handle a slow path. During parsing of such a + // partial intrinsic, these calls are given frame states + // that exclude the outer frame state denoting a position + // in the intrinsic code. + assert inlineGraph.method().getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + + frameState; + } else { + throw new AssertionError(frameState.toString()); + } + } + return true; + } + + private static final ValueNode[] NO_ARGS = {}; + private static boolean isStateAfterException(FrameState frameState) { return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized()); } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Sun Mar 22 17:04:03 2015 +0100 @@ -50,7 +50,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Sun Mar 22 17:04:03 2015 +0100 @@ -36,7 +36,6 @@ import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.word.*; import com.oracle.graal.word.nodes.*; @@ -55,11 +54,9 @@ installer = (ReplacementsImpl) getProviders().getReplacements(); } - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Sun Mar 22 17:04:03 2015 +0100 @@ -24,14 +24,25 @@ import org.junit.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.runtime.*; public class ReplacementsParseTest extends GraalCompilerTest { + private static final Object THROW_EXCEPTION_MARKER = new Object() { + @Override + public String toString() { + return "THROW_EXCEPTION_MARKER"; + } + }; + static class TestMethods { static double next(double v) { return Math.nextAfter(v, 1.0); @@ -45,6 +56,14 @@ return Math.nextAfter(x, d); } + static String stringize(Object obj) { + String res = String.valueOf(obj); + if (res.equals(THROW_EXCEPTION_MARKER.toString())) { + // Tests exception throwing from partial intrinsification + throw new RuntimeException("ex: " + obj); + } + return res; + } } @ClassSubstitution(TestMethods.class) @@ -55,6 +74,23 @@ double xx = (x == -0.0 ? 0.0 : x); return Math.nextAfter(xx, d); } + + @MethodSubstitution + static String stringize(Object obj) { + if (obj != null && obj.getClass() == String.class) { + return asNonNullString(obj); + } else { + return stringize(obj); + } + } + + public static String asNonNullString(Object object) { + return asNonNullStringIntrinsic(object, String.class, true, true); + } + + @NodeIntrinsic(PiNode.class) + private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); + } private static boolean substitutionsInstalled; @@ -112,4 +148,23 @@ outArray[i] = TestMethods.nextAfter(inArray[i], direction); } } + + @Test + public void testCallStringize() { + test("callStringize", "a string"); + test("callStringize", THROW_EXCEPTION_MARKER); + test("callStringize", Boolean.TRUE); + } + + public Object callStringize(Object obj) { + return TestMethods.stringize(obj); + } + + @Test + public void testRootCompileStringize() { + ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize"); + test(method, null, "a string"); + test(method, null, Boolean.TRUE); + test(method, null, THROW_EXCEPTION_MARKER); + } } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Sun Mar 22 17:04:03 2015 +0100 @@ -45,7 +45,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Sun Mar 22 17:04:03 2015 +0100 @@ -32,141 +32,109 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; -import com.oracle.graal.word.*; public class BoxingSnippets implements Snippets { - /** - * This snippet inlining policy differs from the default one in that it does normal inlining of - * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution). - */ - public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy { - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return false; - } - } - - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object booleanValueOf(boolean value) { valueOfCounter.inc(); return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object byteValueOf(byte value) { valueOfCounter.inc(); return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object charValueOf(char value) { valueOfCounter.inc(); return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object doubleValueOf(double value) { valueOfCounter.inc(); return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object floatValueOf(float value) { valueOfCounter.inc(); return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object intValueOf(int value) { valueOfCounter.inc(); return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object longValueOf(long value) { valueOfCounter.inc(); return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object shortValueOf(short value) { valueOfCounter.inc(); return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static boolean booleanValue(Boolean value) { valueOfCounter.inc(); return value.booleanValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static byte byteValue(Byte value) { valueOfCounter.inc(); return value.byteValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static char charValue(Character value) { valueOfCounter.inc(); return value.charValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static double doubleValue(Double value) { valueOfCounter.inc(); return value.doubleValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static float floatValue(Float value) { valueOfCounter.inc(); return value.floatValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static int intValue(Integer value) { valueOfCounter.inc(); return value.intValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static long longValue(Long value) { valueOfCounter.inc(); return value.longValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static short shortValue(Short value) { valueOfCounter.inc(); return value.shortValue(); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Sun Mar 22 17:04:03 2015 +0100 @@ -28,16 +28,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -50,6 +55,7 @@ protected final Providers providers; protected final StructuredGraph graph; protected final WordTypes wordTypes; + protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins; protected FixedWithNextNode lastFixedNode; private final List structures; @@ -57,10 +63,11 @@ abstract static class Structure { } - public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes) { + public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) { this.providers = providers; this.graph = graph; this.wordTypes = wordTypes; + this.graphBuilderPlugins = graphBuilderPlugins; this.lastFixedNode = graph.start(); structures = new ArrayList<>(); @@ -202,14 +209,28 @@ } /** - * Inlines a given invocation to a method. The graph of the inlined method is - * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and - * method substitutions. + * Inlines a given invocation to a method. The graph of the inlined method is processed in the + * same manner as for snippets and method substitutions. */ public void inline(InvokeNode invoke) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); - ReplacementsImpl replacements = (ReplacementsImpl) providers.getReplacements(); - StructuredGraph calleeGraph = replacements.makeGraph(method, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + + MetaAccessProvider metaAccess = providers.getMetaAccess(); + Plugins plugins = new Plugins(graphBuilderPlugins); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + + StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph); + + // Remove all frame states from inlinee + for (Node node : calleeGraph.getNodes()) { + if (node instanceof StateSplit) { + ((StateSplit) node).setStateAfter(null); + } + } + new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph); + InliningUtil.inline(invoke, calleeGraph, false, null); } diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Mar 22 17:04:03 2015 +0100 @@ -41,10 +41,11 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.Graph.Mark; +import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPhase.Instance; import com.oracle.graal.nodes.*; @@ -53,11 +54,8 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; public class ReplacementsImpl implements Replacements { @@ -273,7 +271,7 @@ try (DebugCloseable a = SnippetPreparationTime.start()) { FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, inliningPolicy(method), frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache || args != null) { return newGraph; @@ -313,7 +311,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, null, original, inliningPolicy(substitute), FrameStateProcessing.None); + graph = makeGraph(substitute, null, original, FrameStateProcessing.None); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -424,26 +422,6 @@ return originalJavaMethod; } - private static SnippetInliningPolicy createPolicyClassInstance(Class policyClass) { - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - public SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(providers.getMetaAccess()); - } - return createPolicyClassInstance(policyClass); - } - /** * Creates a preprocessed graph for a snippet or method substitution. * @@ -451,11 +429,10 @@ * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null - * @param policy the inlining policy to use during preprocessing * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) { - return createGraphMaker(method, original, frameStateProcessing).makeGraph(args, policy); + public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + return createGraphMaker(method, original, frameStateProcessing).makeGraph(args); } /** @@ -527,9 +504,9 @@ this.frameStateProcessing = frameStateProcessing; } - public StructuredGraph makeGraph(Object[] args, final SnippetInliningPolicy policy) { + public StructuredGraph makeGraph(Object[] args) { try (Scope s = Debug.scope("BuildSnippetGraph", method)) { - StructuredGraph graph = parseGraph(method, args, policy, 0); + StructuredGraph graph = parseGraph(method, args); if (args == null) { // Cannot have a finalized version of a graph in the cache @@ -603,14 +580,12 @@ return false; } - private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough - - private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { + private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) { StructuredGraph graph = args == null ? replacements.graphCache.get(methodToParse) : null; if (graph == null) { StructuredGraph newGraph = null; try (Scope s = Debug.scope("ParseGraph", methodToParse)) { - newGraph = buildGraph(methodToParse, args, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth); + newGraph = buildGraph(methodToParse, args); } catch (Throwable e) { throw Debug.handle(e); } @@ -662,8 +637,17 @@ protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - ResolvedJavaMethod rootMethodIsReplacement = substitutedMethod == null ? method : substitutedMethod; - return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + ReplacementContext initialReplacementContext = null; + if (method.getAnnotation(MethodSubstitution.class) != null) { + // Late inlined intrinsic + initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1); + } else { + // Snippet + assert method.getAnnotation(Snippet.class) != null; + ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; + initialReplacementContext = new ReplacementContext(original, method); + } + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } /** @@ -700,67 +684,10 @@ } } - private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { - assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args) { assert methodToParse.hasBytecodes() : methodToParse; final StructuredGraph graph = buildInitialGraph(methodToParse, args); try (Scope s = Debug.scope("buildGraph", graph)) { - Set doNotInline = null; - for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { - if (doNotInline != null && doNotInline.contains(callTarget)) { - continue; - } - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (substitutedMethod != null && (callee.equals(method) || callee.equals(substitutedMethod))) { - /* - * Ensure that calls to the original method inside of a substitution ends up - * calling it instead of the Graal substitution. - */ - if (substitutedMethod.hasBytecodes()) { - final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod, null); - Mark mark = graph.getMark(); - InliningUtil.inline(callTarget.invoke(), originalGraph, true, null); - for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) { - if (doNotInline == null) { - doNotInline = new HashSet<>(); - } - // We do not want to do further inlining (now) for calls - // in the original method as this can cause unlimited - // recursive inlining given an eager inlining policy such - // as DefaultSnippetInliningPolicy. - doNotInline.add(inlinedCallTarget); - } - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph, null); - } - } else { - Class macroNodeClass = InliningUtil.getMacroNodeClass(replacements, callee); - if (macroNodeClass != null) { - InliningUtil.inlineMacroNode(callTarget.invoke(), callee, macroNodeClass); - } else { - StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(replacements, callee); - if (callTarget.invokeKind().isDirect() && (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) { - StructuredGraph targetGraph; - if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { - targetGraph = intrinsicGraph; - } else { - if (callee.getName().startsWith("$jacoco")) { - throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + callee.format("%H.%n(%p)") + " from " + methodToParse.format("%H.%n(%p)") + - " while preparing replacement " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + - methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); - } - targetGraph = parseGraph(callee, null, policy, inliningDepth + 1); - } - Object beforeInlineData = beforeInline(callTarget, targetGraph); - InliningUtil.inline(callTarget.invoke(), targetGraph, true, null); - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, targetGraph, beforeInlineData); - } - } - } - } - - afterInlining(graph); for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) { end.disableSafepoint(); diff -r bca124e6ad58 -r aaf5039e56d7 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Sun Mar 22 17:03:42 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Sun Mar 22 17:04:03 2015 +0100 @@ -24,11 +24,7 @@ import java.lang.annotation.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; /** * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering @@ -39,12 +35,6 @@ public @interface Snippet { /** - * Specifies the class defining the inlining policy for this snippet. A - * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied. - */ - Class inlining() default SnippetInliningPolicy.class; - - /** * Specifies whether all FrameStates within this snippet should always be removed. If this is * false, FrameStates are only removed if there are no side-effecting instructions in the * snippet. @@ -52,70 +42,6 @@ boolean removeAllFrameStates() default false; /** - * Guides inlining decisions used when installing a snippet. - */ - public interface SnippetInliningPolicy { - - /** - * Determines if {@code method} should be inlined into {@code caller}. - */ - boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); - - /** - * Determines if {@code method} should be inlined using its replacement graph. - * - * @return true if the replacement graph should be used, false for normal inlining. - */ - boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse); - } - - /** - * The default inlining policy which inlines everything except for methods in any of the - * following categories. - *
    - *
  • {@linkplain Fold foldable} methods
  • - *
  • {@linkplain NodeIntrinsic node intrinsics}
  • - *
  • native methods
  • - *
  • constructors of {@link Throwable} classes
  • - *
- */ - public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { - - private final MetaAccessProvider metaAccess; - - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) { - this.metaAccess = metaAccess; - } - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.isConstructor()) { - return false; - } - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return true; - } - } - - /** * Denotes a snippet parameter representing 0 or more arguments that will be bound during * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet * template creation, its value must be an array whose length specifies the number of arguments