blob: e1fbf011caec2ce706d2911172c150aa1602a82d [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,
42 kIntrinsicAbsInt,
43 kIntrinsicAbsLong,
44 kIntrinsicAbsFloat,
45 kIntrinsicAbsDouble,
46 kIntrinsicMinMaxInt,
Serban Constantinescu23abec92014-07-02 16:13:38 +010047 kIntrinsicMinMaxLong,
48 kIntrinsicMinMaxFloat,
49 kIntrinsicMinMaxDouble,
Vladimir Markoe3e02602014-03-12 15:42:41 +000050 kIntrinsicSqrt,
51 kIntrinsicCharAt,
52 kIntrinsicCompareTo,
53 kIntrinsicIsEmptyOrLength,
54 kIntrinsicIndexOf,
55 kIntrinsicCurrentThread,
56 kIntrinsicPeek,
57 kIntrinsicPoke,
58 kIntrinsicCas,
59 kIntrinsicUnsafeGet,
60 kIntrinsicUnsafePut,
61
62 kInlineOpNop,
63 kInlineOpReturnArg,
64 kInlineOpNonWideConst,
65 kInlineOpIGet,
66 kInlineOpIPut,
67};
68std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
69
70enum InlineMethodFlags : uint16_t {
71 kNoInlineMethodFlags = 0x0000,
72 kInlineIntrinsic = 0x0001,
73 kInlineSpecial = 0x0002,
74};
75
76// IntrinsicFlags are stored in InlineMethod::d::raw_data
77enum IntrinsicFlags {
78 kIntrinsicFlagNone = 0,
79
80 // kIntrinsicMinMaxInt
81 kIntrinsicFlagMax = kIntrinsicFlagNone,
82 kIntrinsicFlagMin = 1,
83
84 // kIntrinsicIsEmptyOrLength
85 kIntrinsicFlagLength = kIntrinsicFlagNone,
86 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
87
88 // kIntrinsicIndexOf
89 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
90
91 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
92 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
93 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
94 kIntrinsicFlagIsVolatile = 2,
95 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
96 kIntrinsicFlagIsObject = 4,
97 // kIntrinsicUnsafePut
98 kIntrinsicFlagIsOrdered = 8,
99};
100
101struct InlineIGetIPutData {
102 // The op_variant below is opcode-Instruction::IGET for IGETs and
103 // opcode-Instruction::IPUT for IPUTs. This is because the runtime
104 // doesn't know the OpSize enumeration.
105 uint16_t op_variant : 3;
Vladimir Markoe1fced12014-04-04 14:52:53 +0100106 uint16_t method_is_static : 1;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000107 uint16_t object_arg : 4;
108 uint16_t src_arg : 4; // iput only
Vladimir Markoe1fced12014-04-04 14:52:53 +0100109 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
Vladimir Markoe3e02602014-03-12 15:42:41 +0000110 uint16_t field_idx;
111 uint32_t is_volatile : 1;
112 uint32_t field_offset : 31;
113};
114COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
115
116struct InlineReturnArgData {
117 uint16_t arg;
118 uint16_t is_wide : 1;
119 uint16_t is_object : 1;
120 uint16_t reserved : 14;
121 uint32_t reserved2;
122};
123COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
124
125struct InlineMethod {
126 InlineMethodOpcode opcode;
127 InlineMethodFlags flags;
128 union {
129 uint64_t data;
130 InlineIGetIPutData ifield_data;
131 InlineReturnArgData return_data;
132 } d;
133};
134
135class InlineMethodAnalyser {
136 public:
137 /**
138 * Analyse method code to determine if the method is a candidate for inlining.
139 * If it is, record the inlining data.
140 *
141 * @param verifier the method verifier holding data about the method to analyse.
142 * @param method placeholder for the inline method data.
143 * @return true if the method is a candidate for inlining, false otherwise.
144 */
145 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
146 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
147
148 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
149 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
150 }
151
152 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
153 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
154 }
155
156 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
157 return opcode - Instruction::IGET;
158 }
159
160 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
161 return opcode - Instruction::IPUT;
162 }
163
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100164 // Determines whether the method is a synthetic accessor (method name starts with "access$").
165 static bool IsSyntheticAccessor(MethodReference ref);
166
Vladimir Markoe3e02602014-03-12 15:42:41 +0000167 private:
168 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
169 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
170 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
171 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
172 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
173 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
174
175 // Can we fast path instance field access in a verified accessor?
176 // If yes, computes field's offset and volatility and whether the method is static or not.
177 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
178 verifier::MethodVerifier* verifier,
179 InlineIGetIPutData* result)
180 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
181};
182
183} // namespace art
184
185#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_