/* * 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<StateSplit> 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 + "}"; } }