blob: 0b09a70be47890b2e1ea151db6dfaeef90897d95 [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 Bik59c94542016-01-25 14:20:58 -080040 kIntrinsicFloatIsInfinite,
41 kIntrinsicDoubleIsInfinite,
42 kIntrinsicFloatIsNaN,
43 kIntrinsicDoubleIsNaN,
Serban Constantinescu23abec92014-07-02 16:13:38 +010044 kIntrinsicReverseBits,
Vladimir Markoe3e02602014-03-12 15:42:41 +000045 kIntrinsicReverseBytes,
Aart Bik3f67e692016-01-15 14:35:12 -080046 kIntrinsicBitCount,
Aart Bik59c94542016-01-25 14:20:58 -080047 kIntrinsicCompare,
48 kIntrinsicHighestOneBit,
49 kIntrinsicLowestOneBit,
Scott Wakeling611d3392015-07-10 11:42:06 +010050 kIntrinsicNumberOfLeadingZeros,
Scott Wakeling9ee23f42015-07-23 10:44:35 +010051 kIntrinsicNumberOfTrailingZeros,
52 kIntrinsicRotateRight,
53 kIntrinsicRotateLeft,
Aart Bik59c94542016-01-25 14:20:58 -080054 kIntrinsicSignum,
Vladimir Markoe3e02602014-03-12 15:42:41 +000055 kIntrinsicAbsInt,
56 kIntrinsicAbsLong,
57 kIntrinsicAbsFloat,
58 kIntrinsicAbsDouble,
59 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010060 kIntrinsicMinMaxLong,
61 kIntrinsicMinMaxFloat,
62 kIntrinsicMinMaxDouble,
Mark Mendella4f12202015-08-06 15:23:34 -040063 kIntrinsicCos,
64 kIntrinsicSin,
65 kIntrinsicAcos,
66 kIntrinsicAsin,
67 kIntrinsicAtan,
68 kIntrinsicAtan2,
69 kIntrinsicCbrt,
70 kIntrinsicCosh,
71 kIntrinsicExp,
72 kIntrinsicExpm1,
73 kIntrinsicHypot,
74 kIntrinsicLog,
75 kIntrinsicLog10,
76 kIntrinsicNextAfter,
77 kIntrinsicSinh,
78 kIntrinsicTan,
79 kIntrinsicTanh,
Vladimir Markoe3e02602014-03-12 15:42:41 +000080 kIntrinsicSqrt,
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010081 kIntrinsicCeil,
82 kIntrinsicFloor,
83 kIntrinsicRint,
84 kIntrinsicRoundFloat,
85 kIntrinsicRoundDouble,
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070086 kIntrinsicReferenceGetReferent,
Vladimir Markoe3e02602014-03-12 15:42:41 +000087 kIntrinsicCharAt,
88 kIntrinsicCompareTo,
agicsaki7da072f2015-08-12 20:30:17 -070089 kIntrinsicEquals,
Jeff Hao848f70a2014-01-15 13:49:50 -080090 kIntrinsicGetCharsNoCheck,
Vladimir Markoe3e02602014-03-12 15:42:41 +000091 kIntrinsicIsEmptyOrLength,
92 kIntrinsicIndexOf,
Jeff Hao848f70a2014-01-15 13:49:50 -080093 kIntrinsicNewStringFromBytes,
94 kIntrinsicNewStringFromChars,
95 kIntrinsicNewStringFromString,
Vladimir Markoe3e02602014-03-12 15:42:41 +000096 kIntrinsicCurrentThread,
97 kIntrinsicPeek,
98 kIntrinsicPoke,
99 kIntrinsicCas,
100 kIntrinsicUnsafeGet,
101 kIntrinsicUnsafePut,
DaniilSokolov70c4f062014-06-24 17:34:00 -0700102 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100103 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000104
105 kInlineOpNop,
106 kInlineOpReturnArg,
107 kInlineOpNonWideConst,
108 kInlineOpIGet,
109 kInlineOpIPut,
Vladimir Marko354efa62016-02-04 19:46:56 +0000110 kInlineOpConstructor,
Jeff Hao848f70a2014-01-15 13:49:50 -0800111 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000112};
113std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
114
115enum InlineMethodFlags : uint16_t {
116 kNoInlineMethodFlags = 0x0000,
117 kInlineIntrinsic = 0x0001,
118 kInlineSpecial = 0x0002,
119};
120
121// IntrinsicFlags are stored in InlineMethod::d::raw_data
122enum IntrinsicFlags {
123 kIntrinsicFlagNone = 0,
124
125 // kIntrinsicMinMaxInt
126 kIntrinsicFlagMax = kIntrinsicFlagNone,
127 kIntrinsicFlagMin = 1,
128
129 // kIntrinsicIsEmptyOrLength
130 kIntrinsicFlagLength = kIntrinsicFlagNone,
131 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
132
133 // kIntrinsicIndexOf
134 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
135
136 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
137 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
138 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
139 kIntrinsicFlagIsVolatile = 2,
140 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
141 kIntrinsicFlagIsObject = 4,
142 // kIntrinsicUnsafePut
143 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800144
145 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
146 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000147};
148
149struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000150 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000151 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100152 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000153 uint16_t object_arg : 4;
154 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100155 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000156 uint16_t field_idx;
157 uint32_t is_volatile : 1;
158 uint32_t field_offset : 31;
159};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800160static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000161
162struct InlineReturnArgData {
163 uint16_t arg;
164 uint16_t is_wide : 1;
165 uint16_t is_object : 1;
166 uint16_t reserved : 14;
167 uint32_t reserved2;
168};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800169static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
170 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000171
Vladimir Marko354efa62016-02-04 19:46:56 +0000172struct InlineConstructorData {
173 // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
174 uint16_t iput0_field_index;
175 uint16_t iput1_field_index;
176 uint16_t iput2_field_index;
177 uint16_t iput0_arg : 4;
178 uint16_t iput1_arg : 4;
179 uint16_t iput2_arg : 4;
180 uint16_t reserved : 4;
181};
182static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
183 "Invalid size of InlineConstructorData");
184
Vladimir Markoe3e02602014-03-12 15:42:41 +0000185struct InlineMethod {
186 InlineMethodOpcode opcode;
187 InlineMethodFlags flags;
188 union {
189 uint64_t data;
190 InlineIGetIPutData ifield_data;
191 InlineReturnArgData return_data;
Vladimir Marko354efa62016-02-04 19:46:56 +0000192 InlineConstructorData constructor_data;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000193 } d;
194};
195
196class InlineMethodAnalyser {
197 public:
198 /**
199 * Analyse method code to determine if the method is a candidate for inlining.
200 * If it is, record the inlining data.
201 *
202 * @param verifier the method verifier holding data about the method to analyse.
203 * @param method placeholder for the inline method data.
204 * @return true if the method is a candidate for inlining, false otherwise.
205 */
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000206 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result)
207 SHARED_REQUIRES(Locks::mutator_lock_);
208 static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700209 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000210
211 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
212 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
213 }
214
215 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
216 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
217 }
218
219 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
220 return opcode - Instruction::IGET;
221 }
222
223 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
224 return opcode - Instruction::IPUT;
225 }
226
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100227 // Determines whether the method is a synthetic accessor (method name starts with "access$").
228 static bool IsSyntheticAccessor(MethodReference ref);
229
Vladimir Markoe3e02602014-03-12 15:42:41 +0000230 private:
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000231 static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
232 const MethodReference& method_ref,
233 bool is_static,
234 ArtMethod* method,
235 InlineMethod* result)
236 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000237 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
238 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000239 static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
240 const MethodReference& method_ref,
241 bool is_static,
242 ArtMethod* method,
243 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700244 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000245 static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
246 const MethodReference& method_ref,
247 bool is_static,
248 ArtMethod* method,
249 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700250 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000251
252 // Can we fast path instance field access in a verified accessor?
253 // If yes, computes field's offset and volatility and whether the method is static or not.
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000254 static bool ComputeSpecialAccessorInfo(ArtMethod* method,
255 uint32_t field_idx,
256 bool is_put,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000257 InlineIGetIPutData* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700258 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000259};
260
261} // namespace art
262
263#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_