--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java 2017-09-12 22:24:22.957650674 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java 2017-09-12 22:24:22.817644365 -0700 @@ -253,13 +253,17 @@ * Comparator for sorting blocks based on loop depth and probability. */ private static class BlockOrderComparator> implements Comparator { + private static final double EPSILON = 1E-6; @Override public int compare(T a, T b) { - // Loop blocks before any loop exit block. - int diff = b.getLoopDepth() - a.getLoopDepth(); - if (diff != 0) { - return diff; + // Loop blocks before any loop exit block. The only exception are blocks that are + // (almost) impossible to reach. + if (a.probability() > EPSILON && b.probability() > EPSILON) { + int diff = b.getLoopDepth() - a.getLoopDepth(); + if (diff != 0) { + return diff; + } } // Blocks with high probability before blocks with low probability. --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java 2017-09-12 22:24:23.517675909 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java 2017-09-12 22:24:23.379669690 -0700 @@ -172,7 +172,7 @@ PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java 2017-09-12 22:24:24.048699838 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java 2017-09-12 22:24:23.919694025 -0700 @@ -1249,7 +1249,7 @@ } protected PhaseSuite getEagerGraphBuilderSuite() { - return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)); + return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true)); } /** --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java 2017-09-12 22:24:24.570723361 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java 2017-09-12 22:24:24.444717683 -0700 @@ -82,7 +82,7 @@ PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java 2017-09-12 22:24:25.065745667 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java 2017-09-12 22:24:24.925739358 -0700 @@ -89,7 +89,7 @@ OptionValues options = getInitialOptions(); StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java 2017-09-12 22:24:25.562768064 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java 2017-09-12 22:24:25.425761890 -0700 @@ -46,11 +46,13 @@ public static double SideEffectD; public static double SideEffectL; + private static final long booleanArrayBaseOffset; private static final long byteArrayBaseOffset; private static final long intArrayBaseOffset; private static final long longArrayBaseOffset; static { + booleanArrayBaseOffset = UNSAFE.arrayBaseOffset(boolean[].class); byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class); longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class); @@ -212,4 +214,77 @@ test("testWriteFloatToIntArraySnippet"); } + public static final byte[] FINAL_BYTE_ARRAY = new byte[16]; + + public static boolean alignedKill() { + int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + FINAL_BYTE_ARRAY[0] = 1; + int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + + FINAL_BYTE_ARRAY[0] = 0; // reset + return beforeKill == afterKill; + } + + @Test + public void testAlignedKill() { + test("alignedKill"); + } + + public static boolean unalignedKill() { + int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + FINAL_BYTE_ARRAY[1] = 1; + int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + + FINAL_BYTE_ARRAY[1] = 0; // reset + return beforeKill == afterKill; + } + + @Test + public void testUnalignedKill() { + test("unalignedKill"); + } + + public static final boolean[] FINAL_BOOLEAN_ARRAY = new boolean[16]; + + public static boolean killBooleanAccessToBooleanArrayViaBASTORE() { + boolean beforeKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + FINAL_BOOLEAN_ARRAY[0] = true; + boolean afterKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return beforeKill == afterKill; + } + + @Test + public void testKillBooleanAccessToBooleanArrayViaBASTORE() { + test("killBooleanAccessToBooleanArrayViaBASTORE"); + } + + public static boolean killByteAccessToBooleanArrayViaBASTORE() { + byte beforeKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + FINAL_BOOLEAN_ARRAY[0] = true; + byte afterKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return beforeKill == afterKill; + } + + @Test + public void testKillByteAccessToBooleanArrayViaBASTORE() { + test("killByteAccessToBooleanArrayViaBASTORE"); + } + + public static boolean unsafeWriteToBooleanArray() { + UNSAFE.putByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset, (byte) 2); + boolean result = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return result; + } + + @Test + public void testUnsafeWriteToBooleanArray() { + test("unsafeWriteToBooleanArray"); + } + } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java 2017-09-12 22:24:26.040789604 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java 2017-09-12 22:24:25.904783475 -0700 @@ -123,7 +123,7 @@ MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java 2017-09-12 22:24:26.530811685 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java 2017-09-12 22:24:26.385805151 -0700 @@ -344,7 +344,7 @@ MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java 2017-09-12 22:24:27.087836785 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java 2017-09-12 22:24:26.945830386 -0700 @@ -268,7 +268,7 @@ MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java 2017-09-12 22:24:27.731865806 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java 2017-09-12 22:24:27.561858145 -0700 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.core.test.ea; +import org.graalvm.compiler.core.test.GraalCompilerTest; import org.junit.Test; import sun.misc.Unsafe; @@ -36,7 +37,7 @@ import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; -public class PEAReadEliminationTest extends EarlyReadEliminationTest { +public class PEAReadEliminationTest extends GraalCompilerTest { public static int testIndexed1Snippet(int[] array) { array[1] = 1; @@ -50,7 +51,7 @@ @Test public void testIndexed1() { - StructuredGraph graph = processMethod("testIndexed1Snippet", false); + StructuredGraph graph = processMethod("testIndexed1Snippet"); assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -70,7 +71,7 @@ @Test public void testIndexed2() { - StructuredGraph graph = processMethod("testIndexed2Snippet", false); + StructuredGraph graph = processMethod("testIndexed2Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count()); } @@ -94,7 +95,7 @@ @Test public void testIndexed3() { - StructuredGraph graph = processMethod("testIndexed3Snippet", false); + StructuredGraph graph = processMethod("testIndexed3Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -113,7 +114,7 @@ @Test public void testIndexed4() { - StructuredGraph graph = processMethod("testIndexed4Snippet", false); + StructuredGraph graph = processMethod("testIndexed4Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -129,7 +130,7 @@ @Test public void testUnsafe1() { - StructuredGraph graph = processMethod("testUnsafe1Snippet", false); + StructuredGraph graph = processMethod("testUnsafe1Snippet"); assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -142,7 +143,7 @@ @Test public void testUnsafe2() { - StructuredGraph graph = processMethod("testUnsafe2Snippet", false); + StructuredGraph graph = processMethod("testUnsafe2Snippet"); assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -158,7 +159,7 @@ @Test public void testUnsafe3() { - StructuredGraph graph = processMethod("testUnsafe3Snippet", false); + StructuredGraph graph = processMethod("testUnsafe3Snippet"); assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -172,28 +173,11 @@ @Test public void testUnsafe4() { - StructuredGraph graph = processMethod("testUnsafe4Snippet", false); + StructuredGraph graph = processMethod("testUnsafe4Snippet"); assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count()); } - private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; - private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; - - public static int testUnsafe5Snippet(int v, long[] array) { - int s = UNSAFE.getInt(array, offsetLong1); - UNSAFE.putInt(array, offsetLong1, v); - UNSAFE.putInt(array, offsetLong2, v); - return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); - } - - @Test - public void testUnsafe5() { - StructuredGraph graph = processMethod("testUnsafe5Snippet", false); - assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); - } - - @Override - protected StructuredGraph processMethod(final String snippet, boolean doLowering) { + protected StructuredGraph processMethod(final String snippet) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); HighTierContext context = getDefaultHighTierContext(); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java 2017-09-12 22:24:28.535902037 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java 2017-09-12 22:24:28.377894917 -0700 @@ -256,7 +256,7 @@ * yet and the bytecode parser would only create a graph. */ Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); /* * For simplicity, we ignore all exception handling during the static analysis. * This is a constraint of this example code, a real static analysis needs to --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java 2017-09-12 22:24:29.227933221 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java 2017-09-12 22:24:29.090927047 -0700 @@ -181,6 +181,12 @@ public String toString() { StringBuilder str = new StringBuilder(); str.append(super.toString()); + str.append(context()); + return str.toString(); + } + + public String context() { + StringBuilder str = new StringBuilder(); for (String s : context) { str.append("\n\tat ").append(s); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java 2017-09-12 22:24:29.818959853 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java 2017-09-12 22:24:29.679953589 -0700 @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Objects; import java.util.function.Predicate; +import java.util.function.Supplier; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; @@ -598,6 +599,15 @@ } } + /** + * Update the source position only if it is null. + */ + public void updateNodeSourcePosition(Supplier sourcePositionSupp) { + if (this.sourcePosition == null) { + setNodeSourcePosition(sourcePositionSupp.get()); + } + } + public DebugCloseable withNodeSourcePosition() { return graph.withNodeSourcePosition(this); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java 2017-09-12 22:24:30.469989189 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java 2017-09-12 22:24:30.314982205 -0700 @@ -195,7 +195,7 @@ Node result = graph.getNode(nodeId); if (result == null) { // node was deleted -> clear the bit and continue searching - bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex); + bits[wordIndex] = bits[wordIndex] & ~(1L << bitIndex); int nextNodeId = nodeId + 1; if ((nextNodeId & (Long.SIZE - 1)) == 0) { // we reached the end of this word --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java 2017-09-12 22:24:31.051015371 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java 2017-09-12 22:24:30.921009513 -0700 @@ -28,6 +28,10 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; import java.util.ArrayList; import java.util.List; @@ -39,6 +43,7 @@ import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.LIRKindTool; import org.graalvm.compiler.debug.DebugContext; @@ -415,49 +420,49 @@ return result; } - @Override - public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL); - Constant[] constants = new Constant[]{constant}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall); append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); return emitMove(result); } - @Override - public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL); + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { Constant[] constants = new Constant[]{constant}; + Object[] notes = new Object[]{action}; + return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState); + } + + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) { AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); + return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState); } @Override - public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS); - Constant[] constants = new Constant[]{method}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); + public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); + } + @Override + public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); } @Override public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL); - Constant[] constants = new Constant[]{constant}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); + return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState); + } + + @Override + public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; + return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState); + } + + @Override + public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) { + AllocatableValue[] constantDescriptions = new AllocatableValue[0]; + return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState); } @Override --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java 2017-09-12 22:24:31.611040607 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java 2017-09-12 22:24:31.478034613 -0700 @@ -27,6 +27,7 @@ import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.calc.Condition; @@ -255,7 +256,7 @@ @Override public void emitPrefetchAllocate(Value address) { SPARCAddressValue addr = asAddressValue(address); - append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr)); + append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads)); } public StackSlot getDeoptimizationRescueSlot() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java 2017-09-12 22:24:32.218067960 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java 2017-09-12 22:24:32.054060570 -0700 @@ -52,8 +52,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -475,6 +477,7 @@ private void compile(String classPath) throws IOException { final String[] entries = classPath.split(File.pathSeparator); long start = System.currentTimeMillis(); + Map initialThreads = Thread.getAllStackTraces(); try { // compile dummy method to get compiler initialized outside of the @@ -549,7 +552,13 @@ classFileCounter++; - if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) { + if (className.startsWith("jdk.management.") || + className.startsWith("jdk.internal.cmm.*") || + // GR-5881: The class initializer for + // sun.tools.jconsole.OutputViewer + // spawns non-daemon threads for redirecting sysout and syserr. + // These threads tend to cause deadlock at VM exit + className.startsWith("sun.tools.jconsole.")) { continue; } @@ -643,6 +652,33 @@ } else { TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get()); } + + // Apart from the main thread, there should be only be daemon threads + // alive now. If not, then a class initializer has probably started + // a thread that could cause a deadlock while trying to exit the VM. + // One known example of this is sun.tools.jconsole.OutputViewer which + // spawns threads to redirect sysout and syserr. To help debug such + // scenarios, the stacks of potentially problematic threads are dumped. + Map suspiciousThreads = new HashMap<>(); + for (Map.Entry e : Thread.getAllStackTraces().entrySet()) { + Thread thread = e.getKey(); + if (thread != Thread.currentThread() && !initialThreads.containsKey(thread) && !thread.isDaemon() && thread.isAlive()) { + suspiciousThreads.put(thread, e.getValue()); + } + } + if (!suspiciousThreads.isEmpty()) { + TTY.println("--- Non-daemon threads started during CTW ---"); + for (Map.Entry e : suspiciousThreads.entrySet()) { + Thread thread = e.getKey(); + if (thread.isAlive()) { + TTY.println(thread.toString() + " " + thread.getState()); + for (StackTraceElement ste : e.getValue()) { + TTY.println("\tat " + ste); + } + } + } + TTY.println("---------------------------------------------"); + } } private synchronized void startThreads() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java 2017-09-12 22:24:32.904098873 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java 2017-09-12 22:24:32.735091258 -0700 @@ -240,7 +240,7 @@ } /** - * @return the compilation id plus a trailing '%' is the compilation is an OSR to match + * @return the compilation id plus a trailing '%' if the compilation is an OSR to match * PrintCompilation style output */ public String getIdString() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2017-09-12 22:24:33.536127353 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2017-09-12 22:24:33.402121315 -0700 @@ -29,7 +29,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -73,7 +72,6 @@ protected CompilerConfigurationFactory(String name, int autoSelectionPriority) { this.name = name; this.autoSelectionPriority = autoSelectionPriority; - assert checkAndAddNewFactory(this); } public abstract CompilerConfiguration createCompilerConfiguration(); @@ -127,18 +125,18 @@ } /** - * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all - * {@link CompilerConfigurationFactory} instances. + * Asserts uniqueness of {@link #name} and {@link #autoSelectionPriority} for {@code factory} in + * {@code factories}. */ - private static final List factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null; - - private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) { + private static boolean checkUnique(CompilerConfigurationFactory factory, List factories) { for (CompilerConfigurationFactory other : factories) { - assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; - assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() + - ": " + factory.autoSelectionPriority; + if (other != factory) { + assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; + assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + + other.getClass().getName() + + ": " + factory.autoSelectionPriority; + } } - factories.add(factory); return true; } @@ -148,6 +146,7 @@ private static List getAllCandidates() { List candidates = new ArrayList<>(); for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + assert checkUnique(candidate, candidates); candidates.add(candidate); } Collections.sort(candidates); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java 2017-09-12 22:24:34.171155969 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java 2017-09-12 22:24:34.026149435 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -35,6 +35,7 @@ } public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol"); + public final long resolveDynamicInvoke = getAddress("CompilerRuntime::resolve_dynamic_invoke"); public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol"); public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters"); public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol"); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java 2017-09-12 22:24:34.795184088 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java 2017-09-12 22:24:34.662178095 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -296,6 +296,11 @@ /** * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new ForeignCallDescriptor("resolve_dynamic_invoke", Object.class, Word.class); + + /** + * @see ResolveConstantStubCall */ public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java 2017-09-12 22:24:35.482215047 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java 2017-09-12 22:24:35.318207656 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -68,7 +68,7 @@ * @return value of loaded address in register */ default Value emitLoadObjectAddress(Constant constant) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load an object address is not currently supported on %s", target().arch); } /** @@ -79,7 +79,7 @@ * @return Value of loaded address in register */ default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load a metaspace address is not currently supported on %s", target().arch); } /** @@ -90,7 +90,7 @@ * @return value of loaded global in register */ default Value emitLoadConfigValue(int markId, LIRKind kind) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load a config value is not currently supported on %s", target().arch); } /** @@ -100,10 +100,21 @@ * @param constantDescription a description of the string that need to be materialized (and * interned) as java.lang.String, generated with {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve an object constant is not currently supported on %s", target().arch); + } + + /** + * Emits code to resolve a dynamic constant. + * + * @param constant original constant + * @param frameState frame state for the runtime call + * @return the address of the requested constant. + */ + default Value emitResolveDynamicInvoke(Constant constant, LIRFrameState frameState) { + throw new GraalError("Emitting code to resolve a dynamic constant is not currently supported on %s", target().arch); } /** @@ -113,10 +124,10 @@ * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} * generated by {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve a metaspace constant is not currently supported on %s", target().arch); } /** @@ -129,10 +140,10 @@ * @param methodDescription is symbolic description of the constant generated by * {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve a method and load counters is not currently supported on %s", target().arch); } /** @@ -144,10 +155,10 @@ * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} * generated by {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to initialize a class is not currently supported on %s", target().arch); } /** @@ -156,7 +167,7 @@ * @return value of the counter */ default Value emitRandomSeed() { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to return a random seed is not currently supported on %s", target().arch); } /** --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java 2017-09-12 22:24:36.070241544 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java 2017-09-12 22:24:35.917234649 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -24,7 +24,6 @@ import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs; import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; @@ -70,6 +69,7 @@ import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; @@ -214,10 +214,8 @@ arraycopySnippets = new ArrayCopySnippets.Templates(options, factories, runtime, providers, target); stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target); hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target); - if (GeneratePIC.getValue(options)) { - resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); - profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); - } + resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); + profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target)); } @@ -364,6 +362,10 @@ } } else if (n instanceof IdentityHashCodeNode) { hashCodeSnippets.lower((IdentityHashCodeNode) n, tool); + } else if (n instanceof ResolveDynamicConstantNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool); + } } else if (n instanceof ResolveConstantNode) { if (graph.getGuardsStage().areFrameStatesAtDeopts()) { resolveConstantSnippets.lower((ResolveConstantNode) n, tool); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java 2017-09-12 22:24:36.651267726 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java 2017-09-12 22:24:36.496260741 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -22,8 +22,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; -import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; @@ -63,7 +61,6 @@ import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.DynamicPiNode; import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.LogicNode; @@ -80,7 +77,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; -import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; import org.graalvm.compiler.nodes.memory.address.AddressNode; @@ -101,13 +97,9 @@ import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -139,42 +131,9 @@ plugins.appendTypePlugin(nodePlugin); plugins.appendNodePlugin(nodePlugin); OptionValues options = replacements.getOptions(); - if (GeneratePIC.getValue(options)) { - // AOT needs to filter out bad invokes - plugins.prependNodePlugin(new NodePlugin() { - @Override - public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if (b.parsingIntrinsic()) { - return false; - } - // check if the holder has a valid fingerprint - if (((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() == 0) { - // Deopt otherwise - b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; - } - // the last argument that may come from appendix, check if it is a supported - // constant type - if (args.length > 0) { - JavaConstant constant = args[args.length - 1].asJavaConstant(); - if (constant != null && constant instanceof HotSpotObjectConstant) { - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType(); - Class clazz = type.mirror(); - if (clazz.equals(String.class)) { - return false; - } - if (Class.class.isAssignableFrom(clazz) && ((HotSpotResolvedObjectType) type).getFingerprint() != 0) { - return false; - } - b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; - } - } - return false; - } - }); + if (!GeneratePIC.getValue(options)) { + plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true)); } - plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true)); plugins.appendInlineInvokePlugin(replacements); if (InlineDuringParsing.getValue(options)) { plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin()); @@ -196,7 +155,9 @@ registerClassPlugins(plugins, config, replacementBytecodeProvider); registerSystemPlugins(invocationPlugins, foreignCalls); registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider); - registerCallSitePlugins(invocationPlugins); + if (!GeneratePIC.getValue(options)) { + registerCallSitePlugins(invocationPlugins); + } registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider); registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider); registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java 2017-09-12 22:24:37.255294944 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java 2017-09-12 22:24:37.088287418 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -44,6 +44,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; @@ -305,6 +306,7 @@ registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore()); linkForeignCall(options, providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(options, providers, RESOLVE_DYNAMIC_INVOKE, cr.resolveDynamicInvoke, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); linkForeignCall(options, providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); linkForeignCall(options, providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(options, providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java 2017-09-12 22:24:37.955326488 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java 2017-09-12 22:24:37.798319413 -0700 @@ -42,6 +42,7 @@ import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -107,6 +108,7 @@ // @formatter:off return n instanceof LoadConstantIndirectlyNode || n instanceof LoadConstantIndirectlyFixedNode || + n instanceof ResolveDynamicConstantNode || n instanceof ResolveConstantNode || n instanceof InitializeKlassNode; // @formatter:on --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java 2017-09-12 22:24:38.587354968 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java 2017-09-12 22:24:38.422347533 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -36,7 +36,9 @@ import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall; import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; @@ -73,6 +75,15 @@ } @Snippet + public static Object resolveDynamicConstant(Object constant) { + Object result = LoadConstantIndirectlyNode.loadObject(constant); + if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) { + result = ResolveDynamicStubCall.resolveInvoke(constant); + } + return result; + } + + @Snippet public static KlassPointer resolveKlassConstant(KlassPointer constant) { KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant); if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { @@ -110,6 +121,7 @@ public static class Templates extends AbstractTemplates { private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant"); + private final SnippetInfo resolveDynamicConstant = snippet(ResolveConstantSnippets.class, "resolveDynamicConstant"); private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant"); private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters"); private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass"); @@ -119,6 +131,25 @@ super(options, factories, providers, providers.getSnippetReflection(), target); } + public void lower(ResolveDynamicConstantNode resolveConstantNode, LoweringTool tool) { + StructuredGraph graph = resolveConstantNode.graph(); + + ValueNode value = resolveConstantNode.value(); + assert value.isConstant() : "Expected a constant: " + value; + SnippetInfo snippet = resolveDynamicConstant; + + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("constant", value); + + SnippetTemplate template = template(graph.getDebug(), args); + template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); + + assert resolveConstantNode.hasNoUsages(); + if (!resolveConstantNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode); + } + } + public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) { StructuredGraph graph = resolveConstantNode.graph(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-09-12 22:24:39.144380068 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-09-12 22:24:38.993373264 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -374,6 +374,7 @@ import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -933,8 +934,13 @@ * @param type the unresolved type of the constant */ protected void handleUnresolvedLoadConstant(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + /* + * Track source position for deopt nodes even if + * GraphBuilderConfiguration.trackNodeSourcePosition is not set. + */ + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -942,7 +948,7 @@ * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); } @@ -952,9 +958,10 @@ * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); AbstractBeginNode successor = graph.add(new BeginNode()); DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1)); lastInstr = successor; frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); @@ -964,8 +971,9 @@ * @param type the type being instantiated */ protected void handleUnresolvedNewInstance(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -973,8 +981,9 @@ * @param length the length of the array */ protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -982,8 +991,9 @@ * @param dims the dimensions for the multi-array */ protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -991,8 +1001,9 @@ * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1001,16 +1012,18 @@ * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** * @param type */ protected void handleUnresolvedExceptionType(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1018,8 +1031,9 @@ * @param invokeKind */ protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) { @@ -1307,7 +1321,12 @@ return false; } - protected void genInvokeStatic(JavaMethod target) { + protected void genInvokeStatic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeStatic(target); + } + + void genInvokeStatic(JavaMethod target) { if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); @@ -1332,6 +1351,11 @@ } } + protected void genInvokeInterface(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeInterface(target); + } + protected void genInvokeInterface(JavaMethod target) { if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); @@ -1341,44 +1365,108 @@ } } - protected void genInvokeDynamic(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false)); - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); - } else { + protected void genInvokeDynamic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeDynamic(target); + } + + void genInvokeDynamic(JavaMethod target) { + if (!(target instanceof ResolvedJavaMethod) || !genDynamicInvokeHelper((ResolvedJavaMethod) target, stream.readCPI4(), INVOKEDYNAMIC)) { handleUnresolvedInvoke(target, InvokeKind.Static); } } - protected void genInvokeVirtual(JavaMethod target) { - if (callTargetIsResolved(target)) { - /* - * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) - * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see - * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic - */ - boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic(); - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); - if (hasReceiver) { - appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + protected void genInvokeVirtual(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeVirtual(target); + } + + private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) { + assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL; + + InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin(); + + if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) { + // regular invokevirtual, let caller handle it + return false; + } + + if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) { + // bail out if static compiler and no dynamic type support + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode); + ValueNode appendixNode = null; + + if (appendix != null) { + if (invokeDynamicPlugin != null) { + invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target); + + // Will perform runtime type checks and static initialization + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore); } else { - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph); } + + frameState.push(JavaKind.Object, appendixNode); + + } else if (GeneratePIC.getValue(options)) { + // Need to emit runtime guard and perform static initialization. + // Not implemented yet. + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic(); + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); + if (hasReceiver) { + appendInvoke(InvokeKind.Virtual, target, args); } else { + appendInvoke(InvokeKind.Static, target, args); + } + + return true; + } + + void genInvokeVirtual(JavaMethod target) { + if (!genInvokeVirtualHelper(target)) { handleUnresolvedInvoke(target, InvokeKind.Virtual); } + } + + private boolean genInvokeVirtualHelper(JavaMethod target) { + if (!callTargetIsResolved(target)) { + return false; + } + + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + int cpi = stream.readCPI(); + + /* + * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or + * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic + */ + + if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) { + return true; + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + + return true; + } + + protected void genInvokeSpecial(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeSpecial(target); } - protected void genInvokeSpecial(JavaMethod target) { + void genInvokeSpecial(JavaMethod target) { if (callTargetIsResolved(target)) { assert target != null; assert target.getSignature() != null; @@ -2149,9 +2237,9 @@ TTY.println(s); } - protected BytecodeParserError asParserError(Throwable e) { + protected RuntimeException throwParserError(Throwable e) { if (e instanceof BytecodeParserError) { - return (BytecodeParserError) e; + throw (BytecodeParserError) e; } BytecodeParser bp = this; BytecodeParserError res = new BytecodeParserError(e); @@ -2159,7 +2247,7 @@ res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci())); bp = bp.parent; } - return res; + throw res; } protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { @@ -2837,7 +2925,7 @@ // Don't wrap bailouts as parser errors throw e; } catch (Throwable e) { - throw asParserError(e); + throw throwParserError(e); } if (lastInstr == null || lastInstr.next() != null) { @@ -3257,7 +3345,7 @@ int nextBC = stream.readUByte(nextBCI); if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { stream.next(); - genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value); + genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); } else { frameState.push(JavaKind.Object, value); } @@ -3506,15 +3594,18 @@ return result; } - private JavaField lookupField(int cpi, int opcode) { + protected JavaField lookupField(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode); + if (graphBuilderConfig.eagerResolving()) { - assert result instanceof ResolvedJavaField : "Not resolved: " + result; - ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); - if (!declaringClass.isInitialized()) { - assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; - declaringClass.initialize(); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; + if (result instanceof ResolvedJavaField) { + ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); + if (!declaringClass.isInitialized()) { + assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; + declaringClass.initialize(); + } } } assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; @@ -3524,11 +3615,11 @@ private Object lookupConstant(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); Object result = constantPool.lookupConstant(cpi); - assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + assert !graphBuilderConfig.unresolvedIsError() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; return result; } - private void maybeEagerlyResolve(int cpi, int bytecode) { + protected void maybeEagerlyResolve(int cpi, int bytecode) { if (intrinsicContext != null) { constantPool.loadReferencedType(cpi, bytecode); } else if (graphBuilderConfig.eagerResolving()) { @@ -3653,9 +3744,12 @@ } } - void genNewInstance(int cpi) { + protected void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); + genNewInstance(type); + } + void genNewInstance(JavaType type) { if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { handleUnresolvedNewInstance(type); return; @@ -3790,8 +3884,13 @@ frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims))); } - private void genGetField(JavaField field) { - genGetField(field, frameState.pop(JavaKind.Object)); + protected void genGetField(int cpi, int opcode) { + genGetField(cpi, opcode, frameState.pop(JavaKind.Object)); + } + + protected void genGetField(int cpi, int opcode, ValueNode receiverInput) { + JavaField field = lookupField(cpi, opcode); + genGetField(field, receiverInput); } private void genGetField(JavaField field, ValueNode receiverInput) { @@ -3867,7 +3966,12 @@ return false; } - private void genPutField(JavaField field) { + protected void genPutField(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutField(field); + } + + protected void genPutField(JavaField field) { genPutField(field, frameState.pop(field.getJavaKind())); } @@ -3895,6 +3999,11 @@ } } + protected void genGetStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genGetStatic(field); + } + private void genGetStatic(JavaField field) { ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null); if (resolvedField == null) { @@ -3956,7 +4065,12 @@ return null; } - private void genPutStatic(JavaField field) { + protected void genPutStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutStatic(field); + } + + protected void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getJavaKind()); ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value); if (resolvedField == null) { @@ -4320,15 +4434,15 @@ case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break; case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break; case RETURN : genReturn(null, JavaKind.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 GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, opcode); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, opcode); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, opcode); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, opcode); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(cpi, opcode); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break; case NEW : genNewInstance(stream.readCPI()); break; case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java 2017-09-12 22:24:39.858412243 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java 2017-09-12 22:24:39.707405439 -0700 @@ -34,18 +34,17 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class); public static final SizeEstimate SIZE = SizeEstimate.create(1); - private final int instr; // AllocatePrefetchInstr + private final SPARCAssembler.Fcn fcn; @Alive({COMPOSITE}) protected SPARCAddressValue address; - public SPARCPrefetchOp(SPARCAddressValue address, int instr) { + public SPARCPrefetchOp(SPARCAddressValue address, SPARCAssembler.Fcn fcn) { super(TYPE, SIZE); this.address = address; - this.instr = instr; + this.fcn = fcn; } @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert instr >= 0 && instr < SPARCAssembler.Fcn.values().length : instr; - masm.prefetch(address.toAddress(), SPARCAssembler.Fcn.values()[instr]); + masm.prefetch(address.toAddress(), fcn); } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java 2017-09-12 22:24:40.451438966 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java 2017-09-12 22:24:40.297432026 -0700 @@ -466,28 +466,6 @@ AbstractMergeNode merge = (AbstractMergeNode) node; EndNode singleEnd = merge.forwardEndAt(0); - /* - * In some corner cases, the MergeNode already has PhiNodes. Since there is a single - * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with - * this single input. - */ - for (PhiNode phi : merge.phis()) { - assert phi.inputs().count() == 1 : "input count must match end count"; - Node singlePhiInput = phi.inputs().first(); - - /* - * We do not have the orderID of the PhiNode anymore, so we need to search through - * the complete list of nodes to find a match. - */ - for (int i = 0; i < loopScope.createdNodes.length; i++) { - if (loopScope.createdNodes[i] == phi) { - loopScope.createdNodes[i] = singlePhiInput; - } - } - - phi.replaceAndDelete(singlePhiInput); - } - /* Nodes that would use this merge as the guard need to use the previous block. */ registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false); @@ -973,8 +951,22 @@ int phiNodeOrderId = readOrderId(methodScope); ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId); - ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId); + + if (existing != null && merge.phiPredecessorCount() == 1) { + /* + * When exploding loops and the code after the loop (FULL_EXPLODE_UNTIL_RETURN), + * then an existing value can already be registered: Parsing of the code before the + * loop registers it when preparing for the later merge. The code after the loop, + * which starts with a clone of the values that were created before the loop, sees + * the stale value when processing the merge the first time. We can safely ignore + * the stale value because it will never be needed to be merged (we are exploding + * until we hit a return). + */ + assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0; + existing = null; + } + if (lazyPhi && (existing == null || existing == phiInput)) { /* Phi function not yet necessary. */ registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java 2017-09-12 22:24:41.003463841 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java 2017-09-12 22:24:40.841456541 -0700 @@ -30,6 +30,8 @@ import java.util.Iterator; import java.util.List; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -52,7 +54,10 @@ import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.graalvm.compiler.nodes.extended.UnboxNode; import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; @@ -256,6 +261,123 @@ } } } + + if (tryEliminateBoxedReferenceEquals(tool)) { + return; + } + } + + private boolean isUnboxedFrom(MetaAccessProvider meta, ValueNode x, ValueNode src) { + if (x == src) { + return true; + } else if (x instanceof UnboxNode) { + return isUnboxedFrom(meta, ((UnboxNode) x).getValue(), src); + } else if (x instanceof PiNode) { + PiNode pi = (PiNode) x; + return isUnboxedFrom(meta, pi.getOriginalNode(), src); + } else if (x instanceof LoadFieldNode) { + LoadFieldNode load = (LoadFieldNode) x; + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + if (load.getValue().stamp().javaType(meta).equals(integerType)) { + return isUnboxedFrom(meta, load.getValue(), src); + } else { + return false; + } + } else { + return false; + } + } + + /** + * Attempts to replace the following pattern: + * + *
+     * Integer x = ...;
+     * Integer y = ...;
+     * if ((x == y) || x.equals(y)) { ... }
+     * 
+ * + * with: + * + *
+     * Integer x = ...;
+     * Integer y = ...;
+     * if (x.equals(y)) { ... }
+     * 
+ * + * whenever the probability that the reference check will pass is relatively small. + * + * See GR-1315 for more information. + */ + private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) { + if (!(condition instanceof ObjectEqualsNode)) { + return false; + } + + MetaAccessProvider meta = tool.getMetaAccess(); + ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition; + ValueNode x = equalsCondition.getX(); + ValueNode y = equalsCondition.getY(); + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + + // At least one argument for reference equal must be a boxed primitive. + if (!x.stamp().javaType(meta).equals(integerType) && !y.stamp().javaType(meta).equals(integerType)) { + return false; + } + + // The reference equality check is usually more efficient compared to a boxing check. + // The success of the reference equals must therefore be relatively rare, otherwise it makes + // no sense to eliminate it. + if (getTrueSuccessorProbability() > 0.4) { + return false; + } + + // True branch must be empty. + if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) { + if (trueSuccessor.next() instanceof EndNode) { + // Empty true branch. + } else { + return false; + } + } else { + return false; + } + + // False branch must only check the unboxed values. + UnboxNode unbox = null; + FixedGuardNode unboxCheck = null; + for (FixedNode node : falseSuccessor.getBlockNodes()) { + if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode || + node instanceof LoadFieldNode || node instanceof LoopExitNode)) { + return false; + } + if (node instanceof UnboxNode) { + if (unbox == null) { + unbox = (UnboxNode) node; + } else { + return false; + } + } + if (!(node instanceof FixedGuardNode)) { + continue; + } + FixedGuardNode fixed = (FixedGuardNode) node; + if (!(fixed.condition() instanceof IntegerEqualsNode)) { + continue; + } + IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition(); + if ((isUnboxedFrom(meta, equals.getX(), x) && isUnboxedFrom(meta, equals.getY(), y)) || (isUnboxedFrom(meta, equals.getX(), y) && isUnboxedFrom(meta, equals.getY(), x))) { + unboxCheck = fixed; + } + } + if (unbox == null || unboxCheck == null) { + return false; + } + + // Falsify the reference check. + setCondition(graph().addOrUnique(LogicConstantNode.contradiction())); + + return true; } /** --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java 2017-09-12 22:24:41.584490022 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java 2017-09-12 22:24:41.433483218 -0700 @@ -60,6 +60,11 @@ */ public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); + /** + * Denotes an off-heap address. + */ + public static final LocationIdentity OFF_HEAP_LOCATION = NamedLocationIdentity.mutable("OFF_HEAP_LOCATION"); + private final String name; private final boolean immutable; @@ -81,7 +86,7 @@ /** * Creates a named unique location identity for read operations against immutable memory. - * Immutable memory will never have a visible write in the graph, which is more restictive than + * Immutable memory will never have a visible write in the graph, which is more restrictive than * Java final. * * @param name the name of the new location identity --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java 2017-09-12 22:24:42.175516655 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java 2017-09-12 22:24:42.040510571 -0700 @@ -60,12 +60,26 @@ return this; // this will trap, can not canonicalize } return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() % y); - } else if (forY.isConstant()) { - long c = forY.asJavaConstant().asLong(); - if (c == 1 || c == -1) { + } else if (forY.isConstant() && forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + long constY = forY.asJavaConstant().asLong(); + IntegerStamp xStamp = (IntegerStamp) forX.stamp(); + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); + if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) { + return new SignedRemNode(forX, ConstantNode.forIntegerStamp(yStamp, -constY)).canonical(tool); + } + + if (constY == 1) { return ConstantNode.forIntegerStamp(stamp(), 0); - } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) { - return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1)); + } else if (CodeUtil.isPowerOf2(constY)) { + if (xStamp.isPositive()) { + return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1)); + } else if (xStamp.isNegative()) { + return new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))); + } else { + return new ConditionalNode(IntegerLessThanNode.create(forX, ConstantNode.forIntegerStamp(forX.stamp(), 0)), + new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))), + new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1))); + } } } return this; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java 2017-09-12 22:24:42.713540899 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java 2017-09-12 22:24:42.579534861 -0700 @@ -30,7 +30,10 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.ReinterpretNode; import org.graalvm.compiler.nodes.java.LoadFieldNode; @@ -38,19 +41,23 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; /** * Load of a value from a location specified as an offset relative to an object. No null check is * performed before the load. */ @NodeInfo(cycles = CYCLES_2, size = SIZE_1) -public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable { +public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable { public static final NodeClass TYPE = NodeClass.create(RawLoadNode.class); /** @@ -123,6 +130,32 @@ } @Override + public Node canonical(CanonicalizerTool tool) { + if (!isAnyLocationForced() && getLocationIdentity().isAny()) { + ValueNode targetObject = object(); + if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) { + ConstantNode objectConstant = (ConstantNode) targetObject; + ResolvedJavaType type = StampTool.typeOrNull(objectConstant); + if (type != null && type.isArray()) { + JavaConstant arrayConstant = objectConstant.asJavaConstant(); + if (arrayConstant != null) { + int stableDimension = objectConstant.getStableDimension(); + if (stableDimension > 0) { + long constantOffset = offset().asJavaConstant().asLong(); + Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset); + boolean isDefaultStable = objectConstant.isDefaultStable(); + if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { + return ConstantNode.forConstant(stamp(), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess()); + } + } + } + } + } + } + return super.canonical(tool); + } + + @Override protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) { return LoadFieldNode.create(assumptions, object(), field); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java 2017-09-12 22:24:43.248565008 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java 2017-09-12 22:24:43.082557527 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -39,6 +39,7 @@ private InlineInvokePlugin[] inlineInvokePlugins; private LoopExplosionPlugin loopExplosionPlugin; private ClassInitializationPlugin classInitializationPlugin; + private InvokeDynamicPlugin invokeDynamicPlugin; private ProfilingPlugin profilingPlugin; /** @@ -54,6 +55,7 @@ this.inlineInvokePlugins = copyFrom.inlineInvokePlugins; this.loopExplosionPlugin = copyFrom.loopExplosionPlugin; this.classInitializationPlugin = copyFrom.classInitializationPlugin; + this.invokeDynamicPlugin = copyFrom.invokeDynamicPlugin; this.profilingPlugin = copyFrom.profilingPlugin; } @@ -167,6 +169,14 @@ this.classInitializationPlugin = plugin; } + public InvokeDynamicPlugin getInvokeDynamicPlugin() { + return invokeDynamicPlugin; + } + + public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) { + this.invokeDynamicPlugin = plugin; + } + public ProfilingPlugin getProfilingPlugin() { return profilingPlugin; } @@ -189,6 +199,7 @@ private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{}; private final boolean eagerResolving; + private final boolean unresolvedIsError; private final BytecodeExceptionMode bytecodeExceptionMode; private final boolean omitAssertions; private final ResolvedJavaType[] skippedExceptionTypes; @@ -216,10 +227,11 @@ Profile } - protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints, + protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints, boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes, Plugins plugins) { this.eagerResolving = eagerResolving; + this.unresolvedIsError = unresolvedIsError; this.bytecodeExceptionMode = bytecodeExceptionMode; this.omitAssertions = omitAssertions; this.insertFullInfopoints = insertFullInfopoints; @@ -235,35 +247,52 @@ */ public GraphBuilderConfiguration copy() { Plugins newPlugins = new Plugins(plugins); - GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, - newPlugins); + GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, + skippedExceptionTypes, newPlugins); return result; } + /** + * Set the {@link #unresolvedIsError} flag. This flag can be set independently from + * {@link #eagerResolving}, i.e., even if eager resolving fails execution is assumed to be + * valid. This allows us for example to process unresolved types/methods/fields even when + * eagerly resolving elements. + */ + public GraphBuilderConfiguration withUnresolvedIsError(boolean newUnresolvedIsError) { + return new GraphBuilderConfiguration(eagerResolving, newUnresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); + } + public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) { - return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(newEagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) { - return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) { - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public ResolvedJavaType[] getSkippedExceptionTypes() { @@ -291,20 +320,16 @@ } public static GraphBuilderConfiguration getDefault(Plugins plugins) { - return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins); + return new GraphBuilderConfiguration(false, false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins); } public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins); + return new GraphBuilderConfiguration(true, true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins); } - /** - * Returns {@code true} if it is an error for a class/field/method resolution to fail. The - * default is the same result as returned by {@link #eagerResolving()}. However, it may be - * overridden to allow failure even when {@link #eagerResolving} is {@code true}. - */ + /** Returns {@code true} if it is an error for a class/field/method resolution to fail. */ public boolean unresolvedIsError() { - return eagerResolving; + return unresolvedIsError; } public Plugins getPlugins() { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java 2017-09-12 22:24:43.885593713 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java 2017-09-12 22:24:43.732586818 -0700 @@ -295,4 +295,20 @@ default void notifyReplacedCall(ResolvedJavaMethod targetMethod, ConstantNode node) { } + + /** + * Interface whose instances hold inlining information about the current context, in a wider + * sense. The wider sense in this case concerns graph building approaches that don't necessarily + * keep a chain of {@link GraphBuilderContext} instances normally available through + * {@linkplain #getParent()}. Examples of such approaches are partial evaluation and incremental + * inlining. + */ + interface ExternalInliningContext { + int getInlinedDepth(); + } + + default ExternalInliningContext getExternalInliningContext() { + return null; + } + } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java 2017-09-12 22:24:44.545623455 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java 2017-09-12 22:24:44.384616200 -0700 @@ -137,8 +137,9 @@ } long offset; if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) { - // On big endian, we do just get expect the type be right aligned in this memory slot - offset = constantOffset - (componentType.getJavaKind().getByteCount() - Math.min(componentType.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount())); + // On big endian, we expect the value to be correctly aligned in memory + int componentByteCount = componentType.getJavaKind().getByteCount(); + offset = constantOffset - (componentByteCount - Math.min(componentByteCount, 4 + expectedEntryKind.getByteCount())); } else { offset = constantOffset; } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java 2017-09-12 22:24:45.139650222 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java 2017-09-12 22:24:45.011644454 -0700 @@ -132,11 +132,11 @@ StructuredGraph targetGraph = null; DebugContext debug = getDebugContext(); try (DebugContext.Scope scope = debug.scope("GraphPETest", testMethod)) { - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true); registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins()); targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build(); CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, - null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null); + null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null); decoder.decode(testMethod); debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph"); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java 2017-09-12 22:24:45.688674962 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java 2017-09-12 22:24:45.547668608 -0700 @@ -63,9 +63,9 @@ public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin, - invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins); + invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod); this.providers = providers; this.graphBuilderConfig = graphBuilderConfig; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java 2017-09-12 22:24:46.167696547 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java 2017-09-12 22:24:46.030690374 -0700 @@ -238,11 +238,11 @@ if (frameStateBuilder != null) { if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.push(returnType.getJavaKind(), invoke); + frameStateBuilder.push(invoke.getStackKind(), invoke); } invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.pop(returnType.getJavaKind()); + frameStateBuilder.pop(invoke.getStackKind()); } } return invoke; @@ -475,11 +475,11 @@ invoke.setNext(noExceptionEdge); if (frameStateBuilder != null) { if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.push(returnType.getJavaKind(), invoke); + frameStateBuilder.push(invoke.getStackKind(), invoke); } invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke)); if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.pop(returnType.getJavaKind()); + frameStateBuilder.pop(invoke.getStackKind()); } } lastFixedNode = null; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java 2017-09-12 22:24:46.629717367 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java 2017-09-12 22:24:46.499711509 -0700 @@ -193,6 +193,24 @@ protected final PEMethodScope methodScope; protected final Invoke invoke; + @Override + public ExternalInliningContext getExternalInliningContext() { + return new ExternalInliningContext() { + @Override + public int getInlinedDepth() { + int count = 0; + PEGraphDecoder.PEMethodScope scope = methodScope; + while (scope != null) { + if (scope.method.equals(callInlinedMethod)) { + count++; + } + scope = scope.caller; + } + return count; + } + }; + } + public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { this.methodScope = methodScope; this.invoke = invoke; @@ -420,11 +438,12 @@ private final NodePlugin[] nodePlugins; private final EconomicMap specialCallTargetCache; private final EconomicMap invocationPluginCache; + private final ResolvedJavaMethod callInlinedMethod; public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true); this.loopExplosionPlugin = loopExplosionPlugin; this.invocationPlugins = invocationPlugins; @@ -433,6 +452,7 @@ this.nodePlugins = nodePlugins; this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT); this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT); + this.callInlinedMethod = callInlinedMethod; } protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java 2017-09-12 22:24:47.117739358 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java 2017-09-12 22:24:46.983733319 -0700 @@ -224,16 +224,12 @@ } /** - * Times instantiations of all templates derived form this snippet. - * - * @see SnippetTemplate#instantiationTimer + * Times instantiations of all templates derived from this snippet. */ private final TimerKey instantiationTimer; /** * Counts instantiations of all templates derived from this snippet. - * - * @see SnippetTemplate#instantiationCounter */ private final CounterKey instantiationCounter; @@ -706,8 +702,6 @@ Object[] constantArgs = getConstantArgs(args); StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs); - instantiationTimer = DebugContext.timer("SnippetTemplateInstantiationTime[%#s]", args); - instantiationCounter = DebugContext.counter("SnippetTemplateInstantiationCount[%#s]", args); ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); @@ -1078,20 +1072,6 @@ private final ArrayList nodes; /** - * Times instantiations of this template. - * - * @see SnippetInfo#instantiationTimer - */ - private final TimerKey instantiationTimer; - - /** - * Counts instantiations of this template. - * - * @see SnippetInfo#instantiationCounter - */ - private final CounterKey instantiationCounter; - - /** * Gets the instantiation-time bindings to this template's parameters. * * @return the map that will be used to bind arguments to parameters when inlining this template @@ -1406,9 +1386,8 @@ public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) { DebugContext debug = replacee.getDebug(); assert assertSnippetKills(replacee); - try (DebugCloseable a = args.info.instantiationTimer.start(debug); DebugCloseable b = instantiationTimer.start(debug)) { + try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); @@ -1561,7 +1540,6 @@ assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); @@ -1614,7 +1592,6 @@ assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java 2017-09-12 22:24:47.633762610 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java 2017-09-12 22:24:47.499756572 -0700 @@ -30,6 +30,7 @@ import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; +import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; import java.lang.reflect.Array; @@ -650,7 +651,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { // Emits a null-check for the otherwise unused receiver unsafe.get(); - b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, LocationIdentity.any())); + b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, OFF_HEAP_LOCATION)); b.getGraph().markUnsafeAccess(); return true; } @@ -662,7 +663,8 @@ if (isVolatile) { b.add(new MembarNode(JMM_PRE_VOLATILE_READ)); } - b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, LocationIdentity.any())); + LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any(); + b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, locationIdentity)); if (isVolatile) { b.add(new MembarNode(JMM_POST_VOLATILE_READ)); } @@ -685,7 +687,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { // Emits a null-check for the otherwise unused receiver unsafe.get(); - b.add(new UnsafeMemoryStoreNode(address, value, kind, LocationIdentity.any())); + b.add(new UnsafeMemoryStoreNode(address, value, kind, OFF_HEAP_LOCATION)); b.getGraph().markUnsafeAccess(); return true; } @@ -697,7 +699,8 @@ if (isVolatile) { b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } - b.add(new RawStoreNode(object, offset, value, kind, LocationIdentity.any())); + LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any(); + b.add(new RawStoreNode(object, offset, value, kind, locationIdentity)); if (isVolatile) { b.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java 2017-09-12 22:24:48.198788071 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java 2017-09-12 22:24:48.069782258 -0700 @@ -25,6 +25,8 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.nodes.ValueNode; @@ -49,11 +51,15 @@ public final int index; public final JavaKind kind; - ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind) { + /* This flag does not affect hashCode or equals implementations. */ + public final boolean overflowAccess; + + ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind, boolean overflowAccess) { this.identity = identity; this.object = object; this.index = index; this.kind = kind; + this.overflowAccess = overflowAccess; } @Override @@ -94,12 +100,38 @@ return super.toString() + " " + readCache; } + private static JavaKind stampToJavaKind(Stamp stamp) { + if (stamp instanceof IntegerStamp) { + switch (((IntegerStamp) stamp).getBits()) { + case 1: + return JavaKind.Boolean; + case 8: + return JavaKind.Byte; + case 16: + return ((IntegerStamp) stamp).isPositive() ? JavaKind.Char : JavaKind.Short; + case 32: + return JavaKind.Int; + case 64: + return JavaKind.Long; + default: + throw new IllegalArgumentException("unexpected IntegerStamp " + stamp); + } + } else { + return stamp.getStackKind(); + } + } + @Override protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List values) { if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, instance.field(i).getJavaKind()), values.get(i)); + JavaKind declaredKind = instance.field(i).getJavaKind(); + if (declaredKind == stampToJavaKind(values.get(i).stamp())) { + // We won't cache unaligned field writes upon instantiation unless we add + // support for non-array objects in PEReadEliminationClosure.processUnsafeLoad. + readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, declaredKind, false), values.get(i)); + } } } } @@ -112,7 +144,7 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PartialEscapeClosure closure) { + public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -121,7 +153,7 @@ } else { cacheObject = object; } - readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind), value); + readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind, overflowAccess), value); } public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure closure) { @@ -133,7 +165,7 @@ } else { cacheObject = object; } - ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind)); + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind, false)); obj = closure.getObjectState(this, cacheValue); if (obj != null) { assert !obj.isVirtual(); @@ -153,7 +185,7 @@ Iterator iter = readCache.getKeys().iterator(); while (iter.hasNext()) { ReadCacheEntry entry = iter.next(); - if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) { + if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index || entry.overflowAccess)) { iter.remove(); } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java 2017-09-12 22:24:48.743812630 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java 2017-09-12 22:24:48.592805826 -0700 @@ -31,7 +31,6 @@ import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; -import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.FieldLocationIdentity; @@ -131,9 +130,10 @@ return false; } - private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) { + private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind accessKind, boolean overflowAccess, ValueNode value, + PEReadEliminationBlockState state, GraphEffectList effects) { ValueNode unproxiedObject = GraphUtil.unproxify(object); - ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this); + ValueNode cachedValue = state.getReadCache(object, identity, index, accessKind, this); ValueNode finalValue = getScalarAlias(value); boolean result = false; @@ -142,7 +142,7 @@ result = true; } state.killReadCache(identity, index); - state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this); + state.addReadCache(unproxiedObject, identity, index, accessKind, overflowAccess, finalValue, this); return result; } @@ -150,43 +150,52 @@ ValueNode unproxiedObject = GraphUtil.unproxify(object); ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this); if (cachedValue != null) { - Stamp loadStamp = load.stamp(); - Stamp cachedValueStamp = cachedValue.stamp(); - if (!loadStamp.isCompatible(cachedValueStamp)) { - /* - * Can either be the first field of a two slot write to a one slot field which would - * have a non compatible stamp or the second load which will see Illegal. - */ - assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double || - cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields."; - return false; - } else { - // perform the read elimination - effects.replaceAtUsages(load, cachedValue, load); - addScalarAlias(load, cachedValue); - return true; - } + // perform the read elimination + effects.replaceAtUsages(load, cachedValue, load); + addScalarAlias(load, cachedValue); + return true; } else { - state.addReadCache(unproxiedObject, identity, index, kind, load, this); + state.addReadCache(unproxiedObject, identity, index, kind, false, load, this); return false; } } + private static boolean isOverflowAccess(JavaKind accessKind, JavaKind declaredKind) { + if (accessKind == declaredKind) { + return false; + } + if (accessKind == JavaKind.Object) { + switch (declaredKind) { + case Object: + case Double: + case Long: + return false; + default: + return true; + } + } + assert accessKind.isPrimitive() : "Illegal access kind"; + return declaredKind.isPrimitive() ? accessKind.getBitCount() > declaredKind.getBitCount() : true; + } + private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) { if (load.offset().isConstant()) { ResolvedJavaType type = StampTool.typeOrNull(load.object()); if (type != null && type.isArray()) { + JavaKind accessKind = load.accessKind(); + JavaKind componentKind = type.getComponentType().getJavaKind(); long offset = load.offset().asJavaConstant().asLong(); - int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE); + int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); ValueNode object = GraphUtil.unproxify(load.object()); - LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind()); - ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this); - if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) { + LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind); + ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this); + assert cachedValue == null || load.stamp().isCompatible(cachedValue.stamp()) : "The RawLoadNode's stamp is not compatible with the cached value."; + if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue, load); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, location, index, load.accessKind(), load, this); + state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this); } } } @@ -196,11 +205,14 @@ private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) { ResolvedJavaType type = StampTool.typeOrNull(store.object()); if (type != null && type.isArray()) { - LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind()); + JavaKind accessKind = store.accessKind(); + JavaKind componentKind = type.getComponentType().getJavaKind(); + LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind); if (store.offset().isConstant()) { long offset = store.offset().asJavaConstant().asLong(); - int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE); - return processStore(store, store.object(), location, index, store.accessKind(), store.value(), state, effects); + boolean overflowAccess = isOverflowAccess(accessKind, componentKind); + int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); + return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects); } else { processIdentity(state, location); } @@ -219,7 +231,8 @@ state.killReadCache(); return false; } - return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects); + JavaKind kind = store.field().getJavaKind(); + return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, kind, false, store.value(), state, effects); } private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) { @@ -230,11 +243,32 @@ return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects); } + private static JavaKind getElementKindFromStamp(ValueNode array) { + ResolvedJavaType type = StampTool.typeOrNull(array); + if (type != null && type.isArray()) { + return type.getComponentType().getJavaKind(); + } else { + // It is likely an OSRLocal without valid stamp + return JavaKind.Illegal; + } + } + private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) { - LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind()); - if (store.index().isConstant()) { - int index = ((JavaConstant) store.index().asConstant()).asInt(); - return processStore(store, store.array(), arrayLocation, index, store.elementKind(), store.value(), state, effects); + int index = store.index().isConstant() ? ((JavaConstant) store.index().asConstant()).asInt() : -1; + // BASTORE (with elementKind being Byte) can be used to store values in boolean arrays. + JavaKind elementKind = store.elementKind(); + if (elementKind == JavaKind.Byte) { + elementKind = getElementKindFromStamp(store.array()); + if (elementKind == JavaKind.Illegal) { + // Could not determine the actual access kind from stamp. Hence kill both. + state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Boolean), index); + state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Byte), index); + return false; + } + } + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind); + if (index != -1) { + return processStore(store, store.array(), arrayLocation, index, elementKind, false, store.value(), state, effects); } else { state.killReadCache(arrayLocation, -1); } @@ -244,8 +278,17 @@ private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) { if (load.index().isConstant()) { int index = ((JavaConstant) load.index().asConstant()).asInt(); - LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind()); - return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects); + // BALOAD (with elementKind being Byte) can be used to retrieve values from boolean + // arrays. + JavaKind elementKind = load.elementKind(); + if (elementKind == JavaKind.Byte) { + elementKind = getElementKindFromStamp(load.array()); + if (elementKind == JavaKind.Illegal) { + return false; + } + } + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind); + return processLoad(load, load.array(), arrayLocation, index, elementKind, state, effects); } return false; } @@ -293,7 +336,7 @@ if (object != null) { Pair pair = firstValueSet.get(object); while (pair != null) { - initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this); + initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, entry.overflowAccess, initialState.getReadCache().get(entry), this); pair = (Pair) pair.getRight(); } } @@ -386,14 +429,14 @@ if (phi.getStackKind() == JavaKind.Object) { for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) { if (entry.object == getPhiValueAt(phi, 0)) { - mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, states); + mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, entry.overflowAccess, states); } } } } } - private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, List states) { ValueNode[] values = new ValueNode[states.size()]; values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this); if (values[0] != null) { @@ -407,12 +450,12 @@ values[i] = value; } - PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted()); + PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), values[0].stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi"); for (int i = 0; i < values.length; i++) { setPhiInput(phiNode, i, values[i]); } - newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind), phiNode); + newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), phiNode); } } } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java 2017-09-12 22:24:49.286837100 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java 2017-09-12 22:24:49.142830611 -0700 @@ -28,6 +28,7 @@ import java.util.Iterator; import java.util.List; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; @@ -52,6 +53,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; @@ -146,37 +148,40 @@ processIdentity(state, write.getLocationIdentity()); } } else if (node instanceof UnsafeAccessNode) { - if (node instanceof RawLoadNode) { - RawLoadNode load = (RawLoadNode) node; - if (load.getLocationIdentity().isSingle()) { - ValueNode object = GraphUtil.unproxify(load.object()); - UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity()); - ValueNode cachedValue = state.getCacheEntry(identifier); - if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) { - effects.replaceAtUsages(load, cachedValue, load); - addScalarAlias(load, cachedValue); - deleted = true; - } else { - state.addCacheEntry(identifier, load); + ResolvedJavaType type = StampTool.typeOrNull(((UnsafeAccessNode) node).object()); + if (type != null && !type.isArray()) { + if (node instanceof RawLoadNode) { + RawLoadNode load = (RawLoadNode) node; + if (load.getLocationIdentity().isSingle()) { + ValueNode object = GraphUtil.unproxify(load.object()); + UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity()); + ValueNode cachedValue = state.getCacheEntry(identifier); + if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) { + effects.replaceAtUsages(load, cachedValue, load); + addScalarAlias(load, cachedValue); + deleted = true; + } else { + state.addCacheEntry(identifier, load); + } } - } - } else { - assert node instanceof RawStoreNode; - RawStoreNode write = (RawStoreNode) node; - if (write.getLocationIdentity().isSingle()) { - ValueNode object = GraphUtil.unproxify(write.object()); - UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity()); - ValueNode cachedValue = state.getCacheEntry(identifier); - - ValueNode value = getScalarAlias(write.value()); - if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { - effects.deleteNode(write); - deleted = true; - } - processIdentity(state, write.getLocationIdentity()); - state.addCacheEntry(identifier, value); } else { - processIdentity(state, write.getLocationIdentity()); + assert node instanceof RawStoreNode; + RawStoreNode write = (RawStoreNode) node; + if (write.getLocationIdentity().isSingle()) { + ValueNode object = GraphUtil.unproxify(write.object()); + UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity()); + ValueNode cachedValue = state.getCacheEntry(identifier); + + ValueNode value = getScalarAlias(write.value()); + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { + effects.deleteNode(write); + deleted = true; + } + processIdentity(state, write.getLocationIdentity()); + state.addCacheEntry(identifier, value); + } else { + processIdentity(state, write.getLocationIdentity()); + } } } } else if (node instanceof MemoryCheckpoint.Single) { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java 2017-09-12 22:24:49.828861524 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java 2017-09-12 22:24:49.704855936 -0700 @@ -268,6 +268,9 @@ } Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod); + if (operation == null) { + throw bailout(b, "Cannot call method on a word value: " + wordMethod.format("%H.%n(%p)")); + } switch (operation.opcode()) { case NODE_CLASS: assert args.length == 2; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java 2017-09-12 22:24:50.373886084 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java 2017-09-12 22:24:50.224879369 -0700 @@ -527,7 +527,7 @@ final int bci = findNodeSourcePositionBCI(pos); writeInt(bci); StackTraceElement ste = findMethodStackTraceElement(method, bci, pos); - if (ste != null) { + if (ste != null && ste.getFileName() != null) { writePoolObject(ste.getFileName()); writeInt(ste.getLineNumber()); } else { --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java 2017-09-12 22:24:50.940911634 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java 2017-09-12 22:24:50.781904469 -0700 @@ -53,13 +53,11 @@ } /** - * Constructs a new option key given a default value and option key. The default value and the - * type must not be null. + * Constructs a new option key given a default value and option key. * * @since 1.0 */ public OptionKey(T defaultValue, OptionType type) { - Objects.requireNonNull(defaultValue); Objects.requireNonNull(type); this.defaultValue = defaultValue; this.type = type; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java 2017-09-12 22:24:51.471935563 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java 2017-09-12 22:24:51.326929029 -0700 @@ -57,7 +57,6 @@ */ public OptionType(String name, T defaultValue, Function stringConverter, Consumer validator) { Objects.requireNonNull(name); - Objects.requireNonNull(defaultValue); Objects.requireNonNull(stringConverter); Objects.requireNonNull(validator); this.name = name; @@ -133,7 +132,7 @@ return "OptionType[name=" + name + ", defaultValue=" + defaultValue + "]"; } - private static Map, OptionType> DEFAULTTYPES = new HashMap<>(); + private static final Map, OptionType> DEFAULTTYPES = new HashMap<>(); static { DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", false, new Function() { public Boolean apply(String t) { @@ -200,13 +199,24 @@ /** * Returns the default option type for a given value. Returns null if no default - * option type is available for this Java type. + * option type is available for the Java type of this value. * * @since 1.0 */ @SuppressWarnings("unchecked") - public static OptionType defaultType(Object value) { - return (OptionType) DEFAULTTYPES.get(value.getClass()); + public static OptionType defaultType(T value) { + return defaultType((Class) value.getClass()); + } + + /** + * Returns the default option type for a class. Returns null if no default option + * type is available for this Java type. + * + * @since 1.0 + */ + @SuppressWarnings("unchecked") + public static OptionType defaultType(Class clazz) { + return (OptionType) DEFAULTTYPES.get(clazz); } } --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java 2017-09-12 22:24:51.845952417 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.compiler.core.test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.junit.Test; + +import java.util.HashMap; + +public class HashMapGetTest extends GraalCompilerTest { + + public static void mapGet(HashMap map, Integer key) { + map.get(key); + } + + @Test + public void hashMapTest() { + HashMap map = new HashMap<>(); + ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet"); + for (int i = 0; i < 5000; i++) { + mapGet(map, i); + map.put(i, i); + mapGet(map, i); + } + test(get, null, map, new Integer(0)); + for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) { + LogicNode condition = ifNode.condition(); + if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) { + assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return.", ifNode.trueSuccessor(), ifNode.trueSuccessor().next()); + } + } + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java 2017-09-12 22:24:52.332974362 -0700 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.core.test; + +import java.lang.reflect.Field; + +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaKind; +import sun.misc.Unsafe; + +/** + * Tests that off-heap memory writes don't prevent optimization of on-heap accesses. + */ +public class OffHeapUnsafeAccessTest extends GraalCompilerTest { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } + + public byte unboxByteAndStore(long memory, byte[] box) { + byte val = box[0]; + UNSAFE.putByte(memory, val); + UNSAFE.putByte(null, memory, val); + return box[0]; + } + + public char unboxCharAndStore(long memory, char[] box) { + char val = box[0]; + UNSAFE.putChar(memory, val); + UNSAFE.putChar(null, memory, val); + return box[0]; + } + + public int unboxIntAndStore(long memory, int[] box) { + int val = box[0]; + UNSAFE.putInt(memory, val); + UNSAFE.putInt(null, memory, val); + return box[0]; + } + + public long unboxLongAndStore(long memory, long[] box) { + long val = box[0]; + UNSAFE.putLong(memory, val); + UNSAFE.putLong(null, memory, val); + UNSAFE.putAddress(memory, val); + return box[0]; + } + + public float unboxFloatAndStore(long memory, float[] box) { + float val = box[0]; + UNSAFE.putFloat(memory, val); + UNSAFE.putFloat(null, memory, val); + return box[0]; + } + + public double unboxDoubleAndStore(long memory, double[] box) { + double val = box[0]; + UNSAFE.putDouble(memory, val); + UNSAFE.putDouble(null, memory, val); + return box[0]; + } + + private void assertExactlyOneArrayLoad(JavaKind elementKind) { + int total = 0; + for (ReadNode read : lastCompiledGraph.getNodes().filter(ReadNode.class)) { + if (read.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind))) { + total++; + } + } + Assert.assertEquals(1, total); + } + + @Test + public void testGet() { + long buf = allocBuf(); + if (buf != 0) { + try { + test("unboxByteAndStore", buf, new byte[]{40}); + assertExactlyOneArrayLoad(JavaKind.Byte); + + test("unboxCharAndStore", buf, new char[]{41}); + assertExactlyOneArrayLoad(JavaKind.Char); + + test("unboxIntAndStore", buf, new int[]{42}); + assertExactlyOneArrayLoad(JavaKind.Int); + + test("unboxLongAndStore", buf, new long[]{43}); + assertExactlyOneArrayLoad(JavaKind.Long); + + test("unboxFloatAndStore", buf, new float[]{44.0F}); + assertExactlyOneArrayLoad(JavaKind.Float); + + test("unboxDoubleAndStore", buf, new double[]{45.0D}); + assertExactlyOneArrayLoad(JavaKind.Double); + } finally { + UNSAFE.freeMemory(buf); + } + } + } + + protected long allocBuf() { + try { + return UNSAFE.allocateMemory(16); + } catch (OutOfMemoryError e) { + return 0L; + } + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java 2017-09-12 22:24:52.784994731 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.core.test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Assume; +import org.junit.Test; + +public class StableArrayReadFoldingTest extends GraalCompilerTest { + + static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; + static final int[] STABLE_INT_ARRAY = new int[16]; + + static final long BOOLEAN_ARRAY_BASE_OFFSET; + static final long INT_ARRAY_BASE_OFFSET; + + static { + BOOLEAN_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + } + + @Override + protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) { + StructuredGraph graph = super.parseForCompile(method, compilationId, options); + // Mimic @Stable array constants. + for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) { + if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) { + ConstantNode newConstantNode = graph.unique(ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess())); + constantNode.replaceAndDelete(newConstantNode); + } + } + return graph; + } + + public static boolean killWithSameType() { + boolean beforeKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + STABLE_BOOLEAN_ARRAY[0] = true; + boolean afterKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + + STABLE_BOOLEAN_ARRAY[0] = false; + return beforeKill == afterKill; + } + + @Test + public void testKillWithSameType() { + ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameType"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithDifferentType() { + byte beforeKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + STABLE_BOOLEAN_ARRAY[0] = true; + byte afterKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + + STABLE_BOOLEAN_ARRAY[0] = false; + return beforeKill == afterKill; + } + + @Test + public void testKillWithDifferentType() { + ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentType"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithSameTypeUnaligned() { + int beforeKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + STABLE_INT_ARRAY[0] = 0x01020304; + int afterKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + + STABLE_INT_ARRAY[0] = 0; + return beforeKill == afterKill; + } + + @Test + public void testKillWithSameTypeUnaligned() { + Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); + ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithDifferentTypeUnaligned() { + byte beforeKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + STABLE_INT_ARRAY[0] = 0x01020304; + byte afterKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + + STABLE_INT_ARRAY[0] = 0; + return beforeKill == afterKill; + } + + @Test + public void testKillWithDifferentTypeUnaligned() { + Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); + ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned"); + testAgainstExpected(method, new Result(true, null), null); + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java 2017-09-12 22:24:53.248015595 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.compiler.core.test.ea; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.RawLoadNode; +import org.graalvm.compiler.nodes.extended.RawStoreNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; +import org.junit.Test; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class TrufflePEATest extends GraalCompilerTest { + + /** + * This class mimics the behavior of {@code FrameWithoutBoxing}. + */ + static class Frame { + long[] primitiveLocals; + + Frame(int size) { + primitiveLocals = new long[size]; + } + } + + /** + * This class mimics the behavior of {@code DynamicObjectL6I6}. + */ + static class DynamicObject { + int primitiveField0; + int primitiveField1; + } + + private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; + private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; + + private static final long primitiveField0Offset; + + static { + try { + Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0"); + primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0); + } catch (NoSuchFieldException | SecurityException e) { + throw new AssertionError(e); + } + } + + public static int unsafeAccessToLongArray(int v, Frame frame) { + long[] array = frame.primitiveLocals; + int s = UNSAFE.getInt(array, offsetLong1); + UNSAFE.putInt(array, offsetLong1, v); + UNSAFE.putInt(array, offsetLong2, v); + return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); + } + + @Test + public void testUnsafeAccessToLongArray() { + StructuredGraph graph = processMethod("unsafeAccessToLongArray"); + assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); + } + + /** + * The following value should be less than the default value of + * {@link GraalOptions#MaximumEscapeAnalysisArrayLength}. + */ + private static final int FRAME_SIZE = 16; + + public static long newFrame(long v) { + Frame frame = new Frame(FRAME_SIZE); + // Testing unsafe accesses with other kinds requires special handling of the initialized + // entry kind. + UNSAFE.putLong(frame.primitiveLocals, offsetLong1, v); + return UNSAFE.getLong(frame.primitiveLocals, offsetLong1); + } + + @Test + public void testNewFrame() { + StructuredGraph graph = processMethod("newFrame"); + assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); + } + + protected StructuredGraph processMethod(final String snippet) { + StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context); + return graph; + } + + public static double accessDynamicObject(double v) { + DynamicObject obj = new DynamicObject(); + UNSAFE.putDouble(obj, primitiveField0Offset, v); + return UNSAFE.getDouble(obj, primitiveField0Offset); + } + + @Test + public void testAccessDynamicObject() { + StructuredGraph graph = processMethod("accessDynamicObject"); + assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java 2017-09-12 22:24:53.703036099 -0700 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test; + +import java.util.function.IntPredicate; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import java.security.PrivilegedAction; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin; +import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.junit.Assert; +import org.junit.Test; + +public class HotSpotInvokeDynamicPluginTest extends HotSpotGraalCompilerTest { + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin()); + plugins.setInvokeDynamicPlugin(new HotSpotInvokeDynamicPlugin() { + @Override + public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + // Allow invokedynamic testing with older JVMCI + ResolvedJavaMethod m = builder.getMethod(); + if (m.getName().startsWith("invokeDynamic") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) { + return false; + } + return super.isResolvedDynamicInvoke(builder, index, opcode); + } + + @Override + public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + // Allow invokehandle testing with older JVMCI + ResolvedJavaMethod m = builder.getMethod(); + if (m.getName().startsWith("invokeHandle") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) { + return true; + } + return super.supportsDynamicInvoke(builder, index, opcode); + } + }); + return plugins; + } + + @Override + protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; + } + + private void test(String name, int expectedResolves, int expectedStubCalls) { + StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true)); + MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count()); + Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count()); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new GuardLoweringPhase().apply(graph, midTierContext); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); + new FrameStateAssignmentPhase().apply(graph); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, context); + Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicConstantNode.class).count()); + Assert.assertEquals(expectedStubCalls, graph.getNodes().filter(ResolveDynamicStubCall.class).count()); + } + + public static IntPredicate invokeDynamic1() { + IntPredicate i = (v) -> v > 1; + return i; + } + + public static PrivilegedAction invokeDynamic2(String s) { + return s::length; + } + + static final MethodHandle objToStringMH; + + static { + MethodHandle mh = null; + try { + mh = MethodHandles.lookup().findVirtual(Object.class, "toString", MethodType.methodType(String.class)); + } catch (Exception e) { + } + objToStringMH = mh; + } + + // invokehandle + public static String invokeHandle1(Object o) throws Throwable { + return (String) objToStringMH.invokeExact(o); + } + + @Test + public void test1() { + test("invokeDynamic1", 1, 1); + } + + @Test + public void test2() { + test("invokeDynamic2", 1, 1); + } + + @Test + public void test3() { + test("invokeHandle1", 1, 1); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java 2017-09-12 22:24:54.149056197 -0700 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test; + +import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; +import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.test.SubprocessUtil; +import org.graalvm.compiler.test.SubprocessUtil.Subprocess; +import org.junit.Assert; +import org.junit.Test; + +import sun.misc.Unsafe; + +/** + * Tests that a hs_err crash log contains expected content. + */ +public class HsErrLogTest extends GraalCompilerTest { + + @Test + public void test1() throws IOException, InterruptedException { + List args = new ArrayList<>(); + if (Java8OrEarlier) { + args.add("-XX:-UseJVMCIClassLoader"); + } + args.add("-XX:+UseJVMCICompiler"); + args.add("-XX:CompileOnly=" + Crasher.class.getName() + "::tryCrash"); + args.add(Crasher.class.getName()); + testHelper(args); + } + + private static final boolean VERBOSE = Boolean.getBoolean(HsErrLogTest.class.getSimpleName() + ".verbose"); + + private static void testHelper(List extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException { + List vmArgs = withoutDebuggerArguments(getVMCommandLine()); + vmArgs.removeIf(a -> a.startsWith("-Dgraal.")); + vmArgs.remove("-esa"); + vmArgs.remove("-ea"); + vmArgs.addAll(extraVmArgs); + + Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs); + if (VERBOSE) { + System.out.println(proc); + } + + Pattern re = Pattern.compile("# +(.*hs_err_pid[\\d]+\\.log)"); + + for (String line : proc.output) { + Matcher m = re.matcher(line); + if (m.matches()) { + File path = new File(m.group(1)); + Assert.assertTrue(path.toString(), path.exists()); + checkHsErr(path); + return; + } + } + + Assert.fail("Could not find " + re.pattern()); + } + + private static void checkHsErr(File hsErrPath) { + try (BufferedReader br = new BufferedReader(new FileReader(hsErrPath))) { + String line = br.readLine(); + String sig = Crasher.class.getName() + ".tryCrash(JI)I"; + List lines = new ArrayList<>(); + while (line != null) { + if (line.contains(sig)) { + if (!VERBOSE) { + hsErrPath.delete(); + } + return; + } + lines.add(line); + line = br.readLine(); + } + throw new AssertionError("Could not find line containing \"" + sig + "\" in " + hsErrPath + + ":" + System.lineSeparator() + String.join(System.lineSeparator(), lines)); + } catch (IOException e) { + throw new AssertionError(e); + } + } +} + +class Crasher { + public static void main(String[] args) { + int iter = 0; + long mem = UNSAFE.allocateMemory(1000); + while (iter < Integer.MAX_VALUE) { + tryCrash(mem, iter); + iter++; + } + } + + protected static int tryCrash(long mem, int iter) { + if (GraalDirectives.inCompiledCode()) { + UNSAFE.putInt(0, iter); + return 0; + } else { + UNSAFE.putInt(mem, iter); + return UNSAFE.getInt(mem); + } + } + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java 2017-09-12 22:24:54.606076791 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.meta; + +import org.graalvm.compiler.bytecode.Bytecodes; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin { + + private static final Class hscp; + private static final MethodHandle isResolvedDynamicInvokeMH; + + static { + MethodHandle m = null; + Class c = null; + try { + c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class); + m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class)); + } catch (Exception e) { + } + isResolvedDynamicInvokeMH = m; + hscp = c; + } + + private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) { + if (isResolvedDynamicInvokeMH != null) { + if (!hscp.isInstance(constantPool)) { + return false; + } + try { + return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); + } + } + throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set"); + } + + private final DynamicTypeStore dynoStore; + private final boolean treatAppendixAsConstant; + + public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) { + this.dynoStore = dynoStore; + this.treatAppendixAsConstant = treatAppendixAsConstant; + } + + public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) { + this(dynoStore, true); + } + + public HotSpotInvokeDynamicPlugin() { + this(null); + } + + // invokehandle support + @Override + public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + ConstantPool constantPool = builder.getCode().getConstantPool(); + if (isResolvedDynamicInvokeMH == null) { + // If older JVMCI, but HotSpotInvokeDynamicPlugin is being + // used for testing, return true so that we continue along the + // plugin path. + return true; + } + return isResolvedDynamicInvoke(constantPool, index, opcode); + } + + @Override + public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null; + } + + public DynamicTypeStore getDynamicTypeStore() { + return dynoStore; + } + + @Override + public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) { + assert supportsDynamicInvoke(builder, index, opcode); + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); + HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); + + HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target; + if (dynoStore != null) { + dynoStore.recordAdapter(opcode, methodHolder, index, adapter); + } + } + + @Override + public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) { + JavaConstant appendix = appendixConstant; + assert supportsDynamicInvoke(builder, index, opcode); + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); + HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); + + if (dynoStore != null) { + appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix); + } + + ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph()); + + Stamp appendixStamp = appendixNode.stamp(); + Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted(); + ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode); + ResolveDynamicConstantNode added = builder.append(resolveNode); + assert added == resolveNode; + added.setStateBefore(frameState); + return resolveNode; + } + + public interface DynamicTypeStore { + + void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter); + + JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix); + + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java 2017-09-12 22:24:55.051096844 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; + +import org.graalvm.word.LocationIdentity; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(cycles = CYCLES_4, size = SIZE_16) +public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(ResolveDynamicConstantNode.class); + + @Input ValueNode value; + + public ResolveDynamicConstantNode(Stamp valueStamp, ValueNode value) { + super(TYPE, valueStamp); + this.value = value; + } + + public ValueNode value() { + return value; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java 2017-09-12 22:24:55.502117168 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.word.LocationIdentity; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +/** + * A call to the VM via a regular stub. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16) +public class ResolveDynamicStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(ResolveDynamicStubCall.class); + + @OptionalInput protected ValueNode value; + @OptionalInput(InputType.State) protected FrameState stateBefore; + protected Constant constant; + + public ResolveDynamicStubCall(ValueNode value) { + super(TYPE, value.stamp()); + this.value = value; + } + + @NodeIntrinsic + public static native Object resolveInvoke(Object value); + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value result; + LIRFrameState fs = gen.state(this); + assert fs != null : "The stateAfter is null"; + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveDynamicInvoke(constant, fs); + gen.setResult(this, result); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + @Override + public FrameState stateBefore() { + return stateBefore; + } + + @Override + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; + } + + @Override + public void markDeleted() { + throw GraalError.shouldNotReachHere("ResolveDynamicStubCall node deleted"); + } + +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java 2017-09-12 22:24:55.977138573 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_irem4 extends JTTTest { + + public static int test(int a) { + return a % 8; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -8); + } + + @Test + public void run3() throws Throwable { + runTest("test", 16); + } + + @Test + public void run4() throws Throwable { + runTest("test", -16); + } + + @Test + public void run5() throws Throwable { + runTest("test", -23); + } + + @Test + public void run6() throws Throwable { + runTest("test", 23); + } +} --- /dev/null 2017-03-16 11:03:49.895616831 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java 2017-09-12 22:24:56.398157544 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.nodes.graphbuilderconf; + +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.JavaConstant; + +/** + * {@link GraphBuilderPlugin} interface for static compilation mode, allowing references to dynamic + * types. + */ +public interface InvokeDynamicPlugin extends GraphBuilderPlugin { + + /** + * Checks for a resolved dynamic adapter method at the specified index, resulting from either a + * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method + * (HotSpot invokehandle). + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @return {@code true} if a signature polymorphic method reference was found, otherwise + * {@code false} + */ + boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); + + /** + * Checks if this plugin instance supports the specified dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the invoke instruction + * @return {@code true} if this dynamic invoke is supported + */ + boolean supportsDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); + + /** + * Notifies this object of the value and context of the dynamic method target (e.g., A HotSpot + * adapter method) for a resolved dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @param target dynamic target method to record + */ + void recordDynamicMethod(GraphBuilderContext builder, int cpi, int opcode, ResolvedJavaMethod target); + + /** + * Notifies this object of the value and context of the dynamic appendix object for a resolved + * dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @return {@link ValueNode} for appendix constant + */ + ValueNode genAppendixNode(GraphBuilderContext builder, int cpi, int opcode, JavaConstant appendix, FrameState frameState); + +}