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}