blob: caf4252da0cb2662bfab3d85947ed62e686585df [file] [log] [blame]
/*
* 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 + "}";
}
}