001/*
002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.graphbuilderconf;
024
025import jdk.internal.jvmci.meta.*;
026import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
027import static jdk.internal.jvmci.code.BytecodeFrame.*;
028
029import com.oracle.graal.nodes.*;
030
031/**
032 * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
033 * snippets) that is itself implemented in Java. This interface provides information about the
034 * intrinsic currently being processed by the graph builder.
035 *
036 * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
037 * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
038 * machine words and pointers.
039 */
040public class IntrinsicContext {
041
042    /**
043     * Gets the method being intrinsified.
044     */
045    final ResolvedJavaMethod method;
046
047    /**
048     * Gets the method providing the intrinsic implementation.
049     */
050    final ResolvedJavaMethod intrinsic;
051
052    public ResolvedJavaMethod getOriginalMethod() {
053        return method;
054    }
055
056    public ResolvedJavaMethod getIntrinsicMethod() {
057        return intrinsic;
058    }
059
060    /**
061     * Determines if a call within the compilation scope of this intrinsic represents a call to the
062     * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
063     * intrinsification falls back to the original method.
064     */
065    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
066        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
067    }
068
069    final CompilationContext compilationContext;
070
071    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, CompilationContext compilationContext) {
072        this.method = method;
073        this.intrinsic = intrinsic;
074        this.compilationContext = compilationContext;
075        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
076    }
077
078    public boolean isPostParseInlined() {
079        return compilationContext.equals(INLINE_AFTER_PARSING);
080    }
081
082    public boolean isCompilationRoot() {
083        return compilationContext.equals(ROOT_COMPILATION);
084    }
085
086    /**
087     * Denotes the compilation context in which an intrinsic is being parsed.
088     */
089    public enum CompilationContext {
090        /**
091         * An intrinsic is being processed when parsing an invoke bytecode that calls the
092         * intrinsified method.
093         */
094        INLINE_DURING_PARSING,
095
096        /**
097         * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
098         */
099        INLINE_AFTER_PARSING,
100
101        /**
102         * An intrinsic is the root of compilation.
103         */
104        ROOT_COMPILATION
105    }
106
107    /**
108     * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
109     * are control flow predecessors of the current point in a graph.
110     */
111    public interface SideEffectsState {
112
113        /**
114         * Determines if the current program point is preceded by one or more side effects.
115         */
116        boolean isAfterSideEffect();
117
118        /**
119         * Gets the side effects preceding the current program point.
120         */
121        Iterable<StateSplit> sideEffects();
122
123        /**
124         * Records a side effect for the current program point.
125         */
126        void addSideEffect(StateSplit sideEffect);
127    }
128
129    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
130        assert forStateSplit != graph.start();
131        if (forStateSplit.hasSideEffect()) {
132            if (sideEffects.isAfterSideEffect()) {
133                // Only the last side effect on any execution path in a replacement
134                // can inherit the stateAfter of the replaced node
135                FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
136                for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
137                    lastSideEffect.setStateAfter(invalid);
138                }
139            }
140            sideEffects.addSideEffect(forStateSplit);
141            return graph.add(new FrameState(AFTER_BCI));
142        } else {
143            if (forStateSplit instanceof AbstractMergeNode) {
144                // Merge nodes always need a frame state
145                if (sideEffects.isAfterSideEffect()) {
146                    // A merge after one or more side effects
147                    return graph.add(new FrameState(AFTER_BCI));
148                } else {
149                    // A merge before any side effects
150                    return graph.add(new FrameState(BEFORE_BCI));
151                }
152            } else {
153                // Other non-side-effects do not need a state
154                return null;
155            }
156        }
157    }
158
159    @Override
160    public String toString() {
161        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
162    }
163}