# HG changeset patch # User Doug Simon # Date 1422913817 -3600 # Node ID cc1020cc05994ad15b617ede1c4d1fb1508e5c72 # Parent 69f2926cd2ab28daffdf245cd8bf7a08ca8d2865# Parent b4056d53623786954b1bb5b6bc304c4bb82eb770 Merge. diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Mon Feb 02 22:50:17 2015 +0100 @@ -29,12 +29,18 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +/** + * Provider of HotSpot specific {@link GraphBuilderPlugin}s. + */ @ServiceProvider(GraphBuilderPluginsProvider.class) public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { plugins.register(metaAccess, ObjectPlugin.class); } + /** + * HotSpot specific plugins for {@link Object}. + */ enum ObjectPlugin implements GraphBuilderPlugin { getClass() { public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { @@ -52,10 +58,5 @@ public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name()); } - - @Override - public String toString() { - return Object.class.getName() + "." + name() + "()"; - } } } diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java Mon Feb 02 22:50:17 2015 +0100 @@ -22,41 +22,31 @@ */ package com.oracle.graal.java; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +/** + * Provider of non-runtime specific {@link GraphBuilderPlugin}s. + */ @ServiceProvider(GraphBuilderPluginsProvider.class) public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { plugins.register(metaAccess, ObjectPlugin.class); + plugins.register(metaAccess, BoxingPlugin.class); } + /** + * Plugins for {@link Object}. + */ enum ObjectPlugin implements GraphBuilderPlugin { init() { public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { - assert args.length == 1; - ValueNode rcvr = args[0]; - ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); - - boolean needsCheck = true; - if (objectStamp.isExactType()) { - needsCheck = objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { - // if either the declared type of receiver or the holder - // can be assumed to have no finalizers - Assumptions assumptions = builder.getAssumptions(); - if (assumptions.useOptimisticAssumptions()) { - assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type()); - needsCheck = false; - } - } - - if (needsCheck) { - builder.append(new RegisterFinalizerNode(rcvr)); + ValueNode object = args[0]; + if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) { + builder.append(new RegisterFinalizerNode(object)); } return true; } @@ -71,4 +61,50 @@ return Object.class.getName() + "." + name() + "()"; } } + + /** + * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends). + */ + enum BoxingPlugin implements GraphBuilderPlugin { + valueOf$Boolean(Kind.Boolean), + booleanValue$Boolean(Kind.Boolean), + valueOf$Byte(Kind.Byte), + byteValue$Byte(Kind.Byte), + valueOf$Short(Kind.Short), + shortValue$Short(Kind.Short), + valueOf$Char(Kind.Char), + charValue$Char(Kind.Char), + valueOf$Int(Kind.Int), + intValue$Int(Kind.Int), + valueOf$Long(Kind.Long), + longValue$Long(Kind.Long), + valueOf$Float(Kind.Float), + floatValue$Float(Kind.Float), + valueOf$Double(Kind.Double), + doubleValue$Double(Kind.Double); + + BoxingPlugin(Kind kind) { + assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$"); + this.kind = kind; + this.box = name().charAt(0) == 'v'; + } + + private final Kind kind; + private final boolean box; + + public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + if (box) { + ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); + builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind))); + } else { + builder.push(kind, builder.append(new UnboxNode(args[0], kind))); + } + return true; + } + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + Class[] parameterTypes = box ? new Class[]{kind.toJavaClass()} : new Class[0]; + return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes); + } + } } diff -r b4056d536237 -r cc1020cc0599 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 Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Feb 02 22:50:17 2015 +0100 @@ -775,9 +775,13 @@ if (graphBuilderPlugins != null) { GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod); if (plugin != null) { + int beforeStackSize = frameState.stackSize; if (plugin.handleInvocation(this, args)) { + // System.out.println("used plugin: " + plugin); + assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize; return; } + assert beforeStackSize == frameState.stackSize; } } diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Mon Feb 02 22:50:17 2015 +0100 @@ -42,14 +42,21 @@ boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args); /** - * Gets the target method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} - * . + * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} . */ ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess); - static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class clazz, String methodName, Class... parameterTypes) { + /** + * Looks up a {@link ResolvedJavaMethod}. + * + * @param methodNameBase the name of the method is the prefix of this value up to the first '$' + * character + */ + static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class declaringClass, String methodNameBase, Class... parameterTypes) { + int index = methodNameBase.indexOf('$'); + String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index); try { - return metaAccess.lookupJavaMethod(methodName.equals("") ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getDeclaredMethod(methodName, parameterTypes)); + return metaAccess.lookupJavaMethod(methodName.equals("") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); } diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Mon Feb 02 22:50:17 2015 +0100 @@ -44,6 +44,7 @@ GraphBuilderPlugin gbp = (GraphBuilderPlugin) o; ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess); GraphBuilderPlugin oldValue = map.put(target, gbp); + // System.out.println("registered: " + gbp); assert oldValue == null; } } diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Mon Feb 02 11:51:06 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Mon Feb 02 22:50:17 2015 +0100 @@ -56,27 +56,31 @@ gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue())); } + /** + * Determines if the compiler should emit code to test whether a given object has a finalizer + * that must be registered with the runtime upon object initialization. + */ + public static boolean mayHaveFinalizer(ValueNode object, Assumptions assumptions) { + ObjectStamp objectStamp = (ObjectStamp) object.stamp(); + if (objectStamp.isExactType()) { + return objectStamp.type().hasFinalizer(); + } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { + // if either the declared type of receiver or the holder + // can be assumed to have no finalizers + if (assumptions.useOptimisticAssumptions()) { + assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type()); + return false; + } + } + return true; + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (!(forValue.stamp() instanceof ObjectStamp)) { return this; } - - ObjectStamp objectStamp = (ObjectStamp) forValue.stamp(); - - boolean needsCheck = true; - if (objectStamp.isExactType()) { - needsCheck = objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { - // if either the declared type of receiver or the holder - // can be assumed to have no finalizers - if (tool.assumptions().useOptimisticAssumptions()) { - tool.assumptions().recordNoFinalizableSubclassAssumption(objectStamp.type()); - needsCheck = false; - } - } - - if (!needsCheck) { + if (!mayHaveFinalizer(forValue, tool.assumptions())) { return null; } diff -r b4056d536237 -r cc1020cc0599 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Mon Feb 02 22:50:17 2015 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.substitutions; + +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.truffle.nodes.frame.*; +import com.oracle.truffle.api.*; + +/** + * Provider of {@link GraphBuilderPlugin}s for Truffle classes. + */ +@ServiceProvider(GraphBuilderPluginsProvider.class) +public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { + public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + plugins.register(metaAccess, CompilerDirectivesPlugin.class); + } + + /** + * Plugins for {@link CompilerDirectives}. + */ + enum CompilerDirectivesPlugin implements GraphBuilderPlugin { + inInterpreter() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(ConstantNode.forBoolean(false)); + return true; + } + }, + inCompiledCode() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(ConstantNode.forBoolean(true)); + return true; + } + }, + transferToInterpreter() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); + return true; + } + }, + transferToInterpreterAndInvalidate() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); + return true; + } + }, + interpreterOnly(Runnable.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + return true; + } + }, + interpreterOnly$(Callable.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + return true; + } + }, + injectBranchProbability(double.class, boolean.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + ValueNode probability = args[0]; + ValueNode condition = args[1]; + builder.append(new BranchProbabilityNode(probability, condition)); + return true; + } + }, + bailout(String.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + // TODO: is this too eager? Should a BailoutNode be created instead? + ValueNode message = args[0]; + if (message.isConstant()) { + throw new BailoutException(message.asConstant().toValueString()); + } + throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)"); + } + }, + + isCompilationConstant(Object.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + ValueNode arg0 = args[0]; + if (arg0 instanceof BoxNode) { + arg0 = ((BoxNode) arg0).getValue(); + } + if (arg0.isConstant()) { + builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true))); + return true; + } + + // Cannot create MacroNodes in a plugin (yet) + return false; + } + }, + materialize(Object.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new ForceMaterializeNode(args[0])); + return true; + } + }; + + CompilerDirectivesPlugin(Class... parameterTypes) { + this.parameterTypes = parameterTypes; + } + + private final Class[] parameterTypes; + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes); + } + } +}