blob: 28c7fe2c3458be434866ad88868fa07fa97ba723 [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
Andreas Gampe5eb0d382015-07-23 01:19:26 -070017#include "dex_to_dex_compiler.h"
18
Andreas Gampe57943812017-12-06 21:39:13 -080019#include <android-base/logging.h>
20#include <android-base/stringprintf.h>
Andreas Gampe46ee31b2016-12-14 10:11:49 -080021
Mathieu Chartierc7853442015-03-27 14:35:38 -070022#include "art_field-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070023#include "art_method-inl.h"
Andreas Gampe170331f2017-12-07 18:41:03 -080024#include "base/logging.h" // For VLOG
Andreas Gampe57943812017-12-06 21:39:13 -080025#include "base/macros.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070026#include "base/mutex.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070027#include "bytecode_utils.h"
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010028#include "compiled_method.h"
David Sehr9e734c72018-01-04 17:56:19 -080029#include "dex/dex_file-inl.h"
30#include "dex/dex_instruction-inl.h"
Mathieu Chartiera79efdb2018-01-18 16:31:01 -080031#include "dex_to_dex_decompiler.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070032#include "driver/compiler_driver.h"
33#include "driver/dex_compilation_unit.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070034#include "mirror/dex_cache.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070035#include "quicken_info.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070036#include "thread-current-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070037
38namespace art {
39namespace optimizer {
40
Andreas Gampe46ee31b2016-12-14 10:11:49 -080041using android::base::StringPrintf;
42
Brian Carlstrom7940e442013-07-12 13:46:57 -070043// Controls quickening activation.
44const bool kEnableQuickening = true;
Sebastien Hertz543959c2013-07-03 12:00:19 +020045// Control check-cast elision.
46const bool kEnableCheckCastEllision = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -070047
Mathieu Chartiera79efdb2018-01-18 16:31:01 -080048DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
49 : driver_(driver),
50 lock_("Quicken lock", kDexToDexCompilerLock) {
51 DCHECK(driver != nullptr);
52}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010053
Mathieu Chartiera79efdb2018-01-18 16:31:01 -080054void DexToDexCompiler::ClearState() {
55 MutexLock lock(Thread::Current(), lock_);
56 active_dex_file_ = nullptr;
57 active_bit_vector_ = nullptr;
58 seen_code_items_.clear();
59 should_quicken_.clear();
60 shared_code_items_.clear();
61 blacklisted_code_items_.clear();
62 shared_code_item_quicken_info_.clear();
63}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010064
Mathieu Chartiera79efdb2018-01-18 16:31:01 -080065size_t DexToDexCompiler::NumUniqueCodeItems(Thread* self) const {
66 MutexLock lock(self, lock_);
67 return seen_code_items_.size();
68}
69
70BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
71 if (active_dex_file_ != dex_file) {
72 active_dex_file_ = dex_file;
73 auto inserted = should_quicken_.emplace(dex_file,
74 BitVector(dex_file->NumMethodIds(),
75 /*expandable*/ false,
76 Allocator::GetMallocAllocator()));
77 active_bit_vector_ = &inserted.first->second;
78 }
79 return active_bit_vector_;
80}
81
82void DexToDexCompiler::MarkForCompilation(Thread* self,
83 const MethodReference& method_ref,
84 const DexFile::CodeItem* code_item) {
85 MutexLock lock(self, lock_);
86 BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
87 DCHECK(bitmap != nullptr);
88 DCHECK(!bitmap->IsBitSet(method_ref.index));
89 bitmap->SetBit(method_ref.index);
90 // Detect the shared code items.
91 if (!seen_code_items_.insert(code_item).second) {
92 shared_code_items_.insert(code_item);
93 }
94}
95
96DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
97 const DexCompilationUnit& unit,
98 const CompilationLevel compilation_level,
99 const std::vector<uint8_t>* quicken_data)
100 : compiler_(compiler),
101 driver_(*compiler->GetDriver()),
Sebastien Hertz75021222013-07-16 18:34:50 +0200102 unit_(unit),
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800103 compilation_level_(compilation_level),
104 already_quickened_(quicken_data != nullptr),
105 existing_quicken_info_(already_quickened_
106 ? ArrayRef<const uint8_t>(*quicken_data) : ArrayRef<const uint8_t>()) {}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800108uint16_t DexToDexCompiler::CompilationState::NextIndex() {
109 DCHECK(already_quickened_);
110 if (kIsDebugBuild && quicken_index_ >= existing_quicken_info_.NumIndices()) {
111 for (const DexInstructionPcPair& pair : unit_.GetCodeItemAccessor()) {
112 LOG(ERROR) << pair->DumpString(nullptr);
113 }
114 LOG(FATAL) << "Mismatched number of quicken slots.";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100115 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800116 const uint16_t ret = existing_quicken_info_.GetData(quicken_index_);
117 quicken_index_++;
118 return ret;
119}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100120
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800121uint16_t DexToDexCompiler::CompilationState::GetIndexForInstruction(const Instruction* inst,
122 uint32_t index) {
123 if (UNLIKELY(already_quickened_)) {
124 return inst->IsQuickened() ? NextIndex() : index;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800126 DCHECK(!inst->IsQuickened());
127 return index;
128}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800130bool DexToDexCompiler::ShouldCompileMethod(const MethodReference& ref) {
131 // TODO: It's probably safe to avoid the lock here if the active_dex_file_ matches since we only
132 // only call ShouldCompileMethod on one dex at a time.
133 MutexLock lock(Thread::Current(), lock_);
134 return GetOrAddBitVectorForDex(ref.dex_file)->IsBitSet(ref.index);
135}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800137std::vector<uint8_t> DexToDexCompiler::CompilationState::Compile() {
138 DCHECK_EQ(compilation_level_, CompilationLevel::kOptimize);
139 const CodeItemDataAccessor& instructions = unit_.GetCodeItemAccessor();
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800140 for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
141 const uint32_t dex_pc = it.DexPc();
142 Instruction* inst = const_cast<Instruction*>(&it.Inst());
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800143
144 if (!already_quickened_) {
145 DCHECK(!inst->IsQuickened());
146 }
147
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 switch (inst->Opcode()) {
149 case Instruction::RETURN_VOID:
150 CompileReturnVoid(inst, dex_pc);
151 break;
152
Sebastien Hertz543959c2013-07-03 12:00:19 +0200153 case Instruction::CHECK_CAST:
154 inst = CompileCheckCast(inst, dex_pc);
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700155 if (inst->Opcode() == Instruction::NOP) {
156 // We turned the CHECK_CAST into two NOPs, avoid visiting the second NOP twice since this
157 // would add 2 quickening info entries.
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800158 ++it;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700159 }
Sebastien Hertz543959c2013-07-03 12:00:19 +0200160 break;
161
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 case Instruction::IGET:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800163 case Instruction::IGET_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
165 break;
166
167 case Instruction::IGET_WIDE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800168 case Instruction::IGET_WIDE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700169 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
170 break;
171
172 case Instruction::IGET_OBJECT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800173 case Instruction::IGET_OBJECT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
175 break;
176
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800177 case Instruction::IGET_BOOLEAN:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800178 case Instruction::IGET_BOOLEAN_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800179 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
180 break;
181
182 case Instruction::IGET_BYTE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800183 case Instruction::IGET_BYTE_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800184 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
185 break;
186
187 case Instruction::IGET_CHAR:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800188 case Instruction::IGET_CHAR_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800189 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
190 break;
191
192 case Instruction::IGET_SHORT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800193 case Instruction::IGET_SHORT_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800194 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
195 break;
196
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 case Instruction::IPUT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800198 case Instruction::IPUT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
200 break;
201
Fred Shih37f05ef2014-07-16 18:38:08 -0700202 case Instruction::IPUT_BOOLEAN:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800203 case Instruction::IPUT_BOOLEAN_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700204 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true);
205 break;
206
207 case Instruction::IPUT_BYTE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800208 case Instruction::IPUT_BYTE_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700209 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true);
210 break;
211
212 case Instruction::IPUT_CHAR:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800213 case Instruction::IPUT_CHAR_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700214 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true);
215 break;
216
217 case Instruction::IPUT_SHORT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800218 case Instruction::IPUT_SHORT_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700219 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true);
220 break;
221
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222 case Instruction::IPUT_WIDE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800223 case Instruction::IPUT_WIDE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
225 break;
226
227 case Instruction::IPUT_OBJECT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800228 case Instruction::IPUT_OBJECT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700229 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
230 break;
231
232 case Instruction::INVOKE_VIRTUAL:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800233 case Instruction::INVOKE_VIRTUAL_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
235 break;
236
237 case Instruction::INVOKE_VIRTUAL_RANGE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800238 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
240 break;
241
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700242 case Instruction::NOP:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800243 if (already_quickened_) {
244 const uint16_t reference_index = NextIndex();
245 quickened_info_.push_back(QuickenedInfo(dex_pc, reference_index));
246 if (reference_index == DexFile::kDexNoIndex16) {
247 // This means it was a normal nop and not a check-cast.
248 break;
249 }
250 const uint16_t type_index = NextIndex();
251 if (driver_.IsSafeCast(&unit_, dex_pc)) {
252 quickened_info_.push_back(QuickenedInfo(dex_pc, type_index));
253 }
254 ++it;
255 } else {
256 // We need to differentiate between check cast inserted NOP and normal NOP, put an invalid
257 // index in the map for normal nops. This should be rare in real code.
258 quickened_info_.push_back(QuickenedInfo(dex_pc, DexFile::kDexNoIndex16));
259 }
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700260 break;
261
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 default:
263 // Nothing to do.
264 break;
265 }
266 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800267
268 if (already_quickened_) {
269 DCHECK_EQ(quicken_index_, existing_quicken_info_.NumIndices());
270 }
271
272 if (GetQuickenedInfo().empty()) {
273 // No need to create a CompiledMethod if there are no quickened opcodes.
274 return std::vector<uint8_t>();
275 }
276
277 std::vector<uint8_t> quicken_data;
278 if (kIsDebugBuild) {
279 // Double check that the counts line up with the size of the quicken info.
280 size_t quicken_count = 0;
281 for (const DexInstructionPcPair& pair : instructions) {
282 if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
283 ++quicken_count;
284 }
285 }
286 CHECK_EQ(quicken_count, GetQuickenedInfo().size());
287 }
288
289 QuickenInfoTable::Builder builder(&quicken_data, GetQuickenedInfo().size());
290 // Length is encoded by the constructor.
291 for (const CompilationState::QuickenedInfo& info : GetQuickenedInfo()) {
292 // Dex pc is not serialized, only used for checking the instructions. Since we access the
293 // array based on the index of the quickened instruction, the indexes must line up perfectly.
294 // The reader side uses the NeedsIndexForInstruction function too.
295 const Instruction& inst = instructions.InstructionAt(info.dex_pc);
296 CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
297 builder.AddIndex(info.dex_member_index);
298 }
299 DCHECK(!quicken_data.empty());
300 return quicken_data;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301}
302
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800303void DexToDexCompiler::CompilationState::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700304 DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID);
305 if (unit_.IsConstructor()) {
306 // Are we compiling a non clinit constructor which needs a barrier ?
307 if (!unit_.IsStatic() &&
308 driver_.RequiresConstructorBarrier(Thread::Current(), unit_.GetDexFile(),
309 unit_.GetClassDefIndex())) {
310 return;
311 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 }
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700313 // Replace RETURN_VOID by RETURN_VOID_NO_BARRIER.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200314 VLOG(compiler) << "Replacing " << Instruction::Name(inst->Opcode())
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700315 << " by " << Instruction::Name(Instruction::RETURN_VOID_NO_BARRIER)
Sebastien Hertz543959c2013-07-03 12:00:19 +0200316 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700317 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700318 inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319}
320
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800321Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
322 uint32_t dex_pc) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700323 if (!kEnableCheckCastEllision) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200324 return inst;
325 }
Vladimir Marko2730db02014-01-27 11:15:17 +0000326 if (!driver_.IsSafeCast(&unit_, dex_pc)) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200327 return inst;
328 }
329 // Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
330 // units and a "nop" instruction size is 1 code unit, we need to replace it by
331 // 2 consecutive NOP instructions.
332 // Because the caller loops over instructions by calling Instruction::Next onto
333 // the current instruction, we need to return the 2nd NOP instruction. Indeed,
334 // its next instruction is the former check-cast's next instruction.
335 VLOG(compiler) << "Removing " << Instruction::Name(inst->Opcode())
336 << " by replacing it with 2 NOPs at dex pc "
337 << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700338 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800339 if (!already_quickened_) {
340 quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
341 quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
342
343 // We are modifying 4 consecutive bytes.
344 inst->SetOpcode(Instruction::NOP);
345 inst->SetVRegA_10x(0u); // keep compliant with verifier.
346 // Get to next instruction which is the second half of check-cast and replace
347 // it by a NOP.
348 inst = const_cast<Instruction*>(inst->Next());
349 inst->SetOpcode(Instruction::NOP);
350 inst->SetVRegA_10x(0u); // keep compliant with verifier.
351 }
Sebastien Hertz543959c2013-07-03 12:00:19 +0200352 return inst;
353}
354
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800355void DexToDexCompiler::CompilationState::CompileInstanceFieldAccess(Instruction* inst,
356 uint32_t dex_pc,
357 Instruction::Code new_opcode,
358 bool is_put) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700359 if (!kEnableQuickening) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360 return;
361 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800362 uint32_t field_idx = GetIndexForInstruction(inst, inst->VRegC_22c());
Vladimir Markobe0e5462014-02-26 11:24:15 +0000363 MemberOffset field_offset(0u);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 bool is_volatile;
Ian Rogers9b297bf2013-09-06 11:11:25 -0700365 bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
366 &field_offset, &is_volatile);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800367 if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200368 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
369 << " to " << Instruction::Name(new_opcode)
370 << " by replacing field index " << field_idx
Vladimir Markobe0e5462014-02-26 11:24:15 +0000371 << " by field offset " << field_offset.Int32Value()
Sebastien Hertz543959c2013-07-03 12:00:19 +0200372 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700373 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800374 if (!already_quickened_) {
375 // We are modifying 4 consecutive bytes.
376 inst->SetOpcode(new_opcode);
377 // Replace field index by field offset.
378 inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
379 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100380 quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 }
382}
383
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800384const DexFile& DexToDexCompiler::CompilationState::GetDexFile() const {
385 return *unit_.GetDexFile();
386}
387
388void DexToDexCompiler::CompilationState::CompileInvokeVirtual(Instruction* inst,
389 uint32_t dex_pc,
390 Instruction::Code new_opcode,
391 bool is_range) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700392 if (!kEnableQuickening) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700393 return;
394 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800395 uint32_t method_idx = GetIndexForInstruction(inst,
396 is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100397 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100398
399 ClassLinker* class_linker = unit_.GetClassLinker();
Vladimir Markoba118822017-06-12 15:41:56 +0100400 ArtMethod* resolved_method =
401 class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
Vladimir Markoba118822017-06-12 15:41:56 +0100402 method_idx,
403 unit_.GetDexCache(),
404 unit_.GetClassLoader(),
405 /* referrer */ nullptr,
406 kVirtual);
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100407
408 if (UNLIKELY(resolved_method == nullptr)) {
409 // Clean up any exception left by type resolution.
410 soa.Self()->ClearException();
411 return;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700412 }
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100413
414 uint32_t vtable_idx = resolved_method->GetMethodIndex();
415 DCHECK(IsUint<16>(vtable_idx));
416 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
David Sehr709b0702016-10-13 09:12:37 -0700417 << "(" << GetDexFile().PrettyMethod(method_idx, true) << ")"
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100418 << " to " << Instruction::Name(new_opcode)
419 << " by replacing method index " << method_idx
420 << " by vtable index " << vtable_idx
421 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700422 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800423 if (!already_quickened_) {
424 // We are modifying 4 consecutive bytes.
425 inst->SetOpcode(new_opcode);
426 // Replace method index by vtable index.
427 if (is_range) {
428 inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
429 } else {
430 inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
431 }
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100432 }
433 quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434}
435
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800436CompiledMethod* DexToDexCompiler::CompileMethod(
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700437 const DexFile::CodeItem* code_item,
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100438 uint32_t access_flags,
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700439 InvokeType invoke_type ATTRIBUTE_UNUSED,
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100440 uint16_t class_def_idx,
441 uint32_t method_idx,
Vladimir Marko8d6768d2017-03-14 10:13:21 +0000442 Handle<mirror::ClassLoader> class_loader,
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700443 const DexFile& dex_file,
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800444 CompilationLevel compilation_level) {
445 if (compilation_level == CompilationLevel::kDontDexToDexCompile) {
446 return nullptr;
447 }
448
449 ScopedObjectAccess soa(Thread::Current());
450 StackHandleScope<1> hs(soa.Self());
451 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
452 art::DexCompilationUnit unit(
453 class_loader,
454 class_linker,
455 dex_file,
456 code_item,
457 class_def_idx,
458 method_idx,
459 access_flags,
460 driver_->GetVerifiedMethod(&dex_file, method_idx),
461 hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
462
463 std::vector<uint8_t> quicken_data;
464 // If the code item is shared with multiple different method ids, make sure that we quicken only
465 // once and verify that all the dequicken maps match.
466 if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
467 // For shared code items, use a lock to prevent races.
468 MutexLock mu(soa.Self(), lock_);
469 // Blacklisted means there was a quickening conflict previously, bail early.
470 if (blacklisted_code_items_.find(code_item) != blacklisted_code_items_.end()) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100471 return nullptr;
472 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800473 auto existing = shared_code_item_quicken_info_.find(code_item);
474 const bool already_quickened = existing != shared_code_item_quicken_info_.end();
475 {
476 CompilationState state(this,
477 unit,
478 compilation_level,
479 already_quickened ? &existing->second.quicken_data_ : nullptr);
480 quicken_data = state.Compile();
481 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100482
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800483 // Already quickened, check that the data matches what was previously seen.
484 MethodReference method_ref(&dex_file, method_idx);
485 if (already_quickened) {
486 QuickenState* const existing_data = &existing->second;
487 if (existing_data->quicken_data_ != quicken_data) {
488 VLOG(compiler) << "Quicken data mismatch, dequickening method "
489 << dex_file.PrettyMethod(method_idx);
490 // Unquicken using the existing quicken data.
491 optimizer::ArtDecompileDEX(dex_file,
492 *code_item,
493 ArrayRef<const uint8_t>(existing_data->quicken_data_),
494 /* decompile_return_instruction*/ false);
495 // Go clear the vmaps for all the methods that were already quickened to avoid writing them
496 // out during oat writing.
497 for (const MethodReference& ref : existing_data->methods_) {
498 CompiledMethod* method = driver_->GetCompiledMethod(ref);
499 DCHECK(method != nullptr);
500 method->ReleaseVMapTable();
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700501 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800502 // Blacklist the method to never attempt to quicken it in the future.
503 blacklisted_code_items_.insert(code_item);
504 shared_code_item_quicken_info_.erase(existing);
505 return nullptr;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700506 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800507 existing_data->methods_.push_back(method_ref);
508 } else {
509 QuickenState new_state;
510 new_state.methods_.push_back(method_ref);
511 new_state.quicken_data_ = quicken_data;
512 bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
513 CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700514 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800515
516 // Easy sanity check is to check that the existing stuff matches by re-quickening using the
517 // newly produced quicken data.
518 // Note that this needs to be behind the lock for this case since we may unquicken in another
519 // thread.
520 if (kIsDebugBuild) {
521 CompilationState state2(this, unit, compilation_level, &quicken_data);
522 std::vector<uint8_t> new_data = state2.Compile();
523 CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100524 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800525 } else {
526 CompilationState state(this, unit, compilation_level, /*quicken_data*/ nullptr);
527 quicken_data = state.Compile();
528
529 // Easy sanity check is to check that the existing stuff matches by re-quickening using the
530 // newly produced quicken data.
531 if (kIsDebugBuild) {
532 CompilationState state2(this, unit, compilation_level, &quicken_data);
533 std::vector<uint8_t> new_data = state2.Compile();
534 CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100535 }
Sebastien Hertz75021222013-07-16 18:34:50 +0200536 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800537
538 if (quicken_data.empty()) {
539 return nullptr;
540 }
541
542 // Create a `CompiledMethod`, with the quickened information in the vmap table.
543 InstructionSet instruction_set = driver_->GetInstructionSet();
544 if (instruction_set == InstructionSet::kThumb2) {
545 // Don't use the thumb2 instruction set to avoid the one off code delta.
546 instruction_set = InstructionSet::kArm;
547 }
548 CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod(
549 driver_,
550 instruction_set,
551 ArrayRef<const uint8_t>(), // no code
552 0,
553 0,
554 0,
555 ArrayRef<const uint8_t>(), // method_info
556 ArrayRef<const uint8_t>(quicken_data), // vmap_table
557 ArrayRef<const uint8_t>(), // cfi data
558 ArrayRef<const linker::LinkerPatch>());
559 return ret;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100561
562} // namespace optimizer
563
564} // namespace art