# HG changeset patch # User Thomas Wuerthinger # Date 1425938848 -3600 # Node ID cb4d01e1c0842ee6dcc889c4f44e8f78431be9a0 # Parent 0493ae8a552dcc612179976d455ac7f32db98562# Parent 415975c5550bfcb2cdc80164498cf4656daab8a4 Merge. diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Mon Mar 09 23:07:28 2015 +0100 @@ -161,9 +161,9 @@ * slot following a double word item. This should really be checked in FrameState itself but * because of Word type rewriting and alternative backends that can't be done. */ - public boolean validateFormat() { + public boolean validateFormat(boolean derivedOk) { if (caller() != null) { - caller().validateFormat(); + caller().validateFormat(derivedOk); } for (int i = 0; i < numLocals + numStack; i++) { if (values[i] != null) { @@ -172,6 +172,7 @@ assert values.length > i + 1 : String.format("missing second word %s", this); assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal : this; } + assert derivedOk || ValueUtil.isIllegal(values[i]) || !values[i].getLIRKind().isDerivedReference() : "Unexpected derived value: " + values[i]; } } return true; diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConcreteSubtypeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConcreteSubtypeTest.java Mon Mar 09 23:07:28 2015 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.graal.api.code.Assumptions.*; +import com.oracle.graal.nodes.*; + +/** + * Ensure that abstract classes with a single implementor are properly optimized and that loading a + * subclass below the leaf type triggers invalidation. + */ +public class ConcreteSubtypeTest extends GraalCompilerAssumptionsTest { + abstract static class AbstractBase { + abstract void check(); + } + + static class Subclass extends AbstractBase { + @Override + public void check() { + throw new InternalError(); + } + } + + static class SubSubclass extends Subclass { + @Override + public void check() { + } + } + + public void callAbstractType(AbstractBase object) { + object.check(); + } + + @Override + protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) { + super.checkGraph(expectedAssumption, graph); + assertTrue(graph.isTrivial()); + } + + /** + * Test that {@link #callAbstractType} gets compiled into an empty method with a + * {@link ConcreteSubtype} assumption on {@link AbstractBase} and {@link Subclass}. Then ensures + * that loading and initialization of {@link SubSubclass} causes the compiled method to be + * invalidated. + */ + @Test + public void testLeafAbstractType() { + testAssumptionInvalidate("callAbstractType", new ConcreteSubtype(resolveAndInitialize(AbstractBase.class), resolveAndInitialize(Subclass.class)), "SubSubclass"); + } +} diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerAssumptionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerAssumptionsTest.java Mon Mar 09 23:07:28 2015 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import static org.junit.Assert.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Assumptions.Assumption; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; + +public abstract class GraalCompilerAssumptionsTest extends GraalCompilerTest { + + public GraalCompilerAssumptionsTest() { + super(); + } + + public GraalCompilerAssumptionsTest(Class arch) { + super(arch); + } + + protected void testAssumptionInvalidate(String methodName, Assumption expected, String classToLoad) { + testAssumption(methodName, expected, classToLoad, true); + } + + /** + * Checks the behavior of class loading on {@link Assumption invalidation}. {@code methodName} + * is compiled and the resulting graph is checked for {@code expectedAssumption}. The code is + * installed and optionally {@code classToLoad} is loaded. The class is assumed to be an inner + * class of the test class and the name of the class to load is constructed relative to that. + * + * @param methodName the method to compile + * @param expectedAssumption expected {@link Assumption} instance to find in graph + * @param classToLoad an optional class to load to trigger an invalidation check + * @param willInvalidate true if loading {@code classToLoad} should invalidate the method + */ + protected void testAssumption(String methodName, Assumption expectedAssumption, String classToLoad, boolean willInvalidate) { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); + + StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES); + assertTrue(!graph.getAssumptions().isEmpty()); + checkGraph(expectedAssumption, graph); + + CompilationResult compilationResult = compile(javaMethod, graph); + final InstalledCode installedCode = getProviders().getCodeCache().setDefaultMethod(javaMethod, compilationResult); + assertTrue(installedCode.isValid()); + if (classToLoad != null) { + String fullName = getClass().getName() + "$" + classToLoad; + try { + Class.forName(fullName); + } catch (ClassNotFoundException e) { + assertFalse(String.format("Can't find class %s", fullName), true); + } + assertTrue(!willInvalidate == installedCode.isValid()); + } + } + + protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) { + boolean found = false; + for (Assumption a : graph.getAssumptions()) { + if (expectedAssumption.equals(a)) { + found = true; + } + } + assertTrue(String.format("Can't find assumption %s", expectedAssumption), found); + } + + /** + * Converts a {@link Class} to an initialized {@link ResolvedJavaType}. + */ + protected ResolvedJavaType resolveAndInitialize(Class clazz) { + ResolvedJavaType type = getMetaAccess().lookupJavaType(clazz); + type.initialize(); + return type; + } +} diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 09 23:07:28 2015 +0100 @@ -113,7 +113,7 @@ } objectStates.clear(); - assert frame.validateFormat(); + assert frame.validateFormat(false); return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); } diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Mon Mar 09 23:07:28 2015 +0100 @@ -115,7 +115,7 @@ Infopoint info = (Infopoint) site; if (info.debugInfo != null) { BytecodeFrame frame = info.debugInfo.frame(); - assert frame == null || frame.validateFormat(); + assert frame == null || frame.validateFormat(false); } } } diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Mar 09 23:07:28 2015 +0100 @@ -739,7 +739,6 @@ @HotSpotVMFlag(name = "VerifyOops") @Stable public boolean verifyOops; @HotSpotVMFlag(name = "CITime") @Stable public boolean ciTime; @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach; - @HotSpotVMFlag(name = "CompileThreshold") @Stable public long compileThreshold; @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt; @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt; @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods; diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Mon Mar 09 23:07:28 2015 +0100 @@ -83,7 +83,7 @@ assert target == providers.getCodeCache().getTarget(); checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target); - instanceofSnippets = new InstanceOfSnippets.Templates(providers, target, config.compileThreshold); + instanceofSnippets = new InstanceOfSnippets.Templates(providers, target); newObjectSnippets = new NewObjectSnippets.Templates(providers, target); monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking); writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null); diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Mon Mar 09 23:07:28 2015 +0100 @@ -44,14 +44,17 @@ public static class Guard implements SubstitutionGuard { - private HotSpotVMConfig config; + @SuppressWarnings("unused") private HotSpotVMConfig config; public Guard(HotSpotVMConfig config) { this.config = config; } public boolean execute() { - return config.useCRC32Intrinsics; + /* + * Disabled until MethodSubstitutions are compiled like snipppets. + */ + return false; // return config.useCRC32Intrinsics; } } diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Mon Mar 09 23:07:28 2015 +0100 @@ -60,33 +60,9 @@ */ public class InstanceOfSnippets implements Snippets { - private static final double COMPILED_VS_INTERPRETER_SPEEDUP = 50; - private static final double INSTANCEOF_DEOPT_SPEEDUP = 1.01; // generous 1% speedup - - private static final int DEOPT_THRESHOLD_FACTOR = (int) (COMPILED_VS_INTERPRETER_SPEEDUP / (INSTANCEOF_DEOPT_SPEEDUP - 1.0)); - /** - * Gets the minimum required probability of a profiled instanceof hitting one the profiled types - * for use of the {@linkplain #instanceofWithProfile deoptimizing} snippet. The value is - * computed to be an order of greater than the configured compilation threshold by a - * {@linkplain #DEOPT_THRESHOLD_FACTOR factor}. - * - *

