Mercurial > hg > truffle
changeset 16389:c68c5fafef92
Merge
author | Tom Rodriguez <tom.rodriguez@oracle.com> |
---|---|
date | Wed, 02 Jul 2014 13:40:10 -0700 |
parents | 31e242cad4d1 (diff) 8057279ec60e (current diff) |
children | ae8f4016792a |
files | |
diffstat | 20 files changed, 322 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jul 02 13:40:10 2014 -0700 @@ -865,14 +865,14 @@ @HotSpotVMField(name = "Array<Klass*>::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset; @HotSpotVMField(name = "Array<Klass*>::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset; - @HotSpotVMField(name = "InstanceKlass::_graal_node_class", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int klassNodeClassOffset; - @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSourceFileNameIndexOffset; - @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int klassStateOffset; + @HotSpotVMField(name = "InstanceKlass::_graal_node_class", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassNodeClassOffset; + @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassSourceFileNameIndexOffset; + @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array<u2>*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; - @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int klassStateLinked; - @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int klassStateFullyInitialized; + @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; + @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; @HotSpotVMField(name = "ObjArrayKlass::_element_klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayClassElementOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Jul 02 13:40:10 2014 -0700 @@ -111,7 +111,7 @@ ResolvedJavaMethod initMethod = null; try { Class<?> rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Jul 02 13:40:10 2014 -0700 @@ -555,6 +555,10 @@ } long[] values = runtime().getCompilerToVM().getLineNumberTable(metaspaceMethod); + if (values.length == 0) { + // Empty table so treat is as non-existent + return null; + } assert values.length % 2 == 0; int[] bci = new int[values.length / 2]; int[] line = new int[values.length / 2];
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Wed Jul 02 13:40:10 2014 -0700 @@ -293,14 +293,12 @@ @Override public boolean isInitialized() { - final int state = getState(); - return state == runtime().getConfig().klassStateFullyInitialized; + return isArray() ? true : getInitState() == runtime().getConfig().instanceKlassStateFullyInitialized; } @Override public boolean isLinked() { - final int state = getState(); - return state >= runtime().getConfig().klassStateLinked; + return isArray() ? true : getInitState() >= runtime().getConfig().instanceKlassStateLinked; } /** @@ -309,8 +307,9 @@ * * @return state field value of this type */ - private int getState() { - return unsafe.getByte(getMetaspaceKlass() + runtime().getConfig().klassStateOffset) & 0xFF; + private int getInitState() { + assert !isArray() : "_init_state only exists in InstanceKlass"; + return unsafe.getByte(getMetaspaceKlass() + runtime().getConfig().instanceKlassInitStateOffset) & 0xFF; } @Override @@ -356,6 +355,22 @@ @Override public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + ResolvedJavaMethod resolvedMethod = resolveMethodInternal(method, callerType); + if (resolvedMethod == null || resolvedMethod.isAbstract()) { + return null; + } + return resolvedMethod; + } + + /** + * Resolve the method against the current type and return the method found, including any + * abstract methods. + * + * @param method + * @param callerType + * @return the method found + */ + private ResolvedJavaMethod resolveMethodInternal(ResolvedJavaMethod method, ResolvedJavaType callerType) { assert !callerType.isArray(); if (!method.isAbstract() && method.getDeclaringClass().equals(this) && method.isPublic()) { return method; @@ -369,11 +384,7 @@ if (resolvedMetaspaceMethod == 0) { return null; } - HotSpotResolvedJavaMethod resolvedMethod = HotSpotResolvedJavaMethod.fromMetaspace(resolvedMetaspaceMethod); - if (resolvedMethod.isAbstract()) { - return null; - } - return resolvedMethod; + return HotSpotResolvedJavaMethod.fromMetaspace(resolvedMetaspaceMethod); } public ConstantPool constantPool() { @@ -464,21 +475,24 @@ /* * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared * holder, usually because of phis, so make sure that the type is related to the declared - * type before using it for lookup. + * type before using it for lookup. Unlinked types should also be ignored because we can't + * resolve the proper method to invoke. Generally unlinked types in invokes should result in + * a deopt instead since they can't really be used if they aren't linked yet. */ - if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder)) { + if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { return hmethod.uniqueConcreteMethod(declaredHolder); } /* * The holder may be a subtype of the decaredHolder so make sure to resolve the method to * the correct method for the subtype. */ - HotSpotResolvedJavaMethod newMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); - if (newMethod != null && !hmethod.equals(newMethod)) { - hmethod = newMethod; + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethodInternal(hmethod, this); + if (resolvedMethod == null) { + // The type isn't known to implement the method. + return null; } - return hmethod.uniqueConcreteMethod(this); + return resolvedMethod.uniqueConcreteMethod(this); } /** @@ -680,7 +694,7 @@ @Override public String getSourceFileName() { HotSpotVMConfig config = runtime().getConfig(); - final int sourceFileNameIndex = unsafe.getChar(getMetaspaceKlass() + config.klassSourceFileNameIndexOffset); + final int sourceFileNameIndex = unsafe.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); if (sourceFileNameIndex == 0) { return null; }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java Wed Jul 02 13:40:10 2014 -0700 @@ -42,6 +42,6 @@ // so we are guaranteed to read a non-null value here. As long as NodeClass // is final, the stamp of the PiNode below will automatically be exact. Word klass = loadHub(node); - return piCastNonNull(klass.readObject(Word.signed(klassNodeClassOffset()), KLASS_NODE_CLASS), NodeClass.class); + return piCastNonNull(klass.readObject(Word.signed(instanceKlassNodeClassOffset()), KLASS_NODE_CLASS), NodeClass.class); } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Wed Jul 02 13:40:10 2014 -0700 @@ -586,21 +586,26 @@ public static final LocationIdentity CLASS_STATE_LOCATION = new NamedLocationIdentity("ClassState"); @Fold - public static int klassStateOffset() { - return config().klassStateOffset; + public static int instanceKlassInitStateOffset() { + return config().instanceKlassInitStateOffset; } @Fold - public static int klassStateFullyInitialized() { - return config().klassStateFullyInitialized; + public static int instanceKlassStateFullyInitialized() { + return config().instanceKlassStateFullyInitialized; } - public static boolean isKlassFullyInitialized(Word hub) { - return readKlassState(hub) == klassStateFullyInitialized(); + /** + * + * @param hub the hub of an InstanceKlass + * @return true is the InstanceKlass represented by hub is fully initialized + */ + public static boolean isInstanceKlassFullyInitialized(Word hub) { + return readInstanceKlassState(hub) == instanceKlassStateFullyInitialized(); } - public static byte readKlassState(Word hub) { - return hub.readByte(klassStateOffset(), CLASS_STATE_LOCATION); + private static byte readInstanceKlassState(Word hub) { + return hub.readByte(instanceKlassInitStateOffset(), CLASS_STATE_LOCATION); } @Fold @@ -621,8 +626,8 @@ public static final LocationIdentity KLASS_NODE_CLASS = new NamedLocationIdentity("KlassNodeClass"); @Fold - public static int klassNodeClassOffset() { - return config().klassNodeClassOffset; + public static int instanceKlassNodeClassOffset() { + return config().instanceKlassNodeClassOffset; } @Fold
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Jul 02 13:40:10 2014 -0700 @@ -154,7 +154,7 @@ public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) { Word hub = loadWordFromObject(type, klassOffset()); if (probability(FAST_PATH_PROBABILITY, !hub.equal(Word.zero()))) { - if (probability(FAST_PATH_PROBABILITY, isKlassFullyInitialized(hub))) { + if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) { int layoutHelper = readLayoutHelper(hub); /* * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number,
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Jul 02 13:40:10 2014 -0700 @@ -99,7 +99,7 @@ int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), LocationIdentity.FINAL_LOCATION); Word thread = registerAsWord(threadRegister); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { - if (isKlassFullyInitialized(hub)) { + if (isInstanceKlassFullyInitialized(hub)) { Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jul 02 13:40:10 2014 -0700 @@ -680,9 +680,25 @@ return new StoreFieldNode(receiver, field, value); } + /** + * Ensure that concrete classes are at least linked before generating an invoke. + * Interfaces may never be linked so simply return true for them. + * + * @param target + * @return true if the declared holder is an interface or is linked + */ + private boolean callTargetIsResolved(JavaMethod target) { + if (target instanceof ResolvedJavaMethod) { + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + ResolvedJavaType resolvedType = resolvedTarget.getDeclaringClass(); + return resolvedType.isInterface() || resolvedType.isLinked(); + } + return false; + } + @Override protected void genInvokeStatic(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { + if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); if (!holder.isInitialized() && ResolveClassBeforeStaticInvoke.getValue()) { @@ -698,7 +714,7 @@ @Override protected void genInvokeInterface(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { + if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args); } else { @@ -722,7 +738,7 @@ @Override protected void genInvokeVirtual(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { + if (callTargetIsResolved(target)) { /* * Special handling for runtimes that rewrite an invocation of * MethodHandle.invoke(...) or MethodHandle.invokeExact(...) to a static @@ -749,7 +765,7 @@ @Override protected void genInvokeSpecial(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { + if (callTargetIsResolved(target)) { assert target != null; assert target.getSignature() != null; ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java Wed Jul 02 13:40:10 2014 -0700 @@ -41,7 +41,7 @@ public Node canonical(CanonicalizerTool tool) { if (clazz.isConstant()) { ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant()); - if (type != null && type.isInitialized()) { + if (type != null && type.isInitialized() && !type.isArray() && !type.isInterface() && !type.isPrimitive()) { return new NewInstanceNode(type, fillContents()); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Wed Jul 02 13:40:10 2014 -0700 @@ -42,20 +42,20 @@ /** * Constructs a NewInstanceNode. - * + * * @param type the class being allocated * @param fillContents determines whether the new object's fields should be initialized to * zero/null. */ public NewInstanceNode(ResolvedJavaType type, boolean fillContents) { super(StampFactory.exactNonNull(type), fillContents); - assert !type.isArray(); + assert !type.isArray() && !type.isInterface() && !type.isPrimitive(); this.instanceClass = type; } /** * Gets the instance class being allocated by this node. - * + * * @return the instance class allocated */ public ResolvedJavaType instanceClass() {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Wed Jul 02 13:40:10 2014 -0700 @@ -55,7 +55,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Wed Jul 02 13:40:10 2014 -0700 @@ -61,7 +61,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Wed Jul 02 13:40:10 2014 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.test; + +import org.junit.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.runtime.*; + +public class ReplacementsParseTest extends GraalCompilerTest { + + static class TestMethods { + static double next(double v) { + return Math.nextAfter(v, 1.0); + } + + static double next2(double v) { + return Math.nextAfter(v, 1.0); + } + + static double nextAfter(double x, double d) { + return Math.nextAfter(x, d); + } + + } + + @ClassSubstitution(TestMethods.class) + static class TestMethodsSubstitutions { + + @MethodSubstitution(isStatic = true) + static double next(double v) { + return TestMethods.next(v); + } + + @MethodSubstitution(isStatic = true) + static double next2(double v) { + return next2(v); + } + + @MethodSubstitution(isStatic = true) + static double nextAfter(double x, double d) { + double xx = (x == -0.0 ? 0.0 : x); + assert !Double.isNaN(xx); + return Math.nextAfter(xx, d); + } + } + + private static boolean substitutionsInstalled; + + public ReplacementsParseTest() { + if (!substitutionsInstalled) { + Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements(); + replacements.registerSubstitutions(TestMethods.class, TestMethodsSubstitutions.class); + substitutionsInstalled = true; + } + } + + /** + * Ensure that calling the original method from the substitution binds correctly. + */ + @Test + public void test1() { + test("test1Snippet", 1.0); + } + + public double test1Snippet(double d) { + return TestMethods.next(d); + } + + /** + * Ensure that calling the substitution method binds to the original method properly. + */ + @Test + public void test2() { + test("test2Snippet", 1.0); + } + + public double test2Snippet(double d) { + return TestMethods.next2(d); + } + + /** + * Ensure that substitution methods with assertions in them don't complain when the exception + * constructor is deleted. + */ + + @Test + public void testNextAfter() { + double[] inArray = new double[1024]; + double[] outArray = new double[1024]; + for (int i = 0; i < inArray.length; i++) { + inArray[i] = -0.0; + } + test("doNextAfter", inArray, outArray); + } + + public void doNextAfter(double[] outArray, double[] inArray) { + for (int i = 0; i < inArray.length; i++) { + double direction = (i & 1) == 0 ? Double.POSITIVE_INFINITY : -Double.NEGATIVE_INFINITY; + outArray[i] = TestMethods.nextAfter(inArray[i], direction); + } + } +}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Wed Jul 02 13:40:10 2014 -0700 @@ -51,7 +51,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = getMetaAccess().lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java Wed Jul 02 13:40:10 2014 -0700 @@ -36,6 +36,9 @@ public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException { // The error cases must be handled here since DynamicNewArrayNode can only deoptimize the // caller in response to exceptions. + if (length < 0) { + throw new NegativeArraySizeException(); + } if (componentType == void.class) { throw new IllegalArgumentException(); }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Jul 02 13:40:10 2014 -0700 @@ -207,7 +207,7 @@ public void inline(InvokeNode invoke, SnippetReflectionProvider snippetReflection) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, new Assumptions(false), providers.getCodeCache().getTarget()); - StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + StructuredGraph calleeGraph = repl.makeGraph(method, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); InliningUtil.inline(invoke, calleeGraph, false, null); }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Jul 02 13:40:10 2014 -0700 @@ -242,7 +242,7 @@ try (TimerCloseable a = SnippetPreparationTime.start()) { FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, recursiveEntry, recursiveEntry, inliningPolicy(method), frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, recursiveEntry, inliningPolicy(method), frameStateProcessing); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache) { return newGraph; @@ -278,7 +278,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, original, substitute, inliningPolicy(substitute), FrameStateProcessing.None); + graph = makeGraph(substitute, original, inliningPolicy(substitute), FrameStateProcessing.None); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -405,15 +405,15 @@ * @param policy the inlining policy to use during preprocessing * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, ResolvedJavaMethod recursiveEntry, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) { - return createGraphMaker(method, original, recursiveEntry, frameStateProcessing).makeGraph(policy); + public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) { + return createGraphMaker(method, original, frameStateProcessing).makeGraph(policy); } /** * Can be overridden to return an object that specializes various parts of graph preprocessing. */ - protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, ResolvedJavaMethod recursiveEntry, FrameStateProcessing frameStateProcessing) { - return new GraphMaker(substitute, original, recursiveEntry, frameStateProcessing); + protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + return new GraphMaker(substitute, original, frameStateProcessing); } /** @@ -437,24 +437,20 @@ protected final ResolvedJavaMethod method; /** - * The method which is used when a call to {@link #recursiveEntry} is found. + * The original method which {@link #method} is substituting. Calls to {@link #method} or + * {@link #substitutedMethod} will be replaced with a forced inline of + * {@link #substitutedMethod}. */ protected final ResolvedJavaMethod substitutedMethod; /** - * The method which is used to detect a recursive call. - */ - protected final ResolvedJavaMethod recursiveEntry; - - /** * Controls how FrameStates are processed. */ private FrameStateProcessing frameStateProcessing; - protected GraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, ResolvedJavaMethod recursiveEntry, FrameStateProcessing frameStateProcessing) { + protected GraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) { this.method = substitute; this.substitutedMethod = substitutedMethod; - this.recursiveEntry = recursiveEntry; this.frameStateProcessing = frameStateProcessing; } @@ -484,9 +480,9 @@ NodeIntrinsificationVerificationPhase.verify(graph); } int sideEffectCount = 0; - assert (sideEffectCount = graph.getNodes().filter(e -> e instanceof StateSplit && ((StateSplit) e).hasSideEffect()).count()) >= 0; + assert (sideEffectCount = graph.getNodes().filter(e -> hasSideEffect(e)).count()) >= 0; new ConvertDeoptimizeToGuardPhase().apply(graph); - assert sideEffectCount == graph.getNodes().filter(e -> e instanceof StateSplit && ((StateSplit) e).hasSideEffect()).count() : "deleted side effecting node"; + assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node"; switch (frameStateProcessing) { case Removal: @@ -503,6 +499,35 @@ new DeadCodeEliminationPhase().apply(graph); } + /** + * Filter nodes has side effects and shouldn't be deleted from snippets when converting + * deoptimizations to guards. Currently this only allows exception constructors to be + * eliminated to cover the case when Java assertions are in the inlined code. + * + * @param node + * @return true for nodes that have side effects and are unsafe to delete + */ + private boolean hasSideEffect(Node node) { + if (node instanceof StateSplit) { + if (((StateSplit) node).hasSideEffect()) { + if (node instanceof Invoke) { + CallTargetNode callTarget = ((Invoke) node).callTarget(); + if (callTarget instanceof MethodCallTargetNode) { + ResolvedJavaMethod targetMethod = ((MethodCallTargetNode) callTarget).targetMethod(); + if (targetMethod.isConstructor()) { + ResolvedJavaType throwableType = providers.getMetaAccess().lookupJavaType(Throwable.class); + return !throwableType.isAssignableFrom(targetMethod.getDeclaringClass()); + } + } + } + // Not an exception constructor call + return true; + } + } + // Not a StateSplit + return false; + } + private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) { @@ -585,7 +610,11 @@ continue; } ResolvedJavaMethod callee = callTarget.targetMethod(); - if (callee.equals(recursiveEntry)) { + if (substitutedMethod != null && (callee.equals(method) || callee.equals(substitutedMethod))) { + /* + * Ensure that calls to the original method inside of a substitution ends up + * calling it instead of the Graal substitution. + */ if (isInlinable(substitutedMethod)) { final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod); Mark mark = graph.getMark();
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java Wed Jul 02 15:04:25 2014 +0200 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java Wed Jul 02 13:40:10 2014 -0700 @@ -33,10 +33,11 @@ public class GraalJUnitCore { /** - * Run the tests contained in the classes named in the <code>args</code>. If all tests run - * successfully, exit with a status of 0. Otherwise exit with a status of 1. Write feedback - * while tests are running and write stack traces for all failed tests after the tests all - * complete. + * Run the tests contained in the classes named in the <code>args</code>. A single test method + * can be specified by adding #method after the class name. Only a single test can be run in + * this way. If all tests run successfully, exit with a status of 0. Otherwise exit with a + * status of 1. Write feedback while tests are running and write stack traces for all failed + * tests after the tests all complete. * * @param args names of classes in which to find tests to run */ @@ -46,6 +47,7 @@ system.out().println("GraalJUnitCore"); system.out().println("JUnit version " + Version.id()); List<Class<?>> classes = new ArrayList<>(); + String methodName = null; List<Failure> missingClasses = new ArrayList<>(); boolean verbose = false; boolean enableTiming = false; @@ -70,6 +72,27 @@ } } else { + /* + * Entries of the form class#method are handled specially. Only one can be specified + * on the command line as there's no obvious way to build a runner for multiple + * ones. + */ + if (methodName != null) { + system.out().println("Only a single class and method can be specified: " + each); + System.exit(1); + } else if (each.contains("#")) { + String[] pair = each.split("#"); + if (pair.length != 2) { + system.out().println("Malformed class and method request: " + each); + System.exit(1); + } else if (classes.size() != 0) { + system.out().println("Only a single class and method can be specified: " + each); + System.exit(1); + } else { + methodName = pair[1]; + each = pair[0]; + } + } try { classes.add(Class.forName(each)); } catch (ClassNotFoundException e) { @@ -99,7 +122,13 @@ graalListener = new GCAfterTestDecorator(graalListener); } junitCore.addListener(GraalTextListener.createRunListener(graalListener)); - Result result = junitCore.run(classes.toArray(new Class[0])); + Request request; + if (methodName == null) { + request = Request.classes(classes.toArray(new Class[0])); + } else { + request = Request.method(classes.get(0), methodName); + } + Result result = junitCore.run(request); for (Failure each : missingClasses) { result.getFailures().add(each); }
--- a/mx/mx_graal.py Wed Jul 02 15:04:25 2014 +0200 +++ b/mx/mx_graal.py Wed Jul 02 13:40:10 2014 -0700 @@ -974,15 +974,31 @@ projectscp = mx.classpath([pcp.name for pcp in mx.projects_opt_limit_to_suites() if pcp.javaCompliance <= mx.java().javaCompliance]) else: projs = set() - for t in tests: - found = False + if len(tests) == 1 and '#' in tests[0]: + words = tests[0].split('#') + if len(words) != 2: + mx.abort("Method specification is class#method: " + tests[0]) + t, method = words for c, p in candidates.iteritems(): if t in c: found = True - classes.append(c) + # this code assumes a single test will be handled by GraalJUnitCore + classes.append(c + '#' + method) projs.add(p.name) if not found: mx.log('warning: no tests matched by substring "' + t) + else: + for t in tests: + if '#' in t: + mx.abort('Method specifications can only be used in a single test: ' + t) + found = False + for c, p in candidates.iteritems(): + if t in c: + found = True + classes.append(c) + projs.add(p.name) + if not found: + mx.log('warning: no tests matched by substring "' + t) projectscp = mx.classpath(projs) if whitelist: @@ -1253,6 +1269,12 @@ t.abort(test.name + ' Failed') tasks.append(t.stop()) + # ensure -Xbatch still works + with VM('graal', 'product'): + t = Task('DaCapo_pmd:BatchMode:product') + dacapo(['-Xbatch', 'pmd']) + tasks.append(t.stop()) + if args.jacocout is not None: jacocoreport([args.jacocout])