--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java 2017-02-15 17:07:30.042882795 -0800 @@ -0,0 +1,192 @@ +/* + * 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 org.graalvm.compiler.nodes.graphbuilderconf; + +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; +import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI; +import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI; +import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI; + +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of + * snippets) that is itself implemented in Java. This interface provides information about the + * intrinsic currently being processed by the graph builder. + * + * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing + * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw + * machine words and pointers. + */ +public class IntrinsicContext { + + /** + * Method being intrinsified. + */ + final ResolvedJavaMethod method; + + /** + * Method providing the intrinsic implementation. + */ + final ResolvedJavaMethod intrinsic; + + /** + * Provider of bytecode to be parsed for a method that is part of an intrinsic. + */ + final BytecodeProvider bytecodeProvider; + + /** + * Gets the method being intrinsified. + */ + public ResolvedJavaMethod getOriginalMethod() { + return method; + } + + /** + * Gets the method providing the intrinsic implementation. + */ + public ResolvedJavaMethod getIntrinsicMethod() { + return intrinsic; + } + + /** + * Gets provider of bytecode to be parsed for a method that is part of an intrinsic. + */ + public BytecodeProvider getBytecodeProvider() { + return bytecodeProvider; + } + + /** + * Determines if a call within the compilation scope of this intrinsic represents a call to the + * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial + * intrinsification falls back to the original method. + */ + public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) { + return method.equals(targetMethod) || intrinsic.equals(targetMethod); + } + + final CompilationContext compilationContext; + + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) { + this.method = method; + this.intrinsic = intrinsic; + this.bytecodeProvider = bytecodeProvider; + assert bytecodeProvider != null; + this.compilationContext = compilationContext; + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)"); + } + + public boolean isPostParseInlined() { + return compilationContext.equals(INLINE_AFTER_PARSING); + } + + public boolean isCompilationRoot() { + return compilationContext.equals(ROOT_COMPILATION); + } + + /** + * Denotes the compilation context in which an intrinsic is being parsed. + */ + public enum CompilationContext { + /** + * An intrinsic is being processed when parsing an invoke bytecode that calls the + * intrinsified method. + */ + INLINE_DURING_PARSING, + + /** + * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph. + */ + INLINE_AFTER_PARSING, + + /** + * An intrinsic is the root of compilation. + */ + ROOT_COMPILATION + } + + /** + * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that + * are control flow predecessors of the current point in a graph. + */ + public interface SideEffectsState { + + /** + * Determines if the current program point is preceded by one or more side effects. + */ + boolean isAfterSideEffect(); + + /** + * Gets the side effects preceding the current program point. + */ + Iterable sideEffects(); + + /** + * Records a side effect for the current program point. + */ + void addSideEffect(StateSplit sideEffect); + } + + public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) { + assert forStateSplit != graph.start(); + if (forStateSplit.hasSideEffect()) { + if (sideEffects.isAfterSideEffect()) { + // Only the last side effect on any execution path in a replacement + // can inherit the stateAfter of the replaced node + FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI)); + for (StateSplit lastSideEffect : sideEffects.sideEffects()) { + lastSideEffect.setStateAfter(invalid); + } + } + sideEffects.addSideEffect(forStateSplit); + return graph.add(new FrameState(AFTER_BCI)); + } else { + if (forStateSplit instanceof AbstractMergeNode) { + // Merge nodes always need a frame state + if (sideEffects.isAfterSideEffect()) { + // A merge after one or more side effects + return graph.add(new FrameState(AFTER_BCI)); + } else { + // A merge before any side effects + return graph.add(new FrameState(BEFORE_BCI)); + } + } else { + // Other non-side-effects do not need a state + return null; + } + } + } + + @Override + public String toString() { + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}"; + } +}