1 /*
2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package jdk.vm.ci.meta;
24 
25 import java.util.Map;
26 import java.util.function.Supplier;
27 
28 /**
29  * Manages unique {@link SpeculationReason} objects that denote why a deoptimization occurred.
30  * Reasons are embedded in compiled code for a method. If the compiled code deoptimizes at a
31  * position associated with a {@link SpeculationReason}, the reason is added to a set of failed
32  * speculations associated with the method. A subsequent compilation of the method can query the
33  * failed speculations via a {@link SpeculationLog} to avoid making a speculation based on
34  * invalidated reasons. This avoids repeated deoptimizations.
35  */
36 public interface SpeculationLog {
37     /**
38      * The specific attributes of a speculation that a compiler uses to denote a speculation in a
39      * compiled method. Typical attributes of a speculation are a bytecode position, type
40      * information about a variable being speculated on and an enum denoting the type of operation
41      * to which the speculation applies. A {@link SpeculationReason} is used as a key in a
42      * {@link Map} and so it must implement {@link Object#equals(Object)} and
43      * {@link Object#hashCode()} in terms of its attributes.
44      *
45      * A JVMCI implementation may serialize speculations for storage off heap (e.g. in native memory
46      * associated with an nmethod). For this reason, the attributes of a {@link SpeculationReason}
47      * are restricted to those supported by the {@code add...} methods of
48      * {@link SpeculationReasonEncoding}.
49      */
50     public interface SpeculationReason {
51 
52         /**
53          * Encodes the attributes of this reason using a {@link SpeculationReasonEncoding}. For
54          * efficiency, a {@link SpeculationReason} implementation should cache the returned value
55          * and return it for all subsequent calls to this method. This also underlines the
56          * requirement that the encoding for a specific reason instance should be stable.
57          *
58          * @param encodingSupplier source of a {@link SpeculationReasonEncoding}
59          * @return a {@link SpeculationReasonEncoding} that encodes all the attributes that uniquely
60          *         identify this reason
61          */
encode(Supplier<SpeculationReasonEncoding> encodingSupplier)62         default SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
63             return null;
64         }
65     }
66 
67     /**
68      * Provides a facility for encoding the attributes of a {@link SpeculationReason}. The encoding
69      * format is determined by the implementation of this interface.
70      */
71     public interface SpeculationReasonEncoding {
addByte(int value)72         void addByte(int value);
73 
addShort(int value)74         void addShort(int value);
75 
addInt(int value)76         void addInt(int value);
77 
addLong(long value)78         void addLong(long value);
79 
addMethod(ResolvedJavaMethod method)80         void addMethod(ResolvedJavaMethod method);
81 
addType(ResolvedJavaType type)82         void addType(ResolvedJavaType type);
83 
addString(String value)84         void addString(String value);
85 
addField(ResolvedJavaField field)86         default void addField(ResolvedJavaField field) {
87             addType(field.getDeclaringClass());
88             addInt(field.getModifiers());
89             addInt(field.getOffset());
90         }
91     }
92 
93     /**
94      * Marker class that indicates that a speculation has no reason.
95      */
96     final class NoSpeculationReason implements SpeculationReason {
97     }
98 
99     class Speculation {
100         private final SpeculationReason reason;
101 
Speculation(SpeculationReason reason)102         public Speculation(SpeculationReason reason) {
103             this.reason = reason;
104         }
105 
getReason()106         public SpeculationReason getReason() {
107             return reason;
108         }
109 
110         @Override
toString()111         public String toString() {
112             return reason.toString();
113         }
114 
115         @Override
equals(Object obj)116         public boolean equals(Object obj) {
117             if (obj instanceof Speculation) {
118                 Speculation other = (Speculation) obj;
119                 return reason.equals(other.reason);
120             }
121             return false;
122         }
123 
124         @Override
hashCode()125         public int hashCode() {
126             return getReason().hashCode();
127         }
128     }
129 
130     Speculation NO_SPECULATION = new Speculation(new NoSpeculationReason());
131 
132     /**
133      * Updates the set of failed speculations recorded in this log. This must be called before
134      * compilation.
135      */
collectFailedSpeculations()136     void collectFailedSpeculations();
137 
138     /**
139      * If this method returns true, the compiler is allowed to {@link #speculate} with the given
140      * reason.
141      */
maySpeculate(SpeculationReason reason)142     boolean maySpeculate(SpeculationReason reason);
143 
144     /**
145      * Registers a speculation performed by the compiler. The compiler must guard every call to this
146      * method for a specific reason with a call to {@link #maySpeculate(SpeculationReason)}.
147      *
148      * This API is subject to a benign race where a during the course of a compilation another
149      * thread might fail a speculation such that {@link #maySpeculate(SpeculationReason)} will
150      * return false but an earlier call returned true. This method will still return a working
151      * {@link Speculation} in that case but the compile will eventually be invalidated and the
152      * compile attempted again without the now invalid speculation.
153      *
154      * @param reason an object representing the reason for the speculation
155      * @return a compiler constant encapsulating the provided reason. It is usually passed as an
156      *         argument to the deoptimization function.
157      */
speculate(SpeculationReason reason)158     Speculation speculate(SpeculationReason reason);
159 
160     /**
161      * Returns if this log has speculations.
162      *
163      * @return true if there are speculations, false otherwise
164      */
hasSpeculations()165     boolean hasSpeculations();
166 
167     /**
168      * Given a {@link JavaConstant} previously returned from
169      * {@link MetaAccessProvider#encodeSpeculation(Speculation)} return the original
170      * {@link Speculation} object.
171      */
lookupSpeculation(JavaConstant constant)172     Speculation lookupSpeculation(JavaConstant constant);
173 }
174