# HG changeset patch # User Lukas Stadler # Date 1365435005 -7200 # Node ID 653110156f8a08e4131c6cb21f1eb7c02d300ffc # Parent 9631f95971a3ef95693bec3efc8f11dcac8b49f3 refactored boxing identification and lowering, removed BoxingMethodPool and explicit boxing phases diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011, 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 java.util.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.phases.common.*; - -public class IfBoxingEliminationTest extends GraalCompilerTest { - - private static final String REFERENCE_SNIPPET = "referenceSnippet"; - - public static int referenceSnippet(int a) { - int result; - if (a < 0) { - result = 1; - } else { - result = 2; - } - return result; - } - - public static Integer boxedInteger() { - return 1; - } - - public static Object boxedObject() { - return 2; - } - - @Test - public void test1() { - test("test1Snippet"); - } - - public static int test1Snippet(int a) { - Integer result; - if (a < 0) { - result = boxedInteger(); - } else { - result = (Integer) boxedObject(); - } - return result; - } - - private void test(final String snippet) { - Debug.scope("IfBoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() { - - @Override - public void run() { - StructuredGraph graph = parse(snippet); - BoxingMethodPool pool = new BoxingMethodPool(runtime()); - IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool); - PhasePlan phasePlan = getDefaultPhasePlan(); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase()); - identifyBoxingPhase.apply(graph); - Map hints = new HashMap<>(); - for (Invoke invoke : graph.getInvokes()) { - hints.put(invoke, 1000d); - } - - Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new PhiStampPhase().apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - Debug.dump(graph, "Graph"); - new BoxingEliminationPhase(runtime()).apply(graph); - Debug.dump(graph, "Graph"); - new ExpandBoxingNodesPhase(pool).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); - new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); - new DeadCodeEliminationPhase().apply(referenceGraph); - - assertEquals(referenceGraph, graph); - } - }); - } -} diff -r 9631f95971a3 -r 653110156f8a 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 Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Apr 08 17:30:05 2013 +0200 @@ -82,21 +82,16 @@ for (Entry entry : virtualObjectsCopy.entrySet()) { if (entry.getValue().getValues() == null) { VirtualObjectNode vobj = entry.getKey(); - if (vobj instanceof BoxedVirtualObjectNode) { - BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj; - entry.getValue().setValues(new Value[]{toValue(boxedVirtualObjectNode.getUnboxedValue())}); - } else { - Value[] values = new Value[vobj.entryCount()]; - if (values.length > 0) { - changed = true; - VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); - assert currentField != null; - for (int i = 0; i < vobj.entryCount(); i++) { - values[i] = toValue(currentField.fieldValues().get(i)); - } + Value[] values = new Value[vobj.entryCount()]; + if (values.length > 0) { + changed = true; + VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); + assert currentField != null; + for (int i = 0; i < vobj.entryCount(); i++) { + values[i] = toValue(currentField.fieldValues().get(i)); } - entry.getValue().setValues(values); } + entry.getValue().setValues(values); } } } while (changed); @@ -165,7 +160,7 @@ if (value instanceof VirtualObjectNode) { VirtualObjectNode obj = (VirtualObjectNode) value; EscapeObjectState state = objectStates.get(obj); - if (state == null && obj.entryCount() > 0 && !(obj instanceof BoxedVirtualObjectNode)) { + if (state == null && obj.entryCount() > 0) { // null states occur for objects with 0 fields throw new GraalInternalError("no mapping found for virtual object %s", obj); } @@ -173,7 +168,7 @@ assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode); return toValue(((MaterializedObjectState) state).materializedValue()); } else { - assert obj.entryCount() == 0 || state instanceof VirtualObjectState || obj instanceof BoxedVirtualObjectNode; + assert obj.entryCount() == 0 || state instanceof VirtualObjectState; VirtualObject vobject = virtualObjects.get(value); if (vobject == null) { vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Apr 08 17:30:05 2013 +0200 @@ -90,6 +90,7 @@ private NewObjectSnippets.Templates newObjectSnippets; private MonitorSnippets.Templates monitorSnippets; private WriteBarrierSnippets.Templates writeBarrierSnippets; + private BoxingSnippets.Templates boxingSnippets; private final Map runtimeCalls = new HashMap<>(); private final Map stubs = new HashMap<>(); @@ -341,11 +342,17 @@ replacements.registerSnippets(NewArrayStub.class); replacements.registerSnippets(WriteBarrierSnippets.class); + replacements.registerSnippets(BoxingSnippets.class); + for (Class clazz : BoxingSubstitutions.getClasses()) { + replacements.registerSubstitutions(clazz); + } + checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget()); instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget()); newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB); monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking); writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget()); + boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget()); registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); @@ -782,6 +789,10 @@ // zero and the MIN_VALUE / -1 cases. } else if (n instanceof UnwindNode || n instanceof ExceptionObjectNode) { // Nothing to do, using direct LIR lowering for these nodes. + } else if (n instanceof BoxNode) { + boxingSnippets.lower((BoxNode) n); + } else if (n instanceof UnboxNode) { + boxingSnippets.lower((UnboxNode) n); } else { assert false : "Node implementing Lowerable not handled: " + n; throw GraalInternalError.shouldNotReachHere(); diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSnippets.java Mon Apr 08 17:30:05 2013 +0200 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.replacements.SnippetTemplate.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.Snippet.Parameter; +import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.Key; +import com.oracle.graal.word.*; + +public class BoxingSnippets implements Snippets { + + /** + * This snippet inlining policy differs from the default one in that it does normal inlining of + * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution). + */ + public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy { + + @Override + public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { + if (Modifier.isNative(method.getModifiers())) { + return false; + } + if (method.getAnnotation(Fold.class) != null) { + return false; + } + if (method.getAnnotation(NodeIntrinsic.class) != null) { + return false; + } + if (method.getAnnotation(Word.Operation.class) != null) { + return false; + } + return true; + } + + @Override + public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { + return false; + } + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Boolean valueOf(@Parameter("value") boolean value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Byte valueOf(@Parameter("value") byte value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Character valueOf(@Parameter("value") char value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Character.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Double valueOf(@Parameter("value") double value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Double.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Float valueOf(@Parameter("value") float value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Float.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Integer valueOf(@Parameter("value") int value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Long valueOf(@Parameter("value") long value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Long.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Short valueOf(@Parameter("value") short value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Short.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static boolean booleanValue(@Parameter("value") Boolean value) { + valueOfCounter.inc(); + return value.booleanValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static byte byteValue(@Parameter("value") Byte value) { + valueOfCounter.inc(); + return value.byteValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static char charValue(@Parameter("value") Character value) { + valueOfCounter.inc(); + return value.charValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static double doubleValue(@Parameter("value") Double value) { + valueOfCounter.inc(); + return value.doubleValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static float floatValue(@Parameter("value") Float value) { + valueOfCounter.inc(); + return value.floatValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static int intValue(@Parameter("value") Integer value) { + valueOfCounter.inc(); + return value.intValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static long longValue(@Parameter("value") Long value) { + valueOfCounter.inc(); + return value.longValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static short shortValue(@Parameter("value") Short value) { + valueOfCounter.inc(); + return value.shortValue(); + } + + public static class Templates extends AbstractTemplates { + + private final ResolvedJavaMethod[] valueOfMethods = new ResolvedJavaMethod[Kind.values().length]; + private final ResolvedJavaMethod[] unboxMethods = new ResolvedJavaMethod[Kind.values().length]; + + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target, BoxingSnippets.class); + for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Char, Kind.Double, Kind.Float, Kind.Int, Kind.Long, Kind.Short}) { + valueOfMethods[kind.ordinal()] = snippet("valueOf", kind.toJavaClass()); + unboxMethods[kind.ordinal()] = snippet(kind.getJavaName() + "Value", kind.toBoxedJavaClass()); + } + } + + private ResolvedJavaMethod getValueOf(Kind kind) { + assert valueOfMethods[kind.ordinal()] != null; + return valueOfMethods[kind.ordinal()]; + } + + private ResolvedJavaMethod getUnbox(Kind kind) { + assert unboxMethods[kind.ordinal()] != null; + return unboxMethods[kind.ordinal()]; + } + + public void lower(BoxNode boxingValueOf) { + Key key = new Key(getValueOf(boxingValueOf.getBoxingKind())); + Arguments arguments = new Arguments().add("value", boxingValueOf.getValue()); + SnippetTemplate template = cache.get(key); + Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", boxingValueOf.graph(), boxingValueOf, template, arguments); + template.instantiate(runtime, boxingValueOf, DEFAULT_REPLACER, arguments); + } + + public void lower(UnboxNode unbox) { + Key key = new Key(getUnbox(unbox.getBoxingKind())); + Arguments arguments = new Arguments().add("value", unbox.getValue()); + SnippetTemplate template = cache.get(key); + Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, arguments); + template.instantiate(runtime, unbox, DEFAULT_REPLACER, arguments); + } + } + + private static final SnippetCounter.Group integerCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Integer intrinsifications") : null; + private static final SnippetCounter valueOfCounter = new SnippetCounter(integerCounters, "valueOf", "valueOf intrinsification"); + +} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java Mon Apr 08 17:30:05 2013 +0200 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.extended.*; + +public class BoxingSubstitutions { + + @ClassSubstitution(Boolean.class) + private static class BooleanSubstitutions { + + @MethodSubstitution + public static Boolean valueOf(boolean value) { + return BoxNode.box(value, Boolean.class, Kind.Boolean); + } + + @MethodSubstitution(isStatic = false) + public static boolean booleanValue(Boolean value) { + return UnboxNode.unbox(value, Kind.Boolean); + } + } + + @ClassSubstitution(Byte.class) + private static class ByteSubstitutions { + + @MethodSubstitution + public static Byte valueOf(byte value) { + return BoxNode.box(value, Byte.class, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static byte byteValue(Byte value) { + return UnboxNode.unbox(value, Kind.Byte); + } + } + + @ClassSubstitution(Character.class) + private static class CharacterSubstitutions { + + @MethodSubstitution + public static Character valueOf(char value) { + return BoxNode.box(value, Character.class, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static char charValue(Character value) { + return UnboxNode.unbox(value, Kind.Char); + } + } + + @ClassSubstitution(Double.class) + private static class DoubleSubstitutions { + + @MethodSubstitution + public static Double valueOf(double value) { + return BoxNode.box(value, Double.class, Kind.Double); + } + + @MethodSubstitution(isStatic = false) + public static double doubleValue(Double value) { + return UnboxNode.unbox(value, Kind.Double); + } + } + + @ClassSubstitution(Float.class) + private static class FloatSubstitutions { + + @MethodSubstitution + public static Float valueOf(float value) { + return BoxNode.box(value, Float.class, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static float floatValue(Float value) { + return UnboxNode.unbox(value, Kind.Float); + } + } + + @ClassSubstitution(Integer.class) + private static class IntegerSubstitutions { + + @MethodSubstitution + public static Integer valueOf(int value) { + return BoxNode.box(value, Integer.class, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static int intValue(Integer value) { + return UnboxNode.unbox(value, Kind.Int); + } + } + + @ClassSubstitution(Long.class) + private static class LongSubstitutions { + + @MethodSubstitution + public static Long valueOf(long value) { + return BoxNode.box(value, Long.class, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static long longValue(Long value) { + return UnboxNode.unbox(value, Kind.Long); + } + } + + @ClassSubstitution(Short.class) + private static class ShortSubstitutions { + + @MethodSubstitution + public static Short valueOf(short value) { + return BoxNode.box(value, Short.class, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static short shortValue(Short value) { + return UnboxNode.unbox(value, Kind.Short); + } + } + + public static Class[] getClasses() { + return new Class[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class, + LongSubstitutions.class, ShortSubstitutions.class}; + } +} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Mon Apr 08 17:30:05 2013 +0200 @@ -186,5 +186,5 @@ } @NodeIntrinsic - public static native T anchor(@ConstantNodeParameter Stamp stamp); + public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp); } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Apr 08 17:30:05 2013 +0200 @@ -239,7 +239,7 @@ copy.remove(copy.size() - 1); } ValueNode lastSlot = copy.get(copy.size() - 1); - assert lastSlot.kind().getStackKind() == popKind.getStackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind == Kind.Object); + assert lastSlot.kind().getStackKind() == popKind.getStackKind(); copy.remove(copy.size() - 1); } Collections.addAll(copy, pushedValues); diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon Apr 08 17:30:05 2013 +0200 @@ -172,5 +172,15 @@ } @NodeIntrinsic - public static native S convert(@ConstantNodeParameter Op op, T value); + public static native float convert(@ConstantNodeParameter Op op, int value); + + @NodeIntrinsic + public static native int convert(@ConstantNodeParameter Op op, float value); + + @NodeIntrinsic + public static native double convert(@ConstantNodeParameter Op op, long value); + + @NodeIntrinsic + public static native long convert(@ConstantNodeParameter Op op, double value); + } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon Apr 08 17:30:05 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,51 +23,45 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.IterableNodeType; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; - -public final class BoxNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Canonicalizable { +import com.oracle.graal.nodes.virtual.*; - @Input private ValueNode source; - private final int bci; - private final Kind sourceKind; +public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, IterableNodeType, Lowerable, Canonicalizable { - public BoxNode(ValueNode value, ResolvedJavaType type, Kind sourceKind, int bci) { - super(StampFactory.exactNonNull(type)); - this.source = value; - this.bci = bci; - this.sourceKind = sourceKind; - assert value.kind() != Kind.Object : "can only box from primitive type"; + @Input private ValueNode value; + private final Kind boxingKind; + + public BoxNode(Invoke invoke) { + this(invoke.methodCallTarget().arguments().get(0), invoke.node().objectStamp().type(), invoke.methodCallTarget().targetMethod().getSignature().getParameterKind(0)); } - public ValueNode source() { - return source; - } - - public Kind getSourceKind() { - return sourceKind; + public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) { + super(StampFactory.exactNonNull(resultType)); + this.value = value; + this.boxingKind = boxingKind; } - public void expand(BoxingMethodPool pool) { - ResolvedJavaMethod boxingMethod = pool.getBoxingMethod(sourceKind); - MethodCallTargetNode callTarget = graph().add( - new MethodCallTargetNode(InvokeKind.Static, boxingMethod, new ValueNode[]{source}, boxingMethod.getSignature().getReturnType(boxingMethod.getDeclaringClass()))); - InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci)); - invokeNode.setProbability(this.probability()); - invokeNode.setStateAfter(stateAfter()); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invokeNode); + public Kind getBoxingKind() { + return boxingKind; + } + + public ValueNode getValue() { + return value; + } + + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); } @Override public ValueNode canonical(CanonicalizerTool tool) { - - if (source.isConstant()) { - Constant sourceConstant = source.asConstant(); - switch (sourceKind) { + if (value.isConstant()) { + Constant sourceConstant = value.asConstant(); + switch (boxingKind) { case Boolean: return ConstantNode.forObject(Boolean.valueOf(sourceConstant.asBoolean()), tool.runtime(), graph()); case Byte: @@ -90,13 +84,51 @@ } } + if (usages().isEmpty()) { + return null; + } + return this; + } - for (Node usage : usages()) { - if (usage != stateAfter()) { - return this; - } - } - replaceAtUsages(null); - return null; + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode v = tool.getReplacedValue(getValue()); + ResolvedJavaType type = objectStamp().type(); + + VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); + assert newVirtual.getFields().length == 1; + + tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0); + tool.replaceWithVirtual(newVirtual); } + + /* + * Normally, all these variants wouldn't be needed because this can be accomplished by using a + * generic method with automatic unboxing. These intrinsics, however, are themselves used for + * recognizing boxings, which means that there would be a circularity issue. + */ + + @NodeIntrinsic + public static native Boolean box(boolean value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Byte box(byte value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Character box(char value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Double box(double value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Float box(float value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Integer box(int value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Long box(long value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Short box(short value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -public class BoxingMethodPool { - - private final Set specialMethods = new HashSet<>(); - private final MetaAccessProvider runtime; - private final ResolvedJavaMethod[] boxingMethods = new ResolvedJavaMethod[Kind.values().length]; - private final ResolvedJavaMethod[] unboxingMethods = new ResolvedJavaMethod[Kind.values().length]; - private final ResolvedJavaField[] boxFields = new ResolvedJavaField[Kind.values().length]; - - public BoxingMethodPool(MetaAccessProvider runtime) { - this.runtime = runtime; - - try { - initialize(Kind.Boolean, Boolean.class, "booleanValue"); - initialize(Kind.Byte, Byte.class, "byteValue"); - initialize(Kind.Char, Character.class, "charValue"); - initialize(Kind.Short, Short.class, "shortValue"); - initialize(Kind.Int, Integer.class, "intValue"); - initialize(Kind.Long, Long.class, "longValue"); - initialize(Kind.Float, Float.class, "floatValue"); - initialize(Kind.Double, Double.class, "doubleValue"); - } catch (SecurityException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private void initialize(Kind kind, Class type, String unboxMethod) throws SecurityException, NoSuchMethodException { - // Get boxing method from runtime. - ResolvedJavaMethod boxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod("valueOf", kind.toJavaClass())); - specialMethods.add(boxingMethod); - boxingMethods[kind.ordinal()] = boxingMethod; - - // Get unboxing method from runtime. - ResolvedJavaMethod unboxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod(unboxMethod)); - unboxingMethods[kind.ordinal()] = unboxingMethod; - specialMethods.add(unboxingMethod); - - // Get the field that contains the boxed value. - ResolvedJavaField[] fields = runtime.lookupJavaType(type).getInstanceFields(false); - ResolvedJavaField boxField = fields[0]; - assert fields.length == 1 && boxField.getKind() == kind; - boxFields[kind.ordinal()] = boxField; - } - - public boolean isSpecialMethod(ResolvedJavaMethod method) { - return specialMethods.contains(method); - } - - public boolean isBoxingMethod(ResolvedJavaMethod method) { - return isSpecialMethod(method) && method.getSignature().getReturnKind() == Kind.Object; - } - - public boolean isUnboxingMethod(ResolvedJavaMethod method) { - return isSpecialMethod(method) && method.getSignature().getReturnKind() != Kind.Object; - } - - public ResolvedJavaMethod getBoxingMethod(Kind kind) { - return boxingMethods[kind.ordinal()]; - } - - public ResolvedJavaMethod getUnboxingMethod(Kind kind) { - return unboxingMethods[kind.ordinal()]; - } - - public ResolvedJavaField getBoxField(Kind kind) { - return boxFields[kind.ordinal()]; - } -} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Apr 08 17:30:05 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,47 +23,50 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.IterableNodeType; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class UnboxNode extends FixedWithNextNode implements Node.IterableNodeType, Canonicalizable { +public class UnboxNode extends FixedWithNextNode implements VirtualizableAllocation, IterableNodeType, Lowerable, Canonicalizable { - @Input private ValueNode source; - private Kind destinationKind; + @Input private ValueNode value; + private final Kind boxingKind; - public UnboxNode(Kind kind, ValueNode source) { - super(StampFactory.forKind(kind)); - this.source = source; - this.destinationKind = kind; - assert kind != Kind.Object : "can only unbox to primitive"; - assert source.kind() == Kind.Object : "can only unbox objects"; + public UnboxNode(ValueNode value, Kind boxingKind) { + super(StampFactory.forKind(boxingKind.getStackKind())); + this.value = value; + this.boxingKind = boxingKind; + } + + public Kind getBoxingKind() { + return boxingKind; } - public ValueNode source() { - return source; + public ValueNode getValue() { + return value; } - public Kind destinationKind() { - return destinationKind; + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); } - public void expand(BoxingMethodPool pool) { - ResolvedJavaField field = pool.getBoxField(kind()); - LoadFieldNode loadField = graph().add(new LoadFieldNode(source, field)); - loadField.setProbability(probability()); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, loadField); + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(value); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.replaceWithValue(state.getEntry(0)); + } } @Override public ValueNode canonical(CanonicalizerTool tool) { - if (source.isConstant()) { - Constant constant = source.asConstant(); + if (value.isConstant()) { + Constant constant = value.asConstant(); Object o = constant.asObject(); if (o != null) { - switch (destinationKind) { + switch (boxingKind) { case Boolean: return ConstantNode.forBoolean((Boolean) o, graph()); case Byte: @@ -84,7 +87,42 @@ ValueNodeUtil.shouldNotReachHere(); } } + } else if (value instanceof BoxNode) { + return ((BoxNode) value).getValue(); + } + if (usages().isEmpty()) { + return null; } return this; } + + /* + * Normally, all these variants wouldn't be needed because this can be accomplished by using a + * generic method with automatic unboxing. These intrinsics, however, are themselves used for + * recognizing boxings, which means that there would be a circularity issue. + */ + + @NodeIntrinsic + public static native boolean unbox(Boolean value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native byte unbox(Byte value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native char unbox(Character value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native double unbox(Double value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native float unbox(Float value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native int unbox(Integer value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native long unbox(Long value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native short unbox(Short value, @ConstantNodeParameter Kind kind); } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.virtual; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -public class BoxedVirtualObjectNode extends VirtualObjectNode implements LIRLowerable, Node.ValueNumberable { - - @Input ValueNode unboxedValue; - private final ResolvedJavaType type; - private final Kind kind; - - public BoxedVirtualObjectNode(ResolvedJavaType type, Kind kind, ValueNode unboxedValue) { - this.type = type; - this.kind = kind; - this.unboxedValue = unboxedValue; - } - - public ValueNode getUnboxedValue() { - return unboxedValue; - } - - @Override - public ResolvedJavaType type() { - return type; - } - - @Override - public int entryCount() { - return 1; - } - - @Override - public String fieldName(int index) { - assert index == 0; - return "value"; - } - - @Override - public int entryIndexForOffset(long constantOffset) { - // (lstadler) unsafe access to a newly created boxing object should only ever touch the - // value field - return 0; - } - - @Override - public Kind entryKind(int index) { - return kind; - } - - @Override - public BoxedVirtualObjectNode duplicate() { - return new BoxedVirtualObjectNode(type, kind, unboxedValue); - } -} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon Apr 08 17:30:05 2013 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +public class VirtualBoxingNode extends VirtualInstanceNode { + + private final Kind boxingKind; + + public VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) { + super(type); + this.boxingKind = boxingKind; + } + + @Override + public VirtualBoxingNode duplicate() { + return new VirtualBoxingNode(type(), boxingKind); + } + + @Override + public boolean hasIdentity() { + return false; + } +} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.common; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; - -public class BoxingEliminationPhase extends Phase { - - private final MetaAccessProvider metaAccess; - - public BoxingEliminationPhase(MetaAccessProvider metaAccess) { - this.metaAccess = metaAccess; - } - - @Override - protected void run(StructuredGraph graph) { - if (graph.getNodes(UnboxNode.class).isNotEmpty()) { - - Map phiReplacements = new HashMap<>(); - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - tryEliminate(graph, unboxNode, phiReplacements); - } - - new DeadCodeEliminationPhase().apply(graph); - - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - tryEliminate(boxNode); - } - } - } - - private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map phiReplacements) { - ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == unboxNode.kind(); - unboxNode.replaceAtUsages(unboxedValue); - graph.removeFixed(unboxNode); - } - } - - private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map phiReplacements) { - if (!phiReplacements.containsKey(phiNode)) { - PhiNode result = null; - ObjectStamp stamp = phiNode.objectStamp(); - if (stamp.nonNull() && stamp.isExactType()) { - ResolvedJavaType type = stamp.type(); - if (type != null && type.equals(metaAccess.lookupJavaType(kind.toBoxedJavaClass()))) { - StructuredGraph graph = (StructuredGraph) phiNode.graph(); - result = graph.add(new PhiNode(kind, phiNode.merge())); - phiReplacements.put(phiNode, result); - virtualizeUsages(phiNode, result, type, kind); - int i = 0; - for (ValueNode n : phiNode.values()) { - ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == kind; - result.addInput(unboxedValue); - } else { - UnboxNode unboxNode = graph.add(new UnboxNode(kind, n)); - FixedNode pred = phiNode.merge().phiPredecessorAt(i); - graph.addBeforeFixed(pred, unboxNode); - result.addInput(unboxNode); - } - ++i; - } - } - } - } - return phiReplacements.get(phiNode); - } - - private ValueNode unboxedValue(ValueNode n, Kind kind, Map phiReplacements) { - if (n instanceof BoxNode) { - BoxNode boxNode = (BoxNode) n; - return boxNode.source(); - } else if (n instanceof PhiNode) { - PhiNode phiNode = (PhiNode) n; - return getReplacementPhi(phiNode, kind, phiReplacements); - } else { - return null; - } - } - - private static void tryEliminate(BoxNode boxNode) { - - assert boxNode.objectStamp().isExactType(); - virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type(), boxNode.getSourceKind()); - - if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { - // Elimination failed, because boxing object escapes. - return; - } - - FrameState stateAfter = boxNode.stateAfter(); - boxNode.setStateAfter(null); - stateAfter.safeDelete(); - - ((StructuredGraph) boxNode.graph()).removeFixed(boxNode); - } - - private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType, Kind sourceKind) { - ValueNode virtualValueNode = null; - VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { - if (virtualValueNode == null) { - virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, sourceKind, replacement)); - } - n.replaceFirstInput(boxNode, virtualObjectNode); - } - } -} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.common; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.phases.*; - -public class ExpandBoxingNodesPhase extends Phase { - - private final BoxingMethodPool pool; - - public ExpandBoxingNodesPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - boxNode.expand(pool); - } - - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - unboxNode.expand(pool); - } - } -} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java Mon Apr 08 14:19:52 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.common; - -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; - -public class IdentifyBoxingPhase extends Phase { - - private final BoxingMethodPool pool; - - public IdentifyBoxingPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - tryIntrinsify(invoke); - } - } - - public void tryIntrinsify(Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - return; - } - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (pool.isSpecialMethod(targetMethod)) { - assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument"; - Kind returnKind = callTarget.returnKind(); - ValueNode sourceValue = callTarget.arguments().get(0); - - // Check whether this is a boxing or an unboxing. - Node newNode = null; - if (returnKind == Kind.Object) { - // We have a boxing method here. - assert Modifier.isStatic(targetMethod.getModifiers()) : "boxing method must be static"; - Kind sourceKind = targetMethod.getSignature().getParameterKind(0); - newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.getDeclaringClass(), sourceKind, invoke.bci())); - } else { - // We have an unboxing method here. - assert !Modifier.isStatic(targetMethod.getModifiers()) : "unboxing method must be an instance method"; - newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue)); - } - - // Intrinsify the invoke to the special node. - invoke.intrinsify(newNode); - } - } -} diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Mon Apr 08 17:30:05 2013 +0200 @@ -28,16 +28,18 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.Fold; /** * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with @@ -46,20 +48,23 @@ public class NodeIntrinsificationPhase extends Phase { private final MetaAccessProvider runtime; - private final BoxingMethodPool pool; - public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { + public NodeIntrinsificationPhase(MetaAccessProvider runtime) { this.runtime = runtime; - this.pool = pool; } @Override protected void run(StructuredGraph graph) { + ArrayList cleanUpReturnList = new ArrayList<>(); for (Invoke i : graph.getInvokes()) { if (i.callTarget() instanceof MethodCallTargetNode) { - tryIntrinsify(i); + tryIntrinsify(i, cleanUpReturnList); } } + + for (Node node : cleanUpReturnList) { + cleanUpReturnCheckCast(node); + } } public static Class[] signatureToTypes(Signature signature, JavaType receiverType, ResolvedJavaType accessingClass) { @@ -76,7 +81,7 @@ return result; } - private boolean tryIntrinsify(Invoke invoke) { + private boolean tryIntrinsify(Invoke invoke, List cleanUpReturnList) { ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); ResolvedJavaType declaringClass = target.getDeclaringClass(); @@ -103,7 +108,7 @@ invoke.intrinsify(newInstance); // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(newInstance); + cleanUpReturnList.add(newInstance); } else if (target.getAnnotation(Fold.class) != null) { Class[] parameterTypes = signatureToTypes(target.getSignature(), receiverType, declaringClass); @@ -129,7 +134,7 @@ invoke.intrinsify(node); // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(node); + cleanUpReturnList.add(node); } else { // Remove the invoke invoke.intrinsify(null); @@ -154,7 +159,7 @@ if (!invoke.methodCallTarget().isStatic()) { parameterIndex--; } - ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); + ValueNode argument = arguments.get(i); if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { if (!(argument instanceof ConstantNode)) { return null; @@ -195,47 +200,6 @@ return result; } - private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { - if (parameterIndex >= 0) { - Type type = target.getGenericParameterTypes()[parameterIndex]; - if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - if (typeVariable.getBounds().length == 1) { - Type boundType = typeVariable.getBounds()[0]; - if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { - // Unbound generic => try boxing elimination - if (node.usages().count() == 2) { - if (node instanceof Invoke) { - Invoke invokeNode = (Invoke) node; - MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); - if (pool.isBoxingMethod(callTarget.targetMethod())) { - FrameState stateAfter = invokeNode.stateAfter(); - assert stateAfter.usages().count() == 1; - invokeNode.node().replaceAtUsages(null); - ValueNode result = callTarget.arguments().get(0); - StructuredGraph graph = (StructuredGraph) node.graph(); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - stateAfter.safeDelete(); - GraphUtil.propagateKill(callTarget); - return result; - } - } - } - } - } - } - } - return node; - } - private static Class asBoxedType(Class type) { if (!type.isPrimitive()) { return type; @@ -379,32 +343,25 @@ if (checkCastUsage instanceof ValueAnchorNode) { ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; graph.removeFixed(valueAnchorNode); + } else if (checkCastUsage instanceof UnboxNode) { + UnboxNode unbox = (UnboxNode) checkCastUsage; + unbox.replaceAtUsages(newInstance); + graph.removeFixed(unbox); } else if (checkCastUsage instanceof MethodCallTargetNode) { MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { - Invoke invokeNode = checkCastCallTarget.invoke(); - invokeNode.node().replaceAtUsages(newInstance); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - checkCastCallTarget.safeDelete(); - } else { - assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + - " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + - checkCastCallTarget.targetMethod(); - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } + assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + + " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + + checkCastCallTarget.targetMethod(); + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); } else if (checkCastUsage instanceof FrameState) { checkCastUsage.replaceFirstInput(checkCastNode, null); } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } else if (checkCastUsage instanceof IsNullNode) { + assert checkCastUsage.usages().count() == 1 && checkCastUsage.usages().first().predecessor() == checkCastNode; + graph.replaceFloating((FloatingNode) checkCastUsage, LogicConstantNode.contradiction(graph)); } else { + Debug.dump(graph, "exception"); assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); } } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Apr 08 17:30:05 2013 +0200 @@ -37,7 +37,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.phases.*; @@ -52,8 +51,6 @@ protected final TargetDescription target; protected final Assumptions assumptions; - private BoxingMethodPool pool; - /** * The preprocessed replacement graphs. */ @@ -204,7 +201,7 @@ policyClass = snippet.inlining(); } if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(runtime, pool()); + return new DefaultSnippetInliningPolicy(runtime); } try { return policyClass.getConstructor().newInstance(); @@ -283,7 +280,7 @@ * Does final processing of a snippet graph. */ protected void finalizeGraph(StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool()).apply(graph); + new NodeIntrinsificationPhase(runtime).apply(graph); assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); if (original == null) { @@ -317,7 +314,6 @@ Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName()); new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); - new NodeIntrinsificationPhase(runtime, pool()).apply(graph); return graph; } @@ -339,7 +335,7 @@ * Called after all inlining for a given graph is complete. */ protected void afterInlining(StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool()).apply(graph); + new NodeIntrinsificationPhase(runtime).apply(graph); new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); @@ -366,7 +362,13 @@ substituteCallsOriginal = true; } else { if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, methodToParse)) { - StructuredGraph targetGraph = parseGraph(callee, policy); + StructuredGraph targetGraph; + StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(callee); + if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { + targetGraph = intrinsicGraph; + } else { + targetGraph = parseGraph(callee, policy); + } InliningUtil.inline(invoke, targetGraph, true); Debug.dump(graph, "after inlining %s", callee); afterInline(graph, targetGraph); @@ -467,14 +469,6 @@ } } - protected BoxingMethodPool pool() { - if (pool == null) { - // A race to create the pool is ok - pool = new BoxingMethodPool(runtime); - } - return pool; - } - @Override public Collection getAllReplacements() { HashSet result = new HashSet<>(); diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Apr 08 17:30:05 2013 +0200 @@ -27,7 +27,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -55,6 +54,13 @@ * Determines if {@code method} should be inlined into {@code caller}. */ boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); + + /** + * Determines if {@code method} should be inlined using its replacement graph. + * + * @return true if the replacement graph should be used, false for normal inlining. + */ + boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse); } /** @@ -70,11 +76,9 @@ public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { private final MetaAccessProvider metaAccess; - private final BoxingMethodPool pool; - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { + public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) { this.metaAccess = metaAccess; - this.pool = pool; } @Override @@ -89,16 +93,18 @@ return false; } if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.getName().equals("")) { + if (method.isConstructor()) { return false; } } if (method.getAnnotation(Word.Operation.class) != null) { return false; } - if (pool.isSpecialMethod(method)) { - return false; - } + return true; + } + + @Override + public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { return true; } } diff -r 9631f95971a3 -r 653110156f8a graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Apr 08 14:19:52 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Apr 08 17:30:05 2013 +0200 @@ -35,13 +35,15 @@ import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.Parameter; +import com.oracle.graal.replacements.Snippet.Varargs; +import com.oracle.graal.replacements.Snippet.VarargsParameter; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; import com.oracle.graal.word.phases.*; @@ -283,7 +285,7 @@ Debug.dump(snippetCopy, "Before specialization"); if (!nodeReplacements.isEmpty()) { // Do deferred intrinsification of node intrinsics - new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); + new NodeIntrinsificationPhase(runtime).apply(snippetCopy); new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); new CanonicalizerPhase(runtime, replacements.getAssumptions(), 0, null).apply(snippetCopy);