blob: 2df2ced7f4142c021e13c724daf5d5d045075ab3 [file] [log] [blame]
Vladimir Markoe3e02602014-03-12 15:42:41 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
18#define ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
19
20#include "base/macros.h"
21#include "base/mutex.h"
22#include "dex_file.h"
23#include "dex_instruction.h"
Vladimir Markoc8f60a62014-04-02 15:24:05 +010024#include "method_reference.h"
Vladimir Markoe3e02602014-03-12 15:42:41 +000025
26/*
27 * NOTE: This code is part of the quick compiler. It lives in the runtime
28 * only to allow the debugger to check whether a method has been inlined.
29 */
30
31namespace art {
32
33namespace verifier {
34class MethodVerifier;
35} // namespace verifier
David Sehr9323e6e2016-09-13 08:58:35 -070036class ArtMethod;
Vladimir Markoe3e02602014-03-12 15:42:41 +000037
38enum InlineMethodOpcode : uint16_t {
39 kIntrinsicDoubleCvt,
40 kIntrinsicFloatCvt,
Aart Bik2a6aad92016-02-25 11:32:32 -080041 kIntrinsicFloat2Int,
42 kIntrinsicDouble2Long,
Aart Bik59c94542016-01-25 14:20:58 -080043 kIntrinsicFloatIsInfinite,
44 kIntrinsicDoubleIsInfinite,
45 kIntrinsicFloatIsNaN,
46 kIntrinsicDoubleIsNaN,
Serban Constantinescu23abec92014-07-02 16:13:38 +010047 kIntrinsicReverseBits,
Vladimir Markoe3e02602014-03-12 15:42:41 +000048 kIntrinsicReverseBytes,
Aart Bik3f67e692016-01-15 14:35:12 -080049 kIntrinsicBitCount,
Aart Bik59c94542016-01-25 14:20:58 -080050 kIntrinsicCompare,
51 kIntrinsicHighestOneBit,
52 kIntrinsicLowestOneBit,
Scott Wakeling611d3392015-07-10 11:42:06 +010053 kIntrinsicNumberOfLeadingZeros,
Scott Wakeling9ee23f42015-07-23 10:44:35 +010054 kIntrinsicNumberOfTrailingZeros,
55 kIntrinsicRotateRight,
56 kIntrinsicRotateLeft,
Aart Bik59c94542016-01-25 14:20:58 -080057 kIntrinsicSignum,
Vladimir Markoe3e02602014-03-12 15:42:41 +000058 kIntrinsicAbsInt,
59 kIntrinsicAbsLong,
60 kIntrinsicAbsFloat,
61 kIntrinsicAbsDouble,
62 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010063 kIntrinsicMinMaxLong,
64 kIntrinsicMinMaxFloat,
65 kIntrinsicMinMaxDouble,
Mark Mendella4f12202015-08-06 15:23:34 -040066 kIntrinsicCos,
67 kIntrinsicSin,
68 kIntrinsicAcos,
69 kIntrinsicAsin,
70 kIntrinsicAtan,
71 kIntrinsicAtan2,
72 kIntrinsicCbrt,
73 kIntrinsicCosh,
74 kIntrinsicExp,
75 kIntrinsicExpm1,
76 kIntrinsicHypot,
77 kIntrinsicLog,
78 kIntrinsicLog10,
79 kIntrinsicNextAfter,
80 kIntrinsicSinh,
81 kIntrinsicTan,
82 kIntrinsicTanh,
Vladimir Markoe3e02602014-03-12 15:42:41 +000083 kIntrinsicSqrt,
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010084 kIntrinsicCeil,
85 kIntrinsicFloor,
86 kIntrinsicRint,
87 kIntrinsicRoundFloat,
88 kIntrinsicRoundDouble,
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070089 kIntrinsicReferenceGetReferent,
Vladimir Markoe3e02602014-03-12 15:42:41 +000090 kIntrinsicCharAt,
91 kIntrinsicCompareTo,
agicsaki7da072f2015-08-12 20:30:17 -070092 kIntrinsicEquals,
Jeff Hao848f70a2014-01-15 13:49:50 -080093 kIntrinsicGetCharsNoCheck,
Vladimir Markoe3e02602014-03-12 15:42:41 +000094 kIntrinsicIsEmptyOrLength,
95 kIntrinsicIndexOf,
Jeff Hao848f70a2014-01-15 13:49:50 -080096 kIntrinsicNewStringFromBytes,
97 kIntrinsicNewStringFromChars,
98 kIntrinsicNewStringFromString,
Vladimir Markoe3e02602014-03-12 15:42:41 +000099 kIntrinsicCurrentThread,
100 kIntrinsicPeek,
101 kIntrinsicPoke,
102 kIntrinsicCas,
103 kIntrinsicUnsafeGet,
104 kIntrinsicUnsafePut,
Aart Bik0e54c012016-03-04 12:08:31 -0800105
106 // 1.8.
107 kIntrinsicUnsafeGetAndAddInt,
108 kIntrinsicUnsafeGetAndAddLong,
109 kIntrinsicUnsafeGetAndSetInt,
110 kIntrinsicUnsafeGetAndSetLong,
111 kIntrinsicUnsafeGetAndSetObject,
112 kIntrinsicUnsafeLoadFence,
113 kIntrinsicUnsafeStoreFence,
114 kIntrinsicUnsafeFullFence,
115
DaniilSokolov70c4f062014-06-24 17:34:00 -0700116 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100117 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000118
119 kInlineOpNop,
120 kInlineOpReturnArg,
121 kInlineOpNonWideConst,
122 kInlineOpIGet,
123 kInlineOpIPut,
Vladimir Marko354efa62016-02-04 19:46:56 +0000124 kInlineOpConstructor,
Jeff Hao848f70a2014-01-15 13:49:50 -0800125 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000126};
127std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
128
129enum InlineMethodFlags : uint16_t {
130 kNoInlineMethodFlags = 0x0000,
131 kInlineIntrinsic = 0x0001,
132 kInlineSpecial = 0x0002,
133};
134
135// IntrinsicFlags are stored in InlineMethod::d::raw_data
136enum IntrinsicFlags {
137 kIntrinsicFlagNone = 0,
138
139 // kIntrinsicMinMaxInt
140 kIntrinsicFlagMax = kIntrinsicFlagNone,
141 kIntrinsicFlagMin = 1,
142
143 // kIntrinsicIsEmptyOrLength
144 kIntrinsicFlagLength = kIntrinsicFlagNone,
145 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
146
147 // kIntrinsicIndexOf
148 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
149
150 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
151 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
152 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
153 kIntrinsicFlagIsVolatile = 2,
154 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
155 kIntrinsicFlagIsObject = 4,
156 // kIntrinsicUnsafePut
157 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800158
159 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
160 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000161};
162
163struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000164 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000165 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100166 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000167 uint16_t object_arg : 4;
168 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100169 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000170 uint16_t field_idx;
171 uint32_t is_volatile : 1;
172 uint32_t field_offset : 31;
173};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800174static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000175
176struct InlineReturnArgData {
177 uint16_t arg;
178 uint16_t is_wide : 1;
179 uint16_t is_object : 1;
180 uint16_t reserved : 14;
181 uint32_t reserved2;
182};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800183static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
184 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000185
Vladimir Marko354efa62016-02-04 19:46:56 +0000186struct InlineConstructorData {
187 // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
188 uint16_t iput0_field_index;
189 uint16_t iput1_field_index;
190 uint16_t iput2_field_index;
191 uint16_t iput0_arg : 4;
192 uint16_t iput1_arg : 4;
193 uint16_t iput2_arg : 4;
194 uint16_t reserved : 4;
195};
196static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
197 "Invalid size of InlineConstructorData");
198
Vladimir Markoe3e02602014-03-12 15:42:41 +0000199struct InlineMethod {
200 InlineMethodOpcode opcode;
201 InlineMethodFlags flags;
202 union {
203 uint64_t data;
204 InlineIGetIPutData ifield_data;
205 InlineReturnArgData return_data;
Vladimir Marko354efa62016-02-04 19:46:56 +0000206 InlineConstructorData constructor_data;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000207 } d;
208};
209
210class InlineMethodAnalyser {
211 public:
212 /**
213 * Analyse method code to determine if the method is a candidate for inlining.
214 * If it is, record the inlining data.
215 *
216 * @param verifier the method verifier holding data about the method to analyse.
217 * @param method placeholder for the inline method data.
218 * @return true if the method is a candidate for inlining, false otherwise.
219 */
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000220 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700221 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000222 static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700223 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000224
225 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
226 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
227 }
228
229 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
230 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
231 }
232
233 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
234 return opcode - Instruction::IGET;
235 }
236
237 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
238 return opcode - Instruction::IPUT;
239 }
240
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100241 // Determines whether the method is a synthetic accessor (method name starts with "access$").
242 static bool IsSyntheticAccessor(MethodReference ref);
243
Vladimir Markoe3e02602014-03-12 15:42:41 +0000244 private:
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000245 static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
246 const MethodReference& method_ref,
247 bool is_static,
248 ArtMethod* method,
249 InlineMethod* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700250 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000251 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
252 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000253 static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
254 const MethodReference& method_ref,
255 bool is_static,
256 ArtMethod* method,
257 InlineMethod* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700258 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000259 static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
260 const MethodReference& method_ref,
261 bool is_static,
262 ArtMethod* method,
263 InlineMethod* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700264 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000265
266 // Can we fast path instance field access in a verified accessor?
267 // If yes, computes field's offset and volatility and whether the method is static or not.
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000268 static bool ComputeSpecialAccessorInfo(ArtMethod* method,
269 uint32_t field_idx,
270 bool is_put,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000271 InlineIGetIPutData* result)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700272 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000273};
274
275} // namespace art
276
277#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_