# HG changeset patch # User Thomas Wuerthinger # Date 1339689823 -7200 # Node ID 65bf69eb147c35b014c2235f7b45c3e96ec874e3 # Parent e1b29c5163548b22d52fef98ae29c7ba1d154894# Parent f8eb2cb76a2f49bc4c0f70cb8d1cac0b940c70fb Merge. diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCall.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCall.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCall.java Thu Jun 14 18:03:43 2012 +0200 @@ -46,7 +46,9 @@ ArithmeticCos(Double, Double), ArithmeticTan(Double, Double), ArithmeticSin(Double, Double), - GenericCallback(Object, Object, Object); + GenericCallback(Object, Object, Object), + LogPrimitive(Void, Int, Long, Boolean), + LogObject(Void, Object, Boolean, Boolean); public final Kind resultKind; public final Kind[] arguments; @@ -55,4 +57,13 @@ this.resultKind = resultKind; this.arguments = args; } + + public boolean hasSideEffect() { + switch (this) { + case LogObject: + case LogPrimitive: + return false; + } + return true; + } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Thu Jun 14 18:03:43 2012 +0200 @@ -24,7 +24,7 @@ /** * Represents a constant (boxed) value, such as an integer, floating point number, or object reference, - * within the compiler and across the compiler/runtime interface. Exports a set of {@code CiConstant} + * within the compiler and across the compiler/runtime interface. Exports a set of {@code Constant} * instances that represent frequently used constant values, such as {@link #ZERO}. */ public final class Constant extends Value { @@ -436,7 +436,7 @@ case Object: return forObject(value); default: - throw new RuntimeException("cannot create CiConstant for boxed " + kind + " value"); + throw new RuntimeException("cannot create Constant for boxed " + kind + " value"); } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Thu Jun 14 18:03:43 2012 +0200 @@ -87,7 +87,7 @@ /** * Looks up a constant at the specified index. * @param cpi the constant pool index - * @return the {@code CiConstant} instance representing the constant + * @return the {@code Constant} or {@code JavaType} instance representing the constant pool entry */ Object lookupConstant(int cpi); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Thu Jun 14 18:03:43 2012 +0200 @@ -56,7 +56,7 @@ ResolvedJavaMethod getResolvedJavaMethod(Method reflectionMethod); /** - * Gets the length of the array that is wrapped in a CiConstant object. + * Gets the length of the array that is wrapped in a Constant object. */ int getArrayLength(Constant array); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu Jun 14 18:03:43 2012 +0200 @@ -261,7 +261,7 @@ * Only instructions in methods whose fully qualified name contains this option will be HIR lowered. */ public static String HIRLowerCheckcast = ""; - public static String HIRLowerNewInstance = null; + public static String HIRLowerNewInstance = "NewInstanceTest"; /** * The profiling info cache directory. diff -r e1b29c516354 -r 65bf69eb147c 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 Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Jun 14 18:03:43 2012 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.virtual.*; public class DebugInfoBuilder { @@ -52,20 +51,13 @@ VirtualObject[] virtualObjectsArray = null; if (virtualObjects.size() != 0) { // collect all VirtualObjectField instances: - IdentityHashMap objectStates = new IdentityHashMap<>(); + IdentityHashMap objectStates = new IdentityHashMap<>(); FrameState current = topState; do { - for (Node n : current.virtualObjectMappings()) { - Node p = n; - while (p instanceof PhiNode) { - PhiNode phi = (PhiNode) p; - assert phi.type() == PhiType.Virtual; - p = phi.valueAt(0); - } - VirtualObjectFieldNode field = (VirtualObjectFieldNode) p; + for (VirtualObjectState state : current.virtualObjectMappings()) { // null states occur for objects with 0 fields - if (field != null && !objectStates.containsKey(field.object())) { - objectStates.put(field.object(), field); + if (!objectStates.containsKey(state.object())) { + objectStates.put(state.object(), state); } } current = current.outerFrameState(); @@ -87,20 +79,11 @@ entry.getValue().setValues(values); if (values.length > 0) { changed = true; - ValueNode currentField = objectStates.get(vobj); + VirtualObjectState currentField = objectStates.get(vobj); assert currentField != null; - do { - if (currentField instanceof VirtualObjectFieldNode) { - int index = ((VirtualObjectFieldNode) currentField).index(); - if (values[index] == null) { - values[index] = toCiValue(((VirtualObjectFieldNode) currentField).input()); - } - currentField = ((VirtualObjectFieldNode) currentField).lastState(); - } else { - assert currentField instanceof PhiNode : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null); + for (int i = 0; i < vobj.fieldsCount(); i++) { + values[i] = toCiValue(currentField.fields().get(i)); + } } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Jun 14 18:03:43 2012 +0200 @@ -381,7 +381,7 @@ lastState = fs; } - List nodes = lir.nodesFor(block); + List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); @@ -974,8 +974,6 @@ @Override public void emitRuntimeCall(RuntimeCallNode x) { - // TODO Merge with emitCallToRuntime() method above. - Value resultOperand = resultOperandFor(x.kind()); CallingConvention cc = frameMap.registerConfig.getCallingConvention(RuntimeCall, x.call().arguments, target(), false); frameMap.callsMethod(cc, RuntimeCall); @@ -996,6 +994,11 @@ // TODO is it correct here that the pointerSlots are not passed to the oop map generation? info = stateFor(stateBeforeReturn, -1); + } else { + // Every runtime call needs an info + // TODO This is conservative. It's not needed for RuntimeCalls that are implemented purely in a stub + // that does not trash any registers and does not call into the runtime. + info = state(); } emitCall(x.call(), resultOperand, argList, Constant.forLong(0), info, null); diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java Thu Jun 14 18:03:43 2012 +0200 @@ -30,7 +30,6 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.util.*; public abstract class LoopFragment { @@ -244,14 +243,8 @@ PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge)); phi.addInput(vpn); phi.addInput(newVpn); - if (vpn.type() == PhiType.Value) { - replaceWith = phi; - } else { - assert vpn.type() == PhiType.Virtual; - ValueNode vof = GraphUtil.unProxify(vpn); - ValueNode newVof = GraphUtil.unProxify(newVpn); - replaceWith = GraphUtil.mergeVirtualChain(graph, vof, newVof, phi, earlyExit, newEarlyExit, merge); - } + assert vpn.type() == PhiType.Value; + replaceWith = phi; } else { replaceWith = vpn.value(); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Thu Jun 14 18:03:43 2012 +0200 @@ -246,9 +246,6 @@ if (duplicateState != null) { duplicateState.replaceFirstInput(phi, firstPhi); // fix the merge's state after } - if (phi.type() == PhiType.Virtual) { - initializer = GraphUtil.mergeVirtualChain(graph, firstPhi, newExitMerge); - } mergedInitializers.put(phi, initializer); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -110,7 +110,7 @@ assert boxNode.objectStamp().isExactType(); virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type()); - if (boxNode.usages().filter(isNotA(FrameState.class).nor(VirtualObjectFieldNode.class)).isNotEmpty()) { + if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { // Elimination failed, because boxing object escapes. return; } @@ -125,7 +125,7 @@ private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) { ValueNode virtualValueNode = null; VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(FrameState.class).or(VirtualObjectFieldNode.class)).snapshot()) { + for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { if (virtualValueNode == null) { virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, replacement)); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.max.criutils.*; import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.graph.*; @@ -38,38 +37,34 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.max.criutils.*; public class EscapeAnalysisPhase extends Phase { + /** + * Encapsulates the state of the virtual object, which is updated while traversing the control flow graph. + */ public static class BlockExitState implements MergeableState { public final ValueNode[] fieldState; public final VirtualObjectNode virtualObject; - public ValueNode virtualObjectField; public final Graph graph; public BlockExitState(EscapeField[] fields, VirtualObjectNode virtualObject) { this.fieldState = new ValueNode[fields.length]; this.virtualObject = virtualObject; - this.virtualObjectField = null; this.graph = virtualObject.graph(); for (int i = 0; i < fields.length; i++) { fieldState[i] = ConstantNode.defaultForKind(fields[i].type().kind(), virtualObject.graph()); - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[i], i)); } } public BlockExitState(BlockExitState state) { this.fieldState = state.fieldState.clone(); this.virtualObject = state.virtualObject; - this.virtualObjectField = state.virtualObjectField; this.graph = state.graph; } - public void updateField(int fieldIndex) { - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[fieldIndex], fieldIndex)); - } - @Override public BlockExitState clone() { return new BlockExitState(this); @@ -77,14 +72,8 @@ @Override public boolean merge(MergeNode merge, List withStates) { - PhiNode vobjPhi = null; PhiNode[] valuePhis = new PhiNode[fieldState.length]; for (BlockExitState other : withStates) { - if (virtualObjectField != other.virtualObjectField && vobjPhi == null) { - vobjPhi = graph.add(new PhiNode(PhiType.Virtual, merge)); - vobjPhi.addInput(virtualObjectField); - virtualObjectField = vobjPhi; - } for (int i2 = 0; i2 < fieldState.length; i2++) { if (fieldState[i2] != other.fieldState[i2] && valuePhis[i2] == null) { valuePhis[i2] = graph.add(new PhiNode(fieldState[i2].kind(), merge)); @@ -94,51 +83,27 @@ } } for (BlockExitState other : withStates) { - if (vobjPhi != null) { - vobjPhi.addInput(other.virtualObjectField); - } for (int i2 = 0; i2 < fieldState.length; i2++) { if (valuePhis[i2] != null) { valuePhis[i2].addInput(other.fieldState[i2]); } } } - assert vobjPhi == null || vobjPhi.valueCount() == withStates.size() + 1; - for (int i2 = 0; i2 < fieldState.length; i2++) { - if (valuePhis[i2] != null) { - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, valuePhis[i2], i2)); - assert valuePhis[i2].valueCount() == withStates.size() + 1; - } - } return true; } @Override public void loopBegin(LoopBeginNode loopBegin) { - assert virtualObjectField != null : "unexpected null virtualObjectField"; - PhiNode vobjPhi = null; - vobjPhi = graph.add(new PhiNode(PhiType.Virtual, loopBegin)); - vobjPhi.addInput(virtualObjectField); - virtualObjectField = vobjPhi; for (int i2 = 0; i2 < fieldState.length; i2++) { PhiNode valuePhi = graph.add(new PhiNode(fieldState[i2].kind(), loopBegin)); valuePhi.addInput(fieldState[i2]); fieldState[i2] = valuePhi; - updateField(i2); } } @Override public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - while (!loopBegin.isPhiAtMerge(virtualObjectField)) { - if (virtualObjectField instanceof PhiNode) { - virtualObjectField = ((PhiNode) virtualObjectField).valueAt(0); - } else { - virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState(); - } - } for (BlockExitState loopEndState : loopEndStates) { - ((PhiNode) virtualObjectField).addInput(loopEndState.virtualObjectField); for (int i2 = 0; i2 < fieldState.length; i2++) { ((PhiNode) fieldState[i2]).addInput(loopEndState.fieldState[i2]); } @@ -175,6 +140,12 @@ } } + private void process() { + for (Node usage : node.usages().snapshot()) { + op.beforeUpdate(node, usage); + } + } + public void removeAllocation() { escapeFields = op.fields(node); for (int i = 0; i < escapeFields.length; i++) { @@ -202,42 +173,21 @@ final PostOrderNodeIterator iterator = new PostOrderNodeIterator(next, startState) { @Override protected void node(FixedNode curNode) { - int changedField = op.updateState(virtual, curNode, fields, state.fieldState); - if (changedField != -1) { - state.updateField(changedField); - } + op.updateState(virtual, curNode, fields, state.fieldState); if (curNode instanceof LoopExitNode) { - state.virtualObjectField = graph.unique(new ValueProxyNode(state.virtualObjectField, (LoopExitNode) curNode, PhiType.Virtual)); for (int i = 0; i < state.fieldState.length; i++) { state.fieldState[i] = graph.unique(new ValueProxyNode(state.fieldState[i], (LoopExitNode) curNode, PhiType.Value)); } } if (!curNode.isDeleted() && curNode instanceof StateSplit && ((StateSplit) curNode).stateAfter() != null) { - if (state.virtualObjectField != null) { - ValueNode v = state.virtualObjectField; - if (curNode instanceof LoopBeginNode) { - while (!((LoopBeginNode) curNode).isPhiAtMerge(v)) { - if (v instanceof PhiNode) { - v = ((PhiNode) v).valueAt(0); - } else { - v = ((VirtualObjectFieldNode) v).lastState(); - } - } - } - ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); - } + VirtualObjectState v = graph.add(new VirtualObjectState(virtual, state.fieldState)); + ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); } } }; iterator.apply(); } } - - private void process() { - for (Node usage : node.usages().snapshot()) { - op.beforeUpdate(node, usage); - } - } } private final TargetDescription target; @@ -278,7 +228,7 @@ private static Node escape(EscapeRecord record, Node usage) { final Node node = record.node; - if (usage instanceof FrameState) { + if (usage instanceof VirtualState) { assert usage.inputs().contains(node); return null; } else { @@ -318,8 +268,6 @@ // in order to not escape, the access needs to have a valid constant index and either a store into node or be self-referencing return EscapeOp.isValidConstantIndex(x) && x.value() != node ? null : x.array(); } - } else if (usage instanceof VirtualObjectFieldNode) { - return null; } else if (usage instanceof RegisterFinalizerNode) { assert ((RegisterFinalizerNode) usage).object() == node; return null; @@ -467,7 +415,7 @@ for (Node usage : node.usages().snapshot()) { boolean escapes = op.escape(node, usage); if (escapes) { - if (usage instanceof FrameState) { + if (usage instanceof VirtualState) { // nothing to do... } else if (usage instanceof MethodCallTargetNode) { if (usage.usages().size() == 0) { diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -49,7 +49,7 @@ protected void run(StructuredGraph graph) { for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { PlaceholderNode p = graph.add(new PlaceholderNode()); - p.setStateAfter(graph.add(new FrameState(null, FrameState.AFTER_BCI, 0, 0, false, false))); + p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); graph.addBeforeFixed(ret, p); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Thu Jun 14 18:03:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +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.phases; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.Fold; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.util.*; - -public class SnippetIntrinsificationPhase extends Phase { - - private final CodeCacheProvider runtime; - private final BoxingMethodPool pool; - - public SnippetIntrinsificationPhase(CodeCacheProvider runtime, BoxingMethodPool pool) { - this.runtime = runtime; - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke i : graph.getInvokes()) { - tryIntrinsify(i); - } - } - - private void tryIntrinsify(Invoke invoke) { - ResolvedJavaMethod target = invoke.callTarget().targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - if (intrinsic != null) { - assert target.getAnnotation(Node.Fold.class) == null; - - Class< ? >[] parameterTypes = CodeUtil.signatureToTypes(target.signature(), target.holder()); - - // Prepare the arguments for the reflective constructor call on the node class. - Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); - - // Create the new node instance. - Class< ? > c = getNodeClass(target, intrinsic); - Node newInstance = createNodeInstance(c, parameterTypes, nodeConstructorArguments); - - // Replace the invoke with the new node. - invoke.node().graph().add(newInstance); - invoke.intrinsify(newInstance); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(newInstance); - } else if (target.getAnnotation(Node.Fold.class) != null) { - Class< ? >[] parameterTypes = CodeUtil.signatureToTypes(target.signature(), target.holder()); - - // Prepare the arguments for the reflective method call - Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); - Object receiver = null; - if (!invoke.callTarget().isStatic()) { - receiver = arguments[0]; - arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); - } - - // Call the method - Constant constant = callMethod(target.signature().returnKind(), target.holder().toJava(), target.name(), parameterTypes, receiver, arguments); - - if (constant != null) { - // Replace the invoke with the result of the call - ConstantNode node = ConstantNode.forCiConstant(constant, runtime, invoke.node().graph()); - invoke.intrinsify(node); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(node); - } else { - // Remove the invoke - invoke.intrinsify(null); - } - } - } - - /** - * Converts the arguments of an invoke node to object values suitable for use as the arguments - * to a reflective invocation of a Java constructor or method. - * - * @param folding specifies if the invocation is for handling a {@link Fold} annotation - */ - private Object[] prepareArguments(Invoke invoke, Class< ? >[] parameterTypes, ResolvedJavaMethod target, boolean folding) { - NodeInputList arguments = invoke.callTarget().arguments(); - Object[] reflectionCallArguments = new Object[arguments.size()]; - for (int i = 0; i < reflectionCallArguments.length; ++i) { - int parameterIndex = i; - if (!invoke.callTarget().isStatic()) { - parameterIndex--; - } - ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); - if (folding || CodeUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { - assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.callTarget().targetMethod() + ": " + argument; - ConstantNode constantNode = (ConstantNode) argument; - Constant constant = constantNode.asConstant(); - Object o = constant.boxedValue(); - if (o instanceof Class< ? >) { - reflectionCallArguments[i] = runtime.getResolvedJavaType((Class< ? >) o); - parameterTypes[i] = ResolvedJavaType.class; - } else { - if (parameterTypes[i] == boolean.class) { - reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); - } else if (parameterTypes[i] == byte.class) { - reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); - } else if (parameterTypes[i] == short.class) { - reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); - } else if (parameterTypes[i] == char.class) { - reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); - } else { - reflectionCallArguments[i] = o; - } - } - } else { - reflectionCallArguments[i] = argument; - parameterTypes[i] = ValueNode.class; - } - } - return reflectionCallArguments; - } - - private static Class< ? > getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { - Class< ? > result = intrinsic.value(); - if (result == NodeIntrinsic.class) { - result = target.holder().toJava(); - } - assert Node.class.isAssignableFrom(result); - 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().size() == 2) { - if (node instanceof Invoke) { - Invoke invokeNode = (Invoke) node; - MethodCallTargetNode callTarget = invokeNode.callTarget(); - if (pool.isBoxingMethod(callTarget.targetMethod())) { - FrameState stateAfter = invokeNode.stateAfter(); - assert stateAfter.usages().size() == 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.NORMAL_EDGE); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - stateAfter.safeDelete(); - GraphUtil.propagateKill(callTarget); - return result; - } - } - } - } - } - } - } - return node; - } - - private static Node createNodeInstance(Class< ? > nodeClass, Class< ? >[] parameterTypes, Object[] nodeConstructorArguments) { - Constructor< ? > constructor; - try { - constructor = nodeClass.getDeclaredConstructor(parameterTypes); - constructor.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - try { - return (ValueNode) constructor.newInstance(nodeConstructorArguments); - } catch (Exception e) { - throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); - } - } - - /** - * Calls a Java method via reflection. - */ - private static Constant callMethod(Kind returnKind, Class< ? > holder, String name, Class< ? >[] parameterTypes, Object receiver, Object[] arguments) { - Method method; - try { - method = holder.getDeclaredMethod(name, parameterTypes); - method.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - try { - Object result = method.invoke(receiver, arguments); - if (result == null) { - return null; - } - return Constant.forBoxed(returnKind, result); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static String sourceLocation(Node n) { - String loc = GraphUtil.approxSourceLocation(n); - return loc == null ? "" : loc; - } - - public void cleanUpReturnCheckCast(Node newInstance) { - if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != Kind.Object) { - StructuredGraph graph = (StructuredGraph) newInstance.graph(); - for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { - for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) { - graph.replaceFloating(vpn, checkCastNode); - } - for (Node checkCastUsage : checkCastNode.usages().snapshot()) { - if (checkCastUsage instanceof ValueAnchorNode) { - ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; - graph.removeFixed(valueAnchorNode); - } else if (checkCastUsage instanceof MethodCallTargetNode) { - MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - assert pool.isUnboxingMethod(checkCastCallTarget.targetMethod()) : - "checkcast at " + sourceLocation(checkCastNode) + " not used by an unboxing method but by a call at " + - sourceLocation(checkCastCallTarget.usages().first()) + " to " + 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.NORMAL_EDGE); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - checkCastCallTarget.safeDelete(); - } else if (checkCastUsage instanceof FrameState) { - checkCastUsage.replaceFirstInput(checkCastNode, null); - } else { - assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); - } - } - FixedNode next = checkCastNode.next(); - checkCastNode.setNext(null); - checkCastNode.replaceAtPredecessor(next); - GraphUtil.killCFG(checkCastNode); - } - } - } -} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -41,7 +41,7 @@ /** * Map from blocks to the nodes in each block. */ - private BlockMap> blockToNodesMap; + private BlockMap> blockToNodesMap; public SchedulePhase() { super("Schedule"); @@ -57,17 +57,20 @@ sortNodesWithinBlocks(graph); } + /** + * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}. + * This method should thus only be called when run has been successfully executed. + */ public void scheduleGraph() { + assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; for (Block block : cfg.getBlocks()) { - List nodeList = blockToNodesMap.get(block); + List nodeList = blockToNodesMap.get(block); ScheduledNode last = null; - for (Node node : nodeList) { - if (!(node instanceof FrameState)) { - if (last != null) { - last.setScheduledNext((ScheduledNode) node); - } - last = (ScheduledNode) node; + for (ScheduledNode node : nodeList) { + if (last != null) { + last.setScheduledNext(node); } + last = node; } } } @@ -79,79 +82,86 @@ /** * Gets the map from each block to the nodes in the block. */ - public BlockMap> getBlockToNodesMap() { + public BlockMap> getBlockToNodesMap() { return blockToNodesMap; } /** * Gets the nodes in a given block. */ - public List nodesFor(Block block) { + public List nodesFor(Block block) { return blockToNodesMap.get(block); } private void assignBlockToNodes(StructuredGraph graph) { for (Block block : cfg.getBlocks()) { - List nodes = new ArrayList<>(); + List nodes = new ArrayList<>(); assert blockToNodesMap.get(block) == null; blockToNodesMap.put(block, nodes); - for (Node node : block.getNodes()) { + for (FixedNode node : block.getNodes()) { nodes.add(node); } } for (Node n : graph.getNodes()) { - assignBlockToNode(n); + if (n instanceof ScheduledNode) { + assignBlockToNode((ScheduledNode) n); + } } } - private void assignBlockToNode(Node n) { - if (n == null) { - return; - } + /** + * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a + * block, since they should already have been placed by {@link ControlFlowGraph#identifyBlocks()}. + * This method will also try to + */ + private void assignBlockToNode(ScheduledNode node) { + assert !node.isDeleted(); - assert !n.isDeleted(); - - Block prevBlock = cfg.getNodeToBlock().get(n); + Block prevBlock = cfg.getNodeToBlock().get(node); if (prevBlock != null) { return; } - assert !(n instanceof PhiNode) : n; - assert !(n instanceof MergeNode); + // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks + assert !(node instanceof PhiNode) : node; + assert !(node instanceof FixedNode) : node; // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(n); + Block latestBlock = latestBlock(node); Block block; if (latestBlock == null) { - block = earliestBlock(n); - } else if (GraalOptions.ScheduleOutOfLoops && !(n instanceof VirtualObjectFieldNode) && !(n instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(n); - block = scheduleOutOfLoops(n, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + n; + block = earliestBlock(node); + } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { + Block earliestBlock = earliestBlock(node); + block = scheduleOutOfLoops(node, latestBlock, earliestBlock); + assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; } else { block = latestBlock; } - cfg.getNodeToBlock().set(n, block); - blockToNodesMap.get(block).add(n); + cfg.getNodeToBlock().set(node, block); + blockToNodesMap.get(block).add(node); } - private Block latestBlock(Node n) { - Block block = null; - for (Node succ : n.successors()) { - if (succ == null) { - continue; - } - assignBlockToNode(succ); - block = getCommonDominator(block, cfg.getNodeToBlock().get(succ)); + /** + * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages. + * To do so all usages are also assigned to blocks. + */ + private Block latestBlock(ScheduledNode node) { + CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); + for (Node succ : node.successors().nonNull()) { + assert cfg.getNodeToBlock().get(succ) != null; + cdbc.apply(cfg.getNodeToBlock().get(succ)); } - ensureScheduledUsages(n); - CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(block); - for (Node usage : n.usages()) { - blocksForUsage(n, usage, cdbc); + ensureScheduledUsages(node); + for (Node usage : node.usages()) { + blocksForUsage(node, usage, cdbc); } return cdbc.block; } - private class CommonDominatorBlockClosure implements BlockClosure { + /** + * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method. + */ + private static class CommonDominatorBlockClosure implements BlockClosure { public Block block; public CommonDominatorBlockClosure(Block block) { this.block = block; @@ -162,42 +172,45 @@ } } - private Block earliestBlock(Node n) { - Block earliest = cfg.getNodeToBlock().get(n); + /** + * Determines the earliest block in which the given node can be scheduled. + */ + private Block earliestBlock(Node node) { + Block earliest = cfg.getNodeToBlock().get(node); if (earliest != null) { return earliest; } - earliest = earliestCache.get(n); + earliest = earliestCache.get(node); if (earliest != null) { return earliest; } - BitSet bits = new BitSet(cfg.getBlocks().length); - ArrayList before = new ArrayList<>(); - if (n.predecessor() != null) { - before.add(n.predecessor()); - } - for (Node input : n.inputs()) { - before.add(input); - } - for (Node pred : before) { - if (pred == null) { - continue; - } - Block b = earliestBlock(pred); - if (!bits.get(b.getId())) { - earliest = b; + /* + * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the + * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block + * placement for this node we need to find the input block that is dominated by all other input blocks. + * + * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained. + * When the block of an input is not within this set, it becomes the current earliest placement and the list of + * dominator blocks is updated. + */ + BitSet dominators = new BitSet(cfg.getBlocks().length); + + assert node.predecessor() == null; + for (Node input : node.inputs().nonNull()) { + assert input instanceof ValueNode; + Block inputEarliest = earliestBlock(input); + if (!dominators.get(inputEarliest.getId())) { + earliest = inputEarliest; do { - bits.set(b.getId()); - b = b.getDominator(); - } while(b != null && !bits.get(b.getId())); + dominators.set(inputEarliest.getId()); + inputEarliest = inputEarliest.getDominator(); + } while(inputEarliest != null && !dominators.get(inputEarliest.getId())); } } if (earliest == null) { - Block start = cfg.getNodeToBlock().get(((StructuredGraph) n.graph()).start()); - assert start != null; - return start; + earliest = cfg.getStartBlock(); } - earliestCache.set(n, earliest); + earliestCache.set(node, earliest); return earliest; } @@ -216,8 +229,20 @@ return result; } - private void blocksForUsage(Node node, Node usage, BlockClosure closure) { + /** + * Passes all blocks that a specific usage of a node is in to a given closure. + * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates. + * + * @param node the node that needs to be scheduled + * @param usage the usage whose blocks need to be considered + * @param closure the closure that will be called for each block + */ + private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { + assert !(node instanceof PhiNode); + if (usage instanceof PhiNode) { + // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input. + // One PhiNode can use an input multiple times, the closure will be called for each usage. PhiNode phi = (PhiNode) usage; MergeNode merge = phi.merge(); Block mergeBlock = cfg.getNodeToBlock().get(merge); @@ -235,22 +260,38 @@ closure.apply(mergeBlock.getPredecessors().get(i)); } } - } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) { - MergeNode merge = ((FrameState) usage).block(); - Block block = null; - for (Node pred : merge.cfgPredecessors()) { - block = getCommonDominator(block, cfg.getNodeToBlock().get(pred)); + } else if (usage instanceof VirtualState) { + // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes. + for (Node unscheduledUsage : usage.usages()) { + if (unscheduledUsage instanceof VirtualState) { + // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing. + blocksForUsage(node, unscheduledUsage, closure); + } else if (unscheduledUsage instanceof MergeNode) { + // Only FrameStates can be connected to MergeNodes. + assert usage instanceof FrameState; + // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes. + for (Node pred : unscheduledUsage.cfgPredecessors()) { + closure.apply(cfg.getNodeToBlock().get(pred)); + } + } else { + // For the time being, only FrameStates can be connected to StateSplits. + assert usage instanceof FrameState; + assert unscheduledUsage instanceof StateSplit; + // Otherwise: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) unscheduledUsage); + closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); + } } - closure.apply(block); } else { - assignBlockToNode(usage); + // All other types of usages: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) usage); closure.apply(cfg.getNodeToBlock().get(usage)); } } private void ensureScheduledUsages(Node node) { - for (Node usage : node.usages().snapshot()) { - assignBlockToNode(usage); + for (Node usage : node.usages().filter(ScheduledNode.class)) { + assignBlockToNode((ScheduledNode) usage); } // now true usages are ready } @@ -266,21 +307,25 @@ } private void sortNodesWithinBlocks(StructuredGraph graph) { - NodeBitMap map = graph.createNodeBitMap(); + NodeBitMap visited = graph.createNodeBitMap(); for (Block b : cfg.getBlocks()) { - sortNodesWithinBlocks(b, map); + sortNodesWithinBlock(b, visited); } } - private void sortNodesWithinBlocks(Block b, NodeBitMap map) { - List instructions = blockToNodesMap.get(b); - List sortedInstructions = new ArrayList<>(instructions.size() + 2); + /** + * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs. + * This means that a node is added to the list after all its inputs have been processed. + */ + private void sortNodesWithinBlock(Block b, NodeBitMap visited) { + List instructions = blockToNodesMap.get(b); + List sortedInstructions = new ArrayList<>(instructions.size() + 2); - assert !map.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !map.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; + assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; - for (Node i : instructions) { - addToSorting(b, i, sortedInstructions, map); + for (ScheduledNode i : instructions) { + addToSorting(b, i, sortedInstructions, visited); } // Make sure that last node gets really last (i.e. when a frame state successor hangs off it). @@ -310,32 +355,45 @@ blockToNodesMap.put(b, sortedInstructions); } - private void addToSorting(Block b, Node i, List sortedInstructions, NodeBitMap map) { - if (i == null || map.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { + private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { + if (state != null) { + // UnscheduledNodes should never be marked as visited. + assert !visited.isMarked(state); + + for (Node input : state.inputs()) { + if (input instanceof VirtualState) { + addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); + } else { + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + } + } + + private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { return; } FrameState state = null; - WriteNode writeNode = null; + WriteNode write = null; for (Node input : i.inputs()) { - if (input instanceof WriteNode && !map.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { - writeNode = (WriteNode) input; + if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { + assert write == null; + write = (WriteNode) input; } else if (input instanceof FrameState) { + assert state == null; state = (FrameState) input; } else { - addToSorting(b, input, sortedInstructions, map); + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); } } - if (i.predecessor() != null) { - addToSorting(b, i.predecessor(), sortedInstructions, map); - } - - map.mark(i); - - addToSorting(b, state, sortedInstructions, map); - assert writeNode == null || !map.isMarked(writeNode); - addToSorting(b, writeNode, sortedInstructions, map); + addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + visited.mark(i); + addUnscheduledToSorting(b, state, sortedInstructions, visited); + assert write == null || !visited.isMarked(write); + addToSorting(b, write, sortedInstructions, visited); // Now predecessors and inputs are scheduled => we can add this node. sortedInstructions.add(i); diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Jun 14 18:03:43 2012 +0200 @@ -90,27 +90,6 @@ Class value() default NodeIntrinsic.class; } - - /** - * Annotates a method replaced by a compile-time constant. - * A (resolved) call to the annotated method is replaced - * with a constant obtained by calling the annotated method via reflection. - * - * All arguments to such a method (including the receiver if applicable) - * must be compile-time constants. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public static @interface Fold { - } - - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public static @interface NodePhase { - Class value() default NodePhase.class; - } - public interface ValueNumberable {} public interface IterableNodeType {} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Thu Jun 14 18:03:43 2012 +0200 @@ -21,11 +21,7 @@ * questions. */ package com.oracle.graal.graph; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; +import java.util.*; import com.oracle.graal.graph.iterators.*; @@ -60,6 +56,7 @@ this.nodes = new Node[elements.length]; for (int i = 0; i < elements.length; i++) { this.nodes[i] = elements[i]; + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); } } } @@ -75,6 +72,7 @@ this.nodes = new Node[elements.size()]; for (int i = 0; i < elements.size(); i++) { this.nodes[i] = elements.get(i); + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Jun 14 18:03:43 2012 +0200 @@ -154,7 +154,7 @@ final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null; compiler.getRuntime().installMethod(method, tm, info); if (info != null) { - Debug.dump(info[0], "After code installation"); + Debug.dump(new Object[] {tm, info[0]}, "After code installation"); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Jun 14 18:03:43 2012 +0200 @@ -41,6 +41,7 @@ public boolean useFastLocking; public boolean useFastNewObjectArray; public boolean useFastNewTypeArray; + public boolean useTLAB; // offsets, ... public int vmPageSize; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Jun 14 18:03:43 2012 +0200 @@ -112,8 +112,9 @@ @Override public void run() { VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime); - GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget()); - runtime.installSnippets(); + SnippetInstaller installer = new SnippetInstaller(runtime, runtime.getCompiler().getTarget()); + GraalIntrinsics.installIntrinsics(installer); + runtime.installSnippets(installer); } }); diff -r e1b29c516354 -r 65bf69eb147c 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 Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jun 14 18:03:43 2012 +0200 @@ -68,14 +68,14 @@ System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName()); } - public void installSnippets() { - Snippets.install(this, compiler.getTarget(), new SystemSnippets()); - Snippets.install(this, compiler.getTarget(), new UnsafeSnippets()); - Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets()); - Snippets.install(this, compiler.getTarget(), new CheckCastSnippets()); - Snippets.install(this, compiler.getTarget(), new NewInstanceSnippets()); + public void installSnippets(SnippetInstaller installer) { + installer.install(SystemSnippets.class); + installer.install(UnsafeSnippets.class); + installer.install(ArrayCopySnippets.class); + installer.install(CheckCastSnippets.class); + installer.install(NewInstanceSnippets.class); checkcastSnippets = new CheckCastSnippets.Templates(this); - newInstanceSnippets = new NewInstanceSnippets.Templates(this); + newInstanceSnippets = new NewInstanceSnippets.Templates(this, config.useTLAB); } @@ -308,7 +308,7 @@ if (arrayType != null && array.objectStamp().isExactType()) { ResolvedJavaType elementType = arrayType.componentType(); if (elementType.superType() != null) { - ConstantNode type = ConstantNode.forCiConstant(elementType.getEncoding(Representation.ObjectHub), this, graph); + ConstantNode type = ConstantNode.forConstant(elementType.getEncoding(Representation.ObjectHub), this, graph); checkcast = graph.add(new CheckCastNode(type, elementType, value)); graph.addBeforeFixed(storeIndexed, checkcast); value = checkcast; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Thu Jun 14 18:03:43 2012 +0200 @@ -49,7 +49,8 @@ public void generate(LIRGenerator gen) { Variable result = gen.newVariable(Kind.Object); gen.emitMove(gen.operand(hub), AMD64.rdx.asValue()); - AMD64NewInstanceStubCallOp op = new AMD64NewInstanceStubCallOp(result, AMD64.rdx.asValue()); + LIRDebugInfo info = gen.state(); + AMD64NewInstanceStubCallOp op = new AMD64NewInstanceStubCallOp(result, AMD64.rdx.asValue(), info); gen.append(op); gen.setResult(this, result); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Thu Jun 14 18:03:43 2012 +0200 @@ -22,13 +22,13 @@ */ package com.oracle.graal.hotspot.snippets; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.Fold; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.Fold; @SuppressWarnings("unused") diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Thu Jun 14 18:03:43 2012 +0200 @@ -38,7 +38,6 @@ import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Fold; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; @@ -46,6 +45,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.snippets.*; import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.Snippet.Parameter; import com.oracle.graal.snippets.SnippetTemplate.Arguments; import com.oracle.graal.snippets.SnippetTemplate.Cache; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java Thu Jun 14 18:03:43 2012 +0200 @@ -37,7 +37,6 @@ import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Fold; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -45,6 +44,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.snippets.*; import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.Snippet.Parameter; import com.oracle.graal.snippets.SnippetTemplate.Arguments; import com.oracle.graal.snippets.SnippetTemplate.Cache; @@ -55,32 +55,46 @@ */ public class NewInstanceSnippets implements SnippetsInterface { - /** - * Type test used when the type being tested against is a final type. - */ + private static final boolean LOG_ALLOCATION = Boolean.getBoolean("graal.traceAllocation"); + @Snippet - public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit) { + public static Object newInstance( + @Parameter("hub") Object hub, + @ConstantParameter("size") int size, + @ConstantParameter("checkInit") boolean checkInit, + @ConstantParameter("useTLAB") boolean useTLAB, + @ConstantParameter("logType") String logType) { + if (checkInit) { int klassState = load(hub, 0, klassStateOffset(), Kind.Int); if (klassState != klassStateFullyInitialized()) { - Object instance = NewInstanceStubCall.call(hub); - return formatInstance(hub, size, instance); + if (logType != null) { + Log.print(logType); + Log.println(" - uninitialized"); + } + return NewInstanceStubCall.call(hub); } } - Word thread = asWord(register(r15, wordKind())); - Word top = loadWord(thread, threadTlabTopOffset()); - Word end = loadWord(thread, threadTlabEndOffset()); - Word newTop = top.plus(size); - Object instance; - if (newTop.cmp(BE, end)) { - instance = cast(top, Object.class); - store(thread, 0, threadTlabTopOffset(), newTop); + if (useTLAB) { + Word thread = asWord(register(r15, wordKind())); + Word top = loadWord(thread, threadTlabTopOffset()); + Word end = loadWord(thread, threadTlabEndOffset()); + Word newTop = top.plus(size); + if (newTop.cmp(BE, end)) { + Object instance = cast(top, Object.class); + store(thread, 0, threadTlabTopOffset(), newTop); + return formatInstance(hub, size, instance, logType); + } else { + if (logType != null) { + Log.print(logType); + Log.println(" - stub allocate"); + } + return NewInstanceStubCall.call(hub); + } } else { - instance = NewInstanceStubCall.call(hub); + return NewInstanceStubCall.call(hub); } - - return formatInstance(hub, size, instance); } private static Word asWord(Object object) { @@ -94,7 +108,7 @@ /** * Formats the header of a created instance and zeroes out its body. */ - private static Object formatInstance(Object hub, int size, Object instance) { + private static Object formatInstance(Object hub, int size, Object instance, String logType) { Word headerPrototype = cast(load(hub, 0, instanceHeaderPrototypeOffset(), wordKind()), Word.class); store(instance, 0, 0, headerPrototype); store(instance, 0, hubOffset(), hub); @@ -102,6 +116,12 @@ for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { store(instance, 0, offset, 0); } + if (logType != null) { + Log.print("allocated instance of "); + Log.print(logType); + Log.print(" at "); + Log.printlnAddress(instance); + } return instance; } @@ -150,12 +170,14 @@ private final Cache cache; private final ResolvedJavaMethod newInstance; private final CodeCacheProvider runtime; + private final boolean useTLAB; - public Templates(CodeCacheProvider runtime) { + public Templates(CodeCacheProvider runtime, boolean useTLAB) { this.runtime = runtime; this.cache = new Cache(runtime); + this.useTLAB = useTLAB; try { - newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class)); + newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class, boolean.class, String.class)); } catch (NoSuchMethodException e) { throw new GraalInternalError(e); } @@ -170,10 +192,11 @@ HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass(); HotSpotKlassOop hub = type.klassOop(); int instanceSize = type.instanceSize(); - Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()); + Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()).add("useTLAB", useTLAB).add("logType", LOG_ALLOCATION ? type.name() : null); Arguments arguments = arguments("hub", hub); SnippetTemplate template = cache.get(key); Debug.log("Lowering newInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, arguments); + //System.out.printf("Lowering newInstance in %s: node=%s, template=%s, arguments=%s%n", graph, newInstanceNode, template, arguments); template.instantiate(runtime, newInstanceNode, newInstanceNode, arguments); new DeadCodeEliminationPhase().apply(graph); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java Thu Jun 14 18:03:43 2012 +0200 @@ -33,11 +33,11 @@ public class SystemSnippets implements SnippetsInterface { public static long currentTimeMillis() { - return RuntimeCallNode.performCall(RuntimeCall.JavaTimeMillis); + return RuntimeCallNode.callLong(RuntimeCall.JavaTimeMillis); } public static long nanoTime() { - return RuntimeCallNode.performCall(RuntimeCall.JavaTimeNanos); + return RuntimeCallNode.callLong(RuntimeCall.JavaTimeNanos); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java Thu Jun 14 18:03:43 2012 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; import com.oracle.max.asm.target.amd64.*; @@ -38,8 +39,8 @@ * and implemented in Runtime1::generate_code_for() which is located in c1_Runtime1_x86.cpp. */ public class AMD64NewInstanceStubCallOp extends AMD64LIRInstruction { - public AMD64NewInstanceStubCallOp(Value result, Value hub) { - super("NEW_INSTANCE", new Value[] {result}, null, new Value[] {hub}, NO_OPERANDS, NO_OPERANDS); + public AMD64NewInstanceStubCallOp(Value result, Value hub, LIRDebugInfo info) { + super("NEW_INSTANCE", new Value[] {result}, info, new Value[] {hub}, NO_OPERANDS, NO_OPERANDS); } @Override @@ -50,7 +51,7 @@ // rdx: (in) hub // rax: (out) result assert asRegister(hub) == AMD64.rdx; - AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().newInstanceStub, null); + AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().newInstanceStub, info); if (asRegister(result) != AMD64.rax) { masm.movq(asRegister(result), AMD64.rax); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Jun 14 18:03:43 2012 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; public class FrameStateBuilder { @@ -155,7 +156,7 @@ } else if (block.isPhiAtMerge(currentValue)) { if (otherValue == null || currentValue.kind() != otherValue.kind()) { - deletePhi((PhiNode) currentValue); + propagateDelete((PhiNode) currentValue); return null; } ((PhiNode) currentValue).addInput(otherValue); @@ -180,45 +181,21 @@ } } - private void deletePhi(PhiNode phi) { - if (phi.isDeleted()) { + private void propagateDelete(FloatingNode node) { + assert node instanceof PhiNode || node instanceof ValueProxyNode; + if (node.isDeleted()) { return; } // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). - List phiUsages = phi.usages().filter(PhiNode.class).snapshot(); - List vpnUsages = phi.usages().filter(ValueProxyNode.class).snapshot(); + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ValueProxyNode.class)).snapshot(); // Remove the phi function from all FrameStates where it is used and then delete it. - assert phi.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; - phi.replaceAtUsages(null); - phi.safeDelete(); - - for (PhiNode phiUsage : phiUsages) { - deletePhi(phiUsage); - } - for (ValueProxyNode proxyUsage : vpnUsages) { - deleteProxy(proxyUsage); - } - } + assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + node.replaceAtUsages(null); + node.safeDelete(); - private void deleteProxy(ValueProxyNode proxy) { - if (proxy.isDeleted()) { - return; - } - // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). - List phiUsages = proxy.usages().filter(PhiNode.class).snapshot(); - List vpnUsages = proxy.usages().filter(ValueProxyNode.class).snapshot(); - - // Remove the proxy function from all FrameStates where it is used and then delete it. - assert proxy.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; - proxy.replaceAtUsages(null); - proxy.safeDelete(); - - for (PhiNode phiUsage : phiUsages) { - deletePhi(phiUsage); - } - for (ValueProxyNode proxyUsage : vpnUsages) { - deleteProxy(proxyUsage); + for (FloatingNode phiUsage : propagateUsages) { + propagateDelete(phiUsage); } } @@ -262,7 +239,7 @@ public void cleanupDeletedPhis() { for (int i = 0; i < localsSize(); i++) { if (localAt(i) != null && localAt(i).isDeleted()) { - assert localAt(i) instanceof PhiNode : "Only phi functions can be deleted during parsing"; + assert localAt(i) instanceof PhiNode || localAt(i) instanceof ValueProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); storeLocal(i, null); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -284,7 +284,7 @@ // this is a load of class constant which might be unresolved JavaType riType = (JavaType) con; if (riType instanceof ResolvedJavaType) { - frameState.push(Kind.Object, append(ConstantNode.forCiConstant(((ResolvedJavaType) riType).getEncoding(Representation.JavaClass), runtime, currentGraph))); + frameState.push(Kind.Object, append(ConstantNode.forConstant(((ResolvedJavaType) riType).getEncoding(Representation.JavaClass), runtime, currentGraph))); } else { append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved, graphId))); frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph))); @@ -1097,7 +1097,7 @@ } private ConstantNode appendConstant(Constant constant) { - return ConstantNode.forCiConstant(constant, runtime, currentGraph); + return ConstantNode.forConstant(constant, runtime, currentGraph); } private ValueNode append(FixedNode fixed) { @@ -1274,7 +1274,7 @@ private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { if (isStatic(target.accessFlags())) { - return append(ConstantNode.forCiConstant(target.holder().getEncoding(Representation.JavaClass), runtime, currentGraph)); + return append(ConstantNode.forConstant(target.holder().getEncoding(Representation.JavaClass), runtime, currentGraph)); } else { return state.loadLocal(0); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Jun 14 18:03:43 2012 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; /** * This class implements the overall container for the LIR graph @@ -42,7 +43,7 @@ * The nodes for the blocks. * TODO: This should go away, we want all nodes connected with a next-pointer. */ - private final BlockMap> blockToNodesMap; + private final BlockMap> blockToNodesMap; /** * The linear-scan ordered list of blocks. @@ -87,7 +88,7 @@ * @param numLoops number of loops * @param compilation the compilation */ - public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { + public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { this.cfg = cfg; this.blockToNodesMap = blockToNodesMap; this.codeEmittingOrder = codeEmittingOrder; @@ -99,7 +100,7 @@ /** * Gets the nodes in a given block. */ - public List nodesFor(Block block) { + public List nodesFor(Block block) { return blockToNodesMap.get(block); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Thu Jun 14 18:03:43 2012 +0200 @@ -106,22 +106,22 @@ */ public enum OperandFlag { /** - * The value can be a {@link CiRegisterValue}. + * The value can be a {@link RegisterValue}. */ Register, /** - * The value can be a {@link CiStackSlot}. + * The value can be a {@link StackSlot}. */ Stack, /** - * The value can be a {@link CiAddress}. + * The value can be a {@link Address}. */ Address, /** - * The value can be a {@link CiConstant}. + * The value can be a {@link Constant}. */ Constant, diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Thu Jun 14 18:03:43 2012 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -33,7 +32,7 @@ protected int id; protected BeginNode beginNode; - protected Node endNode; + protected FixedNode endNode; protected Loop loop; protected double probability; @@ -62,7 +61,7 @@ return beginNode; } - public Node getEndNode() { + public FixedNode getEndNode() { return endNode; } @@ -122,8 +121,8 @@ return postdominator; } - private class NodeIterator implements Iterator { - private Node cur; + private class NodeIterator implements Iterator { + private FixedNode cur; public NodeIterator() { cur = getBeginNode(); @@ -135,8 +134,8 @@ } @Override - public Node next() { - Node result = cur; + public FixedNode next() { + FixedNode result = cur; if (cur == getEndNode()) { cur = null; } else { @@ -152,10 +151,10 @@ } } - public Iterable getNodes() { - return new Iterable() { + public Iterable getNodes() { + return new Iterable() { @Override - public Iterator iterator() { + public Iterator iterator() { return new NodeIterator(); } }; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Thu Jun 14 18:03:43 2012 +0200 @@ -118,9 +118,9 @@ block.beginNode = (BeginNode) node; Node cur = node; + Node last; do { assert !cur.isDeleted(); - block.endNode = cur; assert nodeToBlock.get(cur) == null; nodeToBlock.set(cur, block); @@ -137,15 +137,11 @@ } } - Node next = null; - for (Node sux : cur.successors()) { - if (sux != null && !(sux instanceof BeginNode)) { - assert next == null; - next = sux; - } - } - cur = next; - } while (cur != null); + last = cur; + cur = cur.successors().first(); + } while (cur != null && !(cur instanceof BeginNode)); + + block.endNode = (FixedNode) last; } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.type.*; public abstract class CallTargetNode extends ValueNode implements LIRLowerable { + @Input protected final NodeInputList arguments; public CallTargetNode(ValueNode[] arguments) { @@ -45,6 +46,6 @@ @Override public void generate(LIRGeneratorTool gen) { - //nop + // nop } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -65,7 +65,7 @@ return usages().filter(NodePredicates.isNotA(FrameState.class)).isEmpty(); } - public static ConstantNode forCiConstant(Constant constant, CodeCacheProvider runtime, Graph graph) { + public static ConstantNode forConstant(Constant constant, CodeCacheProvider runtime, Graph graph) { if (constant.kind == Kind.Object) { return graph.unique(new ConstantNode(constant, runtime)); } else { diff -r e1b29c516354 -r 65bf69eb147c 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 Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Jun 14 18:03:43 2012 +0200 @@ -35,7 +35,7 @@ * The {@code FrameState} class encapsulates the frame state (i.e. local variables and * operand stack) at a particular point in the abstract interpretation. */ -public final class FrameState extends Node implements Node.IterableNodeType, LIRLowerable { +public final class FrameState extends VirtualState implements Node.IterableNodeType, LIRLowerable { protected final int localsSize; @@ -74,11 +74,10 @@ @Input private final NodeInputList values; - @Input private final NodeInputList virtualObjectMappings; + @Input private final NodeInputList virtualObjectMappings; /** - * The bytecode index to which this frame state applies. This will be {@code -1} - * iff this state is mutable. + * The bytecode index to which this frame state applies. */ public final int bci; @@ -93,19 +92,28 @@ * @param stackSize size of the stack * @param rethrowException if true the VM should re-throw the exception on top of the stack when deopt'ing using this framestate */ - public FrameState(ResolvedJavaMethod method, int bci, int localsSize, int stackSize, boolean rethrowException, boolean duringCall) { + public FrameState(ResolvedJavaMethod method, int bci, List values, int stackSize, boolean rethrowException, boolean duringCall, List virtualObjectMappings) { assert stackSize >= 0; + assert (bci >= 0 && method != null) || (bci < 0 && method == null && values.isEmpty()); this.method = method; this.bci = bci; - this.localsSize = localsSize; + this.localsSize = values.size() - stackSize; this.stackSize = stackSize; - this.values = new NodeInputList<>(this, localsSize + stackSize); - this.virtualObjectMappings = new NodeInputList<>(this); + this.values = new NodeInputList<>(this, values); + this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings); this.rethrowException = rethrowException; this.duringCall = duringCall; assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; } + /** + * Simple constructor used to create marker FrameStates. + * @param bci marker bci, needs to be < 0 + */ + public FrameState(int bci) { + this(null, bci, Collections.emptyList(), 0, false, false, Collections.emptyList()); + } + public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException, boolean duringCall) { this.method = method; this.bci = bci; @@ -140,10 +148,6 @@ this.outerFrameState = x; } - private void setValueAt(int i, ValueNode x) { - values.set(i, x); - } - public boolean rethrowException() { return rethrowException; } @@ -160,8 +164,7 @@ return method; } - public void addVirtualObjectMapping(Node virtualObject) { - assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode || virtualObject instanceof ValueProxyNode : virtualObject; + public void addVirtualObjectMapping(VirtualObjectState virtualObject) { virtualObjectMappings.add(virtualObject); } @@ -173,7 +176,7 @@ return virtualObjectMappings.get(i); } - public Iterable virtualObjectMappings() { + public Iterable virtualObjectMappings() { return virtualObjectMappings; } @@ -192,9 +195,7 @@ } public FrameState duplicate(int newBci, boolean duplicateOuter) { - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException, duringCall)); - other.values.setAll(values); - other.virtualObjectMappings.setAll(virtualObjectMappings); + FrameState other = graph().add(new FrameState(method, newBci, values, stackSize, rethrowException, duringCall, virtualObjectMappings)); FrameState newOuterFrameState = outerFrameState(); if (duplicateOuter && newOuterFrameState != null) { newOuterFrameState = newOuterFrameState.duplicate(newOuterFrameState.bci, duplicateOuter); @@ -209,29 +210,18 @@ * or double is followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { - int popSlots = 0; + ArrayList copy = new ArrayList<>(values); if (popKind != Kind.Void) { if (stackAt(stackSize() - 1) == null) { - popSlots = 2; - } else { - popSlots = 1; + copy.remove(copy.size() - 1); } - assert stackAt(stackSize() - popSlots).kind().stackKind() == popKind.stackKind() || (stackAt(stackSize() - popSlots) instanceof BoxedVirtualObjectNode && popKind.isObject()); + ValueNode lastSlot = copy.get(copy.size() - 1); + assert lastSlot.kind().stackKind() == popKind.stackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind.isObject()); + copy.remove(copy.size() - 1); } + Collections.addAll(copy, pushedValues); - int pushSlots = pushedValues.length; - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize - popSlots + pushSlots, newRethrowException, false)); - for (int i = 0; i < localsSize; i++) { - other.setValueAt(i, localAt(i)); - } - for (int i = 0; i < stackSize - popSlots; i++) { - other.setValueAt(localsSize + i, stackAt(i)); - } - int slot = localsSize + stackSize - popSlots; - for (int i = 0; i < pushSlots; i++) { - other.setValueAt(slot++, pushedValues[i]); - } - other.virtualObjectMappings.setAll(virtualObjectMappings); + FrameState other = graph().add(new FrameState(method, newBci, copy, copy.size() - localsSize, newRethrowException, false, virtualObjectMappings)); other.setOuterFrameState(outerFrameState()); return other; } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -135,6 +135,7 @@ @Override public void intrinsify(Node node) { + assert !(node instanceof ValueNode) || ((ValueNode) node).kind().isVoid() == kind().isVoid(); MethodCallTargetNode call = callTarget; FrameState stateAfter = stateAfter(); if (node instanceof StateSplit) { diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -175,6 +175,7 @@ @Override public void intrinsify(Node node) { + assert !(node instanceof ValueNode) || ((ValueNode) node).kind().isVoid() == kind().isVoid(); MethodCallTargetNode call = callTarget; FrameState state = stateAfter(); killExceptionEdge(); diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -36,8 +36,7 @@ public static enum PhiType { Value(null), // normal value phis - Memory(StampFactory.dependency()), // memory phis - Virtual(StampFactory.virtual()); // phis used for VirtualObjectField merges + Memory(StampFactory.dependency()); public final Stamp stamp; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.graph.*; -public class ScheduledNode extends Node { +public abstract class ScheduledNode extends Node { @Successor private ScheduledNode scheduledNext; // the immediate successor of the current node diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Thu Jun 14 18:03:43 2012 +0200 @@ -0,0 +1,33 @@ +/* + * 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.nodes; + +import com.oracle.graal.graph.*; + +/** + * Base class for nodes that contain "virtual" state, like FrameState and VirtualObjectState. + * Subclasses of this class will be treated in a special way by the scheduler. + */ +public abstract class VirtualState extends Node { + +} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -68,7 +68,7 @@ Kind kind = location().kind(); Constant constant = kind.readUnsafeConstant(value, displacement); if (constant != null) { - return ConstantNode.forCiConstant(constant, runtime, graph()); + return ConstantNode.forConstant(constant, runtime, graph()); } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -67,7 +67,7 @@ } if (exactType != null) { - return ConstantNode.forCiConstant(exactType.getEncoding(Representation.ObjectHub), runtime, graph()); + return ConstantNode.forConstant(exactType.getEncoding(Representation.ObjectHub), runtime, graph()); } } return this; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -51,7 +51,7 @@ Kind kind = location().kind(); Constant constant = kind.readUnsafeConstant(value, displacement); if (constant != null) { - return ConstantNode.forCiConstant(constant, runtime, graph()); + return ConstantNode.forConstant(constant, runtime, graph()); } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -39,13 +39,14 @@ this(call, new ValueNode[0]); } - public RuntimeCallNode(RuntimeCall call, ValueNode arg1) { - this(call, new ValueNode[] {arg1}); + public RuntimeCallNode(RuntimeCall call, ValueNode... arguments) { + super(StampFactory.forKind(call.resultKind), arguments); + this.call = call; } - public RuntimeCallNode(RuntimeCall call, ValueNode[] arguments) { - super(StampFactory.forKind(call.resultKind), arguments); - this.call = call; + @Override + public boolean hasSideEffect() { + return call.hasSideEffect(); } @Override @@ -53,16 +54,24 @@ gen.emitRuntimeCall(this); } + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(verbosity) + "#" + call; + } + return super.toString(verbosity); + } + // specialized on return type (instead of public static T performCall) until boxing/unboxing is sorted out in intrinsification @SuppressWarnings("unused") @NodeIntrinsic - public static double performCall(@ConstantNodeParameter RuntimeCall call, S arg1) { + public static double callDouble(@ConstantNodeParameter RuntimeCall call, S arg1) { throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); } @SuppressWarnings("unused") @NodeIntrinsic - public static long performCall(@ConstantNodeParameter RuntimeCall call) { + public static long callLong(@ConstantNodeParameter RuntimeCall call) { throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -34,11 +34,10 @@ /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. */ - public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType { public ValueAnchorNode(ValueNode... values) { - super(StampFactory.dependency(), values); + super(StampFactory.forVoid(), values); } @Override @@ -53,6 +52,12 @@ } @Override + public boolean verify() { + assertTrue(usages().isEmpty(), "upwards dependencies should target BeginNodes only"); + return super.verify(); + } + + @Override public ValueNode canonical(CanonicalizerTool tool) { if (this.predecessor() instanceof ValueAnchorNode) { // transfer values and remove @@ -69,7 +74,7 @@ if (node instanceof IntegerDivNode || node instanceof IntegerRemNode) { ArithmeticNode arithmeticNode = (ArithmeticNode) node; if (arithmeticNode.y().isConstant()) { - Constant constant = arithmeticNode.y().asConstant(); + Constant constant = arithmeticNode.y().asConstant(); assert constant.kind == arithmeticNode.kind() : constant.kind + " != " + arithmeticNode.kind(); if (constant.asLong() != 0) { continue; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -64,7 +64,7 @@ constant = field().constantValue(object().asConstant()); } if (constant != null) { - return ConstantNode.forCiConstant(constant, runtime, graph()); + return ConstantNode.forConstant(constant, runtime, graph()); } } return this; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -70,7 +70,7 @@ Object array = arrayConst.asObject(); int length = Array.getLength(array); if (index >= 0 && index < length) { - return ConstantNode.forCiConstant(elementKind().readUnsafeConstant(array, + return ConstantNode.forConstant(elementKind().readUnsafeConstant(array, elementKind().arrayBaseOffset() + index * elementKind().arrayIndexScale()), runtime, graph()); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Jun 14 18:03:43 2012 +0200 @@ -29,8 +29,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; - public abstract class EscapeOp { @@ -43,7 +41,7 @@ } else if (usage instanceof IsTypeNode) { assert ((IsTypeNode) usage).objectClass() == node; return false; - } else if (usage instanceof FrameState) { + } else if (usage instanceof VirtualState) { assert usage.inputs().contains(node); return true; } else if (usage instanceof AccessMonitorNode) { @@ -73,8 +71,6 @@ // in order to not escape the access needs to have a valid constant index and either a store into node or self-referencing return !isValidConstantIndex(x) || x.value() == node && x.array() != node; } - } else if (usage instanceof VirtualObjectFieldNode) { - return false; } else if (usage instanceof RegisterFinalizerNode) { assert ((RegisterFinalizerNode) usage).object() == node; return false; @@ -112,8 +108,8 @@ ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph())); } else if (usage instanceof IsTypeNode) { IsTypeNode x = (IsTypeNode) usage; - assert x.type() == ((ValueNode) node).objectStamp().type(); - ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(true, node.graph())); + boolean result = ((ValueNode) node).objectStamp().type() == x.type(); + ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(result, node.graph())); } else if (usage instanceof AccessMonitorNode) { ((AccessMonitorNode) usage).eliminate(); } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Jun 14 18:03:43 2012 +0200 @@ -31,14 +31,12 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; public class GraphUtil { - private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class).or(VirtualObjectFieldNode.class).or(VirtualObjectNode.class); + private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class); public static void killCFG(FixedNode node) { assert node.isAlive(); @@ -61,30 +59,32 @@ private static void killEnd(EndNode end) { MergeNode merge = end.merge(); - merge.removeEnd(end); - StructuredGraph graph = (StructuredGraph) end.graph(); - if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop - for (PhiNode phi : merge.phis().snapshot()) { - propagateKill(phi); - } - LoopBeginNode begin = (LoopBeginNode) merge; - // disconnect and delete loop ends & loop exits - for (LoopEndNode loopend : begin.loopEnds().snapshot()) { - loopend.predecessor().replaceFirstSuccessor(loopend, null); - loopend.safeDelete(); + if (merge != null) { + merge.removeEnd(end); + StructuredGraph graph = (StructuredGraph) end.graph(); + if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop + for (PhiNode phi : merge.phis().snapshot()) { + propagateKill(phi); + } + LoopBeginNode begin = (LoopBeginNode) merge; + // disconnect and delete loop ends & loop exits + for (LoopEndNode loopend : begin.loopEnds().snapshot()) { + loopend.predecessor().replaceFirstSuccessor(loopend, null); + loopend.safeDelete(); + } + for (LoopExitNode loopexit : begin.loopExits().snapshot()) { + for (ValueProxyNode vpn : loopexit.proxies().snapshot()) { + graph.replaceFloating(vpn, vpn.value()); + } + graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); + } + killCFG(begin.next()); + begin.safeDelete(); + } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore + graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); + } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore + graph.reduceTrivialMerge(merge); } - for (LoopExitNode loopexit : begin.loopExits().snapshot()) { - for (ValueProxyNode vpn : loopexit.proxies().snapshot()) { - graph.replaceFloating(vpn, vpn.value()); - } - graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); - } - killCFG(begin.next()); - begin.safeDelete(); - } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore - graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); - } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore - graph.reduceTrivialMerge(merge); } } @@ -219,144 +219,4 @@ } return v; } - - private static ValueProxyNode findProxy(ValueNode value, BeginNode proxyPoint) { - for (ValueProxyNode vpn : proxyPoint.proxies()) { - ValueNode v = vpn; - while (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); - if (v == value) { - return vpn; - } - } - } - return null; - } - - public static ValueNode mergeVirtualChain( - StructuredGraph graph, - ValueNode vof, - ValueNode newVof, - PhiNode vPhi, - BeginNode earlyExit, - BeginNode newEarlyExit, - MergeNode merge) { - VirtualObjectNode vObject = virtualObject(vof); - assert virtualObject(newVof) == vObject; - ValueNode[] virtualState = virtualState(vof); - ValueNode[] newVirtualState = virtualState(newVof); - ValueNode chain = vPhi; - for (int i = 0; i < virtualState.length; i++) { - ValueNode value = virtualState[i]; - ValueNode newValue = newVirtualState[i]; - assert value.kind() == newValue.kind(); - if (value != newValue) { - PhiNode valuePhi = graph.add(new PhiNode(value.kind(), merge)); - ValueProxyNode inputProxy = findProxy(value, earlyExit); - if (inputProxy != null) { - ValueProxyNode newInputProxy = findProxy(newValue, newEarlyExit); - assert newInputProxy != null : "no proxy for " + newValue + " at " + newEarlyExit; - valuePhi.addInput(inputProxy); - valuePhi.addInput(newInputProxy); - } else { - valuePhi.addInput(graph.unique(new ValueProxyNode(value, earlyExit, PhiType.Value))); - valuePhi.addInput(newValue); - } - chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i)); - } - } - return chain; - } - - public static ValueNode mergeVirtualChain( - StructuredGraph graph, - PhiNode vPhi, - MergeNode merge) { - NodeInputList virtuals = vPhi.values(); - VirtualObjectNode vObject = virtualObject(unProxify(virtuals.first())); - List virtualStates = new ArrayList<>(virtuals.size()); - for (ValueNode virtual : virtuals) { - virtualStates.add(virtualState(unProxify(virtual))); - } - ValueNode chain = vPhi; - int stateLength = virtualStates.get(0).length; - for (int i = 0; i < stateLength; i++) { - ValueNode v = null; - boolean reconcile = false; - for (ValueNode[] state : virtualStates) { - if (v == null) { - v = state[i]; - } else if (v != state[i]) { - reconcile = true; - break; - } - assert v.kind() == state[i].kind(); - } - if (reconcile) { - PhiNode valuePhi = graph.add(new PhiNode(v.kind(), merge)); - for (ValueNode[] state : virtualStates) { - valuePhi.addInput(state[i]); - } - chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i)); - } - } - return chain; - } - - /** - * Returns the VirtualObjectNode associated with the virtual chain of the provided virtual node. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @return the VirtualObjectNode associated with the virtual chain of the provided virtual node. - */ - public static VirtualObjectNode virtualObject(ValueNode vof) { - assert vof instanceof VirtualObjectFieldNode || (vof instanceof PhiNode && ((PhiNode) vof).type() == PhiType.Virtual) : vof; - ValueNode currentField = vof; - do { - if (currentField instanceof VirtualObjectFieldNode) { - return ((VirtualObjectFieldNode) currentField).object(); - } else { - assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null); - throw new GraalInternalError("Invalid virtual chain : cound not find virtual object from %s", vof); - } - - /** - * Builds the state of the virtual object at the provided point into a virtual chain. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @return the state of the virtual object at the provided point into a virtual chain. - */ - public static ValueNode[] virtualState(ValueNode vof) { - return virtualState(vof, virtualObject(vof)); - } - - /** - * Builds the state of the virtual object at the provided point into a virtual chain. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @param vObj the virtual object - * @return the state of the virtual object at the provided point into a virtual chain. - */ - public static ValueNode[] virtualState(ValueNode vof, VirtualObjectNode vObj) { - int fieldsCount = vObj.fieldsCount(); - int dicovered = 0; - ValueNode[] state = new ValueNode[fieldsCount]; - ValueNode currentField = vof; - do { - if (currentField instanceof VirtualObjectFieldNode) { - int index = ((VirtualObjectFieldNode) currentField).index(); - if (state[index] == null) { - dicovered++; - state[index] = ((VirtualObjectFieldNode) currentField).input(); - } - currentField = ((VirtualObjectFieldNode) currentField).lastState(); - } else if (currentField instanceof ValueProxyNode) { - currentField = ((ValueProxyNode) currentField).value(); - } else { - assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null && dicovered < fieldsCount); - return state; - } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java Thu Jun 14 18:03:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +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.virtual; - -import java.util.*; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class VirtualObjectFieldNode extends ValueNode implements LIRLowerable { - - @Input private VirtualObjectNode object; - @Input private ValueNode lastState; - @Input private ValueNode input; - - private int index; - - public VirtualObjectNode object() { - return object; - } - - public ValueNode lastState() { - return lastState; - } - - public ValueNode input() { - return input; - } - - public VirtualObjectFieldNode(VirtualObjectNode object, ValueNode lastState, ValueNode input, int index) { - super(StampFactory.virtual()); - this.index = index; - this.object = object; - this.lastState = lastState; - this.input = input; - } - - public int index() { - return index; - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nothing to do... - } - - @Override - public boolean verify() { - assertTrue(object != null, "No object"); - assertTrue(input != null, "No input"); - return super.verify(); - } - - @Override - public Map getDebugProperties() { - Map properties = super.getDebugProperties(); - properties.put("index", index); - return properties; - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name && object() != null && object().fields() != null) { - return super.toString(Verbosity.Name) + " " + object().fields()[index].name(); - } else { - return super.toString(verbosity); - } - } -} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Jun 14 18:03:43 2012 +0200 @@ -23,12 +23,11 @@ package com.oracle.graal.nodes.virtual; import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; - -public class VirtualObjectNode extends ValueNode implements LIRLowerable { +public class VirtualObjectNode extends FloatingNode implements LIRLowerable { private ResolvedJavaType type; private EscapeField[] fields; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Thu Jun 14 18:03:43 2012 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 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.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This class encapsulated the virtual state of an escape analyzed object. + */ +public final class VirtualObjectState extends VirtualState implements Node.IterableNodeType, LIRLowerable { + + @Input private VirtualObjectNode object; + @Input private NodeInputList fields; + + public VirtualObjectNode object() { + return object; + } + + public NodeInputList fields() { + return fields; + } + + public VirtualObjectState(VirtualObjectNode object, ValueNode[] fields) { + this.object = object; + assert object.fields().length == fields.length; + this.fields = new NodeInputList<>(this, fields); + } + + @Override + public void generate(LIRGeneratorTool generator) { + // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. + } +} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Thu Jun 14 18:03:43 2012 +0200 @@ -22,20 +22,18 @@ */ package com.oracle.graal.snippets; -import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.cri.*; /** * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. */ public class GraalIntrinsics { - public static void installIntrinsics(ExtendedRiRuntime runtime, TargetDescription target) { + public static void installIntrinsics(SnippetInstaller installer) { if (GraalOptions.Intrinsify) { - Snippets.install(runtime, target, new MathSnippetsX86()); - Snippets.install(runtime, target, new DoubleSnippets()); - Snippets.install(runtime, target, new FloatSnippets()); - Snippets.install(runtime, target, new NodeClassSnippets()); + installer.install(MathSnippetsX86.class); + installer.install(DoubleSnippets.class); + installer.install(FloatSnippets.class); + installer.install(NodeClassSnippets.class); } } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Thu Jun 14 18:03:43 2012 +0200 @@ -0,0 +1,163 @@ +/* + * 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.snippets; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; + +/** + * Provides printf-like debug facility. This should only be used in {@linkplain Snippet snippets}. + */ +public final class Log { + + @SuppressWarnings("unused") + @NodeIntrinsic(RuntimeCallNode.class) + private static void log(@ConstantNodeParameter RuntimeCall logObject, Object object, boolean newline, boolean string) { + throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); + } + + @SuppressWarnings("unused") + @NodeIntrinsic(RuntimeCallNode.class) + private static void log(@ConstantNodeParameter RuntimeCall logPrimitive, int typeChar, long value, boolean newline) { + throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); + } + + public static void print(boolean value) { + log(RuntimeCall.LogPrimitive, Kind.Boolean.typeChar, value ? 1L : 0L, false); + } + + public static void print(byte value) { + log(RuntimeCall.LogPrimitive, Kind.Byte.typeChar, value, false); + } + + public static void print(char value) { + log(RuntimeCall.LogPrimitive, Kind.Char.typeChar, value, false); + } + + public static void print(short value) { + log(RuntimeCall.LogPrimitive, Kind.Short.typeChar, value, false); + } + + public static void print(int value) { + log(RuntimeCall.LogPrimitive, Kind.Int.typeChar, value, false); + } + + public static void print(long value) { + log(RuntimeCall.LogPrimitive, Kind.Long.typeChar, value, false); + } + + public static void print(float value) { + if (Float.isNaN(value)) { + print("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(RuntimeCall.LogPrimitive, Kind.Float.typeChar, Float.floatToRawIntBits(value), false); + } + } + + public static void print(double value) { + if (Double.isNaN(value)) { + print("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(RuntimeCall.LogPrimitive, Kind.Double.typeChar, Double.doubleToRawLongBits(value), false); + } + } + + public static void print(String value) { + log(RuntimeCall.LogObject, value, false, true); + } + + public static void printAddress(Object o) { + log(RuntimeCall.LogObject, o, false, false); + } + + public static void println(boolean value) { + log(RuntimeCall.LogPrimitive, Kind.Boolean.typeChar, value ? 1L : 0L, true); + } + + public static void println(byte value) { + log(RuntimeCall.LogPrimitive, Kind.Byte.typeChar, value, true); + } + + public static void println(char value) { + log(RuntimeCall.LogPrimitive, Kind.Char.typeChar, value, true); + } + + public static void println(short value) { + log(RuntimeCall.LogPrimitive, Kind.Short.typeChar, value, true); + } + + public static void println(int value) { + log(RuntimeCall.LogPrimitive, Kind.Int.typeChar, value, true); + } + + public static void println(long value) { + log(RuntimeCall.LogPrimitive, Kind.Long.typeChar, value, true); + } + + public static void println(float value) { + if (Float.isNaN(value)) { + println("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(RuntimeCall.LogPrimitive, Kind.Float.typeChar, Float.floatToRawIntBits(value), true); + } + } + + public static void println(double value) { + if (Double.isNaN(value)) { + println("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(RuntimeCall.LogPrimitive, Kind.Double.typeChar, Double.doubleToRawLongBits(value), true); + } + } + + public static void println(String value) { + log(RuntimeCall.LogObject, value, true, true); + } + + public static void printlnAddress(Object o) { + log(RuntimeCall.LogObject, o, true, false); + } + + public static void println() { + println(""); + } +} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java Thu Jun 14 18:03:43 2012 +0200 @@ -61,7 +61,7 @@ if (abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.SIN); } else { - return RuntimeCallNode.performCall(RuntimeCall.ArithmeticSin, x); + return RuntimeCallNode.callDouble(RuntimeCall.ArithmeticSin, x); } } @@ -69,7 +69,7 @@ if (abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.COS); } else { - return RuntimeCallNode.performCall(RuntimeCall.ArithmeticCos, x); + return RuntimeCallNode.callDouble(RuntimeCall.ArithmeticCos, x); } } @@ -77,7 +77,7 @@ if (abs(x) < PI_4) { return MathIntrinsicNode.compute(x, Operation.TAN); } else { - return RuntimeCallNode.performCall(RuntimeCall.ArithmeticTan, x); + return RuntimeCallNode.callDouble(RuntimeCall.ArithmeticTan, x); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Thu Jun 14 18:03:43 2012 +0200 @@ -25,6 +25,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.snippets.nodes.*; @@ -41,6 +42,50 @@ public @interface Snippet { /** + * Specifies the class defining the inlining policy for this snippet. + * A {@linkplain InliningPolicy#Default default} policy is used if none is supplied. + */ + Class inlining() default InliningPolicy.class; + + /** + * Guides inlining decisions used when installing a snippet. + */ + public interface InliningPolicy { + /** + * Determines if {@code method} should be inlined into {@code caller}. + */ + boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); + + /** + * The default inlining policy which inlines everything except for + * constructors of {@link Throwable} classes. + */ + InliningPolicy Default = new InliningPolicy() { + public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { + if (Throwable.class.isAssignableFrom(method.holder().toJava())) { + if (method.name().equals("")) { + return false; + } + } + return true; + } + }; + } + + /** + * Annotates a method replaced by a compile-time constant. + * A (resolved) call to the annotated method is replaced + * with a constant obtained by calling the annotated method via reflection. + * + * All arguments to such a method (including the receiver if applicable) + * must be compile-time constants. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public static @interface Fold { + } + + /** * Denotes a snippet parameter that will be bound during snippet * template {@linkplain SnippetTemplate#instantiate instantiation}. */ diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Thu Jun 14 18:03:43 2012 +0200 @@ -0,0 +1,195 @@ +/* + * 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.snippets; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.util.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.debug.*; +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.snippets.Snippet.InliningPolicy; + +/** + * Utility for snippet {@linkplain #install(Class) installation}. + */ +public class SnippetInstaller { + + private final ExtendedRiRuntime runtime; + private final TargetDescription target; + private final BoxingMethodPool pool; + + /** + * A graph cache used by this installer to avoid using the compiler + * storage for each method processed during snippet installation. + * Without this, all processed methods are to be determined as + * {@linkplain IntrinsificationPhase#canIntrinsify intrinsifiable}. + */ + private final Map graphCache; + + public SnippetInstaller(ExtendedRiRuntime runtime, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.pool = new BoxingMethodPool(runtime); + this.graphCache = new HashMap<>(); + } + + /** + * Finds all the snippet methods in a given class, builds a graph for them and + * installs the graph with the key value of {@code Graph.class} in the + * {@linkplain ResolvedJavaMethod#compilerStorage() compiler storage} of each method. + *

+ * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all + * methods in the class are snippets. Otherwise, the snippets are those methods + * annotated with {@link Snippet}. + */ + public void install(Class snippetsHolder) { + if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) { + installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value()); + } else { + installSnippets(snippetsHolder); + } + } + + private void installSnippets(Class< ? extends SnippetsInterface> clazz) { + for (Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method); + assert snippet.compilerStorage().get(Graph.class) == null; + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + snippet.compilerStorage().put(Graph.class, graph); + } + } + } + + private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class originalClazz) { + for (Method method : clazz.getDeclaredMethods()) { + try { + Method originalMethod = originalClazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) { + throw new RuntimeException("Snippet has incompatible return type"); + } + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + runtime.getResolvedJavaMethod(originalMethod).compilerStorage().put(Graph.class, graph); + } catch (NoSuchMethodException e) { + throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e); + } + } + } + + private static InliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class policyClass = InliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == InliningPolicy.class) { + return InliningPolicy.Default; + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + private StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { + StructuredGraph graph = graphCache.get(method); + if (graph == null) { + graph = buildGraph(method, policy); + //System.out.println("built " + graph); + graphCache.put(method, graph); + } + return graph; + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { + final StructuredGraph graph = new StructuredGraph(method); + return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable() { + @Override + public StructuredGraph call() throws Exception { + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", method.name(), GraphBuilderPhase.class.getSimpleName()); + + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.callTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = makeGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(target).apply(graph); + new CanonicalizerPhase(target, runtime, null).apply(graph); + } + } + } + + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); + + new WordTypeRewriterPhase(target).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, null).apply(graph); + } + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + new InsertStateAfterPlaceholderPhase().apply(graph); + + Debug.dump(graph, "%s: Final", method.name()); + + return graph; + } + }); + } +} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Thu Jun 14 18:03:43 2012 +0200 @@ -0,0 +1,353 @@ +/* + * 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.snippets; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.phases.*; +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.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.snippets.Snippet.Fold; + +public class SnippetIntrinsificationPhase extends Phase { + + private final CodeCacheProvider runtime; + private final BoxingMethodPool pool; + + public SnippetIntrinsificationPhase(CodeCacheProvider runtime, BoxingMethodPool pool) { + this.runtime = runtime; + this.pool = pool; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + tryIntrinsify(i); + } + } + + private void tryIntrinsify(Invoke invoke) { + ResolvedJavaMethod target = invoke.callTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + if (intrinsic != null) { + assert target.getAnnotation(Fold.class) == null; + + Class< ? >[] parameterTypes = CodeUtil.signatureToTypes(target.signature(), target.holder()); + + // Prepare the arguments for the reflective constructor call on the node class. + Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); + + // Create the new node instance. + Class< ? > c = getNodeClass(target, intrinsic); + Node newInstance = createNodeInstance(c, parameterTypes, nodeConstructorArguments); + + // Replace the invoke with the new node. + invoke.node().graph().add(newInstance); + invoke.intrinsify(newInstance); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(newInstance); + } else if (target.getAnnotation(Fold.class) != null) { + Class< ? >[] parameterTypes = CodeUtil.signatureToTypes(target.signature(), target.holder()); + + // Prepare the arguments for the reflective method call + Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); + Object receiver = null; + if (!invoke.callTarget().isStatic()) { + receiver = arguments[0]; + arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); + } + + // Call the method + Constant constant = callMethod(target.signature().returnKind(), target.holder().toJava(), target.name(), parameterTypes, receiver, arguments); + + if (constant != null) { + // Replace the invoke with the result of the call + ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); + invoke.intrinsify(node); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(node); + } else { + // Remove the invoke + invoke.intrinsify(null); + } + } + } + + /** + * Converts the arguments of an invoke node to object values suitable for use as the arguments + * to a reflective invocation of a Java constructor or method. + * + * @param folding specifies if the invocation is for handling a {@link Fold} annotation + */ + private Object[] prepareArguments(Invoke invoke, Class< ? >[] parameterTypes, ResolvedJavaMethod target, boolean folding) { + NodeInputList arguments = invoke.callTarget().arguments(); + Object[] reflectionCallArguments = new Object[arguments.size()]; + for (int i = 0; i < reflectionCallArguments.length; ++i) { + int parameterIndex = i; + if (!invoke.callTarget().isStatic()) { + parameterIndex--; + } + ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); + if (folding || CodeUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { + assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.callTarget().targetMethod() + ": " + argument; + ConstantNode constantNode = (ConstantNode) argument; + Constant constant = constantNode.asConstant(); + Object o = constant.boxedValue(); + if (o instanceof Class< ? >) { + reflectionCallArguments[i] = runtime.getResolvedJavaType((Class< ? >) o); + parameterTypes[i] = ResolvedJavaType.class; + } else { + if (parameterTypes[i] == boolean.class) { + reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); + } else if (parameterTypes[i] == byte.class) { + reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); + } else if (parameterTypes[i] == short.class) { + reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); + } else if (parameterTypes[i] == char.class) { + reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); + } else { + reflectionCallArguments[i] = o; + } + } + } else { + reflectionCallArguments[i] = argument; + parameterTypes[i] = ValueNode.class; + } + } + return reflectionCallArguments; + } + + private static Class< ? > getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { + Class< ? > result = intrinsic.value(); + if (result == NodeIntrinsic.class) { + result = target.holder().toJava(); + } + assert Node.class.isAssignableFrom(result); + 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().size() == 2) { + if (node instanceof Invoke) { + Invoke invokeNode = (Invoke) node; + MethodCallTargetNode callTarget = invokeNode.callTarget(); + if (pool.isBoxingMethod(callTarget.targetMethod())) { + FrameState stateAfter = invokeNode.stateAfter(); + assert stateAfter.usages().size() == 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.NORMAL_EDGE); + } 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; + } + + if (Boolean.TYPE == type) { + return Boolean.class; + } + if (Character.TYPE == type) { + return Character.class; + } + if (Byte.TYPE == type) { + return Byte.class; + } + if (Short.TYPE == type) { + return Short.class; + } + if (Integer.TYPE == type) { + return Integer.class; + } + if (Long.TYPE == type) { + return Long.class; + } + if (Float.TYPE == type) { + return Float.class; + } + assert Double.TYPE == type; + return Double.class; + } + + static final int VARARGS = 0x00000080; + + private static Node createNodeInstance(Class< ? > nodeClass, Class< ? >[] parameterTypes, Object[] nodeConstructorArguments) { + Object[] arguments = null; + Constructor< ? > constructor = null; + nextConstructor: + for (Constructor c : nodeClass.getDeclaredConstructors()) { + Class[] signature = c.getParameterTypes(); + if ((c.getModifiers() & VARARGS) != 0) { + int fixedArgs = signature.length - 1; + if (parameterTypes.length < fixedArgs) { + continue nextConstructor; + } + + for (int i = 0; i < fixedArgs; i++) { + if (!parameterTypes[i].equals(signature[i])) { + continue nextConstructor; + } + } + + Class componentType = signature[fixedArgs].getComponentType(); + assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; + Class boxedType = asBoxedType(componentType); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + if (!boxedType.isInstance(nodeConstructorArguments[i])) { + continue nextConstructor; + } + } + + arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); + int varargsLength = nodeConstructorArguments.length - fixedArgs; + Object varargs = Array.newInstance(componentType, varargsLength); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); + } + arguments[fixedArgs] = varargs; + constructor = c; + break; + } else if (Arrays.equals(parameterTypes, signature)) { + arguments = nodeConstructorArguments; + constructor = c; + break; + } + } + if (constructor == null) { + throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); + } + constructor.setAccessible(true); + try { + return (ValueNode) constructor.newInstance(arguments); + } catch (Exception e) { + throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); + } + } + + /** + * Calls a Java method via reflection. + */ + private static Constant callMethod(Kind returnKind, Class< ? > holder, String name, Class< ? >[] parameterTypes, Object receiver, Object[] arguments) { + Method method; + try { + method = holder.getDeclaredMethod(name, parameterTypes); + method.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Object result = method.invoke(receiver, arguments); + if (result == null) { + return null; + } + return Constant.forBoxed(returnKind, result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String sourceLocation(Node n) { + String loc = GraphUtil.approxSourceLocation(n); + return loc == null ? "" : loc; + } + + public void cleanUpReturnCheckCast(Node newInstance) { + if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != Kind.Object) { + StructuredGraph graph = (StructuredGraph) newInstance.graph(); + for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { + for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) { + graph.replaceFloating(vpn, checkCastNode); + } + for (Node checkCastUsage : checkCastNode.usages().snapshot()) { + if (checkCastUsage instanceof ValueAnchorNode) { + ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; + graph.removeFixed(valueAnchorNode); + } else if (checkCastUsage instanceof MethodCallTargetNode) { + MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; + assert pool.isUnboxingMethod(checkCastCallTarget.targetMethod()) : + "checkcast at " + sourceLocation(checkCastNode) + " not used by an unboxing method but by a call at " + + sourceLocation(checkCastCallTarget.usages().first()) + " to " + 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.NORMAL_EDGE); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + checkCastCallTarget.safeDelete(); + } else if (checkCastUsage instanceof FrameState) { + checkCastUsage.replaceFirstInput(checkCastNode, null); + } else { + assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); + } + } + FixedNode next = checkCastNode.next(); + checkCastNode.setNext(null); + checkCastNode.replaceAtPredecessor(next); + GraphUtil.killCFG(checkCastNode); + } + } + } +} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Thu Jun 14 18:03:43 2012 +0200 @@ -68,10 +68,12 @@ } public Key add(String name, Object value) { - assert value != null; assert !map.containsKey(name); map.put(name, value); - hash = hash ^ name.hashCode() * (value.hashCode() + 1); + hash = hash ^ name.hashCode(); + if (value != null) { + hash *= (value.hashCode() + 1); + } return this; } @@ -194,10 +196,9 @@ if (c != null) { String name = c.value(); Object arg = key.get(name); - assert arg != null : method + ": requires a constant named " + name; Kind kind = signature.argumentKindAt(i); assert checkConstantArgument(method, signature, i, name, arg, kind); - replacements.put(snippetGraph.getLocal(i), ConstantNode.forCiConstant(Constant.forBoxed(kind, arg), runtime, snippetCopy)); + replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(Constant.forBoxed(kind, arg), runtime, snippetCopy)); } else { Parameter p = CodeUtil.getParameterAnnotation(Parameter.class, i, method); assert p != null : method + ": parameter " + i + " must be annotated with either @Constant or @Parameter"; @@ -327,11 +328,11 @@ private static boolean checkConstantArgument(final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { if (kind.isObject()) { Class type = signature.argumentTypeAt(i, method.holder()).resolve(method.holder()).toJava(); - assert type.isInstance(arg) : + assert arg == null || type.isInstance(arg) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); } else { - assert kind.toBoxedJavaClass() == arg.getClass() : - method + ": wrong value kind for " + name + ": expected " + kind + ", got " + arg.getClass().getSimpleName(); + assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : + method + ": wrong value kind for " + name + ": expected " + kind + ", got " + (arg == null ? "null" : arg.getClass().getSimpleName()); } return true; } @@ -386,7 +387,7 @@ } else { Kind kind = ((LocalNode) parameter).kind(); Constant constant = Constant.forBoxed(kind, argument); - replacements.put((LocalNode) parameter, ConstantNode.forCiConstant(constant, runtime, replaceeGraph)); + replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); } } else { assert parameter instanceof LocalNode[]; @@ -399,7 +400,7 @@ LocalNode local = locals[j]; assert local != null; Constant constant = Constant.forBoxed(local.kind(), Array.get(array, j)); - ConstantNode element = ConstantNode.forCiConstant(constant, runtime, replaceeGraph); + ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); replacements.put(local, element); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Thu Jun 14 18:03:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +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.snippets; - -import java.lang.reflect.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.cri.*; -import com.oracle.graal.debug.*; -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.*; - -/** - * Utilities for snippet installation and management. - */ -public class Snippets { - - public static void install(ExtendedRiRuntime runtime, TargetDescription target, SnippetsInterface obj) { - Class clazz = obj.getClass(); - BoxingMethodPool pool = new BoxingMethodPool(runtime); - if (clazz.isAnnotationPresent(ClassSubstitution.class)) { - installSubstitution(runtime, target, clazz, pool, clazz.getAnnotation(ClassSubstitution.class).value()); - } else { - installSnippets(runtime, target, clazz, pool); - } - } - - private static void installSnippets(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) { - for (Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - Method snippet = method; - int modifiers = snippet.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet); - if (snippetRiMethod.compilerStorage().get(Graph.class) == null) { - buildSnippetGraph(snippetRiMethod, runtime, target, pool); - } - } - } - } - - private static void installSubstitution(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz, - BoxingMethodPool pool, Class original) throws GraalInternalError { - for (Method snippet : clazz.getDeclaredMethods()) { - try { - Method method = original.getDeclaredMethod(snippet.getName(), snippet.getParameterTypes()); - if (!method.getReturnType().isAssignableFrom(snippet.getReturnType())) { - throw new RuntimeException("Snippet has incompatible return type"); - } - int modifiers = snippet.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet); - StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool); - runtime.getResolvedJavaMethod(method).compilerStorage().put(Graph.class, graph); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Could not resolve method to substitute with: " + snippet.getName(), e); - } - } - } - - private static StructuredGraph buildSnippetGraph(final ResolvedJavaMethod snippetRiMethod, final ExtendedRiRuntime runtime, final TargetDescription target, final BoxingMethodPool pool) { - final StructuredGraph graph = new StructuredGraph(snippetRiMethod); - return Debug.scope("BuildSnippetGraph", new Object[] {snippetRiMethod, graph}, new Callable() { - @Override - public StructuredGraph call() throws Exception { - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", snippetRiMethod.name(), GraphBuilderPhase.class.getSimpleName()); - - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.callTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - ResolvedJavaType holder = targetMethod.holder(); - if (enclosedInSnippetsClass(holder)) { - StructuredGraph targetGraph = (StructuredGraph) targetMethod.compilerStorage().get(Graph.class); - if (targetGraph == null) { - targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool); - } - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", targetMethod); - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(target).apply(graph); - new CanonicalizerPhase(target, runtime, null).apply(graph); - } - } - } - - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - new WordTypeRewriterPhase(target).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, null).apply(graph); - } - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - new InsertStateAfterPlaceholderPhase().apply(graph); - - Debug.dump(graph, "%s: Final", snippetRiMethod.name()); - - snippetRiMethod.compilerStorage().put(Graph.class, graph); - - return graph; - } - - private boolean enclosedInSnippetsClass(ResolvedJavaType holder) { - Class enclosingClass = holder.toJava(); - while (enclosingClass != null) { - if (SnippetsInterface.class.isAssignableFrom(enclosingClass)) { - return true; - } - enclosingClass = enclosingClass.getEnclosingClass(); - } - return false; - } - }); - - } -} diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java Thu Jun 14 18:03:43 2012 +0200 @@ -147,6 +147,10 @@ private static int compilationId = 0; + protected void assertEquals(Object expected, Object actual) { + Assert.assertEquals(expected, actual); + } + protected void test(String name, Object... args) { Method method = getMethod(name); Object expect = null; @@ -171,7 +175,7 @@ } } else { Object actual = compiledMethod.executeVarargs(args); - Assert.assertEquals(expect, actual); + assertEquals(expect, actual); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Thu Jun 14 18:03:43 2012 +0200 @@ -40,7 +40,7 @@ Block aBlock = nodeToBlock.get(a); if (bBlock == aBlock) { - List instructions = ibp.nodesFor(bBlock); + List instructions = ibp.nodesFor(bBlock); Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a)); } else { Block block = bBlock; diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NewInstanceTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NewInstanceTest.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NewInstanceTest.java Thu Jun 14 18:03:43 2012 +0200 @@ -26,25 +26,35 @@ import org.junit.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; - /** * Tests the implementation of {@code NEW}. */ -public class NewInstanceTest extends TypeCheckTest { +public class NewInstanceTest extends GraalCompilerTest { @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); } @Test public void test1() { + test("newObject"); + test("newBigObject"); test("newEmptyString"); test("newString", "value"); test("newHashMap", 31); } + public static Object newObject() { + return new Object(); + } + + public static BigObject newBigObject() { + return new BigObject(); + } + public static String newEmptyString() { return new String(); } @@ -56,4 +66,51 @@ public static HashMap newHashMap(int initialCapacity) { return new HashMap(initialCapacity); } + + static class BigObject { + Object f01; + Object f02; + Object f03; + Object f04; + Object f05; + Object f06; + Object f07; + Object f08; + Object f09; + Object f10; + Object f12; + Object f13; + Object f14; + Object f15; + Object f16; + Object f17; + Object f18; + Object f19; + Object f20; + Object f21; + Object f22; + Object f23; + Object f24; + Object f25; + Object f26; + Object f27; + Object f28; + Object f29; + Object f30; + Object f31; + Object f32; + Object f33; + Object f34; + Object f35; + Object f36; + Object f37; + Object f38; + Object f39; + Object f40; + Object f41; + Object f42; + Object f43; + Object f44; + Object f45; + } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Thu Jun 14 18:03:43 2012 +0200 @@ -160,17 +160,14 @@ } private void test(final String snippet, final String referenceSnippet) { - Debug.scope("ScalarTypeSystemTest", new DebugDumpScope(snippet), new Runnable() { - public void run() { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); -// TypeSystemTest.outputGraph(graph); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - new CheckCastEliminationPhase().apply(graph); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - StructuredGraph referenceGraph = parse(referenceSnippet); - assertEquals(referenceGraph, graph); - } - }); + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); +// TypeSystemTest.outputGraph(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + new CheckCastEliminationPhase().apply(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + StructuredGraph referenceGraph = parse(referenceSnippet); + assertEquals(referenceGraph, graph); } } diff -r e1b29c516354 -r 65bf69eb147c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Thu Jun 14 18:03:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Thu Jun 14 18:03:43 2012 +0200 @@ -85,14 +85,11 @@ } private void test(final String snippet) { - Debug.scope("StraighteningTest", new DebugDumpScope(snippet), new Runnable() { - public void run() { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); - assertEquals(referenceGraph, graph); - } - }); + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); + assertEquals(referenceGraph, graph); } } diff -r e1b29c516354 -r 65bf69eb147c mx/commands.py --- a/mx/commands.py Thu Jun 14 18:03:18 2012 +0200 +++ b/mx/commands.py Thu Jun 14 18:03:43 2012 +0200 @@ -338,6 +338,11 @@ for line in lines: f.write(line) + # Install a copy of the disassembler library + try: + hsdis([], copyToDir=_vmLibDirInJdk(jdk)) + except SystemExit: + pass else: if not exists(jdk): mx.abort('The ' + build + ' VM has not been created - run \'mx clean; mx build ' + build + '\'') @@ -553,11 +558,12 @@ vm = _vm build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' + jdk = _jdk(build) mx.expand_project_in_args(args) if _make_eclipse_launch: mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True)) if len([a for a in args if 'PrintAssembly' in a]) != 0: - hsdis([]) + hsdis([], copyToDir=_vmLibDirInJdk(jdk)) if mx.java().debug_port is not None: args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args if _jacoco == 'on' or _jacoco == 'append': @@ -573,7 +579,7 @@ 'excludes' : ':'.join(excludes) } args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args - exe = join(_jdk(build), 'bin', mx.exe_suffix('java')) + exe = join(jdk, 'bin', mx.exe_suffix('java')) return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) def _find_classes_with_annotations(classes, p, pkgRoot, annotations, includeInnerClasses=False): @@ -967,19 +973,20 @@ vm = _vm; sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs) -def hsdis(args): - """install the hsdis library +def hsdis(args, copyToDir=None): + """downloads the hsdis library This is needed to support HotSpot's assembly dumping features. - By default it installs the Intel syntax version, use the 'att' argument to install AT&T syntax.""" + By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax.""" flavor = 'intel' if 'att' in args: flavor = 'att' - build = _vmbuild if _vmSourcesAvailable else 'product' lib = mx.lib_suffix('hsdis-amd64') - path = join(_vmLibDirInJdk(_jdk(build)), lib) + path = join(_graal_home, 'lib', lib) if not exists(path): mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib]) + if copyToDir is not None and exists(copyToDir): + shutil.copy(path, copyToDir) def hcfdis(args): """disassembles HexCodeFiles embedded in text files diff -r e1b29c516354 -r 65bf69eb147c mxtool/mx.py --- a/mxtool/mx.py Thu Jun 14 18:03:18 2012 +0200 +++ b/mxtool/mx.py Thu Jun 14 18:03:43 2012 +0200 @@ -172,6 +172,13 @@ self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance is not None else None self.native = False self.dir = dir + + # Create directories for projects that don't yet exist + if not exists(dir): + os.mkdir(dir) + for s in self.source_dirs(): + if not exists(s): + os.mkdir(s) def all_deps(self, deps, includeLibs, includeSelf=True): """ diff -r e1b29c516354 -r 65bf69eb147c src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Jun 14 18:03:43 2012 +0200 @@ -990,37 +990,6 @@ return oop_maps; } -#ifdef GRAAL -JRT_ENTRY(void, graal_create_null_exception(JavaThread* thread)) - thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); -JRT_END - -JRT_ENTRY(void, graal_create_out_of_bounds_exception(JavaThread* thread, jint index)) - char message[jintAsStringSize]; - sprintf(message, "%d", index); - thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message)()); -JRT_END - -JRT_ENTRY(void, graal_generic_callback(JavaThread* thread, oop _callback, oop _argument)) - HandleMark hm; - Handle callback(_callback); - Handle argument(_argument); - - KlassHandle klass = SystemDictionary::resolve_or_null(vmSymbols::com_oracle_graal_api_code_GenericCallback(), SystemDictionary::java_system_loader(), NULL, thread); - if (klass.is_null()) { - tty->print_cr("couldn't resolve com_oracle_graal_api_code_GenericCallback"); - } - - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(Handle(callback)); - args.push_oop(Handle(argument)); - JavaCalls::call_virtual(&result, klass, vmSymbols::callbackInternal_name(), vmSymbols::callback_signature(), &args, thread); - - thread->set_vm_result((oop) result.get_jobject()); -JRT_END -#endif - OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // for better readability @@ -1916,6 +1885,30 @@ break; } + case graal_log_primitive_id: { + __ enter(); + oop_maps = new OopMapSet(); + OopMap* oop_map = save_live_registers(sasm, 0); + int call_offset = __ call_RT(noreg, noreg, (address)graal_log_primitive, j_rarg0, j_rarg1, j_rarg2); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + __ leave(); + __ ret(0); + break; + } + + case graal_log_object_id: { + __ enter(); + oop_maps = new OopMapSet(); + OopMap* oop_map = save_live_registers(sasm, 0); + int call_offset = __ call_RT(noreg, noreg, (address)graal_log_object, j_rarg0, j_rarg1, j_rarg2); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + __ leave(); + __ ret(0); + break; + } + case graal_generic_callback_id: { __ enter(); oop_maps = new OopMapSet(); diff -r e1b29c516354 -r 65bf69eb147c src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Thu Jun 14 18:03:43 2012 +0200 @@ -648,6 +648,36 @@ JRT_END #ifdef GRAAL + +JRT_ENTRY(void, Runtime1::graal_create_null_exception(JavaThread* thread)) + thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); +JRT_END + +JRT_ENTRY(void, Runtime1::graal_create_out_of_bounds_exception(JavaThread* thread, jint index)) + char message[jintAsStringSize]; + sprintf(message, "%d", index); + thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message)()); +JRT_END + +JRT_ENTRY(void, Runtime1::graal_generic_callback(JavaThread* thread, oop _callback, oop _argument)) + HandleMark hm; + Handle callback(_callback); + Handle argument(_argument); + + KlassHandle klass = SystemDictionary::resolve_or_null(vmSymbols::com_oracle_graal_api_code_GenericCallback(), SystemDictionary::java_system_loader(), NULL, thread); + if (klass.is_null()) { + tty->print_cr("couldn't resolve com_oracle_graal_api_code_GenericCallback"); + } + + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(Handle(callback)); + args.push_oop(Handle(argument)); + JavaCalls::call_virtual(&result, klass, vmSymbols::callbackInternal_name(), vmSymbols::callback_signature(), &args, thread); + + thread->set_vm_result((oop) result.get_jobject()); +JRT_END + JRT_ENTRY_NO_ASYNC(void, Runtime1::graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) NOT_PRODUCT(_monitorenter_slowcase_cnt++;) #ifdef ASSERT @@ -708,7 +738,72 @@ } JRT_END -#endif +JRT_ENTRY(void, Runtime1::graal_log_object(JavaThread* thread, oop obj, jboolean newline, jboolean string)) + if (!string) { + tty->print("%p", obj); + } else { + assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); + + typeArrayOop value = java_lang_String::value(obj); + int offset = java_lang_String::offset(obj); + int length = java_lang_String::length(obj); + + if (length != 0) { + int printLength = MIN2(length, 1024); + if (value == NULL) { + // This can happen if, e.g., printing a String + // object before its initializer has been called + tty->print("null"); + } else if (printLength < 256 - 1) { + // Use an intermediate buffer to try and prevent interlacing of multi-threaded output + char buf[256]; + for (int index = 0; index < printLength; index++) { + buf[index] = value->char_at(index + offset); + } + buf[printLength] = 0; + tty->print("%s", buf); + if (printLength < length) { + tty->print("... (%d more)", length - printLength); + } + } else { + for (int index = 0; index < printLength; index++) { + tty->print("%c", value->char_at(index + offset)); + } + if (printLength < length) { + tty->print("... (%d more)", length - printLength); + } + } + } + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(void, Runtime1::graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) + union { + jlong l; + jdouble d; + jfloat f; + } uu; + uu.l = value; + switch (typeChar) { + case 'z': tty->print(value == 0 ? "false" : "true"); break; + case 'b': tty->print("%d", (jbyte) value); break; + case 'c': tty->print("%c", (jchar) value); break; + case 's': tty->print("%d", (jshort) value); break; + case 'i': tty->print("%d", (jint) value); break; + case 'f': tty->print("%f", uu.f); break; + case 'j': tty->print(INT64_FORMAT, value); break; + case 'd': tty->print("%lf", uu.d); break; + default: assert(false, "unknown typeChar"); break; + } + if (newline) { + tty->cr(); + } +JRT_END + +#endif /* GRAAL */ JRT_ENTRY_NO_ASYNC(void, Runtime1::monitorenter(JavaThread* thread, oopDesc* obj, BasicObjectLock* lock)) diff -r e1b29c516354 -r 65bf69eb147c src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.hpp Thu Jun 14 18:03:43 2012 +0200 @@ -81,6 +81,8 @@ stub(graal_create_null_pointer_exception) \ stub(graal_create_out_of_bounds_exception) \ stub(graal_generic_callback) \ + stub(graal_log_object) \ + stub(graal_log_primitive) \ last_entry(number_of_ids) #else #define RUNTIME1_STUBS(stub, last_entry) \ @@ -199,8 +201,13 @@ static void monitorenter(JavaThread* thread, oopDesc* obj, BasicObjectLock* lock); static void monitorexit (JavaThread* thread, BasicObjectLock* lock); #ifdef GRAAL + static void graal_create_null_exception(JavaThread* thread); + static void graal_create_out_of_bounds_exception(JavaThread* thread, jint index); + static void graal_generic_callback(JavaThread* thread, oop _callback, oop _argument); static void graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); static void graal_monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); + static void graal_log_object(JavaThread* thread, oop msg, jboolean newline, jboolean string); #endif static void deoptimize(JavaThread* thread); diff -r e1b29c516354 -r 65bf69eb147c src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Thu Jun 14 18:03:43 2012 +0200 @@ -581,6 +581,12 @@ } else if (runtime_call == RuntimeCall::GenericCallback()) { target_addr = Runtime1::entry_for(Runtime1::graal_generic_callback_id); TRACE_graal_3("RuntimeCall::GenericCallback()"); + } else if (runtime_call == RuntimeCall::LogPrimitive()) { + target_addr = Runtime1::entry_for(Runtime1::graal_log_primitive_id); + TRACE_graal_3("RuntimeCall::LogPrimitive()"); + } else if (runtime_call == RuntimeCall::LogObject()) { + target_addr = Runtime1::entry_for(Runtime1::graal_log_object_id); + TRACE_graal_3("RuntimeCall::LogObject()"); } else { runtime_call->print(); fatal("runtime_call not implemented"); @@ -598,7 +604,7 @@ if (target_klass->is_subclass_of(SystemDictionary::Long_klass())) { global_stub = target; - } else if (target_klass->name() == vmSymbols::com_oracle_graal_api_code_RuntimeCall()) { + } else if (target->is_a(RuntimeCall::klass())) { runtime_call = target; } else { hotspot_method = target; diff -r e1b29c516354 -r 65bf69eb147c src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Jun 14 18:03:43 2012 +0200 @@ -785,6 +785,7 @@ set_boolean(env, config, "useFastLocking", UseFastLocking); set_boolean(env, config, "useFastNewObjectArray", UseFastNewObjectArray); set_boolean(env, config, "useFastNewTypeArray", UseFastNewTypeArray); + set_boolean(env, config, "useTLAB", UseTLAB); set_int(env, config, "codeEntryAlignment", CodeEntryAlignment); set_int(env, config, "vmPageSize", os::vm_page_size()); set_int(env, config, "stackShadowPages", StackShadowPages); diff -r e1b29c516354 -r 65bf69eb147c src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Thu Jun 14 18:03:18 2012 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Thu Jun 14 18:03:43 2012 +0200 @@ -203,6 +203,8 @@ static_oop_field(RuntimeCall, ArithmeticSin, "Lcom/oracle/graal/api/code/RuntimeCall;"); \ static_oop_field(RuntimeCall, Deoptimize, "Lcom/oracle/graal/api/code/RuntimeCall;"); \ static_oop_field(RuntimeCall, GenericCallback, "Lcom/oracle/graal/api/code/RuntimeCall;"); \ + static_oop_field(RuntimeCall, LogPrimitive, "Lcom/oracle/graal/api/code/RuntimeCall;"); \ + static_oop_field(RuntimeCall, LogObject, "Lcom/oracle/graal/api/code/RuntimeCall;"); \ end_class \ start_class(JavaMethod) \ end_class \