blob: ca456c2861d09c1ec3e7e53b8a007f379e11c8ac [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,
Serban Constantinescu23abec92014-07-02 16:13:38 +010040 kIntrinsicReverseBits,
Vladimir Markoe3e02602014-03-12 15:42:41 +000041 kIntrinsicReverseBytes,
Aart Bik3f67e692016-01-15 14:35:12 -080042 kIntrinsicBitCount,
Scott Wakeling611d3392015-07-10 11:42:06 +010043 kIntrinsicNumberOfLeadingZeros,
Scott Wakeling9ee23f42015-07-23 10:44:35 +010044 kIntrinsicNumberOfTrailingZeros,
45 kIntrinsicRotateRight,
46 kIntrinsicRotateLeft,
Vladimir Markoe3e02602014-03-12 15:42:41 +000047 kIntrinsicAbsInt,
48 kIntrinsicAbsLong,
49 kIntrinsicAbsFloat,
50 kIntrinsicAbsDouble,
51 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010052 kIntrinsicMinMaxLong,
53 kIntrinsicMinMaxFloat,
54 kIntrinsicMinMaxDouble,
Mark Mendella4f12202015-08-06 15:23:34 -040055 kIntrinsicCos,
56 kIntrinsicSin,
57 kIntrinsicAcos,
58 kIntrinsicAsin,
59 kIntrinsicAtan,
60 kIntrinsicAtan2,
61 kIntrinsicCbrt,
62 kIntrinsicCosh,
63 kIntrinsicExp,
64 kIntrinsicExpm1,
65 kIntrinsicHypot,
66 kIntrinsicLog,
67 kIntrinsicLog10,
68 kIntrinsicNextAfter,
69 kIntrinsicSinh,
70 kIntrinsicTan,
71 kIntrinsicTanh,
Vladimir Markoe3e02602014-03-12 15:42:41 +000072 kIntrinsicSqrt,
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010073 kIntrinsicCeil,
74 kIntrinsicFloor,
75 kIntrinsicRint,
76 kIntrinsicRoundFloat,
77 kIntrinsicRoundDouble,
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070078 kIntrinsicReferenceGetReferent,
Vladimir Markoe3e02602014-03-12 15:42:41 +000079 kIntrinsicCharAt,
80 kIntrinsicCompareTo,
agicsaki7da072f2015-08-12 20:30:17 -070081 kIntrinsicEquals,
Jeff Hao848f70a2014-01-15 13:49:50 -080082 kIntrinsicGetCharsNoCheck,
Vladimir Markoe3e02602014-03-12 15:42:41 +000083 kIntrinsicIsEmptyOrLength,
84 kIntrinsicIndexOf,
Jeff Hao848f70a2014-01-15 13:49:50 -080085 kIntrinsicNewStringFromBytes,
86 kIntrinsicNewStringFromChars,
87 kIntrinsicNewStringFromString,
Vladimir Markoe3e02602014-03-12 15:42:41 +000088 kIntrinsicCurrentThread,
89 kIntrinsicPeek,
90 kIntrinsicPoke,
91 kIntrinsicCas,
92 kIntrinsicUnsafeGet,
93 kIntrinsicUnsafePut,
DaniilSokolov70c4f062014-06-24 17:34:00 -070094 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +010095 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +000096
97 kInlineOpNop,
98 kInlineOpReturnArg,
99 kInlineOpNonWideConst,
100 kInlineOpIGet,
101 kInlineOpIPut,
Jeff Hao848f70a2014-01-15 13:49:50 -0800102 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000103};
104std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
105
106enum InlineMethodFlags : uint16_t {
107 kNoInlineMethodFlags = 0x0000,
108 kInlineIntrinsic = 0x0001,
109 kInlineSpecial = 0x0002,
110};
111
112// IntrinsicFlags are stored in InlineMethod::d::raw_data
113enum IntrinsicFlags {
114 kIntrinsicFlagNone = 0,
115
116 // kIntrinsicMinMaxInt
117 kIntrinsicFlagMax = kIntrinsicFlagNone,
118 kIntrinsicFlagMin = 1,
119
120 // kIntrinsicIsEmptyOrLength
121 kIntrinsicFlagLength = kIntrinsicFlagNone,
122 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
123
124 // kIntrinsicIndexOf
125 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
126
127 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
128 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
129 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
130 kIntrinsicFlagIsVolatile = 2,
131 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
132 kIntrinsicFlagIsObject = 4,
133 // kIntrinsicUnsafePut
134 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800135
136 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
137 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000138};
139
140struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000141 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000142 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100143 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000144 uint16_t object_arg : 4;
145 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100146 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000147 uint16_t field_idx;
148 uint32_t is_volatile : 1;
149 uint32_t field_offset : 31;
150};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800151static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000152
153struct InlineReturnArgData {
154 uint16_t arg;
155 uint16_t is_wide : 1;
156 uint16_t is_object : 1;
157 uint16_t reserved : 14;
158 uint32_t reserved2;
159};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800160static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
161 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000162
163struct InlineMethod {
164 InlineMethodOpcode opcode;
165 InlineMethodFlags flags;
166 union {
167 uint64_t data;
168 InlineIGetIPutData ifield_data;
169 InlineReturnArgData return_data;
170 } d;
171};
172
173class InlineMethodAnalyser {
174 public:
175 /**
176 * Analyse method code to determine if the method is a candidate for inlining.
177 * If it is, record the inlining data.
178 *
179 * @param verifier the method verifier holding data about the method to analyse.
180 * @param method placeholder for the inline method data.
181 * @return true if the method is a candidate for inlining, false otherwise.
182 */
183 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
Mathieu Chartier90443472015-07-16 20:32:27 -0700184 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000185
186 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
187 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
188 }
189
190 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
191 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
192 }
193
194 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
195 return opcode - Instruction::IGET;
196 }
197
198 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
199 return opcode - Instruction::IPUT;
200 }
201
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100202 // Determines whether the method is a synthetic accessor (method name starts with "access$").
203 static bool IsSyntheticAccessor(MethodReference ref);
204
Vladimir Markoe3e02602014-03-12 15:42:41 +0000205 private:
206 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
207 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
208 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700209 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000210 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700211 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000212
213 // Can we fast path instance field access in a verified accessor?
214 // If yes, computes field's offset and volatility and whether the method is static or not.
215 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
216 verifier::MethodVerifier* verifier,
217 InlineIGetIPutData* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700218 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000219};
220
221} // namespace art
222
223#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_