blob: 7e84b405e771bb3cadb463861877ee4f2a645f83 [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
36
37enum InlineMethodOpcode : uint16_t {
38 kIntrinsicDoubleCvt,
39 kIntrinsicFloatCvt,
Aart Bik2a6aad92016-02-25 11:32:32 -080040 kIntrinsicFloat2Int,
41 kIntrinsicDouble2Long,
Aart Bik59c94542016-01-25 14:20:58 -080042 kIntrinsicFloatIsInfinite,
43 kIntrinsicDoubleIsInfinite,
44 kIntrinsicFloatIsNaN,
45 kIntrinsicDoubleIsNaN,
Serban Constantinescu23abec92014-07-02 16:13:38 +010046 kIntrinsicReverseBits,
Vladimir Markoe3e02602014-03-12 15:42:41 +000047 kIntrinsicReverseBytes,
Aart Bik3f67e692016-01-15 14:35:12 -080048 kIntrinsicBitCount,
Aart Bik59c94542016-01-25 14:20:58 -080049 kIntrinsicCompare,
50 kIntrinsicHighestOneBit,
51 kIntrinsicLowestOneBit,
Scott Wakeling611d3392015-07-10 11:42:06 +010052 kIntrinsicNumberOfLeadingZeros,
Scott Wakeling9ee23f42015-07-23 10:44:35 +010053 kIntrinsicNumberOfTrailingZeros,
54 kIntrinsicRotateRight,
55 kIntrinsicRotateLeft,
Aart Bik59c94542016-01-25 14:20:58 -080056 kIntrinsicSignum,
Vladimir Markoe3e02602014-03-12 15:42:41 +000057 kIntrinsicAbsInt,
58 kIntrinsicAbsLong,
59 kIntrinsicAbsFloat,
60 kIntrinsicAbsDouble,
61 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010062 kIntrinsicMinMaxLong,
63 kIntrinsicMinMaxFloat,
64 kIntrinsicMinMaxDouble,
Mark Mendella4f12202015-08-06 15:23:34 -040065 kIntrinsicCos,
66 kIntrinsicSin,
67 kIntrinsicAcos,
68 kIntrinsicAsin,
69 kIntrinsicAtan,
70 kIntrinsicAtan2,
71 kIntrinsicCbrt,
72 kIntrinsicCosh,
73 kIntrinsicExp,
74 kIntrinsicExpm1,
75 kIntrinsicHypot,
76 kIntrinsicLog,
77 kIntrinsicLog10,
78 kIntrinsicNextAfter,
79 kIntrinsicSinh,
80 kIntrinsicTan,
81 kIntrinsicTanh,
Vladimir Markoe3e02602014-03-12 15:42:41 +000082 kIntrinsicSqrt,
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010083 kIntrinsicCeil,
84 kIntrinsicFloor,
85 kIntrinsicRint,
86 kIntrinsicRoundFloat,
87 kIntrinsicRoundDouble,
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070088 kIntrinsicReferenceGetReferent,
Vladimir Markoe3e02602014-03-12 15:42:41 +000089 kIntrinsicCharAt,
90 kIntrinsicCompareTo,
agicsaki7da072f2015-08-12 20:30:17 -070091 kIntrinsicEquals,
Jeff Hao848f70a2014-01-15 13:49:50 -080092 kIntrinsicGetCharsNoCheck,
Vladimir Markoe3e02602014-03-12 15:42:41 +000093 kIntrinsicIsEmptyOrLength,
94 kIntrinsicIndexOf,
Jeff Hao848f70a2014-01-15 13:49:50 -080095 kIntrinsicNewStringFromBytes,
96 kIntrinsicNewStringFromChars,
97 kIntrinsicNewStringFromString,
Vladimir Markoe3e02602014-03-12 15:42:41 +000098 kIntrinsicCurrentThread,
99 kIntrinsicPeek,
100 kIntrinsicPoke,
101 kIntrinsicCas,
102 kIntrinsicUnsafeGet,
103 kIntrinsicUnsafePut,
DaniilSokolov70c4f062014-06-24 17:34:00 -0700104 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100105 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000106
107 kInlineOpNop,
108 kInlineOpReturnArg,
109 kInlineOpNonWideConst,
110 kInlineOpIGet,
111 kInlineOpIPut,
Vladimir Marko354efa62016-02-04 19:46:56 +0000112 kInlineOpConstructor,
Jeff Hao848f70a2014-01-15 13:49:50 -0800113 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000114};
115std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
116
117enum InlineMethodFlags : uint16_t {
118 kNoInlineMethodFlags = 0x0000,
119 kInlineIntrinsic = 0x0001,
120 kInlineSpecial = 0x0002,
121};
122
123// IntrinsicFlags are stored in InlineMethod::d::raw_data
124enum IntrinsicFlags {
125 kIntrinsicFlagNone = 0,
126
127 // kIntrinsicMinMaxInt
128 kIntrinsicFlagMax = kIntrinsicFlagNone,
129 kIntrinsicFlagMin = 1,
130
131 // kIntrinsicIsEmptyOrLength
132 kIntrinsicFlagLength = kIntrinsicFlagNone,
133 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
134
135 // kIntrinsicIndexOf
136 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
137
138 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
139 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
140 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
141 kIntrinsicFlagIsVolatile = 2,
142 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
143 kIntrinsicFlagIsObject = 4,
144 // kIntrinsicUnsafePut
145 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800146
147 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
148 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000149};
150
151struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000152 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000153 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100154 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000155 uint16_t object_arg : 4;
156 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100157 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000158 uint16_t field_idx;
159 uint32_t is_volatile : 1;
160 uint32_t field_offset : 31;
161};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800162static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000163
164struct InlineReturnArgData {
165 uint16_t arg;
166 uint16_t is_wide : 1;
167 uint16_t is_object : 1;
168 uint16_t reserved : 14;
169 uint32_t reserved2;
170};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800171static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
172 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000173
Vladimir Marko354efa62016-02-04 19:46:56 +0000174struct InlineConstructorData {
175 // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
176 uint16_t iput0_field_index;
177 uint16_t iput1_field_index;
178 uint16_t iput2_field_index;
179 uint16_t iput0_arg : 4;
180 uint16_t iput1_arg : 4;
181 uint16_t iput2_arg : 4;
182 uint16_t reserved : 4;
183};
184static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
185 "Invalid size of InlineConstructorData");
186
Vladimir Markoe3e02602014-03-12 15:42:41 +0000187struct InlineMethod {
188 InlineMethodOpcode opcode;
189 InlineMethodFlags flags;
190 union {
191 uint64_t data;
192 InlineIGetIPutData ifield_data;
193 InlineReturnArgData return_data;
Vladimir Marko354efa62016-02-04 19:46:56 +0000194 InlineConstructorData constructor_data;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000195 } d;
196};
197
198class InlineMethodAnalyser {
199 public:
200 /**
201 * Analyse method code to determine if the method is a candidate for inlining.
202 * If it is, record the inlining data.
203 *
204 * @param verifier the method verifier holding data about the method to analyse.
205 * @param method placeholder for the inline method data.
206 * @return true if the method is a candidate for inlining, false otherwise.
207 */
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000208 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result)
209 SHARED_REQUIRES(Locks::mutator_lock_);
210 static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700211 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000212
213 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
214 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
215 }
216
217 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
218 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
219 }
220
221 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
222 return opcode - Instruction::IGET;
223 }
224
225 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
226 return opcode - Instruction::IPUT;
227 }
228
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100229 // Determines whether the method is a synthetic accessor (method name starts with "access$").
230 static bool IsSyntheticAccessor(MethodReference ref);
231
Vladimir Markoe3e02602014-03-12 15:42:41 +0000232 private:
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000233 static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
234 const MethodReference& method_ref,
235 bool is_static,
236 ArtMethod* method,
237 InlineMethod* result)
238 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000239 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
240 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000241 static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
242 const MethodReference& method_ref,
243 bool is_static,
244 ArtMethod* method,
245 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700246 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000247 static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
248 const MethodReference& method_ref,
249 bool is_static,
250 ArtMethod* method,
251 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700252 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000253
254 // Can we fast path instance field access in a verified accessor?
255 // If yes, computes field's offset and volatility and whether the method is static or not.
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000256 static bool ComputeSpecialAccessorInfo(ArtMethod* method,
257 uint32_t field_idx,
258 bool is_put,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000259 InlineIGetIPutData* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700260 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000261};
262
263} // namespace art
264
265#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_