blob: fb6a72b1c524664c9fbcc88ebcd089279f24ac1c [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"
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +010027#include "compiled_method.h"
David Sehr312f3b22018-03-19 08:39:26 -070028#include "dex/bytecode_utils.h"
Mathieu Chartierc8c8d5f2018-05-22 11:56:14 -070029#include "dex/class_accessor-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080030#include "dex/dex_file-inl.h"
31#include "dex/dex_instruction-inl.h"
Mathieu Chartiera79efdb2018-01-18 16:31:01 -080032#include "dex_to_dex_decompiler.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070033#include "driver/compiler_driver.h"
34#include "driver/dex_compilation_unit.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070035#include "mirror/dex_cache.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070036#include "quicken_info.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070037#include "thread-current-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070038
39namespace art {
40namespace optimizer {
41
Andreas Gampe46ee31b2016-12-14 10:11:49 -080042using android::base::StringPrintf;
43
Brian Carlstrom7940e442013-07-12 13:46:57 -070044// Controls quickening activation.
45const bool kEnableQuickening = true;
Sebastien Hertz543959c2013-07-03 12:00:19 +020046// Control check-cast elision.
47const bool kEnableCheckCastEllision = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -070048
Mathieu Chartier279e3a32018-01-24 18:17:55 -080049// Holds the state for compiling a single method.
50struct DexToDexCompiler::CompilationState {
51 struct QuickenedInfo {
52 QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
53
54 uint32_t dex_pc;
55 uint16_t dex_member_index;
56 };
57
58 CompilationState(DexToDexCompiler* compiler,
59 const DexCompilationUnit& unit,
60 const CompilationLevel compilation_level,
61 const std::vector<uint8_t>* quicken_data);
62
63 const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
64 return quickened_info_;
65 }
66
67 // Returns the quickening info, or an empty array if it was not quickened.
68 // If already_quickened is true, then don't change anything but still return what the quicken
69 // data would have been.
70 std::vector<uint8_t> Compile();
71
72 const DexFile& GetDexFile() const;
73
74 // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
75 // a barrier is required.
76 void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
77
78 // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
79 // this case, returns the second NOP instruction pointer. Otherwise, returns
80 // the given "inst".
81 Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
82
83 // Compiles a field access into a quick field access.
84 // The field index is replaced by an offset within an Object where we can read
85 // from / write to this field. Therefore, this does not involve any resolution
86 // at runtime.
87 // Since the field index is encoded with 16 bits, we can replace it only if the
88 // field offset can be encoded with 16 bits too.
89 void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
90 Instruction::Code new_opcode, bool is_put);
91
92 // Compiles a virtual method invocation into a quick virtual method invocation.
93 // The method index is replaced by the vtable index where the corresponding
94 // executable can be found. Therefore, this does not involve any resolution
95 // at runtime.
96 // Since the method index is encoded with 16 bits, we can replace it only if the
97 // vtable index can be encoded with 16 bits too.
98 void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
99 Instruction::Code new_opcode, bool is_range);
100
101 // Return the next index.
102 uint16_t NextIndex();
103
104 // Returns the dequickened index if an instruction is quickened, otherwise return index.
105 uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
106
107 DexToDexCompiler* const compiler_;
108 CompilerDriver& driver_;
109 const DexCompilationUnit& unit_;
110 const CompilationLevel compilation_level_;
111
112 // Filled by the compiler when quickening, in order to encode that information
113 // in the .oat file. The runtime will use that information to get to the original
114 // opcodes.
115 std::vector<QuickenedInfo> quickened_info_;
116
117 // True if we optimized a return void to a return void no barrier.
118 bool optimized_return_void_ = false;
119
120 // If the code item was already quickened previously.
121 const bool already_quickened_;
122 const QuickenInfoTable existing_quicken_info_;
123 uint32_t quicken_index_ = 0u;
124
125 DISALLOW_COPY_AND_ASSIGN(CompilationState);
126};
127
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800128DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
129 : driver_(driver),
130 lock_("Quicken lock", kDexToDexCompilerLock) {
131 DCHECK(driver != nullptr);
132}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100133
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800134void DexToDexCompiler::ClearState() {
135 MutexLock lock(Thread::Current(), lock_);
136 active_dex_file_ = nullptr;
137 active_bit_vector_ = nullptr;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800138 should_quicken_.clear();
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800139 shared_code_item_quicken_info_.clear();
140}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100141
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800142size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const {
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800143 MutexLock lock(self, lock_);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800144 return num_code_items_;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800145}
146
147BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
148 if (active_dex_file_ != dex_file) {
149 active_dex_file_ = dex_file;
150 auto inserted = should_quicken_.emplace(dex_file,
151 BitVector(dex_file->NumMethodIds(),
152 /*expandable*/ false,
153 Allocator::GetMallocAllocator()));
154 active_bit_vector_ = &inserted.first->second;
155 }
156 return active_bit_vector_;
157}
158
159void DexToDexCompiler::MarkForCompilation(Thread* self,
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800160 const MethodReference& method_ref) {
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800161 MutexLock lock(self, lock_);
162 BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
163 DCHECK(bitmap != nullptr);
164 DCHECK(!bitmap->IsBitSet(method_ref.index));
165 bitmap->SetBit(method_ref.index);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800166 ++num_code_items_;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800167}
168
169DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
170 const DexCompilationUnit& unit,
171 const CompilationLevel compilation_level,
172 const std::vector<uint8_t>* quicken_data)
173 : compiler_(compiler),
174 driver_(*compiler->GetDriver()),
Sebastien Hertz75021222013-07-16 18:34:50 +0200175 unit_(unit),
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800176 compilation_level_(compilation_level),
177 already_quickened_(quicken_data != nullptr),
178 existing_quicken_info_(already_quickened_
179 ? ArrayRef<const uint8_t>(*quicken_data) : ArrayRef<const uint8_t>()) {}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700180
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800181uint16_t DexToDexCompiler::CompilationState::NextIndex() {
182 DCHECK(already_quickened_);
183 if (kIsDebugBuild && quicken_index_ >= existing_quicken_info_.NumIndices()) {
184 for (const DexInstructionPcPair& pair : unit_.GetCodeItemAccessor()) {
185 LOG(ERROR) << pair->DumpString(nullptr);
186 }
187 LOG(FATAL) << "Mismatched number of quicken slots.";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100188 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800189 const uint16_t ret = existing_quicken_info_.GetData(quicken_index_);
190 quicken_index_++;
191 return ret;
192}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100193
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800194uint16_t DexToDexCompiler::CompilationState::GetIndexForInstruction(const Instruction* inst,
195 uint32_t index) {
196 if (UNLIKELY(already_quickened_)) {
197 return inst->IsQuickened() ? NextIndex() : index;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800199 DCHECK(!inst->IsQuickened());
200 return index;
201}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700202
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800203bool DexToDexCompiler::ShouldCompileMethod(const MethodReference& ref) {
204 // TODO: It's probably safe to avoid the lock here if the active_dex_file_ matches since we only
205 // only call ShouldCompileMethod on one dex at a time.
206 MutexLock lock(Thread::Current(), lock_);
207 return GetOrAddBitVectorForDex(ref.dex_file)->IsBitSet(ref.index);
208}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800210std::vector<uint8_t> DexToDexCompiler::CompilationState::Compile() {
211 DCHECK_EQ(compilation_level_, CompilationLevel::kOptimize);
212 const CodeItemDataAccessor& instructions = unit_.GetCodeItemAccessor();
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800213 for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
214 const uint32_t dex_pc = it.DexPc();
215 Instruction* inst = const_cast<Instruction*>(&it.Inst());
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800216
217 if (!already_quickened_) {
218 DCHECK(!inst->IsQuickened());
219 }
220
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221 switch (inst->Opcode()) {
222 case Instruction::RETURN_VOID:
223 CompileReturnVoid(inst, dex_pc);
224 break;
225
Sebastien Hertz543959c2013-07-03 12:00:19 +0200226 case Instruction::CHECK_CAST:
227 inst = CompileCheckCast(inst, dex_pc);
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700228 if (inst->Opcode() == Instruction::NOP) {
229 // We turned the CHECK_CAST into two NOPs, avoid visiting the second NOP twice since this
230 // would add 2 quickening info entries.
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800231 ++it;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700232 }
Sebastien Hertz543959c2013-07-03 12:00:19 +0200233 break;
234
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235 case Instruction::IGET:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800236 case Instruction::IGET_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
238 break;
239
240 case Instruction::IGET_WIDE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800241 case Instruction::IGET_WIDE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
243 break;
244
245 case Instruction::IGET_OBJECT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800246 case Instruction::IGET_OBJECT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700247 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
248 break;
249
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800250 case Instruction::IGET_BOOLEAN:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800251 case Instruction::IGET_BOOLEAN_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800252 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
253 break;
254
255 case Instruction::IGET_BYTE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800256 case Instruction::IGET_BYTE_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800257 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
258 break;
259
260 case Instruction::IGET_CHAR:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800261 case Instruction::IGET_CHAR_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800262 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
263 break;
264
265 case Instruction::IGET_SHORT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800266 case Instruction::IGET_SHORT_QUICK:
Mathieu Chartierffc605c2014-12-10 10:35:44 -0800267 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
268 break;
269
Brian Carlstrom7940e442013-07-12 13:46:57 -0700270 case Instruction::IPUT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800271 case Instruction::IPUT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700272 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
273 break;
274
Fred Shih37f05ef2014-07-16 18:38:08 -0700275 case Instruction::IPUT_BOOLEAN:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800276 case Instruction::IPUT_BOOLEAN_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700277 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true);
278 break;
279
280 case Instruction::IPUT_BYTE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800281 case Instruction::IPUT_BYTE_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700282 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true);
283 break;
284
285 case Instruction::IPUT_CHAR:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800286 case Instruction::IPUT_CHAR_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700287 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true);
288 break;
289
290 case Instruction::IPUT_SHORT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800291 case Instruction::IPUT_SHORT_QUICK:
Fred Shih37f05ef2014-07-16 18:38:08 -0700292 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true);
293 break;
294
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 case Instruction::IPUT_WIDE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800296 case Instruction::IPUT_WIDE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
298 break;
299
300 case Instruction::IPUT_OBJECT:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800301 case Instruction::IPUT_OBJECT_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
303 break;
304
305 case Instruction::INVOKE_VIRTUAL:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800306 case Instruction::INVOKE_VIRTUAL_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
308 break;
309
310 case Instruction::INVOKE_VIRTUAL_RANGE:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800311 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
313 break;
314
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700315 case Instruction::NOP:
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800316 if (already_quickened_) {
317 const uint16_t reference_index = NextIndex();
318 quickened_info_.push_back(QuickenedInfo(dex_pc, reference_index));
319 if (reference_index == DexFile::kDexNoIndex16) {
320 // This means it was a normal nop and not a check-cast.
321 break;
322 }
323 const uint16_t type_index = NextIndex();
324 if (driver_.IsSafeCast(&unit_, dex_pc)) {
325 quickened_info_.push_back(QuickenedInfo(dex_pc, type_index));
326 }
327 ++it;
328 } else {
329 // We need to differentiate between check cast inserted NOP and normal NOP, put an invalid
330 // index in the map for normal nops. This should be rare in real code.
331 quickened_info_.push_back(QuickenedInfo(dex_pc, DexFile::kDexNoIndex16));
332 }
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700333 break;
334
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 default:
336 // Nothing to do.
337 break;
338 }
339 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800340
341 if (already_quickened_) {
342 DCHECK_EQ(quicken_index_, existing_quicken_info_.NumIndices());
343 }
344
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800345 // Even if there are no indicies, generate an empty quicken info so that we know the method was
346 // quickened.
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800347
348 std::vector<uint8_t> quicken_data;
349 if (kIsDebugBuild) {
350 // Double check that the counts line up with the size of the quicken info.
351 size_t quicken_count = 0;
352 for (const DexInstructionPcPair& pair : instructions) {
353 if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
354 ++quicken_count;
355 }
356 }
357 CHECK_EQ(quicken_count, GetQuickenedInfo().size());
358 }
359
360 QuickenInfoTable::Builder builder(&quicken_data, GetQuickenedInfo().size());
361 // Length is encoded by the constructor.
362 for (const CompilationState::QuickenedInfo& info : GetQuickenedInfo()) {
363 // Dex pc is not serialized, only used for checking the instructions. Since we access the
364 // array based on the index of the quickened instruction, the indexes must line up perfectly.
365 // The reader side uses the NeedsIndexForInstruction function too.
366 const Instruction& inst = instructions.InstructionAt(info.dex_pc);
367 CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
368 builder.AddIndex(info.dex_member_index);
369 }
370 DCHECK(!quicken_data.empty());
371 return quicken_data;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372}
373
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800374void DexToDexCompiler::CompilationState::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700375 DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID);
376 if (unit_.IsConstructor()) {
377 // Are we compiling a non clinit constructor which needs a barrier ?
378 if (!unit_.IsStatic() &&
379 driver_.RequiresConstructorBarrier(Thread::Current(), unit_.GetDexFile(),
380 unit_.GetClassDefIndex())) {
381 return;
382 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 }
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700384 // Replace RETURN_VOID by RETURN_VOID_NO_BARRIER.
Sebastien Hertz543959c2013-07-03 12:00:19 +0200385 VLOG(compiler) << "Replacing " << Instruction::Name(inst->Opcode())
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700386 << " by " << Instruction::Name(Instruction::RETURN_VOID_NO_BARRIER)
Sebastien Hertz543959c2013-07-03 12:00:19 +0200387 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700388 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartierd7cbf8a2015-03-19 12:43:20 -0700389 inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800390 optimized_return_void_ = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700391}
392
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800393Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
394 uint32_t dex_pc) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700395 if (!kEnableCheckCastEllision) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200396 return inst;
397 }
Vladimir Marko2730db02014-01-27 11:15:17 +0000398 if (!driver_.IsSafeCast(&unit_, dex_pc)) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200399 return inst;
400 }
401 // Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
402 // units and a "nop" instruction size is 1 code unit, we need to replace it by
403 // 2 consecutive NOP instructions.
404 // Because the caller loops over instructions by calling Instruction::Next onto
405 // the current instruction, we need to return the 2nd NOP instruction. Indeed,
406 // its next instruction is the former check-cast's next instruction.
407 VLOG(compiler) << "Removing " << Instruction::Name(inst->Opcode())
408 << " by replacing it with 2 NOPs at dex pc "
409 << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700410 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800411 if (!already_quickened_) {
412 quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
413 quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
414
415 // We are modifying 4 consecutive bytes.
416 inst->SetOpcode(Instruction::NOP);
417 inst->SetVRegA_10x(0u); // keep compliant with verifier.
418 // Get to next instruction which is the second half of check-cast and replace
419 // it by a NOP.
420 inst = const_cast<Instruction*>(inst->Next());
421 inst->SetOpcode(Instruction::NOP);
422 inst->SetVRegA_10x(0u); // keep compliant with verifier.
423 }
Sebastien Hertz543959c2013-07-03 12:00:19 +0200424 return inst;
425}
426
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800427void DexToDexCompiler::CompilationState::CompileInstanceFieldAccess(Instruction* inst,
428 uint32_t dex_pc,
429 Instruction::Code new_opcode,
430 bool is_put) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700431 if (!kEnableQuickening) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 return;
433 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800434 uint32_t field_idx = GetIndexForInstruction(inst, inst->VRegC_22c());
Vladimir Markobe0e5462014-02-26 11:24:15 +0000435 MemberOffset field_offset(0u);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 bool is_volatile;
Ian Rogers9b297bf2013-09-06 11:11:25 -0700437 bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
438 &field_offset, &is_volatile);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800439 if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) {
Sebastien Hertz543959c2013-07-03 12:00:19 +0200440 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
441 << " to " << Instruction::Name(new_opcode)
442 << " by replacing field index " << field_idx
Vladimir Markobe0e5462014-02-26 11:24:15 +0000443 << " by field offset " << field_offset.Int32Value()
Sebastien Hertz543959c2013-07-03 12:00:19 +0200444 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700445 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800446 if (!already_quickened_) {
447 // We are modifying 4 consecutive bytes.
448 inst->SetOpcode(new_opcode);
449 // Replace field index by field offset.
450 inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
451 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100452 quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453 }
454}
455
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800456const DexFile& DexToDexCompiler::CompilationState::GetDexFile() const {
457 return *unit_.GetDexFile();
458}
459
460void DexToDexCompiler::CompilationState::CompileInvokeVirtual(Instruction* inst,
461 uint32_t dex_pc,
462 Instruction::Code new_opcode,
463 bool is_range) {
Andreas Gampe1a4bc7f2017-03-27 14:57:30 -0700464 if (!kEnableQuickening) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 return;
466 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800467 uint32_t method_idx = GetIndexForInstruction(inst,
468 is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100469 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100470
471 ClassLinker* class_linker = unit_.GetClassLinker();
Vladimir Markoba118822017-06-12 15:41:56 +0100472 ArtMethod* resolved_method =
473 class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
Vladimir Markoba118822017-06-12 15:41:56 +0100474 method_idx,
475 unit_.GetDexCache(),
476 unit_.GetClassLoader(),
477 /* referrer */ nullptr,
478 kVirtual);
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100479
480 if (UNLIKELY(resolved_method == nullptr)) {
481 // Clean up any exception left by type resolution.
482 soa.Self()->ClearException();
483 return;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 }
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100485
486 uint32_t vtable_idx = resolved_method->GetMethodIndex();
487 DCHECK(IsUint<16>(vtable_idx));
488 VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
David Sehr709b0702016-10-13 09:12:37 -0700489 << "(" << GetDexFile().PrettyMethod(method_idx, true) << ")"
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100490 << " to " << Instruction::Name(new_opcode)
491 << " by replacing method index " << method_idx
492 << " by vtable index " << vtable_idx
493 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
David Sehr709b0702016-10-13 09:12:37 -0700494 << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800495 if (!already_quickened_) {
496 // We are modifying 4 consecutive bytes.
497 inst->SetOpcode(new_opcode);
498 // Replace method index by vtable index.
499 if (is_range) {
500 inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
501 } else {
502 inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
503 }
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100504 }
505 quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506}
507
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800508CompiledMethod* DexToDexCompiler::CompileMethod(
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700509 const DexFile::CodeItem* code_item,
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100510 uint32_t access_flags,
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700511 InvokeType invoke_type ATTRIBUTE_UNUSED,
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100512 uint16_t class_def_idx,
513 uint32_t method_idx,
Vladimir Marko8d6768d2017-03-14 10:13:21 +0000514 Handle<mirror::ClassLoader> class_loader,
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700515 const DexFile& dex_file,
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800516 CompilationLevel compilation_level) {
517 if (compilation_level == CompilationLevel::kDontDexToDexCompile) {
518 return nullptr;
519 }
520
521 ScopedObjectAccess soa(Thread::Current());
522 StackHandleScope<1> hs(soa.Self());
523 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
524 art::DexCompilationUnit unit(
525 class_loader,
526 class_linker,
527 dex_file,
528 code_item,
529 class_def_idx,
530 method_idx,
531 access_flags,
532 driver_->GetVerifiedMethod(&dex_file, method_idx),
533 hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
534
535 std::vector<uint8_t> quicken_data;
536 // If the code item is shared with multiple different method ids, make sure that we quicken only
537 // once and verify that all the dequicken maps match.
538 if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800539 // Avoid quickening the shared code items for now because the existing conflict detection logic
540 // does not currently handle cases where the code item is quickened in one place but
541 // compiled in another.
542 static constexpr bool kAvoidQuickeningSharedCodeItems = true;
543 if (kAvoidQuickeningSharedCodeItems) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100544 return nullptr;
545 }
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800546 // For shared code items, use a lock to prevent races.
547 MutexLock mu(soa.Self(), lock_);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800548 auto existing = shared_code_item_quicken_info_.find(code_item);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800549 QuickenState* existing_data = nullptr;
550 std::vector<uint8_t>* existing_quicken_data = nullptr;
551 if (existing != shared_code_item_quicken_info_.end()) {
552 existing_data = &existing->second;
553 if (existing_data->conflict_) {
554 return nullptr;
555 }
556 existing_quicken_data = &existing_data->quicken_data_;
557 }
558 bool optimized_return_void;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800559 {
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800560 CompilationState state(this, unit, compilation_level, existing_quicken_data);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800561 quicken_data = state.Compile();
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800562 optimized_return_void = state.optimized_return_void_;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800563 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100564
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800565 // Already quickened, check that the data matches what was previously seen.
566 MethodReference method_ref(&dex_file, method_idx);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800567 if (existing_data != nullptr) {
568 if (*existing_quicken_data != quicken_data ||
569 existing_data->optimized_return_void_ != optimized_return_void) {
570 VLOG(compiler) << "Quicken data mismatch, for method "
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800571 << dex_file.PrettyMethod(method_idx);
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800572 // Mark the method as a conflict to never attempt to quicken it in the future.
573 existing_data->conflict_ = true;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700574 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800575 existing_data->methods_.push_back(method_ref);
576 } else {
577 QuickenState new_state;
578 new_state.methods_.push_back(method_ref);
579 new_state.quicken_data_ = quicken_data;
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800580 new_state.optimized_return_void_ = optimized_return_void;
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800581 bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
582 CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700583 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800584
585 // Easy sanity check is to check that the existing stuff matches by re-quickening using the
586 // newly produced quicken data.
587 // Note that this needs to be behind the lock for this case since we may unquicken in another
588 // thread.
589 if (kIsDebugBuild) {
590 CompilationState state2(this, unit, compilation_level, &quicken_data);
591 std::vector<uint8_t> new_data = state2.Compile();
592 CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100593 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800594 } else {
595 CompilationState state(this, unit, compilation_level, /*quicken_data*/ nullptr);
596 quicken_data = state.Compile();
597
598 // Easy sanity check is to check that the existing stuff matches by re-quickening using the
599 // newly produced quicken data.
600 if (kIsDebugBuild) {
601 CompilationState state2(this, unit, compilation_level, &quicken_data);
602 std::vector<uint8_t> new_data = state2.Compile();
603 CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100604 }
Sebastien Hertz75021222013-07-16 18:34:50 +0200605 }
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800606
607 if (quicken_data.empty()) {
608 return nullptr;
609 }
610
611 // Create a `CompiledMethod`, with the quickened information in the vmap table.
612 InstructionSet instruction_set = driver_->GetInstructionSet();
613 if (instruction_set == InstructionSet::kThumb2) {
614 // Don't use the thumb2 instruction set to avoid the one off code delta.
615 instruction_set = InstructionSet::kArm;
616 }
617 CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod(
618 driver_,
619 instruction_set,
620 ArrayRef<const uint8_t>(), // no code
621 0,
622 0,
623 0,
624 ArrayRef<const uint8_t>(), // method_info
625 ArrayRef<const uint8_t>(quicken_data), // vmap_table
626 ArrayRef<const uint8_t>(), // cfi data
627 ArrayRef<const linker::LinkerPatch>());
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800628 DCHECK(ret != nullptr);
Mathieu Chartiera79efdb2018-01-18 16:31:01 -0800629 return ret;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700630}
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100631
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800632void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) {
633 // Record what code items are already seen to detect when multiple methods have the same code
634 // item.
635 std::unordered_set<const DexFile::CodeItem*> seen_code_items;
636 for (const DexFile* dex_file : dex_files) {
Mathieu Chartierc8c8d5f2018-05-22 11:56:14 -0700637 for (ClassAccessor accessor : dex_file->GetClasses()) {
Mathieu Chartier0d896bd2018-05-25 00:20:27 -0700638 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
Mathieu Chartierc8c8d5f2018-05-22 11:56:14 -0700639 const DexFile::CodeItem* code_item = method.GetCodeItem();
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800640 // Detect the shared code items.
641 if (!seen_code_items.insert(code_item).second) {
642 shared_code_items_.insert(code_item);
643 }
Mathieu Chartier0d896bd2018-05-25 00:20:27 -0700644 }
Mathieu Chartier279e3a32018-01-24 18:17:55 -0800645 }
646 }
647 VLOG(compiler) << "Shared code items " << shared_code_items_.size();
648}
649
650void DexToDexCompiler::UnquickenConflictingMethods() {
651 MutexLock mu(Thread::Current(), lock_);
652 size_t unquicken_count = 0;
653 for (const auto& pair : shared_code_item_quicken_info_) {
654 const DexFile::CodeItem* code_item = pair.first;
655 const QuickenState& state = pair.second;
656 CHECK_GE(state.methods_.size(), 1u);
657 if (state.conflict_) {
658 // Unquicken using the existing quicken data.
659 // TODO: Do we really need to pass a dex file in?
660 optimizer::ArtDecompileDEX(*state.methods_[0].dex_file,
661 *code_item,
662 ArrayRef<const uint8_t>(state.quicken_data_),
663 /* decompile_return_instruction*/ true);
664 ++unquicken_count;
665 // Go clear the vmaps for all the methods that were already quickened to avoid writing them
666 // out during oat writing.
667 for (const MethodReference& ref : state.methods_) {
668 CompiledMethod* method = driver_->RemoveCompiledMethod(ref);
669 if (method != nullptr) {
670 // There is up to one compiled method for each method ref. Releasing it leaves the
671 // deduped data intact, this means its safe to do even when other threads might be
672 // compiling.
673 CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
674 }
675 }
676 }
677 }
678}
679
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100680} // namespace optimizer
681
682} // namespace art