blob: 6cea90219eefbe5006c56793d8f61967e61cdad5 [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,
Scott Wakeling611d3392015-07-10 11:42:06 +010042 kIntrinsicNumberOfLeadingZeros,
Scott Wakeling9ee23f42015-07-23 10:44:35 +010043 kIntrinsicNumberOfTrailingZeros,
44 kIntrinsicRotateRight,
45 kIntrinsicRotateLeft,
Vladimir Markoe3e02602014-03-12 15:42:41 +000046 kIntrinsicAbsInt,
47 kIntrinsicAbsLong,
48 kIntrinsicAbsFloat,
49 kIntrinsicAbsDouble,
50 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010051 kIntrinsicMinMaxLong,
52 kIntrinsicMinMaxFloat,
53 kIntrinsicMinMaxDouble,
Mark Mendella4f12202015-08-06 15:23:34 -040054 kIntrinsicCos,
55 kIntrinsicSin,
56 kIntrinsicAcos,
57 kIntrinsicAsin,
58 kIntrinsicAtan,
59 kIntrinsicAtan2,
60 kIntrinsicCbrt,
61 kIntrinsicCosh,
62 kIntrinsicExp,
63 kIntrinsicExpm1,
64 kIntrinsicHypot,
65 kIntrinsicLog,
66 kIntrinsicLog10,
67 kIntrinsicNextAfter,
68 kIntrinsicSinh,
69 kIntrinsicTan,
70 kIntrinsicTanh,
Vladimir Markoe3e02602014-03-12 15:42:41 +000071 kIntrinsicSqrt,
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010072 kIntrinsicCeil,
73 kIntrinsicFloor,
74 kIntrinsicRint,
75 kIntrinsicRoundFloat,
76 kIntrinsicRoundDouble,
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070077 kIntrinsicReferenceGetReferent,
Vladimir Markoe3e02602014-03-12 15:42:41 +000078 kIntrinsicCharAt,
79 kIntrinsicCompareTo,
agicsaki7da072f2015-08-12 20:30:17 -070080 kIntrinsicEquals,
Jeff Hao848f70a2014-01-15 13:49:50 -080081 kIntrinsicGetCharsNoCheck,
Vladimir Markoe3e02602014-03-12 15:42:41 +000082 kIntrinsicIsEmptyOrLength,
83 kIntrinsicIndexOf,
Jeff Hao848f70a2014-01-15 13:49:50 -080084 kIntrinsicNewStringFromBytes,
85 kIntrinsicNewStringFromChars,
86 kIntrinsicNewStringFromString,
Vladimir Markoe3e02602014-03-12 15:42:41 +000087 kIntrinsicCurrentThread,
88 kIntrinsicPeek,
89 kIntrinsicPoke,
90 kIntrinsicCas,
91 kIntrinsicUnsafeGet,
92 kIntrinsicUnsafePut,
DaniilSokolov70c4f062014-06-24 17:34:00 -070093 kIntrinsicSystemArrayCopyCharArray,
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +010094 kIntrinsicSystemArrayCopy,
Vladimir Markoe3e02602014-03-12 15:42:41 +000095
96 kInlineOpNop,
97 kInlineOpReturnArg,
98 kInlineOpNonWideConst,
99 kInlineOpIGet,
100 kInlineOpIPut,
Jeff Hao848f70a2014-01-15 13:49:50 -0800101 kInlineStringInit,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000102};
103std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
104
105enum InlineMethodFlags : uint16_t {
106 kNoInlineMethodFlags = 0x0000,
107 kInlineIntrinsic = 0x0001,
108 kInlineSpecial = 0x0002,
109};
110
111// IntrinsicFlags are stored in InlineMethod::d::raw_data
112enum IntrinsicFlags {
113 kIntrinsicFlagNone = 0,
114
115 // kIntrinsicMinMaxInt
116 kIntrinsicFlagMax = kIntrinsicFlagNone,
117 kIntrinsicFlagMin = 1,
118
119 // kIntrinsicIsEmptyOrLength
120 kIntrinsicFlagLength = kIntrinsicFlagNone,
121 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
122
123 // kIntrinsicIndexOf
124 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
125
126 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
127 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
128 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
129 kIntrinsicFlagIsVolatile = 2,
130 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
131 kIntrinsicFlagIsObject = 4,
132 // kIntrinsicUnsafePut
133 kIntrinsicFlagIsOrdered = 8,
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800134
135 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
136 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
Vladimir Markoe3e02602014-03-12 15:42:41 +0000137};
138
139struct InlineIGetIPutData {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000140 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000141 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100142 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000143 uint16_t object_arg : 4;
144 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100145 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000146 uint16_t field_idx;
147 uint32_t is_volatile : 1;
148 uint32_t field_offset : 31;
149};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800150static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000151
152struct InlineReturnArgData {
153 uint16_t arg;
154 uint16_t is_wide : 1;
155 uint16_t is_object : 1;
156 uint16_t reserved : 14;
157 uint32_t reserved2;
158};
Andreas Gampe575e78c2014-11-03 23:41:03 -0800159static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
160 "Invalid size of InlineReturnArgData");
Vladimir Markoe3e02602014-03-12 15:42:41 +0000161
162struct InlineMethod {
163 InlineMethodOpcode opcode;
164 InlineMethodFlags flags;
165 union {
166 uint64_t data;
167 InlineIGetIPutData ifield_data;
168 InlineReturnArgData return_data;
169 } d;
170};
171
172class InlineMethodAnalyser {
173 public:
174 /**
175 * Analyse method code to determine if the method is a candidate for inlining.
176 * If it is, record the inlining data.
177 *
178 * @param verifier the method verifier holding data about the method to analyse.
179 * @param method placeholder for the inline method data.
180 * @return true if the method is a candidate for inlining, false otherwise.
181 */
182 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
Mathieu Chartier90443472015-07-16 20:32:27 -0700183 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000184
185 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
186 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
187 }
188
189 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
190 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
191 }
192
193 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
194 return opcode - Instruction::IGET;
195 }
196
197 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
198 return opcode - Instruction::IPUT;
199 }
200
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100201 // Determines whether the method is a synthetic accessor (method name starts with "access$").
202 static bool IsSyntheticAccessor(MethodReference ref);
203
Vladimir Markoe3e02602014-03-12 15:42:41 +0000204 private:
205 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
206 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
207 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700208 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000209 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700210 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000211
212 // Can we fast path instance field access in a verified accessor?
213 // If yes, computes field's offset and volatility and whether the method is static or not.
214 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
215 verifier::MethodVerifier* verifier,
216 InlineIGetIPutData* result)
Mathieu Chartier90443472015-07-16 20:32:27 -0700217 SHARED_REQUIRES(Locks::mutator_lock_);
Vladimir Markoe3e02602014-03-12 15:42:41 +0000218};
219
220} // namespace art
221
222#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_