# HG changeset patch # User Christian Wimmer # Date 1432930745 25200 # Node ID 625b2b12b4181db8d3a5a8e1dde5b62609110e82 # Parent 7a7cf422160b041bdbed2026c76c5153c19fd1c4 Cleanup and generalize graph builder plugins diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GenericInvocationPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GenericInvocationPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * 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.graphbuilderconf; - -import com.oracle.jvmci.meta.ResolvedJavaMethod; -import com.oracle.graal.nodes.*; - -/** - * Plugin for handling an invocation based on some property of the method being invoked such as any - * annotations it may have. - */ -public interface GenericInvocationPlugin extends GraphBuilderPlugin { - /** - * Executes this plugin for an invocation of a given method with a given set of arguments. - * - * @return {@code true} if this plugin handled the invocation, {@code false} if not - */ - boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args); -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Fri May 29 13:19:05 2015 -0700 @@ -32,12 +32,9 @@ public static class Plugins { private final InvocationPlugins invocationPlugins; - private LoadFieldPlugin loadFieldPlugin; - private LoadIndexedPlugin loadIndexedPlugin; - private TypeCheckPlugin typeCheckPlugin; + private NodePlugin[] nodePlugins; private ParameterPlugin parameterPlugin; private InlineInvokePlugin inlineInvokePlugin; - private GenericInvocationPlugin genericInvocationPlugin; private LoopExplosionPlugin loopExplosionPlugin; /** @@ -48,12 +45,9 @@ public Plugins(Plugins copyFrom) { this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins); this.parameterPlugin = copyFrom.parameterPlugin; - this.loadFieldPlugin = copyFrom.loadFieldPlugin; - this.loadIndexedPlugin = copyFrom.loadIndexedPlugin; - this.typeCheckPlugin = copyFrom.typeCheckPlugin; + this.nodePlugins = copyFrom.nodePlugins; this.inlineInvokePlugin = copyFrom.inlineInvokePlugin; this.loopExplosionPlugin = copyFrom.loopExplosionPlugin; - this.genericInvocationPlugin = copyFrom.genericInvocationPlugin; } /** @@ -64,42 +58,20 @@ */ public Plugins(InvocationPlugins invocationPlugins) { this.invocationPlugins = invocationPlugins; + this.nodePlugins = new NodePlugin[0]; } public InvocationPlugins getInvocationPlugins() { return invocationPlugins; } - public GenericInvocationPlugin getGenericInvocationPlugin() { - return genericInvocationPlugin; - } - - public void setGenericInvocationPlugin(GenericInvocationPlugin plugin) { - this.genericInvocationPlugin = plugin; - } - - public LoadFieldPlugin getLoadFieldPlugin() { - return loadFieldPlugin; + public NodePlugin[] getNodePlugins() { + return nodePlugins; } - public void setLoadFieldPlugin(LoadFieldPlugin plugin) { - this.loadFieldPlugin = plugin; - } - - public LoadIndexedPlugin getLoadIndexedPlugin() { - return loadIndexedPlugin; - } - - public void setLoadIndexedPlugin(LoadIndexedPlugin plugin) { - this.loadIndexedPlugin = plugin; - } - - public TypeCheckPlugin getTypeCheckPlugin() { - return typeCheckPlugin; - } - - public void setTypeCheckPlugin(TypeCheckPlugin typeCheckPlugin) { - this.typeCheckPlugin = typeCheckPlugin; + public void appendNodePlugin(NodePlugin plugin) { + nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1); + nodePlugins[nodePlugins.length - 1] = plugin; } public ParameterPlugin getParameterPlugin() { diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * 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.graphbuilderconf; - -import com.oracle.jvmci.meta.ConstantReflectionProvider; -import com.oracle.jvmci.meta.JavaConstant; -import com.oracle.jvmci.meta.MetaAccessProvider; -import com.oracle.jvmci.meta.ResolvedJavaField; -import com.oracle.graal.nodes.*; - -public interface LoadFieldPlugin extends GraphBuilderPlugin { - @SuppressWarnings("unused") - default boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { - return false; - } - - @SuppressWarnings("unused") - default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) { - return false; - } - - default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) { - JavaConstant result = constantReflection.readConstantFieldValue(field, receiver); - if (result != null) { - ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess); - b.addPush(field.getKind(), constantNode); - return true; - } - return false; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadIndexedPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadIndexedPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * 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.graphbuilderconf; - -import com.oracle.jvmci.meta.Kind; -import com.oracle.graal.nodes.*; - -public interface LoadIndexedPlugin extends GraphBuilderPlugin { - @SuppressWarnings("unused") - default boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { - return false; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/NodePlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/NodePlugin.java Fri May 29 13:19:05 2015 -0700 @@ -0,0 +1,155 @@ +/* + * 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.graphbuilderconf; + +import com.oracle.jvmci.meta.*; +import com.oracle.graal.nodes.*; + +public interface NodePlugin extends GraphBuilderPlugin { + /** + * Handle the parsing of a method invocation bytecode to a method that can be bound statically. + * If the method returns true, it must {@link GraphBuilderContext#push push} a value as the + * result of the method invocation using the {@link Signature#getReturnKind return kind} of the + * method. + * + * @param b the context + * @param method the statically bound, invoked method + * @param args the arguments of the method invocation + * @return true if the plugin handles the invocation, false otherwise + */ + default boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + return false; + } + + /** + * Handle the parsing of a GETFIELD bytecode. If the method returns true, it must + * {@link GraphBuilderContext#push push} a value using the {@link ResolvedJavaField#getKind() + * kind} of the field. + * + * @param b the context + * @param object the receiver object for the field access + * @param field the accessed field + * @return true if the plugin handles the field access, false otherwise + */ + default boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { + return false; + } + + /** + * Handle the parsing of a GETSTATIC bytecode. If the method returns true, it must + * {@link GraphBuilderContext#push push} a value using the {@link ResolvedJavaField#getKind() + * kind} of the field. + * + * @param b the context + * @param field the accessed field + * @return true if the plugin handles the field access, false otherwise + */ + default boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) { + return false; + } + + /** + * Handle the parsing of a PUTFIELD bytecode. + * + * @param b the context + * @param object the receiver object for the field access + * @param field the accessed field + * @param value the value to be stored into the field + * @return true if the plugin handles the field access, false otherwise + */ + default boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { + return false; + } + + /** + * Handle the parsing of a PUTSTATIC bytecode. + * + * @param b the context + * @param field the accessed field + * @param value the value to be stored into the field + * @return true if the plugin handles the field access, false otherwise. + */ + default boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { + return false; + } + + /** + * Handle the parsing of an array load bytecode. If the method returns true, it must + * {@link GraphBuilderContext#push push} a value using the provided elementKind. + * + * @param b the context + * @param array the accessed array + * @param index the index for the array access + * @param elementKind the element kind of the accessed array + * @return true if the plugin handles the array access, false otherwise. + */ + default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { + return false; + } + + /** + * Handle the parsing of an array store bytecode. + * + * @param b the context + * @param array the accessed array + * @param index the index for the array access + * @param elementKind the element kind of the accessed array + * @param value the value to be stored into the array + * @return true if the plugin handles the array access, false otherwise. + */ + default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind, ValueNode value) { + return false; + } + + /** + * Handle the parsing of a CHECKCAST bytecode. If the method returns true, it must + * {@link GraphBuilderContext#push push} a value with the result of the cast using + * {@link Kind#Object}. + * + * @param b the context + * @param object the object to be type checked + * @param type the type that the object is checked against + * @param profile the profiling information for the type check, or null if no profiling + * information is available + * @return true if the plugin handles the cast, false otherwise + */ + default boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + return false; + } + + /** + * Handle the parsing of a INSTANCEOF bytecode. If the method returns true, it must + * {@link GraphBuilderContext#push push} a value with the result of the instanceof using + * {@link Kind#Int}. + * + * @param b the context + * @param object the object to be type checked + * @param type the type that the object is checked against + * @param profile the profiling information for the type check, or null if no profiling + * information is available + * @return true if the plugin handles the instanceof, false otherwise + */ + default boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + return false; + } +} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/TypeCheckPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/TypeCheckPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * 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.graphbuilderconf; - -import com.oracle.jvmci.meta.ResolvedJavaType; -import com.oracle.jvmci.meta.JavaTypeProfile; -import com.oracle.graal.nodes.*; - -public interface TypeCheckPlugin extends GraphBuilderPlugin { - /** - * Intercept the parsing of a CHECKCAST bytecode. If the method returns true, it must push - * {@link GraphBuilderContext#push push} an object value as the result of the cast. - * - * @param b The context. - * @param object The object to be type checked. - * @param type The type that the object is checked against. - * @param profile The profiling information for the type check, or null if no profiling - * information is available. - * @return True if the plugin handled the cast, false if the bytecode parser should handle the - * cast. - */ - default boolean checkCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { - return false; - } - - /** - * Intercept the parsing of a INSTANCEOF bytecode. If the method returns true, it must push - * {@link GraphBuilderContext#push push} an integer value with the result of the instanceof. - * - * @param b The context. - * @param object The object to be type checked. - * @param type The type that the object is checked against. - * @param profile The profiling information for the type check, or null if no profiling - * information is available. - * @return True if the plugin handled the instanceof, false if the bytecode parser should handle - * the instanceof. - */ - default boolean instanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { - return false; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri May 29 13:19:05 2015 -0700 @@ -73,16 +73,15 @@ InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess); Plugins plugins = new Plugins(invocationPlugins); - NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider); + NodeIntrinsificationPhase nodeIntrinsificationPhase = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider); + NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin(metaAccess, nodeIntrinsificationPhase, wordTypes, false); HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes); + HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(metaAccess, constantReflection, wordOperationPlugin, nodeIntrinsificationPlugin); - plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes)); - plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection)); - plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); - plugins.setTypeCheckPlugin(wordOperationPlugin); + plugins.setParameterPlugin(nodePlugin); + plugins.appendNodePlugin(nodePlugin); + plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess())); plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); - plugins.setGenericInvocationPlugin(new MethodHandleInvocationPlugin(constantReflection.getMethodHandleAccess(), new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, - wordOperationPlugin))); registerObjectPlugins(invocationPlugins); registerClassPlugins(plugins); diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * 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.hotspot.meta; - -import com.oracle.jvmci.meta.ResolvedJavaField; -import com.oracle.jvmci.meta.MetaAccessProvider; -import com.oracle.jvmci.meta.JavaConstant; -import com.oracle.jvmci.meta.ConstantReflectionProvider; -import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.hotspot.meta.HotSpotGraalConstantReflectionProvider.*; - -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.nodes.*; - -public final class HotSpotLoadFieldPlugin implements LoadFieldPlugin { - private final MetaAccessProvider metaAccess; - private final ConstantReflectionProvider constantReflection; - - public HotSpotLoadFieldPlugin(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { - this.metaAccess = metaAccess; - this.constantReflection = constantReflection; - } - - public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { - if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { - if (receiver.isConstant()) { - JavaConstant asJavaConstant = receiver.asJavaConstant(); - return tryReadField(b, field, asJavaConstant); - } - } - return false; - } - - private boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant receiver) { - // FieldReadEnabledInImmutableCode is non null only if assertions are enabled - if (FieldReadEnabledInImmutableCode != null && ImmutableCode.getValue()) { - FieldReadEnabledInImmutableCode.set(Boolean.TRUE); - try { - return tryConstantFold(b, metaAccess, constantReflection, field, receiver); - } finally { - FieldReadEnabledInImmutableCode.set(null); - } - } else { - return tryConstantFold(b, metaAccess, constantReflection, field, receiver); - } - } - - public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) { - if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { - return tryReadField(b, staticField, null); - } - return false; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * 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.hotspot.meta; - -import com.oracle.jvmci.meta.ResolvedJavaType; -import com.oracle.jvmci.meta.Kind; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.nodes.type.*; -import com.oracle.graal.hotspot.word.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; - -public final class HotSpotLoadIndexedPlugin implements LoadIndexedPlugin { - private final HotSpotWordTypes wordTypes; - - public HotSpotLoadIndexedPlugin(HotSpotWordTypes wordTypes) { - this.wordTypes = wordTypes; - } - - public boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { - if (b.parsingIntrinsic()) { - ResolvedJavaType arrayType = StampTool.typeOrNull(array); - /* - * There are cases where the array does not have a known type yet, i.e., the type is - * null. In that case we assume it is not a word type. - */ - if (arrayType != null && wordTypes.isWord(arrayType.getComponentType()) && elementKind != wordTypes.getWordKind()) { - /* - * The elementKind of the node is a final field, and other information such as the - * stamp depends on elementKind. Therefore, just create a new node and replace the - * old one. - */ - Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType()); - if (componentStamp instanceof MetaspacePointerStamp) { - b.addPush(elementKind, new LoadIndexedPointerNode(componentStamp, array, index)); - } else { - b.addPush(elementKind, new LoadIndexedNode(array, index, wordTypes.getWordKind())); - } - return true; - } - } - return false; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNodePlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNodePlugin.java Fri May 29 13:19:05 2015 -0700 @@ -0,0 +1,187 @@ +/* + * 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.hotspot.meta; + +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.hotspot.meta.HotSpotGraalConstantReflectionProvider.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.Node.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; +import com.oracle.jvmci.meta.*; + +/** + * This plugin handles the HotSpot-specific customizations of bytecode parsing: + *

+ * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions + * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that + * we forward the {@link NodePlugin} and {@link ParameterPlugin} methods, but not the + * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not + * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined, + * i.e., there are never non-inlined invokes that involve the {@link Word} type. + *

+ * Handling of {@link Fold} and {@link NodeIntrinsic} annotated methods, by forwarding to the + * {@link NodeIntrinsificationPlugin} when parsing intrinsic functions. + *

+ * Constant folding of field loads. + */ +public final class HotSpotNodePlugin implements NodePlugin, ParameterPlugin { + private final MetaAccessProvider metaAccess; + private final ConstantReflectionProvider constantReflection; + + protected final WordOperationPlugin wordOperationPlugin; + protected final NodeIntrinsificationPlugin nodeIntrinsificationPlugin; + + public HotSpotNodePlugin(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, WordOperationPlugin wordOperationPlugin, + NodeIntrinsificationPlugin nodeIntrinsificationPlugin) { + this.metaAccess = metaAccess; + this.constantReflection = constantReflection; + this.wordOperationPlugin = wordOperationPlugin; + this.nodeIntrinsificationPlugin = nodeIntrinsificationPlugin; + } + + @Override + public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) { + if (b.parsingIntrinsic()) { + return wordOperationPlugin.interceptParameter(b, index, stamp); + } + return null; + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleInvoke(b, method, args)) { + return true; + } + if (b.parsingIntrinsic() && nodeIntrinsificationPlugin.handleInvoke(b, method, args)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { + if (object.isConstant()) { + JavaConstant asJavaConstant = object.asJavaConstant(); + if (tryReadField(b, field, asJavaConstant)) { + return true; + } + } + } + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) { + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { + if (tryReadField(b, field, null)) { + return true; + } + } + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { + return true; + } + return false; + } + + private boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) { + // FieldReadEnabledInImmutableCode is non null only if assertions are enabled + if (FieldReadEnabledInImmutableCode != null && ImmutableCode.getValue()) { + FieldReadEnabledInImmutableCode.set(Boolean.TRUE); + try { + return tryConstantFold(b, field, object); + } finally { + FieldReadEnabledInImmutableCode.set(null); + } + } else { + return tryConstantFold(b, field, object); + } + } + + private boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) { + JavaConstant result = constantReflection.readConstantFieldValue(field, object); + if (result != null) { + ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess, b.getGraph()); + b.push(field.getKind(), constantNode); + return true; + } + return false; + } + + @Override + public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreField(b, object, field, value)) { + return true; + } + return false; + } + + @Override + public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreStaticField(b, field, value)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, elementKind)) { + return true; + } + return false; + } + + @Override + public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, elementKind, value)) { + return true; + } + return false; + } + + @Override + public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleCheckCast(b, object, type, profile)) { + return true; + } + return false; + } + + @Override + public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) { + return true; + } + return false; + } +} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * 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.hotspot.meta; - -import com.oracle.jvmci.meta.ResolvedJavaType; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -public final class HotSpotParameterPlugin implements ParameterPlugin { - private final WordTypes wordTypes; - - public HotSpotParameterPlugin(WordTypes wordTypes) { - this.wordTypes = wordTypes; - } - - public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) { - if (b.parsingIntrinsic()) { - ResolvedJavaType type = StampTool.typeOrNull(stamp); - if (wordTypes.isWord(type)) { - return new ParameterNode(index, wordTypes.getWordStamp(type)); - } - } - return null; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Fri May 29 13:19:05 2015 -0700 @@ -22,26 +22,28 @@ */ package com.oracle.graal.hotspot.meta; -import com.oracle.jvmci.meta.ResolvedJavaMethod; -import com.oracle.jvmci.meta.Kind; -import static com.oracle.jvmci.meta.LocationIdentity.*; import static com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode.*; import static com.oracle.graal.nodes.ConstantNode.*; +import static com.oracle.jvmci.meta.LocationIdentity.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; import com.oracle.jvmci.common.*; +import com.oracle.jvmci.meta.*; /** * Extends {@link WordOperationPlugin} to handle {@linkplain HotSpotOperation HotSpot word @@ -53,7 +55,18 @@ } @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) { + ResolvedJavaType arrayType = StampTool.typeOrNull(array); + Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType()); + if (componentStamp instanceof MetaspacePointerStamp) { + return new LoadIndexedPointerNode(componentStamp, array, index); + } else { + return super.createLoadIndexedNode(array, index); + } + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { if (!wordTypes.isWordOperation(method)) { return false; } @@ -67,7 +80,7 @@ return true; } - public void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) { + protected void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) { Kind returnKind = method.getSignature().getReturnKind(); switch (operation.opcode()) { case POINTER_EQ: diff -r 7a7cf422160b -r 625b2b12b418 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 Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri May 29 13:19:05 2015 -0700 @@ -1488,8 +1488,12 @@ } private boolean tryGenericInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod) { - GenericInvocationPlugin plugin = graphBuilderConfig.getPlugins().getGenericInvocationPlugin(); - return plugin != null && plugin.apply(this, targetMethod, args); + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleInvoke(this, targetMethod, args)) { + return true; + } + } + return false; } private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, JavaType returnType) { @@ -2737,27 +2741,27 @@ private void genLoadIndexed(Kind kind) { ValueNode index = frameState.pop(Kind.Int); ValueNode array = emitExplicitExceptions(frameState.pop(Kind.Object), index); - if (!tryLoadIndexedPlugin(kind, index, array)) { - frameState.push(kind, append(genLoadIndexed(array, index, kind))); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadIndexed(this, array, index, kind)) { + return; + } } - } - - protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) { - LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin(); - if (loadIndexedPlugin != null && loadIndexedPlugin.apply(this, array, index, kind)) { - if (TraceParserPlugins.getValue()) { - traceWithContext("used load indexed plugin"); - } - return true; - } else { - return false; - } + + frameState.push(kind, append(genLoadIndexed(array, index, kind))); } private void genStoreIndexed(Kind kind) { ValueNode value = frameState.pop(kind); ValueNode index = frameState.pop(Kind.Int); ValueNode array = emitExplicitExceptions(frameState.pop(Kind.Object), index); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreIndexed(this, array, index, kind, value)) { + return; + } + } + genStoreIndexed(array, index, kind, value); } @@ -2985,85 +2989,99 @@ int cpi = getStream().readCPI(); JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.pop(Kind.Object); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !this.parsingIntrinsic() || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) { - ValueNode checkCastNode = null; - if (profile != null) { - if (profile.getNullSeen().isFalse()) { - object = append(GuardingPiNode.createNullCheck(object)); - ResolvedJavaType singleType = profile.asSingleType(); - if (singleType != null) { - LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); - if (typeCheck.isTautology()) { - checkCastNode = object; - } else { - GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated, - DeoptimizationAction.InvalidateReprofile, StampFactory.exactNonNull(singleType))); - checkCastNode = piNode; - } - } + + if (!(type instanceof ResolvedJavaType)) { + handleUnresolvedCheckCast(type, object); + return; + } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleCheckCast(this, object, resolvedType, profile)) { + return; + } + } + + ValueNode checkCastNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + if (typeCheck.isTautology()) { + checkCastNode = object; + } else { + GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, + StampFactory.exactNonNull(singleType))); + checkCastNode = piNode; } } - if (checkCastNode == null) { - checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); - } - frameState.push(Kind.Object, checkCastNode); } - } else { - handleUnresolvedCheckCast(type, object); } + if (checkCastNode == null) { + checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + } + frameState.push(Kind.Object, checkCastNode); } private void genInstanceOf() { int cpi = getStream().readCPI(); JavaType type = lookupType(cpi, INSTANCEOF); ValueNode object = frameState.pop(Kind.Object); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) { - ValueNode instanceOfNode = null; - if (profile != null) { - if (profile.getNullSeen().isFalse()) { - object = append(GuardingPiNode.createNullCheck(object)); - ResolvedJavaType singleType = profile.asSingleType(); - if (singleType != null) { - LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); - append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); - instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType)); - } - } + + if (!(type instanceof ResolvedJavaType)) { + handleUnresolvedInstanceOf(type, object); + return; + } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleInstanceOf(this, object, resolvedType, profile)) { + return; + } + } + + ValueNode instanceOfNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); + instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType)); } - if (instanceOfNode == null) { - instanceOfNode = createInstanceOf(resolvedType, object, profile); - } - frameState.push(Kind.Int, append(genConditional(genUnique(instanceOfNode)))); } - } else { - handleUnresolvedInstanceOf(type, object); } + if (instanceOfNode == null) { + instanceOfNode = createInstanceOf(resolvedType, object, profile); + } + frameState.push(Kind.Int, append(genConditional(genUnique(instanceOfNode)))); } void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); - if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { - ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); - if (skippedExceptionTypes != null) { - for (ResolvedJavaType exceptionType : skippedExceptionTypes) { - if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) { - append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); - return; - } + + if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { + handleUnresolvedNewInstance(type); + return; + } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); + if (skippedExceptionTypes != null) { + for (ResolvedJavaType exceptionType : skippedExceptionTypes) { + if (exceptionType.isAssignableFrom(resolvedType)) { + append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); + return; } } - frameState.push(Kind.Object, append(createNewInstance((ResolvedJavaType) type, true))); - } else { - handleUnresolvedNewInstance(type); } + + frameState.push(Kind.Object, append(createNewInstance(resolvedType, true))); } private void genNewPrimitiveArray(int typeCode) { @@ -3075,12 +3093,14 @@ private void genNewObjectArray(int cpi) { JavaType type = lookupType(cpi, ANEWARRAY); ValueNode length = frameState.pop(Kind.Int); - if (type instanceof ResolvedJavaType) { - frameState.push(Kind.Object, append(createNewArray((ResolvedJavaType) type, length, true))); - } else { + + if (!(type instanceof ResolvedJavaType)) { handleUnresolvedNewObjectArray(type, length); + return; } - + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + frameState.push(Kind.Object, append(createNewArray(resolvedType, length, true))); } private void genNewMultiArray(int cpi) { @@ -3090,25 +3110,32 @@ for (int i = rank - 1; i >= 0; i--) { dims.set(i, frameState.pop(Kind.Int)); } - if (type instanceof ResolvedJavaType) { - frameState.push(Kind.Object, append(createNewMultiArray((ResolvedJavaType) type, dims))); - } else { + + if (!(type instanceof ResolvedJavaType)) { handleUnresolvedNewMultiArray(type, dims); + return; } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + frameState.push(Kind.Object, append(createNewMultiArray(resolvedType, dims))); } private void genGetField(JavaField field) { ValueNode receiver = emitExplicitExceptions(frameState.pop(Kind.Object), null); - if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - ResolvedJavaField resolvedField = (ResolvedJavaField) field; - - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, receiver, resolvedField)) { - frameState.push(field.getKind(), append(genLoadField(receiver, resolvedField))); + + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + handleUnresolvedLoadField(field, receiver); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadField(this, receiver, resolvedField)) { + return; } - } else { - handleUnresolvedLoadField(field, receiver); } + + frameState.push(field.getKind(), append(genLoadField(receiver, resolvedField))); } /** @@ -3137,41 +3164,62 @@ private void genPutField(JavaField field) { ValueNode value = frameState.pop(field.getKind()); ValueNode receiver = emitExplicitExceptions(frameState.pop(Kind.Object), null); - if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - genStoreField(receiver, (ResolvedJavaField) field, value); - } else { + + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { handleUnresolvedStoreField(field, value, receiver); + return; } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreField(this, receiver, resolvedField, value)) { + return; + } + } + + genStoreField(receiver, resolvedField, value); } private void genGetStatic(JavaField field) { - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - ResolvedJavaField resolvedField = (ResolvedJavaField) field; - - // Javac does not allow use of "$assertionsDisabled" for a field name but - // Eclipse does in which case a suffix is added to the generated field. - if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { - frameState.push(field.getKind(), ConstantNode.forBoolean(true, graph)); + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + handleUnresolvedLoadField(field, null); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + /* + * Javac does not allow use of "$assertionsDisabled" for a field name but Eclipse + * does, in which case a suffix is added to the generated field. + */ + if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { + frameState.push(field.getKind(), ConstantNode.forBoolean(true, graph)); + return; + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadStaticField(this, resolvedField)) { return; } - - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) { - frameState.push(field.getKind(), append(genLoadField(null, resolvedField))); - } - } else { - handleUnresolvedLoadField(field, null); } + + frameState.push(field.getKind(), append(genLoadField(null, resolvedField))); } private void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getKind()); - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - ResolvedJavaField resolvedField = (ResolvedJavaField) field; - genStoreField(null, resolvedField, value); - } else { + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { handleUnresolvedStoreField(field, value, null); + return; } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreStaticField(this, resolvedField, value)) { + return; + } + } + + genStoreField(null, resolvedField, value); } private double[] switchProbability(int numberOfCases, int bci) { diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * 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.replacements; - -import static com.oracle.graal.replacements.NodeIntrinsificationPhase.*; -import static com.oracle.jvmci.meta.MetaUtil.*; - -import java.util.*; - -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodeinfo.StructuralInput.MarkerType; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.word.*; -import com.oracle.jvmci.common.*; -import com.oracle.jvmci.meta.*; - -/** - * An {@link GenericInvocationPlugin} that handles methods annotated by {@link Fold}, - * {@link NodeIntrinsic} and all annotations supported by a given {@link WordOperationPlugin}. - */ -public class DefaultGenericInvocationPlugin implements GenericInvocationPlugin { - protected final NodeIntrinsificationPhase nodeIntrinsification; - protected final WordOperationPlugin wordOperationPlugin; - - private final ResolvedJavaType structuralInputType; - - public DefaultGenericInvocationPlugin(MetaAccessProvider metaAccess, NodeIntrinsificationPhase nodeIntrinsification, WordOperationPlugin wordOperationPlugin) { - this.nodeIntrinsification = nodeIntrinsification; - this.wordOperationPlugin = wordOperationPlugin; - - this.structuralInputType = metaAccess.lookupJavaType(StructuralInput.class); - } - - /** - * Calls in replacements to methods matching one of these filters are elided. Only void methods - * are considered for elision. The use of "snippets" in name of the variable and system property - * is purely for legacy reasons. - */ - private static final MethodFilter[] MethodsElidedInSnippets = getMethodsElidedInSnippets(); - - private static MethodFilter[] getMethodsElidedInSnippets() { - String commaSeparatedPatterns = System.getProperty("graal.MethodsElidedInSnippets"); - if (commaSeparatedPatterns != null) { - return MethodFilter.parse(commaSeparatedPatterns); - } - return null; - } - - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if (b.parsingIntrinsic() && wordOperationPlugin.apply(b, method, args)) { - return true; - } else if (b.parsingIntrinsic()) { - NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method); - if (intrinsic != null) { - Signature sig = method.getSignature(); - Kind returnKind = sig.getReturnKind(); - Stamp stamp = StampFactory.forKind(returnKind); - if (returnKind == Kind.Object) { - JavaType returnType = sig.getReturnType(method.getDeclaringClass()); - if (returnType instanceof ResolvedJavaType) { - ResolvedJavaType resolvedReturnType = (ResolvedJavaType) returnType; - WordTypes wordTypes = wordOperationPlugin.getWordTypes(); - if (wordTypes.isWord(resolvedReturnType)) { - stamp = wordTypes.getWordStamp(resolvedReturnType); - } else { - stamp = StampFactory.declared(resolvedReturnType); - } - } - } - - return processNodeIntrinsic(b, method, intrinsic, Arrays.asList(args), returnKind, stamp); - } else if (nodeIntrinsification.isFoldable(method)) { - ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass()); - JavaConstant constant = nodeIntrinsification.tryFold(Arrays.asList(args), parameterTypes, method); - if (!COULD_NOT_FOLD.equals(constant)) { - if (constant != null) { - // Replace the invoke with the result of the call - b.push(method.getSignature().getReturnKind(), ConstantNode.forConstant(constant, b.getMetaAccess(), b.getGraph())); - } else { - // This must be a void invoke - assert method.getSignature().getReturnKind() == Kind.Void; - } - return true; - } - } else if (MethodsElidedInSnippets != null) { - if (MethodFilter.matches(MethodsElidedInSnippets, method)) { - if (method.getSignature().getReturnKind() != Kind.Void) { - throw new JVMCIError("Cannot elide non-void method " + method.format("%H.%n(%p)")); - } - return true; - } - } - } - return false; - } - - private InputType getInputType(ResolvedJavaType type) { - if (type != null && structuralInputType.isAssignableFrom(type)) { - MarkerType markerType = type.getAnnotation(MarkerType.class); - if (markerType != null) { - return markerType.value(); - } else { - throw JVMCIError.shouldNotReachHere(String.format("%s extends StructuralInput, but is not annotated with @MarkerType", type)); - } - } else { - return InputType.Value; - } - } - - protected boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List args, Kind returnKind, Stamp stamp) { - ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp); - if (res == null) { - return false; - } - if (res instanceof UnsafeCopyNode) { - UnsafeCopyNode copy = (UnsafeCopyNode) res; - UnsafeLoadNode value = b.add(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity())); - b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity())); - return true; - } else if (res instanceof ForeignCallNode) { - /* - * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the - * case that the foreign call can deoptimize. As with all deoptimization, we need a - * state in a non-intrinsic method. - */ - GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor(); - if (nonIntrinsicAncestor != null) { - ForeignCallNode foreign = (ForeignCallNode) res; - foreign.setBci(nonIntrinsicAncestor.bci()); - } - } - - boolean nonValueType = false; - if (returnKind == Kind.Object && stamp instanceof ObjectStamp) { - ResolvedJavaType type = ((ObjectStamp) stamp).type(); - if (type != null && structuralInputType.isAssignableFrom(type)) { - assert res.isAllowedUsageType(getInputType(type)); - nonValueType = true; - } - } - - if (returnKind != Kind.Void) { - assert nonValueType || res.getKind().getStackKind() != Kind.Void; - res = b.addPush(returnKind, res); - } else { - assert res.getKind().getStackKind() == Kind.Void; - res = b.add(res); - } - - return true; - } - - protected ValueNode createNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List args, Stamp stamp) { - ValueNode res = nodeIntrinsification.createIntrinsicNode(args, stamp, method, b.getGraph(), intrinsic); - assert res != null || b.getGraph().method().getAnnotation(Snippet.class) != null : String.format( - "Could not create node intrinsic for call to %s as one of the arguments expected to be constant isn't: arguments=%s", method.format("%H.%n(%p)"), args); - return res; - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java Fri May 29 17:23:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * 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.replacements; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.jvmci.meta.*; -import com.oracle.jvmci.meta.MethodHandleAccessProvider.IntrinsicMethod; - -public class MethodHandleInvocationPlugin implements GenericInvocationPlugin { - private final MethodHandleAccessProvider methodHandleAccess; - private final GenericInvocationPlugin delegate; - - public MethodHandleInvocationPlugin(MethodHandleAccessProvider methodHandleAccess, GenericInvocationPlugin delegate) { - this.methodHandleAccess = methodHandleAccess; - this.delegate = delegate; - } - - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method); - if (intrinsicMethod != null) { - InvokeKind invokeKind = b.getInvokeKind(); - if (invokeKind != InvokeKind.Static) { - args[0] = b.nullCheckedValue(args[0]); - } - JavaType invokeReturnType = b.getInvokeReturnType(); - InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args); - if (invoke == null) { - MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args); - if (invokeReturnType.getKind() == Kind.Void) { - b.add(methodHandleNode); - } else { - b.addPush(invokeReturnType.getKind(), methodHandleNode); - } - } else { - CallTargetNode callTarget = invoke.callTarget(); - NodeInputList argumentsList = callTarget.arguments(); - ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]); - for (ValueNode arg : newArgs) { - b.recursiveAppend(arg); - } - b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs); - } - return true; - } - return delegate.apply(b, method, args); - } -} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandlePlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandlePlugin.java Fri May 29 13:19:05 2015 -0700 @@ -0,0 +1,70 @@ +/* + * 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.replacements; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.jvmci.meta.*; +import com.oracle.jvmci.meta.MethodHandleAccessProvider.IntrinsicMethod; + +public class MethodHandlePlugin implements NodePlugin { + private final MethodHandleAccessProvider methodHandleAccess; + + public MethodHandlePlugin(MethodHandleAccessProvider methodHandleAccess) { + this.methodHandleAccess = methodHandleAccess; + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + InvokeKind invokeKind = b.getInvokeKind(); + if (invokeKind != InvokeKind.Static) { + args[0] = b.nullCheckedValue(args[0]); + } + JavaType invokeReturnType = b.getInvokeReturnType(); + InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args); + if (invoke == null) { + MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args); + if (invokeReturnType.getKind() == Kind.Void) { + b.add(methodHandleNode); + } else { + b.addPush(invokeReturnType.getKind(), methodHandleNode); + } + } else { + CallTargetNode callTarget = invoke.callTarget(); + NodeInputList argumentsList = callTarget.arguments(); + ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]); + for (ValueNode arg : newArgs) { + b.recursiveAppend(arg); + } + b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs); + } + return true; + } + return false; + } +} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java Fri May 29 13:19:05 2015 -0700 @@ -0,0 +1,201 @@ +/* + * 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.replacements; + +import static com.oracle.graal.replacements.NodeIntrinsificationPhase.*; +import static com.oracle.jvmci.meta.MetaUtil.*; + +import java.util.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodeinfo.StructuralInput.MarkerType; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.word.*; +import com.oracle.jvmci.common.*; +import com.oracle.jvmci.meta.*; + +/** + * An {@link NodePlugin} that handles methods annotated by {@link Fold} and {@link NodeIntrinsic}. + */ +public class NodeIntrinsificationPlugin implements NodePlugin { + protected final NodeIntrinsificationPhase nodeIntrinsification; + private final WordTypes wordTypes; + private final ResolvedJavaType structuralInputType; + private final boolean mustIntrinsify; + + public NodeIntrinsificationPlugin(MetaAccessProvider metaAccess, NodeIntrinsificationPhase nodeIntrinsification, WordTypes wordTypes, boolean mustIntrinsify) { + this.nodeIntrinsification = nodeIntrinsification; + this.wordTypes = wordTypes; + this.mustIntrinsify = mustIntrinsify; + this.structuralInputType = metaAccess.lookupJavaType(StructuralInput.class); + } + + /** + * Calls in replacements to methods matching one of these filters are elided. Only void methods + * are considered for elision. The use of "snippets" in name of the variable and system property + * is purely for legacy reasons. + */ + private static final MethodFilter[] MethodsElidedInSnippets = getMethodsElidedInSnippets(); + + private static MethodFilter[] getMethodsElidedInSnippets() { + String commaSeparatedPatterns = System.getProperty("graal.MethodsElidedInSnippets"); + if (commaSeparatedPatterns != null) { + return MethodFilter.parse(commaSeparatedPatterns); + } + return null; + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method); + if (intrinsic != null) { + Signature sig = method.getSignature(); + Kind returnKind = sig.getReturnKind(); + Stamp stamp = StampFactory.forKind(returnKind); + if (returnKind == Kind.Object) { + JavaType returnType = sig.getReturnType(method.getDeclaringClass()); + if (returnType instanceof ResolvedJavaType) { + ResolvedJavaType resolvedReturnType = (ResolvedJavaType) returnType; + if (wordTypes.isWord(resolvedReturnType)) { + stamp = wordTypes.getWordStamp(resolvedReturnType); + } else { + stamp = StampFactory.declared(resolvedReturnType); + } + } + } + + boolean result = processNodeIntrinsic(b, method, intrinsic, Arrays.asList(args), returnKind, stamp); + if (!result && mustIntrinsify) { + reportIntrinsificationFailure(b, method, args); + } + return result; + + } else if (nodeIntrinsification.isFoldable(method)) { + ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass()); + JavaConstant constant = nodeIntrinsification.tryFold(Arrays.asList(args), parameterTypes, method); + if (!COULD_NOT_FOLD.equals(constant)) { + if (constant != null) { + // Replace the invoke with the result of the call + b.push(method.getSignature().getReturnKind(), ConstantNode.forConstant(constant, b.getMetaAccess(), b.getGraph())); + } else { + // This must be a void invoke + assert method.getSignature().getReturnKind() == Kind.Void; + } + return true; + } else if (mustIntrinsify) { + reportIntrinsificationFailure(b, method, args); + } + + } else if (MethodsElidedInSnippets != null) { + if (MethodFilter.matches(MethodsElidedInSnippets, method)) { + if (method.getSignature().getReturnKind() != Kind.Void) { + throw new JVMCIError("Cannot elide non-void method " + method.format("%H.%n(%p)")); + } + return true; + } + } + return false; + } + + private static boolean reportIntrinsificationFailure(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + StringBuilder msg = new StringBuilder(); + msg.append("Call in ").append(b.getMethod().format("%H.%n(%p)")); + msg.append(" to ").append(method.format("%H.%n(%p)")); + msg.append(" cannot be intrisfied or folded, probably because an argument is not a constant. Arguments: "); + String sep = ""; + for (ValueNode node : args) { + msg.append(sep).append(node.toString()); + sep = ", "; + } + throw new JVMCIError(msg.toString()); + } + + private InputType getInputType(ResolvedJavaType type) { + if (type != null && structuralInputType.isAssignableFrom(type)) { + MarkerType markerType = type.getAnnotation(MarkerType.class); + if (markerType != null) { + return markerType.value(); + } else { + throw JVMCIError.shouldNotReachHere(String.format("%s extends StructuralInput, but is not annotated with @MarkerType", type)); + } + } else { + return InputType.Value; + } + } + + private boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List args, Kind returnKind, Stamp stamp) { + ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp); + if (res == null) { + return false; + } + if (res instanceof UnsafeCopyNode) { + UnsafeCopyNode copy = (UnsafeCopyNode) res; + UnsafeLoadNode value = b.add(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity())); + b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity())); + return true; + } else if (res instanceof ForeignCallNode) { + /* + * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the + * case that the foreign call can deoptimize. As with all deoptimization, we need a + * state in a non-intrinsic method. + */ + GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor(); + if (nonIntrinsicAncestor != null) { + ForeignCallNode foreign = (ForeignCallNode) res; + foreign.setBci(nonIntrinsicAncestor.bci()); + } + } + + boolean nonValueType = false; + if (returnKind == Kind.Object && stamp instanceof ObjectStamp) { + ResolvedJavaType type = ((ObjectStamp) stamp).type(); + if (type != null && structuralInputType.isAssignableFrom(type)) { + assert res.isAllowedUsageType(getInputType(type)); + nonValueType = true; + } + } + + if (returnKind != Kind.Void) { + assert nonValueType || res.getKind().getStackKind() != Kind.Void; + res = b.addPush(returnKind, res); + } else { + assert res.getKind().getStackKind() == Kind.Void; + res = b.add(res); + } + + return true; + } + + private ValueNode createNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List args, Stamp stamp) { + ValueNode res = nodeIntrinsification.createIntrinsicNode(args, stamp, method, b.getGraph(), intrinsic); + assert res != null || b.getGraph().method().getAnnotation(Snippet.class) != null : String.format( + "Could not create node intrinsic for call to %s as one of the arguments expected to be constant isn't: arguments=%s", method.format("%H.%n(%p)"), args); + return res; + } +} diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri May 29 13:19:05 2015 -0700 @@ -105,7 +105,7 @@ return null; } if (b.parsingIntrinsic()) { - assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); + assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), NodeIntrinsificationPlugin.class.getName()); assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Fri May 29 13:19:05 2015 -0700 @@ -34,7 +34,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; @@ -43,10 +45,10 @@ import com.oracle.jvmci.meta.*; /** - * A {@link GenericInvocationPlugin} for calls to {@linkplain Operation word operations}, and a - * {@link TypeCheckPlugin} to handle casts between word types. + * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that + * need special handling for {@link Word} types. */ -public class WordOperationPlugin implements GenericInvocationPlugin, TypeCheckPlugin { +public class WordOperationPlugin implements NodePlugin, ParameterPlugin, InlineInvokePlugin { protected final WordTypes wordTypes; protected final Kind wordKind; protected final SnippetReflectionProvider snippetReflection; @@ -64,7 +66,8 @@ * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus * processed by this method) */ - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { if (!wordTypes.isWordOperation(method)) { return false; } @@ -73,7 +76,79 @@ } @Override - public boolean checkCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) { + ResolvedJavaType type = StampTool.typeOrNull(stamp); + if (wordTypes.isWord(type)) { + return new ParameterNode(index, wordTypes.getWordStamp(type)); + } + return null; + } + + @Override + public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { + if (wordTypes.isWord(invoke.asNode())) { + invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode()))); + } + } + + @Override + public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { + if (field.getType() instanceof ResolvedJavaType && wordTypes.isWord((ResolvedJavaType) field.getType())) { + LoadFieldNode loadFieldNode = new LoadFieldNode(receiver, field); + loadFieldNode.setStamp(wordTypes.getWordStamp((ResolvedJavaType) field.getType())); + b.addPush(field.getKind(), loadFieldNode); + return true; + } + return false; + } + + @Override + public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) { + return handleLoadField(b, null, staticField); + } + + @Override + public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { + ResolvedJavaType arrayType = StampTool.typeOrNull(array); + /* + * There are cases where the array does not have a known type yet, i.e., the type is null. + * In that case we assume it is not a word type. + */ + if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) { + assert elementKind == Kind.Object; + b.addPush(elementKind, createLoadIndexedNode(array, index)); + return true; + } + return false; + } + + protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) { + return new LoadIndexedNode(array, index, wordTypes.getWordKind()); + } + + @Override + public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind, ValueNode value) { + ResolvedJavaType arrayType = StampTool.typeOrNull(array); + if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) { + assert elementKind == Kind.Object; + if (value.getKind() != wordTypes.getWordKind()) { + throw b.bailout("Cannot store a non-word value into a word array: " + arrayType.toJavaName(true)); + } + b.add(createStoreIndexedNode(array, index, value)); + return true; + } + if (elementKind == Kind.Object && value.getKind() == wordTypes.getWordKind()) { + throw b.bailout("Cannot store a word value into a non-word array: " + arrayType.toJavaName(true)); + } + return false; + } + + protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) { + return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value); + } + + @Override + public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { if (!wordTypes.isWord(type)) { if (object.getKind() != Kind.Object) { throw b.bailout("Cannot cast a word value to a non-word type: " + type.toJavaName(true)); @@ -89,7 +164,7 @@ } @Override - public boolean instanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { if (wordTypes.isWord(type)) { throw b.bailout("Cannot use instanceof for word a type: " + type.toJavaName(true)); } else if (object.getKind() != Kind.Object) { diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java Fri May 29 13:19:05 2015 -0700 @@ -22,12 +22,6 @@ */ package com.oracle.graal.truffle.test; -import com.oracle.jvmci.meta.ConstantReflectionProvider; -import com.oracle.jvmci.meta.ResolvedJavaMethod; -import com.oracle.jvmci.meta.JavaConstant; -import com.oracle.jvmci.meta.MetaAccessProvider; -import com.oracle.jvmci.meta.JavaType; -import com.oracle.jvmci.meta.ResolvedJavaField; import static com.oracle.graal.graph.test.matchers.NodeIterableCount.*; import static com.oracle.graal.graph.test.matchers.NodeIterableIsEmpty.*; import static org.hamcrest.core.IsInstanceOf.*; @@ -49,6 +43,7 @@ import com.oracle.graal.phases.tiers.*; import com.oracle.graal.truffle.nodes.*; import com.oracle.graal.truffle.substitutions.*; +import com.oracle.jvmci.meta.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.unsafe.*; @@ -146,7 +141,6 @@ TruffleGraphBuilderPlugins.registerUnsafeAccessImplPlugins(conf.getPlugins().getInvocationPlugins(), false); // get UnsafeAccess.getInt inlined conf.getPlugins().setInlineInvokePlugin(new InlineEverythingPlugin()); - conf.getPlugins().setLoadFieldPlugin(new FoldLoadsPlugins(getMetaAccess(), getConstantReflection())); return super.editGraphBuilderConfiguration(conf); } @@ -156,26 +150,4 @@ return new InlineInfo(method, false); } } - - private static final class FoldLoadsPlugins implements LoadFieldPlugin { - private final MetaAccessProvider metaAccess; - private final ConstantReflectionProvider constantReflection; - - public FoldLoadsPlugins(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { - this.metaAccess = metaAccess; - this.constantReflection = constantReflection; - } - - public boolean apply(GraphBuilderContext graphBuilderContext, ValueNode receiver, ResolvedJavaField field) { - if (receiver.isConstant()) { - JavaConstant asJavaConstant = receiver.asJavaConstant(); - return tryConstantFold(graphBuilderContext, metaAccess, constantReflection, field, asJavaConstant); - } - return false; - } - - public boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) { - return tryConstantFold(graphBuilderContext, metaAccess, constantReflection, staticField, null); - } - } } diff -r 7a7cf422160b -r 625b2b12b418 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri May 29 17:23:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri May 29 13:19:05 2015 -0700 @@ -22,13 +22,6 @@ */ package com.oracle.graal.truffle; -import com.oracle.jvmci.code.Architecture; -import com.oracle.jvmci.meta.JavaType; -import com.oracle.jvmci.meta.JavaConstant; -import com.oracle.jvmci.meta.ResolvedJavaField; -import com.oracle.jvmci.meta.ResolvedJavaType; -import com.oracle.jvmci.meta.ResolvedJavaMethod; -import com.oracle.jvmci.meta.Kind; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.truffle.TruffleCompilerOptions.*; @@ -60,9 +53,11 @@ import com.oracle.graal.truffle.phases.*; import com.oracle.graal.truffle.substitutions.*; import com.oracle.graal.virtual.phases.ea.*; +import com.oracle.jvmci.code.*; import com.oracle.jvmci.common.*; import com.oracle.jvmci.debug.*; import com.oracle.jvmci.debug.Debug.Scope; +import com.oracle.jvmci.meta.*; import com.oracle.jvmci.options.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -134,21 +129,6 @@ return graph; } - private class InterceptLoadFieldPlugin implements LoadFieldPlugin { - - public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) { - if (receiver.isConstant()) { - JavaConstant asJavaConstant = receiver.asJavaConstant(); - return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), field, asJavaConstant); - } - return false; - } - - public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) { - return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null); - } - } - private class InterceptReceiverPlugin implements ParameterPlugin { private final Object receiver; @@ -309,7 +289,6 @@ newConfig.setUseProfiling(false); Plugins plugins = newConfig.getPlugins(); - plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin()); plugins.setParameterPlugin(new InterceptReceiverPlugin(callTarget)); callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); @@ -334,7 +313,6 @@ newConfig.setUseProfiling(false); Plugins plugins = newConfig.getPlugins(); - plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin()); plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue()));