blob: 0e12d735954d4138f29426c1594538dd11ee66ec [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,
Aart Bik0e54c012016-03-04 12:08:31 -0800104
105 // 1.8.
106 kIntrinsicUnsafeGetAndAddInt,
107 kIntrinsicUnsafeGetAndAddLong,
108 kIntrinsicUnsafeGetAndSetInt,
109 kIntrinsicUnsafeGetAndSetLong,
110 kIntrinsicUnsafeGetAndSetObject,
111 kIntrinsicUnsafeLoadFence,
112 kIntrinsicUnsafeStoreFence,
113 kIntrinsicUnsafeFullFence,
114
DaniilSokolov70c4f062014-06-24 17:34:00 -0700115 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100116 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000117
118 kInlineOpNop,
119 kInlineOpReturnArg,
120 kInlineOpNonWideConst,
121 kInlineOpIGet,
122 kInlineOpIPut,
Vladimir Marko354efa62016-02-04 19:46:56 +0000123 kInlineOpConstructor,
Jeff Hao848f70a2014-01-15 13:49:50 -0800124 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000125};
126std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
127
128enum InlineMethodFlags : uint16_t {
129 kNoInlineMethodFlags = 0x0000,
130 kInlineIntrinsic = 0x0001,
131 kInlineSpecial = 0x0002,
132};
133
134// IntrinsicFlags are stored in InlineMethod::d::raw_data
135enum IntrinsicFlags {
136 kIntrinsicFlagNone = 0,
137
138 // kIntrinsicMinMaxInt
139 kIntrinsicFlagMax = kIntrinsicFlagNone,
140 kIntrinsicFlagMin = 1,
141
142 // kIntrinsicIsEmptyOrLength
143 kIntrinsicFlagLength = kIntrinsicFlagNone,
144 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
145
146 // kIntrinsicIndexOf
147 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
148
149 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
150 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
151 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
152 kIntrinsicFlagIsVolatile = 2,
153 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
154 kIntrinsicFlagIsObject = 4,
155 // kIntrinsicUnsafePut
156 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800157
158 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
159 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000160};
161
162struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000163 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000164 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100165 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000166 uint16_t object_arg : 4;
167 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100168 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000169 uint16_t field_idx;
170 uint32_t is_volatile : 1;
171 uint32_t field_offset : 31;
172};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800173static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000174
175struct InlineReturnArgData {
176 uint16_t arg;
177 uint16_t is_wide : 1;
178 uint16_t is_object : 1;
179 uint16_t reserved : 14;
180 uint32_t reserved2;
181};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800182static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
183 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000184
Vladimir Marko354efa62016-02-04 19:46:56 +0000185struct InlineConstructorData {
186 // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
187 uint16_t iput0_field_index;
188 uint16_t iput1_field_index;
189 uint16_t iput2_field_index;
190 uint16_t iput0_arg : 4;
191 uint16_t iput1_arg : 4;
192 uint16_t iput2_arg : 4;
193 uint16_t reserved : 4;
194};
195static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
196 "Invalid size of InlineConstructorData");
197
Vladimir Markoe3e02602014-03-12 15:42:41 +0000198struct InlineMethod {
199 InlineMethodOpcode opcode;
200 InlineMethodFlags flags;
201 union {
202 uint64_t data;
203 InlineIGetIPutData ifield_data;
204 InlineReturnArgData return_data;
Vladimir Marko354efa62016-02-04 19:46:56 +0000205 InlineConstructorData constructor_data;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000206 } d;
207};
208
209class InlineMethodAnalyser {
210 public:
211 /**
212 * Analyse method code to determine if the method is a candidate for inlining.
213 * If it is, record the inlining data.
214 *
215 * @param verifier the method verifier holding data about the method to analyse.
216 * @param method placeholder for the inline method data.
217 * @return true if the method is a candidate for inlining, false otherwise.
218 */
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000219 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result)
220 SHARED_REQUIRES(Locks::mutator_lock_);
221 static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700222 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000223
224 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
225 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
226 }
227
228 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
229 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
230 }
231
232 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
233 return opcode - Instruction::IGET;
234 }
235
236 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
237 return opcode - Instruction::IPUT;
238 }
239
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100240 // Determines whether the method is a synthetic accessor (method name starts with "access$").
241 static bool IsSyntheticAccessor(MethodReference ref);
242
Vladimir Markoe3e02602014-03-12 15:42:41 +0000243 private:
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000244 static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
245 const MethodReference& method_ref,
246 bool is_static,
247 ArtMethod* method,
248 InlineMethod* result)
249 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000250 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
251 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000252 static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
253 const MethodReference& method_ref,
254 bool is_static,
255 ArtMethod* method,
256 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700257 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000258 static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
259 const MethodReference& method_ref,
260 bool is_static,
261 ArtMethod* method,
262 InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700263 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000264
265 // Can we fast path instance field access in a verified accessor?
266 // If yes, computes field's offset and volatility and whether the method is static or not.
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000267 static bool ComputeSpecialAccessorInfo(ArtMethod* method,
268 uint32_t field_idx,
269 bool is_put,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000270 InlineIGetIPutData* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700271 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000272};
273
274} // namespace art
275
276#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_