blob: 4b56b69a11f18b3201fbd0381c84bdd29e12b434 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2011 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
Mathieu Chartierc7853442015-03-27 14:35:38 -070017#include "art_field-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070018#include "art_method-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070019#include "base/logging.h"
20#include "base/mutex.h"
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010021#include "compiled_method.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "dex_file-inl.h"
23#include "dex_instruction-inl.h"
24#include "driver/compiler_driver.h"
25#include "driver/dex_compilation_unit.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070026#include "mirror/class-inl.h"
27#include "mirror/dex_cache.h"
Ian Rogers02ed4c02013-09-06 13:10:04 -070028#include "thread-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070029
30namespace art {
31namespace optimizer {
32
33// Controls quickening activation.
34const bool kEnableQuickening = true;
Sebastien Hertz543959c2013-07-03 12:00:19 +020035// Control check-cast elision.
36const bool kEnableCheckCastEllision = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -070037
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010038struct QuickenedInfo {
39 QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
40
41 uint32_t dex_pc;
42 uint16_t dex_member_index;
43};
44
Brian Carlstrom7940e442013-07-12 13:46:57 -070045class DexCompiler {
46 public:
47 DexCompiler(art::CompilerDriver& compiler,
Sebastien Hertz75021222013-07-16 18:34:50 +020048 const DexCompilationUnit& unit,
49 DexToDexCompilationLevel dex_to_dex_compilation_level)
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 : driver_(compiler),
Sebastien Hertz75021222013-07-16 18:34:50 +020051 unit_(unit),
52 dex_to_dex_compilation_level_(dex_to_dex_compilation_level) {}
Brian Carlstrom7940e442013-07-12 13:46:57 -070053
Brian Carlstrom9b7085a2013-07-18 15:15:21 -070054 ~DexCompiler() {}
Brian Carlstrom7940e442013-07-12 13:46:57 -070055
56 void Compile();
57
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010058 const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
59 return quickened_info_;
60 }
61
Brian Carlstrom7940e442013-07-12 13:46:57 -070062 private:
63 const DexFile& GetDexFile() const {
64 return *unit_.GetDexFile();
65 }
66
Sebastien Hertz75021222013-07-16 18:34:50 +020067 bool PerformOptimizations() const {
68 return dex_to_dex_compilation_level_ >= kOptimize;
69 }
70
Brian Carlstrom7940e442013-07-12 13:46:57 -070071 // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
72 // a barrier is required.
73 void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
74
Sebastien Hertz543959c2013-07-03 12:00:19 +020075 // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
76 // this case, returns the second NOP instruction pointer. Otherwise, returns
77 // the given "inst".
78 Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
79
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 // Compiles a field access into a quick field access.
81 // The field index is replaced by an offset within an Object where we can read
82 // from / write to this field. Therefore, this does not involve any resolution
83 // at runtime.
84 // Since the field index is encoded with 16 bits, we can replace it only if the
85 // field offset can be encoded with 16 bits too.
86 void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
87 Instruction::Code new_opcode, bool is_put);
88
89 // Compiles a virtual method invocation into a quick virtual method invocation.
90 // The method index is replaced by the vtable index where the corresponding
91 // AbstractMethod can be found. Therefore, this does not involve any resolution
92 // at runtime.
93 // Since the method index is encoded with 16 bits, we can replace it only if the
94 // vtable index can be encoded with 16 bits too.
95 void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
96 Instruction::Code new_opcode, bool is_range);
97
98 CompilerDriver& driver_;
99 const DexCompilationUnit& unit_;
Sebastien Hertz75021222013-07-16 18:34:50 +0200100 const DexToDexCompilationLevel dex_to_dex_compilation_level_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700101
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100102 // Filled by the compiler when quickening, in order to encode that information
103 // in the .oat file. The runtime will use that information to get to the original
104 // opcodes.
105 std::vector<QuickenedInfo> quickened_info_;
106
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 DISALLOW_COPY_AND_ASSIGN(DexCompiler);
108};
109
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110void DexCompiler::Compile() {
Sebastien Hertz75021222013-07-16 18:34:50 +0200111 DCHECK_GE(dex_to_dex_compilation_level_, kRequired);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700112 const DexFile::CodeItem* code_item = unit_.GetCodeItem();
113 const uint16_t* insns = code_item->insns_;
114 const uint32_t insns_size = code_item->insns_size_in_code_units_;
115 Instruction* inst = const_cast<Instruction*>(Instruction::At(insns));
116
117 for (uint32_t dex_pc = 0; dex_pc < insns_size;
118 inst = const_cast<Instruction*>(inst->Next()), dex_pc = inst->GetDexPc(insns)) {
119 switch (inst->Opcode()) {
120 case Instruction::RETURN_VOID:
121 CompileReturnVoid(inst, dex_pc);
122 break;
123
Sebastien Hertz543959c2013-07-03 12:00:19 +0200124 case Instruction::CHECK_CAST:
125 inst = CompileCheckCast(inst, dex_pc);
126 break;
127
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128 case Instruction::IGET:
129 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
130 break;
131
132 case Instruction::IGET_WIDE:
133 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
134 break;
135
136 case Instruction::IGET_OBJECT:
137 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
138 break;
139
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800140 case Instruction::IGET_BOOLEAN:
141 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
142 break;
143
144 case Instruction::IGET_BYTE:
145 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
146 break;
147
148 case Instruction::IGET_CHAR:
149 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
150 break;
151
152 case Instruction::IGET_SHORT:
153 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
154 break;
155
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 case Instruction::IPUT:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
158 break;
159
Fred Shih37f05ef2014-07-16 18:38:08 -0700160 case Instruction::IPUT_BOOLEAN:
161 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true);
162 break;
163
164 case Instruction::IPUT_BYTE:
165 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true);
166 break;
167
168 case Instruction::IPUT_CHAR:
169 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true);
170 break;
171
172 case Instruction::IPUT_SHORT:
173 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true);
174 break;
175
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176 case Instruction::IPUT_WIDE:
177 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
178 break;
179
180 case Instruction::IPUT_OBJECT:
181 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
182 break;
183
184 case Instruction::INVOKE_VIRTUAL:
185 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
186 break;
187
188 case Instruction::INVOKE_VIRTUAL_RANGE:
189 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
190 break;
191
192 default:
193 // Nothing to do.
194 break;
195 }
196 }
197}
198
199void DexCompiler::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700200 DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID);
201 if (unit_.IsConstructor()) {
202 // Are we compiling a non clinit constructor which needs a barrier ?
203 if (!unit_.IsStatic() &&
204 driver_.RequiresConstructorBarrier(Thread::Current(), unit_.GetDexFile(),
205 unit_.GetClassDefIndex())) {
206 return;
207 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 }
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700209 // Replace RETURN_VOID by RETURN_VOID_NO_BARRIER.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200210 VLOG(compiler) << "Replacing " << Instruction::Name(inst->Opcode())
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700211 << " by " << Instruction::Name(Instruction::RETURN_VOID_NO_BARRIER)
Sebastien Hertz543959c2013-07-03 12:00:19 +0200212 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
213 << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700214 inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215}
216
Sebastien Hertz543959c2013-07-03 12:00:19 +0200217Instruction* DexCompiler::CompileCheckCast(Instruction* inst, uint32_t dex_pc) {
Sebastien Hertz75021222013-07-16 18:34:50 +0200218 if (!kEnableCheckCastEllision || !PerformOptimizations()) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200219 return inst;
220 }
Vladimir Marko2730db02014-01-27 11:15:17 +0000221 if (!driver_.IsSafeCast(&unit_, dex_pc)) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200222 return inst;
223 }
224 // Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
225 // units and a "nop" instruction size is 1 code unit, we need to replace it by
226 // 2 consecutive NOP instructions.
227 // Because the caller loops over instructions by calling Instruction::Next onto
228 // the current instruction, we need to return the 2nd NOP instruction. Indeed,
229 // its next instruction is the former check-cast's next instruction.
230 VLOG(compiler) << "Removing " << Instruction::Name(inst->Opcode())
231 << " by replacing it with 2 NOPs at dex pc "
232 << StringPrintf("0x%x", dex_pc) << " in method "
233 << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
234 // We are modifying 4 consecutive bytes.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200235 inst->SetOpcode(Instruction::NOP);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700236 inst->SetVRegA_10x(0u); // keep compliant with verifier.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200237 // Get to next instruction which is the second half of check-cast and replace
238 // it by a NOP.
239 inst = const_cast<Instruction*>(inst->Next());
240 inst->SetOpcode(Instruction::NOP);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700241 inst->SetVRegA_10x(0u); // keep compliant with verifier.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200242 return inst;
243}
244
Brian Carlstrom7940e442013-07-12 13:46:57 -0700245void DexCompiler::CompileInstanceFieldAccess(Instruction* inst,
246 uint32_t dex_pc,
247 Instruction::Code new_opcode,
248 bool is_put) {
Sebastien Hertz75021222013-07-16 18:34:50 +0200249 if (!kEnableQuickening || !PerformOptimizations()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 return;
251 }
252 uint32_t field_idx = inst->VRegC_22c();
Vladimir Markobe0e5462014-02-26 11:24:15 +0000253 MemberOffset field_offset(0u);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 bool is_volatile;
Ian Rogers9b297bf2013-09-06 11:11:25 -0700255 bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
256 &field_offset, &is_volatile);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800257 if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200258 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
259 << " to " << Instruction::Name(new_opcode)
260 << " by replacing field index " << field_idx
Vladimir Markobe0e5462014-02-26 11:24:15 +0000261 << " by field offset " << field_offset.Int32Value()
Sebastien Hertz543959c2013-07-03 12:00:19 +0200262 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
263 << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 // We are modifying 4 consecutive bytes.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700265 inst->SetOpcode(new_opcode);
266 // Replace field index by field offset.
Vladimir Markobe0e5462014-02-26 11:24:15 +0000267 inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100268 quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 }
270}
271
Mathieu Chartier091d2382015-03-06 10:59:06 -0800272void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
273 Instruction::Code new_opcode, bool is_range) {
Sebastien Hertz75021222013-07-16 18:34:50 +0200274 if (!kEnableQuickening || !PerformOptimizations()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 return;
276 }
277 uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
278 MethodReference target_method(&GetDexFile(), method_idx);
279 InvokeType invoke_type = kVirtual;
280 InvokeType original_invoke_type = invoke_type;
281 int vtable_idx;
282 uintptr_t direct_code;
283 uintptr_t direct_method;
Sebastien Hertz1e54d682013-09-06 14:52:10 +0200284 // TODO: support devirtualization.
285 const bool kEnableDevirtualization = false;
Ian Rogers65ec92c2013-09-06 10:49:58 -0700286 bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc,
287 false, kEnableDevirtualization,
288 &invoke_type,
289 &target_method, &vtable_idx,
290 &direct_code, &direct_method);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 if (fast_path && original_invoke_type == invoke_type) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800292 if (vtable_idx >= 0 && IsUint<16>(vtable_idx)) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200293 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
294 << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
295 << " to " << Instruction::Name(new_opcode)
296 << " by replacing method index " << method_idx
297 << " by vtable index " << vtable_idx
298 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
299 << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 // We are modifying 4 consecutive bytes.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 inst->SetOpcode(new_opcode);
302 // Replace method index by vtable index.
303 if (is_range) {
304 inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
305 } else {
306 inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
307 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100308 quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 }
310 }
311}
312
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100313extern "C" CompiledMethod* ArtCompileDEX(
314 art::CompilerDriver& driver,
315 const art::DexFile::CodeItem* code_item,
316 uint32_t access_flags,
317 art::InvokeType invoke_type ATTRIBUTE_UNUSED,
318 uint16_t class_def_idx,
319 uint32_t method_idx,
320 jobject class_loader,
321 const art::DexFile& dex_file,
322 art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
Sebastien Hertz75021222013-07-16 18:34:50 +0200323 if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700324 art::DexCompilationUnit unit(nullptr, class_loader, art::Runtime::Current()->GetClassLinker(),
Vladimir Marko2730db02014-01-27 11:15:17 +0000325 dex_file, code_item, class_def_idx, method_idx, access_flags,
326 driver.GetVerifiedMethod(&dex_file, method_idx));
327 art::optimizer::DexCompiler dex_compiler(driver, unit, dex_to_dex_compilation_level);
Sebastien Hertz75021222013-07-16 18:34:50 +0200328 dex_compiler.Compile();
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100329 if (dex_compiler.GetQuickenedInfo().empty()) {
330 // No need to create a CompiledMethod if there are no quickened opcodes.
331 return nullptr;
332 }
333
334 // Create a `CompiledMethod`, with the quickened information in the vmap table.
335 Leb128EncodingVector builder;
336 for (QuickenedInfo info : dex_compiler.GetQuickenedInfo()) {
337 builder.PushBackUnsigned(info.dex_pc);
338 builder.PushBackUnsigned(info.dex_member_index);
339 }
340 InstructionSet instruction_set = driver.GetInstructionSet();
341 if (instruction_set == kThumb2) {
342 // Don't use the thumb2 instruction set to avoid the one off code delta.
343 instruction_set = kArm;
344 }
345 return CompiledMethod::SwapAllocCompiledMethod(
346 &driver,
347 instruction_set,
348 ArrayRef<const uint8_t>(), // no code
349 0,
350 0,
351 0,
352 nullptr, // src_mapping_table
353 ArrayRef<const uint8_t>(), // mapping_table
354 ArrayRef<const uint8_t>(builder.GetData()), // vmap_table
355 ArrayRef<const uint8_t>(), // gc_map
356 ArrayRef<const uint8_t>(), // cfi data
357 ArrayRef<const LinkerPatch>());
Sebastien Hertz75021222013-07-16 18:34:50 +0200358 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100359 return nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100361
362} // namespace optimizer
363
364} // namespace art