- * This factor is such that the additional executions we get from using the deoptimizing snippet - * (({@linkplain #INSTANCEOF_DEOPT_SPEEDUP speedup} - 1) / probability threshold) is greater - * than the time lost during re-interpretation ({@linkplain #COMPILED_VS_INTERPRETER_SPEEDUP - * compiled code speedup} × compilation threshold). - *

- */ - public static double hintHitProbabilityThresholdForDeoptimizingSnippet(long compilationThreshold) { - return 1.0D - (1.0D / (compilationThreshold * DEOPT_THRESHOLD_FACTOR)); - } - - /** - * A test against a set of hints derived from a profile with very close to 100% precise coverage - * of seen types. This snippet deoptimizes on hint miss paths. - * - * @see #hintHitProbabilityThresholdForDeoptimizingSnippet(long) + * A test against a set of hints derived from a profile with 100% precise coverage of seen + * types. This snippet deoptimizes on hint miss paths. */ @Snippet public static Object instanceofWithProfile(Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue, @@ -243,11 +219,9 @@ private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary"); private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic"); private final SnippetInfo isAssignableFrom = snippet(InstanceOfSnippets.class, "isAssignableFrom"); - private final long compilationThreshold; - public Templates(HotSpotProviders providers, TargetDescription target, long compilationThreshold) { + public Templates(HotSpotProviders providers, TargetDescription target) { super(providers, providers.getSnippetReflection(), target); - this.compilationThreshold = compilationThreshold; } @Override @@ -263,7 +237,7 @@ Arguments args; StructuredGraph graph = instanceOf.graph(); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet(compilationThreshold) && hintInfo.exact == null) { + if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) { Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph); args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage()); args.add("object", object); @@ -288,7 +262,7 @@ } args.add("trueValue", replacer.trueValue); args.add("falseValue", replacer.falseValue); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet(compilationThreshold) && hintInfo.exact == null) { + if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) { args.addConst("nullSeen", hintInfo.profile.getNullSeen() != TriState.FALSE); } return args; diff -r 0493ae8a552d -r cb4d01e1c084 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Mon Mar 09 23:06:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Mon Mar 09 23:07:28 2015 +0100 @@ -534,4 +534,12 @@ public Set getInlinedMethods() { return inlinedMethods; } + + /** + * + * @return true if the graph contains only a {@link StartNode} and {@link ReturnNode} + */ + public boolean isTrivial() { + return !(start.next() instanceof ReturnNode); + } } diff -r 0493ae8a552d -r cb4d01e1c084 mx/mx_graal.py --- a/mx/mx_graal.py Mon Mar 09 23:06:11 2015 +0100 +++ b/mx/mx_graal.py Mon Mar 09 23:07:28 2015 +0100 @@ -940,8 +940,7 @@ # This removes the need to unzip the *.diz files before debugging in gdb setMakeVar('ZIP_DEBUGINFO_FILES', '0', env=env) - # Clear these 2 variables as having them set can cause very confusing build problems - env.pop('LD_LIBRARY_PATH', None) + # Clear this variable as having it set can cause very confusing build problems env.pop('CLASSPATH', None) # Issue an env prefix that can be used to run the make on the command line diff -r 0493ae8a552d -r cb4d01e1c084 src/cpu/x86/vm/compiledIC_x86.cpp --- a/src/cpu/x86/vm/compiledIC_x86.cpp Mon Mar 09 23:06:11 2015 +0100 +++ b/src/cpu/x86/vm/compiledIC_x86.cpp Mon Mar 09 23:07:28 2015 +0100 @@ -135,10 +135,15 @@ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), +#ifdef ASSERT + // read the value once + intptr_t data = method_holder->data(); + address destination = jump->jump_destination(); + assert(data == 0 || data == (intptr_t)callee(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + assert(destination == (address)-1 || destination == entry, "b) MT-unsafe modification of inline cache"); +#endif // Update stub. method_holder->set_data((intptr_t)callee()); diff -r 0493ae8a552d -r cb4d01e1c084 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Mon Mar 09 23:06:11 2015 +0100 +++ b/src/share/vm/code/nmethod.cpp Mon Mar 09 23:07:28 2015 +0100 @@ -856,7 +856,8 @@ CodeCache::commit(this); } - if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { + bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level; + if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { ttyLocker ttyl; // keep the following output all in one block // This output goes directly to the tty, not the compiler log. // To enable tools to match it up with the compilation activity, @@ -870,7 +871,7 @@ // print the header part first print(); // then print the requested information - if (PrintNMethods) { + if (printnmethods) { print_code(); } if (PrintRelocations) { @@ -1014,7 +1015,7 @@ " entry points must be same for static methods and vice versa"); } - bool printnmethods = PrintNMethods + bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level || CompilerOracle::should_print(_method) || CompilerOracle::has_option_string(_method, "PrintNMethods"); if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { @@ -1105,13 +1106,13 @@ oop_maps()->print(); } } - if (PrintDebugInfo) { + if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations) { + if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies) { + if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } if (PrintExceptionHandlers) { diff -r 0493ae8a552d -r cb4d01e1c084 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Mon Mar 09 23:06:11 2015 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Mon Mar 09 23:07:28 2015 +0100 @@ -212,6 +212,7 @@ oop lirKind = AbstractValue::lirKind(value); oop platformKind = LIRKind::platformKind(lirKind); jint referenceMask = LIRKind::referenceMask(lirKind); + assert(referenceMask != -1, "derived pointers are not allowed"); assert(referenceMask == 0 || referenceMask == 1, "unexpected referenceMask"); bool reference = referenceMask == 1; @@ -660,9 +661,8 @@ if (context != subtype) { assert(context->is_abstract(), ""); _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype); - } else { - _dependencies->assert_leaf_type(subtype); } + _dependencies->assert_leaf_type(subtype); } void CodeInstaller::assumption_ConcreteMethod(Handle assumption) { diff -r 0493ae8a552d -r cb4d01e1c084 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Mar 09 23:06:11 2015 +0100 +++ b/src/share/vm/runtime/globals.hpp Mon Mar 09 23:07:28 2015 +0100 @@ -993,6 +993,9 @@ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \ + diagnostic(intx, PrintNMethodsAtLevel, -1, \ + "Only print code for nmethods at the given compilation level") \ + \ diagnostic(bool, PrintNativeNMethods, false, \ "Print assembly code for native nmethods when generated") \ \