1 /*
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 
17 #include "dex_to_dex_compiler.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 
22 #include "art_field-inl.h"
23 #include "art_method-inl.h"
24 #include "base/logging.h"  // For VLOG
25 #include "base/macros.h"
26 #include "base/mutex.h"
27 #include "compiled_method.h"
28 #include "dex/bytecode_utils.h"
29 #include "dex/dex_file-inl.h"
30 #include "dex/dex_instruction-inl.h"
31 #include "dex_to_dex_decompiler.h"
32 #include "driver/compiler_driver.h"
33 #include "driver/dex_compilation_unit.h"
34 #include "mirror/dex_cache.h"
35 #include "quicken_info.h"
36 #include "thread-current-inl.h"
37 
38 namespace art {
39 namespace optimizer {
40 
41 using android::base::StringPrintf;
42 
43 // Controls quickening activation.
44 const bool kEnableQuickening = true;
45 // Control check-cast elision.
46 const bool kEnableCheckCastEllision = true;
47 
48 // Holds the state for compiling a single method.
49 struct DexToDexCompiler::CompilationState {
50   struct QuickenedInfo {
QuickenedInfoart::optimizer::DexToDexCompiler::CompilationState::QuickenedInfo51     QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
52 
53     uint32_t dex_pc;
54     uint16_t dex_member_index;
55   };
56 
57   CompilationState(DexToDexCompiler* compiler,
58                    const DexCompilationUnit& unit,
59                    const CompilationLevel compilation_level,
60                    const std::vector<uint8_t>* quicken_data);
61 
GetQuickenedInfoart::optimizer::DexToDexCompiler::CompilationState62   const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
63     return quickened_info_;
64   }
65 
66   // Returns the quickening info, or an empty array if it was not quickened.
67   // If already_quickened is true, then don't change anything but still return what the quicken
68   // data would have been.
69   std::vector<uint8_t> Compile();
70 
71   const DexFile& GetDexFile() const;
72 
73   // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
74   // a barrier is required.
75   void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
76 
77   // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
78   // this case, returns the second NOP instruction pointer. Otherwise, returns
79   // the given "inst".
80   Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
81 
82   // Compiles a field access into a quick field access.
83   // The field index is replaced by an offset within an Object where we can read
84   // from / write to this field. Therefore, this does not involve any resolution
85   // at runtime.
86   // Since the field index is encoded with 16 bits, we can replace it only if the
87   // field offset can be encoded with 16 bits too.
88   void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
89                                   Instruction::Code new_opcode, bool is_put);
90 
91   // Compiles a virtual method invocation into a quick virtual method invocation.
92   // The method index is replaced by the vtable index where the corresponding
93   // executable can be found. Therefore, this does not involve any resolution
94   // at runtime.
95   // Since the method index is encoded with 16 bits, we can replace it only if the
96   // vtable index can be encoded with 16 bits too.
97   void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
98                             Instruction::Code new_opcode, bool is_range);
99 
100   // Return the next index.
101   uint16_t NextIndex();
102 
103   // Returns the dequickened index if an instruction is quickened, otherwise return index.
104   uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
105 
106   DexToDexCompiler* const compiler_;
107   CompilerDriver& driver_;
108   const DexCompilationUnit& unit_;
109   const CompilationLevel compilation_level_;
110 
111   // Filled by the compiler when quickening, in order to encode that information
112   // in the .oat file. The runtime will use that information to get to the original
113   // opcodes.
114   std::vector<QuickenedInfo> quickened_info_;
115 
116   // True if we optimized a return void to a return void no barrier.
117   bool optimized_return_void_ = false;
118 
119   // If the code item was already quickened previously.
120   const bool already_quickened_;
121   const QuickenInfoTable existing_quicken_info_;
122   uint32_t quicken_index_ = 0u;
123 
124   DISALLOW_COPY_AND_ASSIGN(CompilationState);
125 };
126 
DexToDexCompiler(CompilerDriver * driver)127 DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
128     : driver_(driver),
129       lock_("Quicken lock", kDexToDexCompilerLock) {
130   DCHECK(driver != nullptr);
131 }
132 
ClearState()133 void DexToDexCompiler::ClearState() {
134   MutexLock lock(Thread::Current(), lock_);
135   active_dex_file_ = nullptr;
136   active_bit_vector_ = nullptr;
137   should_quicken_.clear();
138   shared_code_item_quicken_info_.clear();
139 }
140 
NumCodeItemsToQuicken(Thread * self) const141 size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const {
142   MutexLock lock(self, lock_);
143   return num_code_items_;
144 }
145 
GetOrAddBitVectorForDex(const DexFile * dex_file)146 BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
147   if (active_dex_file_ != dex_file) {
148     active_dex_file_ = dex_file;
149     auto inserted = should_quicken_.emplace(dex_file,
150                                             BitVector(dex_file->NumMethodIds(),
151                                                       /*expandable*/ false,
152                                                       Allocator::GetMallocAllocator()));
153     active_bit_vector_ = &inserted.first->second;
154   }
155   return active_bit_vector_;
156 }
157 
MarkForCompilation(Thread * self,const MethodReference & method_ref)158 void DexToDexCompiler::MarkForCompilation(Thread* self,
159                                           const MethodReference& method_ref) {
160   MutexLock lock(self, lock_);
161   BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
162   DCHECK(bitmap != nullptr);
163   DCHECK(!bitmap->IsBitSet(method_ref.index));
164   bitmap->SetBit(method_ref.index);
165   ++num_code_items_;
166 }
167 
CompilationState(DexToDexCompiler * compiler,const DexCompilationUnit & unit,const CompilationLevel compilation_level,const std::vector<uint8_t> * quicken_data)168 DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
169                                                      const DexCompilationUnit& unit,
170                                                      const CompilationLevel compilation_level,
171                                                      const std::vector<uint8_t>* quicken_data)
172     : compiler_(compiler),
173       driver_(*compiler->GetDriver()),
174       unit_(unit),
175       compilation_level_(compilation_level),
176       already_quickened_(quicken_data != nullptr),
177       existing_quicken_info_(already_quickened_
178           ? ArrayRef<const uint8_t>(*quicken_data) : ArrayRef<const uint8_t>()) {}
179 
NextIndex()180 uint16_t DexToDexCompiler::CompilationState::NextIndex() {
181   DCHECK(already_quickened_);
182   if (kIsDebugBuild && quicken_index_ >= existing_quicken_info_.NumIndices()) {
183     for (const DexInstructionPcPair& pair : unit_.GetCodeItemAccessor()) {
184       LOG(ERROR) << pair->DumpString(nullptr);
185     }
186     LOG(FATAL) << "Mismatched number of quicken slots.";
187   }
188   const uint16_t ret = existing_quicken_info_.GetData(quicken_index_);
189   quicken_index_++;
190   return ret;
191 }
192 
GetIndexForInstruction(const Instruction * inst,uint32_t index)193 uint16_t DexToDexCompiler::CompilationState::GetIndexForInstruction(const Instruction* inst,
194                                                                     uint32_t index) {
195   if (UNLIKELY(already_quickened_)) {
196     return inst->IsQuickened() ? NextIndex() : index;
197   }
198   DCHECK(!inst->IsQuickened());
199   return index;
200 }
201 
ShouldCompileMethod(const MethodReference & ref)202 bool DexToDexCompiler::ShouldCompileMethod(const MethodReference& ref) {
203   // TODO: It's probably safe to avoid the lock here if the active_dex_file_ matches since we only
204   // only call ShouldCompileMethod on one dex at a time.
205   MutexLock lock(Thread::Current(), lock_);
206   return GetOrAddBitVectorForDex(ref.dex_file)->IsBitSet(ref.index);
207 }
208 
Compile()209 std::vector<uint8_t> DexToDexCompiler::CompilationState::Compile() {
210   DCHECK_EQ(compilation_level_, CompilationLevel::kOptimize);
211   const CodeItemDataAccessor& instructions = unit_.GetCodeItemAccessor();
212   for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
213     const uint32_t dex_pc = it.DexPc();
214     Instruction* inst = const_cast<Instruction*>(&it.Inst());
215 
216     if (!already_quickened_) {
217       DCHECK(!inst->IsQuickened());
218     }
219 
220     switch (inst->Opcode()) {
221       case Instruction::RETURN_VOID:
222         CompileReturnVoid(inst, dex_pc);
223         break;
224 
225       case Instruction::CHECK_CAST:
226         inst = CompileCheckCast(inst, dex_pc);
227         if (inst->Opcode() == Instruction::NOP) {
228           // We turned the CHECK_CAST into two NOPs, avoid visiting the second NOP twice since this
229           // would add 2 quickening info entries.
230           ++it;
231         }
232         break;
233 
234       case Instruction::IGET:
235       case Instruction::IGET_QUICK:
236         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
237         break;
238 
239       case Instruction::IGET_WIDE:
240       case Instruction::IGET_WIDE_QUICK:
241         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
242         break;
243 
244       case Instruction::IGET_OBJECT:
245       case Instruction::IGET_OBJECT_QUICK:
246         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
247         break;
248 
249       case Instruction::IGET_BOOLEAN:
250       case Instruction::IGET_BOOLEAN_QUICK:
251         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
252         break;
253 
254       case Instruction::IGET_BYTE:
255       case Instruction::IGET_BYTE_QUICK:
256         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
257         break;
258 
259       case Instruction::IGET_CHAR:
260       case Instruction::IGET_CHAR_QUICK:
261         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
262         break;
263 
264       case Instruction::IGET_SHORT:
265       case Instruction::IGET_SHORT_QUICK:
266         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
267         break;
268 
269       case Instruction::IPUT:
270       case Instruction::IPUT_QUICK:
271         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
272         break;
273 
274       case Instruction::IPUT_BOOLEAN:
275       case Instruction::IPUT_BOOLEAN_QUICK:
276         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true);
277         break;
278 
279       case Instruction::IPUT_BYTE:
280       case Instruction::IPUT_BYTE_QUICK:
281         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true);
282         break;
283 
284       case Instruction::IPUT_CHAR:
285       case Instruction::IPUT_CHAR_QUICK:
286         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true);
287         break;
288 
289       case Instruction::IPUT_SHORT:
290       case Instruction::IPUT_SHORT_QUICK:
291         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true);
292         break;
293 
294       case Instruction::IPUT_WIDE:
295       case Instruction::IPUT_WIDE_QUICK:
296         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
297         break;
298 
299       case Instruction::IPUT_OBJECT:
300       case Instruction::IPUT_OBJECT_QUICK:
301         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
302         break;
303 
304       case Instruction::INVOKE_VIRTUAL:
305       case Instruction::INVOKE_VIRTUAL_QUICK:
306         CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
307         break;
308 
309       case Instruction::INVOKE_VIRTUAL_RANGE:
310       case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
311         CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
312         break;
313 
314       case Instruction::NOP:
315         if (already_quickened_) {
316           const uint16_t reference_index = NextIndex();
317           quickened_info_.push_back(QuickenedInfo(dex_pc, reference_index));
318           if (reference_index == DexFile::kDexNoIndex16) {
319             // This means it was a normal nop and not a check-cast.
320             break;
321           }
322           const uint16_t type_index = NextIndex();
323           if (driver_.IsSafeCast(&unit_, dex_pc)) {
324             quickened_info_.push_back(QuickenedInfo(dex_pc, type_index));
325           }
326           ++it;
327         } else {
328           // We need to differentiate between check cast inserted NOP and normal NOP, put an invalid
329           // index in the map for normal nops. This should be rare in real code.
330           quickened_info_.push_back(QuickenedInfo(dex_pc, DexFile::kDexNoIndex16));
331         }
332         break;
333 
334       default:
335         // Nothing to do.
336         break;
337     }
338   }
339 
340   if (already_quickened_) {
341     DCHECK_EQ(quicken_index_, existing_quicken_info_.NumIndices());
342   }
343 
344   // Even if there are no indicies, generate an empty quicken info so that we know the method was
345   // quickened.
346 
347   std::vector<uint8_t> quicken_data;
348   if (kIsDebugBuild) {
349     // Double check that the counts line up with the size of the quicken info.
350     size_t quicken_count = 0;
351     for (const DexInstructionPcPair& pair : instructions) {
352       if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
353         ++quicken_count;
354       }
355     }
356     CHECK_EQ(quicken_count, GetQuickenedInfo().size());
357   }
358 
359   QuickenInfoTable::Builder builder(&quicken_data, GetQuickenedInfo().size());
360   // Length is encoded by the constructor.
361   for (const CompilationState::QuickenedInfo& info : GetQuickenedInfo()) {
362     // Dex pc is not serialized, only used for checking the instructions. Since we access the
363     // array based on the index of the quickened instruction, the indexes must line up perfectly.
364     // The reader side uses the NeedsIndexForInstruction function too.
365     const Instruction& inst = instructions.InstructionAt(info.dex_pc);
366     CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
367     builder.AddIndex(info.dex_member_index);
368   }
369   DCHECK(!quicken_data.empty());
370   return quicken_data;
371 }
372 
CompileReturnVoid(Instruction * inst,uint32_t dex_pc)373 void DexToDexCompiler::CompilationState::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
374   DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID);
375   if (unit_.IsConstructor()) {
376     // Are we compiling a non clinit constructor which needs a barrier ?
377     if (!unit_.IsStatic() &&
378         driver_.RequiresConstructorBarrier(Thread::Current(), unit_.GetDexFile(),
379                                            unit_.GetClassDefIndex())) {
380       return;
381     }
382   }
383   // Replace RETURN_VOID by RETURN_VOID_NO_BARRIER.
384   VLOG(compiler) << "Replacing " << Instruction::Name(inst->Opcode())
385                  << " by " << Instruction::Name(Instruction::RETURN_VOID_NO_BARRIER)
386                  << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
387                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
388   inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
389   optimized_return_void_ = true;
390 }
391 
CompileCheckCast(Instruction * inst,uint32_t dex_pc)392 Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
393                                                                   uint32_t dex_pc) {
394   if (!kEnableCheckCastEllision) {
395     return inst;
396   }
397   if (!driver_.IsSafeCast(&unit_, dex_pc)) {
398     return inst;
399   }
400   // Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
401   // units and a "nop" instruction size is 1 code unit, we need to replace it by
402   // 2 consecutive NOP instructions.
403   // Because the caller loops over instructions by calling Instruction::Next onto
404   // the current instruction, we need to return the 2nd NOP instruction. Indeed,
405   // its next instruction is the former check-cast's next instruction.
406   VLOG(compiler) << "Removing " << Instruction::Name(inst->Opcode())
407                  << " by replacing it with 2 NOPs at dex pc "
408                  << StringPrintf("0x%x", dex_pc) << " in method "
409                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
410   if (!already_quickened_) {
411     quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
412     quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
413 
414     // We are modifying 4 consecutive bytes.
415     inst->SetOpcode(Instruction::NOP);
416     inst->SetVRegA_10x(0u);  // keep compliant with verifier.
417     // Get to next instruction which is the second half of check-cast and replace
418     // it by a NOP.
419     inst = const_cast<Instruction*>(inst->Next());
420     inst->SetOpcode(Instruction::NOP);
421     inst->SetVRegA_10x(0u);  // keep compliant with verifier.
422   }
423   return inst;
424 }
425 
CompileInstanceFieldAccess(Instruction * inst,uint32_t dex_pc,Instruction::Code new_opcode,bool is_put)426 void DexToDexCompiler::CompilationState::CompileInstanceFieldAccess(Instruction* inst,
427                                                                     uint32_t dex_pc,
428                                                                     Instruction::Code new_opcode,
429                                                                     bool is_put) {
430   if (!kEnableQuickening) {
431     return;
432   }
433   uint32_t field_idx = GetIndexForInstruction(inst, inst->VRegC_22c());
434   MemberOffset field_offset(0u);
435   bool is_volatile;
436   bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
437                                                     &field_offset, &is_volatile);
438   if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) {
439     VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
440                    << " to " << Instruction::Name(new_opcode)
441                    << " by replacing field index " << field_idx
442                    << " by field offset " << field_offset.Int32Value()
443                    << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
444                    << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
445     if (!already_quickened_) {
446       // We are modifying 4 consecutive bytes.
447       inst->SetOpcode(new_opcode);
448       // Replace field index by field offset.
449       inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
450     }
451     quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
452   }
453 }
454 
GetDexFile() const455 const DexFile& DexToDexCompiler::CompilationState::GetDexFile() const {
456   return *unit_.GetDexFile();
457 }
458 
CompileInvokeVirtual(Instruction * inst,uint32_t dex_pc,Instruction::Code new_opcode,bool is_range)459 void DexToDexCompiler::CompilationState::CompileInvokeVirtual(Instruction* inst,
460                                                               uint32_t dex_pc,
461                                                               Instruction::Code new_opcode,
462                                                               bool is_range) {
463   if (!kEnableQuickening) {
464     return;
465   }
466   uint32_t method_idx = GetIndexForInstruction(inst,
467                                                is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
468   ScopedObjectAccess soa(Thread::Current());
469 
470   ClassLinker* class_linker = unit_.GetClassLinker();
471   ArtMethod* resolved_method =
472       class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
473           method_idx,
474           unit_.GetDexCache(),
475           unit_.GetClassLoader(),
476           /* referrer */ nullptr,
477           kVirtual);
478 
479   if (UNLIKELY(resolved_method == nullptr)) {
480     // Clean up any exception left by type resolution.
481     soa.Self()->ClearException();
482     return;
483   }
484 
485   uint32_t vtable_idx = resolved_method->GetMethodIndex();
486   DCHECK(IsUint<16>(vtable_idx));
487   VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
488                  << "(" << GetDexFile().PrettyMethod(method_idx, true) << ")"
489                  << " to " << Instruction::Name(new_opcode)
490                  << " by replacing method index " << method_idx
491                  << " by vtable index " << vtable_idx
492                  << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
493                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
494   if (!already_quickened_) {
495     // We are modifying 4 consecutive bytes.
496     inst->SetOpcode(new_opcode);
497     // Replace method index by vtable index.
498     if (is_range) {
499       inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
500     } else {
501       inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
502     }
503   }
504   quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
505 }
506 
CompileMethod(const DexFile::CodeItem * code_item,uint32_t access_flags,InvokeType invoke_type ATTRIBUTE_UNUSED,uint16_t class_def_idx,uint32_t method_idx,Handle<mirror::ClassLoader> class_loader,const DexFile & dex_file,CompilationLevel compilation_level)507 CompiledMethod* DexToDexCompiler::CompileMethod(
508     const DexFile::CodeItem* code_item,
509     uint32_t access_flags,
510     InvokeType invoke_type ATTRIBUTE_UNUSED,
511     uint16_t class_def_idx,
512     uint32_t method_idx,
513     Handle<mirror::ClassLoader> class_loader,
514     const DexFile& dex_file,
515     CompilationLevel compilation_level) {
516   if (compilation_level == CompilationLevel::kDontDexToDexCompile) {
517     return nullptr;
518   }
519 
520   ScopedObjectAccess soa(Thread::Current());
521   StackHandleScope<1> hs(soa.Self());
522   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
523   art::DexCompilationUnit unit(
524       class_loader,
525       class_linker,
526       dex_file,
527       code_item,
528       class_def_idx,
529       method_idx,
530       access_flags,
531       driver_->GetVerifiedMethod(&dex_file, method_idx),
532       hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
533 
534   std::vector<uint8_t> quicken_data;
535   // If the code item is shared with multiple different method ids, make sure that we quicken only
536   // once and verify that all the dequicken maps match.
537   if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
538     // Avoid quickening the shared code items for now because the existing conflict detection logic
539     // does not currently handle cases where the code item is quickened in one place but
540     // compiled in another.
541     static constexpr bool kAvoidQuickeningSharedCodeItems = true;
542     if (kAvoidQuickeningSharedCodeItems) {
543       return nullptr;
544     }
545     // For shared code items, use a lock to prevent races.
546     MutexLock mu(soa.Self(), lock_);
547     auto existing = shared_code_item_quicken_info_.find(code_item);
548     QuickenState* existing_data = nullptr;
549     std::vector<uint8_t>* existing_quicken_data = nullptr;
550     if (existing != shared_code_item_quicken_info_.end()) {
551       existing_data = &existing->second;
552       if (existing_data->conflict_) {
553         return nullptr;
554       }
555       existing_quicken_data = &existing_data->quicken_data_;
556     }
557     bool optimized_return_void;
558     {
559       CompilationState state(this, unit, compilation_level, existing_quicken_data);
560       quicken_data = state.Compile();
561       optimized_return_void = state.optimized_return_void_;
562     }
563 
564     // Already quickened, check that the data matches what was previously seen.
565     MethodReference method_ref(&dex_file, method_idx);
566     if (existing_data != nullptr) {
567       if (*existing_quicken_data != quicken_data ||
568           existing_data->optimized_return_void_ != optimized_return_void) {
569         VLOG(compiler) << "Quicken data mismatch, for method "
570                        << dex_file.PrettyMethod(method_idx);
571         // Mark the method as a conflict to never attempt to quicken it in the future.
572         existing_data->conflict_ = true;
573       }
574       existing_data->methods_.push_back(method_ref);
575     } else {
576       QuickenState new_state;
577       new_state.methods_.push_back(method_ref);
578       new_state.quicken_data_ = quicken_data;
579       new_state.optimized_return_void_ = optimized_return_void;
580       bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
581       CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
582     }
583 
584     // Easy sanity check is to check that the existing stuff matches by re-quickening using the
585     // newly produced quicken data.
586     // Note that this needs to be behind the lock for this case since we may unquicken in another
587     // thread.
588     if (kIsDebugBuild) {
589       CompilationState state2(this, unit, compilation_level, &quicken_data);
590       std::vector<uint8_t> new_data = state2.Compile();
591       CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
592     }
593   } else {
594     CompilationState state(this, unit, compilation_level, /*quicken_data*/ nullptr);
595     quicken_data = state.Compile();
596 
597     // Easy sanity check is to check that the existing stuff matches by re-quickening using the
598     // newly produced quicken data.
599     if (kIsDebugBuild) {
600       CompilationState state2(this, unit, compilation_level, &quicken_data);
601       std::vector<uint8_t> new_data = state2.Compile();
602       CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
603     }
604   }
605 
606   if (quicken_data.empty()) {
607     return nullptr;
608   }
609 
610   // Create a `CompiledMethod`, with the quickened information in the vmap table.
611   InstructionSet instruction_set = driver_->GetInstructionSet();
612   if (instruction_set == InstructionSet::kThumb2) {
613     // Don't use the thumb2 instruction set to avoid the one off code delta.
614     instruction_set = InstructionSet::kArm;
615   }
616   CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod(
617       driver_,
618       instruction_set,
619       ArrayRef<const uint8_t>(),                   // no code
620       0,
621       0,
622       0,
623       ArrayRef<const uint8_t>(),                   // method_info
624       ArrayRef<const uint8_t>(quicken_data),       // vmap_table
625       ArrayRef<const uint8_t>(),                   // cfi data
626       ArrayRef<const linker::LinkerPatch>());
627   DCHECK(ret != nullptr);
628   return ret;
629 }
630 
SetDexFiles(const std::vector<const DexFile * > & dex_files)631 void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) {
632   // Record what code items are already seen to detect when multiple methods have the same code
633   // item.
634   std::unordered_set<const DexFile::CodeItem*> seen_code_items;
635   for (const DexFile* dex_file : dex_files) {
636     for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
637       const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
638       const uint8_t* class_data = dex_file->GetClassData(class_def);
639       if (class_data == nullptr) {
640         continue;
641       }
642       ClassDataItemIterator it(*dex_file, class_data);
643       it.SkipAllFields();
644       for (; it.HasNextMethod(); it.Next()) {
645         const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
646         // Detect the shared code items.
647         if (!seen_code_items.insert(code_item).second) {
648           shared_code_items_.insert(code_item);
649         }
650       }
651     }
652   }
653   VLOG(compiler) << "Shared code items " << shared_code_items_.size();
654 }
655 
UnquickenConflictingMethods()656 void DexToDexCompiler::UnquickenConflictingMethods() {
657   MutexLock mu(Thread::Current(), lock_);
658   size_t unquicken_count = 0;
659   for (const auto& pair : shared_code_item_quicken_info_) {
660     const DexFile::CodeItem* code_item = pair.first;
661     const QuickenState& state = pair.second;
662     CHECK_GE(state.methods_.size(), 1u);
663     if (state.conflict_) {
664       // Unquicken using the existing quicken data.
665       // TODO: Do we really need to pass a dex file in?
666       optimizer::ArtDecompileDEX(*state.methods_[0].dex_file,
667                                  *code_item,
668                                  ArrayRef<const uint8_t>(state.quicken_data_),
669                                  /* decompile_return_instruction*/ true);
670       ++unquicken_count;
671       // Go clear the vmaps for all the methods that were already quickened to avoid writing them
672       // out during oat writing.
673       for (const MethodReference& ref : state.methods_) {
674         CompiledMethod* method = driver_->RemoveCompiledMethod(ref);
675         if (method != nullptr) {
676           // There is up to one compiled method for each method ref. Releasing it leaves the
677           // deduped data intact, this means its safe to do even when other threads might be
678           // compiling.
679           CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
680         }
681       }
682     }
683   }
684 }
685 
686 }  // namespace optimizer
687 
688 }  // namespace art
689