blob: 8e1a4083cdf89cae4d5b1100832d27b7966b8e52 [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"
24
25/*
26 * NOTE: This code is part of the quick compiler. It lives in the runtime
27 * only to allow the debugger to check whether a method has been inlined.
28 */
29
30namespace art {
31
32namespace verifier {
33class MethodVerifier;
34} // namespace verifier
35
36enum InlineMethodOpcode : uint16_t {
37 kIntrinsicDoubleCvt,
38 kIntrinsicFloatCvt,
39 kIntrinsicReverseBytes,
40 kIntrinsicAbsInt,
41 kIntrinsicAbsLong,
42 kIntrinsicAbsFloat,
43 kIntrinsicAbsDouble,
44 kIntrinsicMinMaxInt,
45 kIntrinsicSqrt,
46 kIntrinsicCharAt,
47 kIntrinsicCompareTo,
48 kIntrinsicIsEmptyOrLength,
49 kIntrinsicIndexOf,
50 kIntrinsicCurrentThread,
51 kIntrinsicPeek,
52 kIntrinsicPoke,
53 kIntrinsicCas,
54 kIntrinsicUnsafeGet,
55 kIntrinsicUnsafePut,
56
57 kInlineOpNop,
58 kInlineOpReturnArg,
59 kInlineOpNonWideConst,
60 kInlineOpIGet,
61 kInlineOpIPut,
62};
63std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
64
65enum InlineMethodFlags : uint16_t {
66 kNoInlineMethodFlags = 0x0000,
67 kInlineIntrinsic = 0x0001,
68 kInlineSpecial = 0x0002,
69};
70
71// IntrinsicFlags are stored in InlineMethod::d::raw_data
72enum IntrinsicFlags {
73 kIntrinsicFlagNone = 0,
74
75 // kIntrinsicMinMaxInt
76 kIntrinsicFlagMax = kIntrinsicFlagNone,
77 kIntrinsicFlagMin = 1,
78
79 // kIntrinsicIsEmptyOrLength
80 kIntrinsicFlagLength = kIntrinsicFlagNone,
81 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
82
83 // kIntrinsicIndexOf
84 kIntrinsicFlagBase0 = kIntrinsicFlagMin,
85
86 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
87 kIntrinsicFlagIsLong = kIntrinsicFlagMin,
88 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
89 kIntrinsicFlagIsVolatile = 2,
90 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
91 kIntrinsicFlagIsObject = 4,
92 // kIntrinsicUnsafePut
93 kIntrinsicFlagIsOrdered = 8,
94};
95
96struct InlineIGetIPutData {
97 // The op_variant below is opcode-Instruction::IGET for IGETs and
98 // opcode-Instruction::IPUT for IPUTs. This is because the runtime
99 // doesn't know the OpSize enumeration.
100 uint16_t op_variant : 3;
101 uint16_t object_arg : 4;
102 uint16_t src_arg : 4; // iput only
103 uint16_t method_is_static : 1;
104 uint16_t reserved : 4;
105 uint16_t field_idx;
106 uint32_t is_volatile : 1;
107 uint32_t field_offset : 31;
108};
109COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
110
111struct InlineReturnArgData {
112 uint16_t arg;
113 uint16_t is_wide : 1;
114 uint16_t is_object : 1;
115 uint16_t reserved : 14;
116 uint32_t reserved2;
117};
118COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
119
120struct InlineMethod {
121 InlineMethodOpcode opcode;
122 InlineMethodFlags flags;
123 union {
124 uint64_t data;
125 InlineIGetIPutData ifield_data;
126 InlineReturnArgData return_data;
127 } d;
128};
129
130class InlineMethodAnalyser {
131 public:
132 /**
133 * Analyse method code to determine if the method is a candidate for inlining.
134 * If it is, record the inlining data.
135 *
136 * @param verifier the method verifier holding data about the method to analyse.
137 * @param method placeholder for the inline method data.
138 * @return true if the method is a candidate for inlining, false otherwise.
139 */
140 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
141 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
142
143 static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
144 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
145 }
146
147 static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
148 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
149 }
150
151 static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
152 return opcode - Instruction::IGET;
153 }
154
155 static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
156 return opcode - Instruction::IPUT;
157 }
158
159 private:
160 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
161 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
162 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
163 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
164 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
165 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
166
167 // Can we fast path instance field access in a verified accessor?
168 // If yes, computes field's offset and volatility and whether the method is static or not.
169 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
170 verifier::MethodVerifier* verifier,
171 InlineIGetIPutData* result)
172 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
173};
174
175} // namespace art
176
177#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_