# HG changeset patch # User Christian Wimmer # Date 1430159853 25200 # Node ID 0f289b082d3d3809f4e88fea2a34628f3f700613 # Parent 647f571f54da4189947203348edf8988e79a1899 Handle checkCast and instanceOf involving word types using a GraphBuilderPlugin diff -r 647f571f54da -r 0f289b082d3d 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 Mon Apr 27 19:03:52 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Mon Apr 27 11:37:33 2015 -0700 @@ -34,6 +34,7 @@ private final InvocationPlugins invocationPlugins; private LoadFieldPlugin loadFieldPlugin; private LoadIndexedPlugin loadIndexedPlugin; + private TypeCheckPlugin typeCheckPlugin; private ParameterPlugin parameterPlugin; private InlineInvokePlugin inlineInvokePlugin; private GenericInvocationPlugin genericInvocationPlugin; @@ -49,6 +50,7 @@ this.parameterPlugin = copyFrom.parameterPlugin; this.loadFieldPlugin = copyFrom.loadFieldPlugin; this.loadIndexedPlugin = copyFrom.loadIndexedPlugin; + this.typeCheckPlugin = copyFrom.typeCheckPlugin; this.inlineInvokePlugin = copyFrom.inlineInvokePlugin; this.loopExplosionPlugin = copyFrom.loopExplosionPlugin; this.genericInvocationPlugin = copyFrom.genericInvocationPlugin; @@ -92,6 +94,14 @@ this.loadIndexedPlugin = plugin; } + public TypeCheckPlugin getTypeCheckPlugin() { + return typeCheckPlugin; + } + + public void setTypeCheckPlugin(TypeCheckPlugin typeCheckPlugin) { + this.typeCheckPlugin = typeCheckPlugin; + } + public ParameterPlugin getParameterPlugin() { return parameterPlugin; } diff -r 647f571f54da -r 0f289b082d3d graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/TypeCheckPlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/TypeCheckPlugin.java Mon Apr 27 11:37:33 2015 -0700 @@ -0,0 +1,60 @@ +/* + * 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.graal.api.meta.*; +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 647f571f54da -r 0f289b082d3d 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 Mon Apr 27 19:03:52 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Apr 27 11:37:33 2015 -0700 @@ -74,6 +74,7 @@ plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes)); plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection)); plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); + plugins.setTypeCheckPlugin(wordOperationPlugin); plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin)); diff -r 647f571f54da -r 0f289b082d3d graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Mon Apr 27 19:03:52 2015 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Mon Apr 27 11:37:33 2015 -0700 @@ -604,9 +604,13 @@ JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.apop(); if (type instanceof ResolvedJavaType) { - JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type); - ValueNode checkCastNode = append(createCheckCast((ResolvedJavaType) type, object, profileForTypeCheck, false)); - frameState.apush(checkCastNode); + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.checkCast((GraphBuilderContext) this, object, resolvedType, profile)) { + ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + frameState.apush(checkCastNode); + } } else { handleUnresolvedCheckCast(type, object); } @@ -622,8 +626,12 @@ ValueNode object = frameState.apop(); if (type instanceof ResolvedJavaType) { ResolvedJavaType resolvedType = (ResolvedJavaType) type; - ValueNode instanceOfNode = createInstanceOf((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType)); - frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf((GraphBuilderContext) this, object, resolvedType, profile)) { + ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile); + frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); + } } else { handleUnresolvedInstanceOf(type, object); } diff -r 647f571f54da -r 0f289b082d3d graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Apr 27 19:03:52 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Apr 27 11:37:33 2015 -0700 @@ -110,6 +110,20 @@ } } + @Test + public void testCast() { + test("cast", 1234L); + } + + @Snippet + public static long cast(long input) { + WordBase base = Word.signed(input); + Unsigned unsigned = (Unsigned) base; + Pointer pointer = (Pointer) unsigned; + Word word = (Word) pointer; + return word.rawValue(); + } + @Snippet public static long unsignedLong(long word) { return Word.unsigned(word).rawValue(); diff -r 647f571f54da -r 0f289b082d3d 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 Mon Apr 27 19:03:52 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Mon Apr 27 11:37:33 2015 -0700 @@ -43,9 +43,10 @@ import com.oracle.graal.word.nodes.*; /** - * A {@link GenericInvocationPlugin} for calls to {@linkplain Operation word operations}. + * A {@link GenericInvocationPlugin} for calls to {@linkplain Operation word operations}, and a + * {@link TypeCheckPlugin} to handle casts between word types. */ -public class WordOperationPlugin implements GenericInvocationPlugin { +public class WordOperationPlugin implements GenericInvocationPlugin, TypeCheckPlugin { protected final WordTypes wordTypes; protected final Kind wordKind; protected final SnippetReflectionProvider snippetReflection; @@ -71,6 +72,32 @@ return true; } + @Override + public boolean checkCast(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)); + } + return false; + } + + if (object.getKind() != wordTypes.getWordKind()) { + throw b.bailout("Cannot cast a non-word value to a word type: " + type.toJavaName(true)); + } + b.push(Kind.Object, object); + return true; + } + + @Override + public boolean instanceOf(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) { + throw b.bailout("Cannot use instanceof on a word value: " + type.toJavaName(true)); + } + return false; + } + protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalInternalError { Operation operation = wordMethod.getAnnotation(Word.Operation.class); Kind returnKind = wordMethod.getSignature().getReturnKind();