xref: /aosp_15_r20/art/tools/dexanalyze/dexanalyze_bytecode.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "dexanalyze_bytecode.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <algorithm>
20*795d594fSAndroid Build Coastguard Worker #include <iomanip>
21*795d594fSAndroid Build Coastguard Worker #include <iostream>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker namespace art {
28*795d594fSAndroid Build Coastguard Worker namespace dexanalyze {
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker // Given a map of <key, usage count>, sort by most used and assign index <key, index in most used>
31*795d594fSAndroid Build Coastguard Worker enum class Order {
32*795d594fSAndroid Build Coastguard Worker   kMostUsed,
33*795d594fSAndroid Build Coastguard Worker   kNormal,
34*795d594fSAndroid Build Coastguard Worker };
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker template <typename T, typename U>
SortByOrder(const SafeMap<T,U> & usage,Order order)37*795d594fSAndroid Build Coastguard Worker static inline SafeMap<T, U> SortByOrder(const SafeMap<T, U>& usage, Order order) {
38*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<U, T>> most_used;
39*795d594fSAndroid Build Coastguard Worker   for (const auto& pair : usage) {
40*795d594fSAndroid Build Coastguard Worker     most_used.emplace_back(pair.second, pair.first);
41*795d594fSAndroid Build Coastguard Worker   }
42*795d594fSAndroid Build Coastguard Worker   if (order == Order::kMostUsed) {
43*795d594fSAndroid Build Coastguard Worker     std::sort(most_used.rbegin(), most_used.rend());
44*795d594fSAndroid Build Coastguard Worker   }
45*795d594fSAndroid Build Coastguard Worker   U current_index = 0u;
46*795d594fSAndroid Build Coastguard Worker   SafeMap<T, U> ret;
47*795d594fSAndroid Build Coastguard Worker   for (auto&& pair : most_used) {
48*795d594fSAndroid Build Coastguard Worker     CHECK(ret.emplace(pair.second, current_index++).second);
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker   return ret;
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker template <typename A, typename B>
operator <<(std::ostream & os,const std::pair<A,B> & pair)54*795d594fSAndroid Build Coastguard Worker std::ostream& operator <<(std::ostream& os, const std::pair<A, B>& pair) {
55*795d594fSAndroid Build Coastguard Worker   return os << "{" << pair.first << ", " << pair.second << "}";
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker template <typename T, typename... Args, template <typename...> class ArrayType>
MakeUsageMap(const ArrayType<T,Args...> & array)59*795d594fSAndroid Build Coastguard Worker SafeMap<size_t, T> MakeUsageMap(const ArrayType<T, Args...>& array) {
60*795d594fSAndroid Build Coastguard Worker   SafeMap<size_t, T> ret;
61*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < array.size(); ++i) {
62*795d594fSAndroid Build Coastguard Worker     if (array[i] > 0) {
63*795d594fSAndroid Build Coastguard Worker       ret.Put(i, array[i]);
64*795d594fSAndroid Build Coastguard Worker     }
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker   return ret;
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker template <typename T, typename U, typename... Args, template <typename...> class Map>
PrintMostUsed(std::ostream & os,const Map<T,U,Args...> & usage,size_t max_count,std::function<void (std::ostream & os,T)> printer=[](std::ostream & os,T v){})70*795d594fSAndroid Build Coastguard Worker void PrintMostUsed(std::ostream& os,
71*795d594fSAndroid Build Coastguard Worker                    const Map<T, U, Args...>& usage,
72*795d594fSAndroid Build Coastguard Worker                    size_t max_count,
73*795d594fSAndroid Build Coastguard Worker                    std::function<void(std::ostream& os, T)> printer =
74*795d594fSAndroid Build Coastguard Worker                        [](std::ostream& os, T v) {
75*795d594fSAndroid Build Coastguard Worker     os << v;
76*795d594fSAndroid Build Coastguard Worker   }) {
77*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<U, T>> sorted;
78*795d594fSAndroid Build Coastguard Worker   uint64_t total = 0u;
79*795d594fSAndroid Build Coastguard Worker   for (const auto& pair : usage) {
80*795d594fSAndroid Build Coastguard Worker     sorted.emplace_back(pair.second, pair.first);
81*795d594fSAndroid Build Coastguard Worker     total += pair.second;
82*795d594fSAndroid Build Coastguard Worker   }
83*795d594fSAndroid Build Coastguard Worker   std::sort(sorted.rbegin(), sorted.rend());
84*795d594fSAndroid Build Coastguard Worker   uint64_t other = 0u;
85*795d594fSAndroid Build Coastguard Worker   for (auto&& pair : sorted) {
86*795d594fSAndroid Build Coastguard Worker     if (max_count > 0) {
87*795d594fSAndroid Build Coastguard Worker       os << Percent(pair.first, total) << " : ";
88*795d594fSAndroid Build Coastguard Worker       printer(os, pair.second);
89*795d594fSAndroid Build Coastguard Worker       os << "\n";
90*795d594fSAndroid Build Coastguard Worker       --max_count;
91*795d594fSAndroid Build Coastguard Worker     } else {
92*795d594fSAndroid Build Coastguard Worker       other += pair.first;
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker   if (other != 0u) {
96*795d594fSAndroid Build Coastguard Worker     os << "other: " << Percent(other, total) << "\n";
97*795d594fSAndroid Build Coastguard Worker   }
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const std::vector<uint8_t> & bytes)100*795d594fSAndroid Build Coastguard Worker static inline std::ostream& operator<<(std::ostream& os, const std::vector<uint8_t>& bytes) {
101*795d594fSAndroid Build Coastguard Worker   os << std::hex;
102*795d594fSAndroid Build Coastguard Worker   for (const uint8_t& c : bytes) {
103*795d594fSAndroid Build Coastguard Worker     os << std::setw(2) << std::setfill('0') << static_cast<uint32_t>(c)
104*795d594fSAndroid Build Coastguard Worker        << (&c != &bytes.back() ? " " : "");
105*795d594fSAndroid Build Coastguard Worker   }
106*795d594fSAndroid Build Coastguard Worker   os << std::dec;
107*795d594fSAndroid Build Coastguard Worker   return os;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>> & dex_files)110*795d594fSAndroid Build Coastguard Worker void NewRegisterInstructions::ProcessDexFiles(
111*795d594fSAndroid Build Coastguard Worker     const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
112*795d594fSAndroid Build Coastguard Worker   std::set<std::vector<uint8_t>> deduped;
113*795d594fSAndroid Build Coastguard Worker   for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
114*795d594fSAndroid Build Coastguard Worker     std::map<size_t, TypeLinkage> types;
115*795d594fSAndroid Build Coastguard Worker     std::set<const void*> visited;
116*795d594fSAndroid Build Coastguard Worker     for (ClassAccessor accessor : dex_file->GetClasses()) {
117*795d594fSAndroid Build Coastguard Worker       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
118*795d594fSAndroid Build Coastguard Worker         ProcessCodeItem(*dex_file,
119*795d594fSAndroid Build Coastguard Worker                         method.GetInstructionsAndData(),
120*795d594fSAndroid Build Coastguard Worker                         accessor.GetClassIdx(),
121*795d594fSAndroid Build Coastguard Worker                         /*count_types=*/ true,
122*795d594fSAndroid Build Coastguard Worker                         types);
123*795d594fSAndroid Build Coastguard Worker       }
124*795d594fSAndroid Build Coastguard Worker     }
125*795d594fSAndroid Build Coastguard Worker     // Reorder to get an index for each map instead of a count.
126*795d594fSAndroid Build Coastguard Worker     for (auto&& pair : types) {
127*795d594fSAndroid Build Coastguard Worker       pair.second.types_ = SortByOrder(pair.second.types_, Order::kMostUsed);
128*795d594fSAndroid Build Coastguard Worker       pair.second.fields_ = SortByOrder(pair.second.fields_, Order::kMostUsed);
129*795d594fSAndroid Build Coastguard Worker       pair.second.methods_ = SortByOrder(pair.second.methods_, Order::kMostUsed);
130*795d594fSAndroid Build Coastguard Worker       pair.second.strings_ = SortByOrder(pair.second.strings_, Order::kMostUsed);
131*795d594fSAndroid Build Coastguard Worker     }
132*795d594fSAndroid Build Coastguard Worker     // Visit classes and convert code items.
133*795d594fSAndroid Build Coastguard Worker     for (ClassAccessor accessor : dex_file->GetClasses()) {
134*795d594fSAndroid Build Coastguard Worker       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
135*795d594fSAndroid Build Coastguard Worker         if (method.GetCodeItem() == nullptr || !visited.insert(method.GetCodeItem()).second) {
136*795d594fSAndroid Build Coastguard Worker           continue;
137*795d594fSAndroid Build Coastguard Worker         }
138*795d594fSAndroid Build Coastguard Worker         if (verbose_level_ >= VerboseLevel::kEverything) {
139*795d594fSAndroid Build Coastguard Worker           std::cout << std::endl
140*795d594fSAndroid Build Coastguard Worker                     << "Processing " << dex_file->PrettyMethod(method.GetIndex(), true);
141*795d594fSAndroid Build Coastguard Worker         }
142*795d594fSAndroid Build Coastguard Worker         CodeItemDataAccessor data = method.GetInstructionsAndData();
143*795d594fSAndroid Build Coastguard Worker         ProcessCodeItem(*dex_file,
144*795d594fSAndroid Build Coastguard Worker                         data,
145*795d594fSAndroid Build Coastguard Worker                         accessor.GetClassIdx(),
146*795d594fSAndroid Build Coastguard Worker                         /*count_types=*/ false,
147*795d594fSAndroid Build Coastguard Worker                         types);
148*795d594fSAndroid Build Coastguard Worker         std::vector<uint8_t> buffer = std::move(buffer_);
149*795d594fSAndroid Build Coastguard Worker         buffer_.clear();
150*795d594fSAndroid Build Coastguard Worker         const size_t buffer_size = buffer.size();
151*795d594fSAndroid Build Coastguard Worker         dex_code_bytes_ += data.InsnsSizeInBytes();
152*795d594fSAndroid Build Coastguard Worker         output_size_ += buffer_size;
153*795d594fSAndroid Build Coastguard Worker         // Add extra data at the end to have fair dedupe.
154*795d594fSAndroid Build Coastguard Worker         EncodeUnsignedLeb128(&buffer, data.RegistersSize());
155*795d594fSAndroid Build Coastguard Worker         EncodeUnsignedLeb128(&buffer, data.InsSize());
156*795d594fSAndroid Build Coastguard Worker         EncodeUnsignedLeb128(&buffer, data.OutsSize());
157*795d594fSAndroid Build Coastguard Worker         EncodeUnsignedLeb128(&buffer, data.TriesSize());
158*795d594fSAndroid Build Coastguard Worker         EncodeUnsignedLeb128(&buffer, data.InsnsSizeInCodeUnits());
159*795d594fSAndroid Build Coastguard Worker         if (deduped.insert(buffer).second) {
160*795d594fSAndroid Build Coastguard Worker           deduped_size_ += buffer_size;
161*795d594fSAndroid Build Coastguard Worker         }
162*795d594fSAndroid Build Coastguard Worker       }
163*795d594fSAndroid Build Coastguard Worker     }
164*795d594fSAndroid Build Coastguard Worker   }
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os,uint64_t total_size) const167*795d594fSAndroid Build Coastguard Worker void NewRegisterInstructions::Dump(std::ostream& os, uint64_t total_size) const {
168*795d594fSAndroid Build Coastguard Worker   os << "Enabled experiments " << experiments_ << std::endl;
169*795d594fSAndroid Build Coastguard Worker   os << "Total Dex code bytes: " << Percent(dex_code_bytes_, total_size) << "\n";
170*795d594fSAndroid Build Coastguard Worker   os << "Total output code bytes: " << Percent(output_size_, total_size) << "\n";
171*795d594fSAndroid Build Coastguard Worker   os << "Total deduped code bytes: " << Percent(deduped_size_, total_size) << "\n";
172*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<size_t, std::vector<uint8_t>>> pairs;
173*795d594fSAndroid Build Coastguard Worker   for (auto&& pair : instruction_freq_) {
174*795d594fSAndroid Build Coastguard Worker     if (pair.second > 0 && !pair.first.empty()) {
175*795d594fSAndroid Build Coastguard Worker       // Savings exclude one byte per occurrence and one occurrence from having the macro
176*795d594fSAndroid Build Coastguard Worker       // dictionary.
177*795d594fSAndroid Build Coastguard Worker       pairs.emplace_back((pair.second - 1) * (pair.first.size() - 1), pair.first);
178*795d594fSAndroid Build Coastguard Worker     }
179*795d594fSAndroid Build Coastguard Worker   }
180*795d594fSAndroid Build Coastguard Worker   std::sort(pairs.rbegin(), pairs.rend());
181*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxMacros = 128;
182*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxPrintedMacros = 32;
183*795d594fSAndroid Build Coastguard Worker   uint64_t top_instructions_savings = 0u;
184*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
185*795d594fSAndroid Build Coastguard Worker     top_instructions_savings += pairs[i].first;
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker   if (verbose_level_ >= VerboseLevel::kNormal) {
188*795d594fSAndroid Build Coastguard Worker     os << "Move result register distribution" << "\n";
189*795d594fSAndroid Build Coastguard Worker     PrintMostUsed(os, MakeUsageMap(move_result_reg_), 16);
190*795d594fSAndroid Build Coastguard Worker     os << "First arg register usage\n";
191*795d594fSAndroid Build Coastguard Worker     std::function<void(std::ostream& os, size_t)> printer = [&](std::ostream& os, size_t idx) {
192*795d594fSAndroid Build Coastguard Worker       os << Instruction::Name(static_cast<Instruction::Code>(idx));
193*795d594fSAndroid Build Coastguard Worker     };
194*795d594fSAndroid Build Coastguard Worker     PrintMostUsed(os, MakeUsageMap(first_arg_reg_count_), 16, printer);
195*795d594fSAndroid Build Coastguard Worker     os << "Most used field linkage pairs\n";
196*795d594fSAndroid Build Coastguard Worker     PrintMostUsed(os, field_linkage_counts_, 32);
197*795d594fSAndroid Build Coastguard Worker     os << "Current extended " << extended_field_ << "\n";
198*795d594fSAndroid Build Coastguard Worker     os << "Most used method linkage pairs\n";
199*795d594fSAndroid Build Coastguard Worker     PrintMostUsed(os, method_linkage_counts_, 32);
200*795d594fSAndroid Build Coastguard Worker     os << "Current extended " << extended_method_ << "\n";
201*795d594fSAndroid Build Coastguard Worker     os << "Top " << kMaxMacros << " instruction bytecode sizes and hex dump" << "\n";
202*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
203*795d594fSAndroid Build Coastguard Worker       auto bytes = pairs[i].second;
204*795d594fSAndroid Build Coastguard Worker       // Remove opcode bytes.
205*795d594fSAndroid Build Coastguard Worker       bytes.erase(bytes.begin());
206*795d594fSAndroid Build Coastguard Worker       if (i < kMaxPrintedMacros) {
207*795d594fSAndroid Build Coastguard Worker         os << Percent(pairs[i].first, total_size) << " "
208*795d594fSAndroid Build Coastguard Worker            << Instruction::Name(static_cast<Instruction::Code>(pairs[i].second[0]))
209*795d594fSAndroid Build Coastguard Worker            << "(" << bytes << ")\n";
210*795d594fSAndroid Build Coastguard Worker       }
211*795d594fSAndroid Build Coastguard Worker     }
212*795d594fSAndroid Build Coastguard Worker   }
213*795d594fSAndroid Build Coastguard Worker   os << "Top instructions 1b macro savings "
214*795d594fSAndroid Build Coastguard Worker      << Percent(top_instructions_savings, total_size) << "\n";
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
ProcessCodeItem(const DexFile & dex_file,const CodeItemDataAccessor & code_item,dex::TypeIndex current_class_type,bool count_types,std::map<size_t,TypeLinkage> & types)217*795d594fSAndroid Build Coastguard Worker void NewRegisterInstructions::ProcessCodeItem(const DexFile& dex_file,
218*795d594fSAndroid Build Coastguard Worker                                               const CodeItemDataAccessor& code_item,
219*795d594fSAndroid Build Coastguard Worker                                               dex::TypeIndex current_class_type,
220*795d594fSAndroid Build Coastguard Worker                                               bool count_types,
221*795d594fSAndroid Build Coastguard Worker                                               std::map<size_t, TypeLinkage>& types) {
222*795d594fSAndroid Build Coastguard Worker   TypeLinkage& current_type = types[current_class_type.index_];
223*795d594fSAndroid Build Coastguard Worker   bool skip_next = false;
224*795d594fSAndroid Build Coastguard Worker   for (auto inst = code_item.begin(); inst != code_item.end(); ++inst) {
225*795d594fSAndroid Build Coastguard Worker     if (verbose_level_ >= VerboseLevel::kEverything) {
226*795d594fSAndroid Build Coastguard Worker       std::cout << std::endl;
227*795d594fSAndroid Build Coastguard Worker       std::cout << inst->DumpString(nullptr);
228*795d594fSAndroid Build Coastguard Worker       if (skip_next) {
229*795d594fSAndroid Build Coastguard Worker         std::cout << " (SKIPPED)";
230*795d594fSAndroid Build Coastguard Worker       }
231*795d594fSAndroid Build Coastguard Worker     }
232*795d594fSAndroid Build Coastguard Worker     if (skip_next) {
233*795d594fSAndroid Build Coastguard Worker       skip_next = false;
234*795d594fSAndroid Build Coastguard Worker       continue;
235*795d594fSAndroid Build Coastguard Worker     }
236*795d594fSAndroid Build Coastguard Worker     bool is_iget = false;
237*795d594fSAndroid Build Coastguard Worker     const Instruction::Code opcode = inst->Opcode();
238*795d594fSAndroid Build Coastguard Worker     Instruction::Code new_opcode = opcode;
239*795d594fSAndroid Build Coastguard Worker     ++opcode_count_[opcode];
240*795d594fSAndroid Build Coastguard Worker     switch (opcode) {
241*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET:
242*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_WIDE:
243*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_OBJECT:
244*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_BOOLEAN:
245*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_BYTE:
246*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_CHAR:
247*795d594fSAndroid Build Coastguard Worker       case Instruction::IGET_SHORT:
248*795d594fSAndroid Build Coastguard Worker         is_iget = true;
249*795d594fSAndroid Build Coastguard Worker         FALLTHROUGH_INTENDED;
250*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT:
251*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_WIDE:
252*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_OBJECT:
253*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_BOOLEAN:
254*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_BYTE:
255*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_CHAR:
256*795d594fSAndroid Build Coastguard Worker       case Instruction::IPUT_SHORT: {
257*795d594fSAndroid Build Coastguard Worker         const uint32_t dex_field_idx = inst->VRegC_22c();
258*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentSingleGetSet)) {
259*795d594fSAndroid Build Coastguard Worker           // Test deduplication improvements from replacing all iget/set with the same opcode.
260*795d594fSAndroid Build Coastguard Worker           new_opcode = is_iget ? Instruction::IGET : Instruction::IPUT;
261*795d594fSAndroid Build Coastguard Worker         }
262*795d594fSAndroid Build Coastguard Worker         CHECK_LT(dex_field_idx, dex_file.NumFieldIds());
263*795d594fSAndroid Build Coastguard Worker         dex::TypeIndex holder_type = dex_file.GetFieldId(dex_field_idx).class_idx_;
264*795d594fSAndroid Build Coastguard Worker         uint32_t receiver = inst->VRegB_22c();
265*795d594fSAndroid Build Coastguard Worker         uint32_t first_arg_reg = code_item.RegistersSize() - code_item.InsSize();
266*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = inst->VRegA_22c();
267*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentInstanceFieldSelf) &&
268*795d594fSAndroid Build Coastguard Worker             first_arg_reg == receiver &&
269*795d594fSAndroid Build Coastguard Worker             holder_type == current_class_type) {
270*795d594fSAndroid Build Coastguard Worker           if (count_types) {
271*795d594fSAndroid Build Coastguard Worker             ++current_type.fields_.FindOrAdd(dex_field_idx)->second;
272*795d594fSAndroid Build Coastguard Worker           } else {
273*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
274*795d594fSAndroid Build Coastguard Worker             ExtendPrefix(&out_reg, &field_idx);
275*795d594fSAndroid Build Coastguard Worker             CHECK(InstNibbles(new_opcode, {out_reg, field_idx}));
276*795d594fSAndroid Build Coastguard Worker             continue;
277*795d594fSAndroid Build Coastguard Worker           }
278*795d594fSAndroid Build Coastguard Worker         } else if (Enabled(kExperimentInstanceField)) {
279*795d594fSAndroid Build Coastguard Worker           if (count_types) {
280*795d594fSAndroid Build Coastguard Worker             ++current_type.types_.FindOrAdd(holder_type.index_)->second;
281*795d594fSAndroid Build Coastguard Worker             ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
282*795d594fSAndroid Build Coastguard Worker           } else {
283*795d594fSAndroid Build Coastguard Worker             uint32_t type_idx = current_type.types_.Get(holder_type.index_);
284*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
285*795d594fSAndroid Build Coastguard Worker             ExtendPrefix(&type_idx, &field_idx);
286*795d594fSAndroid Build Coastguard Worker             CHECK(InstNibbles(new_opcode, {out_reg, receiver, type_idx, field_idx}));
287*795d594fSAndroid Build Coastguard Worker             continue;
288*795d594fSAndroid Build Coastguard Worker           }
289*795d594fSAndroid Build Coastguard Worker         }
290*795d594fSAndroid Build Coastguard Worker         break;
291*795d594fSAndroid Build Coastguard Worker       }
292*795d594fSAndroid Build Coastguard Worker       case Instruction::CONST_STRING:
293*795d594fSAndroid Build Coastguard Worker       case Instruction::CONST_STRING_JUMBO: {
294*795d594fSAndroid Build Coastguard Worker         const bool is_jumbo = opcode == Instruction::CONST_STRING_JUMBO;
295*795d594fSAndroid Build Coastguard Worker         const uint16_t str_idx = is_jumbo ? inst->VRegB_31c() : inst->VRegB_21c();
296*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = is_jumbo ? inst->VRegA_31c() : inst->VRegA_21c();
297*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentString)) {
298*795d594fSAndroid Build Coastguard Worker           new_opcode = Instruction::CONST_STRING;
299*795d594fSAndroid Build Coastguard Worker           if (count_types) {
300*795d594fSAndroid Build Coastguard Worker             ++current_type.strings_.FindOrAdd(str_idx)->second;
301*795d594fSAndroid Build Coastguard Worker           } else {
302*795d594fSAndroid Build Coastguard Worker             uint32_t idx = current_type.strings_.Get(str_idx);
303*795d594fSAndroid Build Coastguard Worker             ExtendPrefix(&out_reg, &idx);
304*795d594fSAndroid Build Coastguard Worker             CHECK(InstNibbles(opcode, {out_reg, idx}));
305*795d594fSAndroid Build Coastguard Worker             continue;
306*795d594fSAndroid Build Coastguard Worker           }
307*795d594fSAndroid Build Coastguard Worker         }
308*795d594fSAndroid Build Coastguard Worker         break;
309*795d594fSAndroid Build Coastguard Worker       }
310*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET:
311*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_WIDE:
312*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_OBJECT:
313*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_BOOLEAN:
314*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_BYTE:
315*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_CHAR:
316*795d594fSAndroid Build Coastguard Worker       case Instruction::SGET_SHORT:
317*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT:
318*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_WIDE:
319*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_OBJECT:
320*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_BOOLEAN:
321*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_BYTE:
322*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_CHAR:
323*795d594fSAndroid Build Coastguard Worker       case Instruction::SPUT_SHORT: {
324*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = inst->VRegA_21c();
325*795d594fSAndroid Build Coastguard Worker         const uint32_t dex_field_idx = inst->VRegB_21c();
326*795d594fSAndroid Build Coastguard Worker         CHECK_LT(dex_field_idx, dex_file.NumFieldIds());
327*795d594fSAndroid Build Coastguard Worker         dex::TypeIndex holder_type = dex_file.GetFieldId(dex_field_idx).class_idx_;
328*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentStaticField)) {
329*795d594fSAndroid Build Coastguard Worker           if (holder_type == current_class_type) {
330*795d594fSAndroid Build Coastguard Worker             if (count_types) {
331*795d594fSAndroid Build Coastguard Worker               ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
332*795d594fSAndroid Build Coastguard Worker             } else {
333*795d594fSAndroid Build Coastguard Worker               uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
334*795d594fSAndroid Build Coastguard Worker               ExtendPrefix(&out_reg, &field_idx);
335*795d594fSAndroid Build Coastguard Worker               if (InstNibbles(new_opcode, {out_reg, field_idx})) {
336*795d594fSAndroid Build Coastguard Worker                 continue;
337*795d594fSAndroid Build Coastguard Worker               }
338*795d594fSAndroid Build Coastguard Worker             }
339*795d594fSAndroid Build Coastguard Worker           } else {
340*795d594fSAndroid Build Coastguard Worker             if (count_types) {
341*795d594fSAndroid Build Coastguard Worker               ++types[current_class_type.index_].types_.FindOrAdd(holder_type.index_)->second;
342*795d594fSAndroid Build Coastguard Worker               ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
343*795d594fSAndroid Build Coastguard Worker             } else {
344*795d594fSAndroid Build Coastguard Worker               uint32_t type_idx = current_type.types_.Get(holder_type.index_);
345*795d594fSAndroid Build Coastguard Worker               uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
346*795d594fSAndroid Build Coastguard Worker               ++field_linkage_counts_[std::make_pair(type_idx, field_idx)];
347*795d594fSAndroid Build Coastguard Worker               extended_field_ += ExtendPrefix(&type_idx, &field_idx) ? 1u : 0u;
348*795d594fSAndroid Build Coastguard Worker               if (InstNibbles(new_opcode, {out_reg >> 4, out_reg & 0xF, type_idx, field_idx})) {
349*795d594fSAndroid Build Coastguard Worker                 continue;
350*795d594fSAndroid Build Coastguard Worker               }
351*795d594fSAndroid Build Coastguard Worker             }
352*795d594fSAndroid Build Coastguard Worker           }
353*795d594fSAndroid Build Coastguard Worker         }
354*795d594fSAndroid Build Coastguard Worker         break;
355*795d594fSAndroid Build Coastguard Worker       }
356*795d594fSAndroid Build Coastguard Worker       // Invoke cases.
357*795d594fSAndroid Build Coastguard Worker       case Instruction::INVOKE_VIRTUAL:
358*795d594fSAndroid Build Coastguard Worker       case Instruction::INVOKE_DIRECT:
359*795d594fSAndroid Build Coastguard Worker       case Instruction::INVOKE_STATIC:
360*795d594fSAndroid Build Coastguard Worker       case Instruction::INVOKE_INTERFACE:
361*795d594fSAndroid Build Coastguard Worker       case Instruction::INVOKE_SUPER: {
362*795d594fSAndroid Build Coastguard Worker         const uint32_t method_idx = DexMethodIndex(inst.Inst());
363*795d594fSAndroid Build Coastguard Worker         const dex::MethodId& method = dex_file.GetMethodId(method_idx);
364*795d594fSAndroid Build Coastguard Worker         const dex::TypeIndex receiver_type = method.class_idx_;
365*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentInvoke)) {
366*795d594fSAndroid Build Coastguard Worker           if (count_types) {
367*795d594fSAndroid Build Coastguard Worker             ++current_type.types_.FindOrAdd(receiver_type.index_)->second;
368*795d594fSAndroid Build Coastguard Worker             ++types[receiver_type.index_].methods_.FindOrAdd(method_idx)->second;
369*795d594fSAndroid Build Coastguard Worker           } else {
370*795d594fSAndroid Build Coastguard Worker             uint32_t args[6] = {};
371*795d594fSAndroid Build Coastguard Worker             uint32_t arg_count = inst->GetVarArgs(args);
372*795d594fSAndroid Build Coastguard Worker             const uint32_t first_arg_reg = code_item.RegistersSize() - code_item.InsSize();
373*795d594fSAndroid Build Coastguard Worker 
374*795d594fSAndroid Build Coastguard Worker             bool next_move_result = false;
375*795d594fSAndroid Build Coastguard Worker             uint32_t dest_reg = 0;
376*795d594fSAndroid Build Coastguard Worker             auto next = std::next(inst);
377*795d594fSAndroid Build Coastguard Worker             if (next != code_item.end()) {
378*795d594fSAndroid Build Coastguard Worker               next_move_result =
379*795d594fSAndroid Build Coastguard Worker                   next->Opcode() == Instruction::MOVE_RESULT ||
380*795d594fSAndroid Build Coastguard Worker                   next->Opcode() == Instruction::MOVE_RESULT_WIDE ||
381*795d594fSAndroid Build Coastguard Worker                   next->Opcode() == Instruction::MOVE_RESULT_OBJECT;
382*795d594fSAndroid Build Coastguard Worker               if (next_move_result) {
383*795d594fSAndroid Build Coastguard Worker                 dest_reg = next->VRegA_11x();
384*795d594fSAndroid Build Coastguard Worker                 ++move_result_reg_[dest_reg];
385*795d594fSAndroid Build Coastguard Worker               }
386*795d594fSAndroid Build Coastguard Worker             }
387*795d594fSAndroid Build Coastguard Worker 
388*795d594fSAndroid Build Coastguard Worker             uint32_t type_idx = current_type.types_.Get(receiver_type.index_);
389*795d594fSAndroid Build Coastguard Worker             uint32_t local_idx = types[receiver_type.index_].methods_.Get(method_idx);
390*795d594fSAndroid Build Coastguard Worker             ++method_linkage_counts_[std::make_pair(type_idx, local_idx)];
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker             // If true, we always put the return value in r0.
393*795d594fSAndroid Build Coastguard Worker             static constexpr bool kMoveToDestReg = true;
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker             std::vector<uint32_t> new_args;
396*795d594fSAndroid Build Coastguard Worker             if (kMoveToDestReg && arg_count % 2 == 1) {
397*795d594fSAndroid Build Coastguard Worker               // Use the extra nibble to sneak in part of the type index.
398*795d594fSAndroid Build Coastguard Worker               new_args.push_back(local_idx >> 4);
399*795d594fSAndroid Build Coastguard Worker               local_idx &= ~0xF0;
400*795d594fSAndroid Build Coastguard Worker             }
401*795d594fSAndroid Build Coastguard Worker             extended_method_ += ExtendPrefix(&type_idx, &local_idx) ? 1u : 0u;
402*795d594fSAndroid Build Coastguard Worker             new_args.push_back(type_idx);
403*795d594fSAndroid Build Coastguard Worker             new_args.push_back(local_idx);
404*795d594fSAndroid Build Coastguard Worker             if (!kMoveToDestReg) {
405*795d594fSAndroid Build Coastguard Worker               ExtendPrefix(&dest_reg, &local_idx);
406*795d594fSAndroid Build Coastguard Worker               new_args.push_back(dest_reg);
407*795d594fSAndroid Build Coastguard Worker             }
408*795d594fSAndroid Build Coastguard Worker             for (size_t i = 0; i < arg_count; ++i) {
409*795d594fSAndroid Build Coastguard Worker               if (args[i] == first_arg_reg) {
410*795d594fSAndroid Build Coastguard Worker                 ++first_arg_reg_count_[opcode];
411*795d594fSAndroid Build Coastguard Worker                 break;
412*795d594fSAndroid Build Coastguard Worker               }
413*795d594fSAndroid Build Coastguard Worker             }
414*795d594fSAndroid Build Coastguard Worker             new_args.insert(new_args.end(), args, args + arg_count);
415*795d594fSAndroid Build Coastguard Worker             if (InstNibbles(opcode, new_args)) {
416*795d594fSAndroid Build Coastguard Worker               skip_next = next_move_result;
417*795d594fSAndroid Build Coastguard Worker               if (kMoveToDestReg && dest_reg != 0u) {
418*795d594fSAndroid Build Coastguard Worker                 CHECK(InstNibbles(Instruction::MOVE, {dest_reg >> 4, dest_reg & 0xF}));
419*795d594fSAndroid Build Coastguard Worker               }
420*795d594fSAndroid Build Coastguard Worker               continue;
421*795d594fSAndroid Build Coastguard Worker             }
422*795d594fSAndroid Build Coastguard Worker           }
423*795d594fSAndroid Build Coastguard Worker         }
424*795d594fSAndroid Build Coastguard Worker         break;
425*795d594fSAndroid Build Coastguard Worker       }
426*795d594fSAndroid Build Coastguard Worker       case Instruction::IF_EQZ:
427*795d594fSAndroid Build Coastguard Worker       case Instruction::IF_NEZ: {
428*795d594fSAndroid Build Coastguard Worker         uint32_t reg = inst->VRegA_21t();
429*795d594fSAndroid Build Coastguard Worker         int16_t offset = inst->VRegB_21t();
430*795d594fSAndroid Build Coastguard Worker         if (!count_types &&
431*795d594fSAndroid Build Coastguard Worker             Enabled(kExperimentSmallIf) &&
432*795d594fSAndroid Build Coastguard Worker             InstNibbles(opcode, {reg, static_cast<uint16_t>(offset)})) {
433*795d594fSAndroid Build Coastguard Worker           continue;
434*795d594fSAndroid Build Coastguard Worker         }
435*795d594fSAndroid Build Coastguard Worker         break;
436*795d594fSAndroid Build Coastguard Worker       }
437*795d594fSAndroid Build Coastguard Worker       case Instruction::INSTANCE_OF: {
438*795d594fSAndroid Build Coastguard Worker         uint32_t type_idx = inst->VRegC_22c();
439*795d594fSAndroid Build Coastguard Worker         uint32_t in_reg = inst->VRegB_22c();
440*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = inst->VRegA_22c();
441*795d594fSAndroid Build Coastguard Worker         if (count_types) {
442*795d594fSAndroid Build Coastguard Worker           ++current_type.types_.FindOrAdd(type_idx)->second;
443*795d594fSAndroid Build Coastguard Worker         } else {
444*795d594fSAndroid Build Coastguard Worker           uint32_t local_type = current_type.types_.Get(type_idx);
445*795d594fSAndroid Build Coastguard Worker           ExtendPrefix(&in_reg, &local_type);
446*795d594fSAndroid Build Coastguard Worker           CHECK(InstNibbles(new_opcode, {in_reg, out_reg, local_type}));
447*795d594fSAndroid Build Coastguard Worker           continue;
448*795d594fSAndroid Build Coastguard Worker         }
449*795d594fSAndroid Build Coastguard Worker         break;
450*795d594fSAndroid Build Coastguard Worker       }
451*795d594fSAndroid Build Coastguard Worker       case Instruction::NEW_ARRAY: {
452*795d594fSAndroid Build Coastguard Worker         uint32_t len_reg = inst->VRegB_22c();
453*795d594fSAndroid Build Coastguard Worker         uint32_t type_idx = inst->VRegC_22c();
454*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = inst->VRegA_22c();
455*795d594fSAndroid Build Coastguard Worker         if (count_types) {
456*795d594fSAndroid Build Coastguard Worker           ++current_type.types_.FindOrAdd(type_idx)->second;
457*795d594fSAndroid Build Coastguard Worker         } else {
458*795d594fSAndroid Build Coastguard Worker           uint32_t local_type = current_type.types_.Get(type_idx);
459*795d594fSAndroid Build Coastguard Worker           ExtendPrefix(&out_reg, &local_type);
460*795d594fSAndroid Build Coastguard Worker           CHECK(InstNibbles(new_opcode, {len_reg, out_reg, local_type}));
461*795d594fSAndroid Build Coastguard Worker           continue;
462*795d594fSAndroid Build Coastguard Worker         }
463*795d594fSAndroid Build Coastguard Worker         break;
464*795d594fSAndroid Build Coastguard Worker       }
465*795d594fSAndroid Build Coastguard Worker       case Instruction::CONST_CLASS:
466*795d594fSAndroid Build Coastguard Worker       case Instruction::CHECK_CAST:
467*795d594fSAndroid Build Coastguard Worker       case Instruction::NEW_INSTANCE: {
468*795d594fSAndroid Build Coastguard Worker         uint32_t type_idx = inst->VRegB_21c();
469*795d594fSAndroid Build Coastguard Worker         uint32_t out_reg = inst->VRegA_21c();
470*795d594fSAndroid Build Coastguard Worker         if (Enabled(kExperimentLocalType)) {
471*795d594fSAndroid Build Coastguard Worker           if (count_types) {
472*795d594fSAndroid Build Coastguard Worker             ++current_type.types_.FindOrAdd(type_idx)->second;
473*795d594fSAndroid Build Coastguard Worker           } else {
474*795d594fSAndroid Build Coastguard Worker             bool next_is_init = false;
475*795d594fSAndroid Build Coastguard Worker             if (opcode == Instruction::NEW_INSTANCE) {
476*795d594fSAndroid Build Coastguard Worker               auto next = std::next(inst);
477*795d594fSAndroid Build Coastguard Worker               if (next != code_item.end() && next->Opcode() == Instruction::INVOKE_DIRECT) {
478*795d594fSAndroid Build Coastguard Worker                 uint32_t args[6] = {};
479*795d594fSAndroid Build Coastguard Worker                 uint32_t arg_count = next->GetVarArgs(args);
480*795d594fSAndroid Build Coastguard Worker                 uint32_t method_idx = DexMethodIndex(next.Inst());
481*795d594fSAndroid Build Coastguard Worker                 if (arg_count == 1u &&
482*795d594fSAndroid Build Coastguard Worker                     args[0] == out_reg &&
483*795d594fSAndroid Build Coastguard Worker                     dex_file.GetMethodName(dex_file.GetMethodId(method_idx)) ==
484*795d594fSAndroid Build Coastguard Worker                         std::string("<init>")) {
485*795d594fSAndroid Build Coastguard Worker                   next_is_init = true;
486*795d594fSAndroid Build Coastguard Worker                 }
487*795d594fSAndroid Build Coastguard Worker               }
488*795d594fSAndroid Build Coastguard Worker             }
489*795d594fSAndroid Build Coastguard Worker             uint32_t local_type = current_type.types_.Get(type_idx);
490*795d594fSAndroid Build Coastguard Worker             ExtendPrefix(&out_reg, &local_type);
491*795d594fSAndroid Build Coastguard Worker             CHECK(InstNibbles(opcode, {out_reg, local_type}));
492*795d594fSAndroid Build Coastguard Worker             skip_next = next_is_init;
493*795d594fSAndroid Build Coastguard Worker             continue;
494*795d594fSAndroid Build Coastguard Worker           }
495*795d594fSAndroid Build Coastguard Worker         }
496*795d594fSAndroid Build Coastguard Worker         break;
497*795d594fSAndroid Build Coastguard Worker       }
498*795d594fSAndroid Build Coastguard Worker       case Instruction::RETURN:
499*795d594fSAndroid Build Coastguard Worker       case Instruction::RETURN_OBJECT:
500*795d594fSAndroid Build Coastguard Worker       case Instruction::RETURN_WIDE:
501*795d594fSAndroid Build Coastguard Worker       case Instruction::RETURN_VOID: {
502*795d594fSAndroid Build Coastguard Worker         if (!count_types && Enabled(kExperimentReturn)) {
503*795d594fSAndroid Build Coastguard Worker           if (opcode == Instruction::RETURN_VOID || inst->VRegA_11x() == 0) {
504*795d594fSAndroid Build Coastguard Worker             if (InstNibbles(opcode, {})) {
505*795d594fSAndroid Build Coastguard Worker               continue;
506*795d594fSAndroid Build Coastguard Worker             }
507*795d594fSAndroid Build Coastguard Worker           }
508*795d594fSAndroid Build Coastguard Worker         }
509*795d594fSAndroid Build Coastguard Worker         break;
510*795d594fSAndroid Build Coastguard Worker       }
511*795d594fSAndroid Build Coastguard Worker       default:
512*795d594fSAndroid Build Coastguard Worker         break;
513*795d594fSAndroid Build Coastguard Worker     }
514*795d594fSAndroid Build Coastguard Worker     if (!count_types) {
515*795d594fSAndroid Build Coastguard Worker       Add(new_opcode, inst.Inst());
516*795d594fSAndroid Build Coastguard Worker     }
517*795d594fSAndroid Build Coastguard Worker   }
518*795d594fSAndroid Build Coastguard Worker   if (verbose_level_ >= VerboseLevel::kEverything) {
519*795d594fSAndroid Build Coastguard Worker     std::cout << std::endl
520*795d594fSAndroid Build Coastguard Worker               << "Bytecode size " << code_item.InsnsSizeInBytes() << " -> " << buffer_.size();
521*795d594fSAndroid Build Coastguard Worker     std::cout << std::endl;
522*795d594fSAndroid Build Coastguard Worker   }
523*795d594fSAndroid Build Coastguard Worker }
524*795d594fSAndroid Build Coastguard Worker 
Add(Instruction::Code opcode,const Instruction & inst)525*795d594fSAndroid Build Coastguard Worker void NewRegisterInstructions::Add(Instruction::Code opcode, const Instruction& inst) {
526*795d594fSAndroid Build Coastguard Worker   const uint8_t* start = reinterpret_cast<const uint8_t*>(&inst);
527*795d594fSAndroid Build Coastguard Worker   const size_t buffer_start = buffer_.size();
528*795d594fSAndroid Build Coastguard Worker   buffer_.push_back(opcode);
529*795d594fSAndroid Build Coastguard Worker   buffer_.insert(buffer_.end(), start + 1, start + 2 * inst.SizeInCodeUnits());
530*795d594fSAndroid Build Coastguard Worker   // Register the instruction blob.
531*795d594fSAndroid Build Coastguard Worker   ++instruction_freq_[std::vector<uint8_t>(buffer_.begin() + buffer_start, buffer_.end())];
532*795d594fSAndroid Build Coastguard Worker }
533*795d594fSAndroid Build Coastguard Worker 
ExtendPrefix(uint32_t * value1,uint32_t * value2)534*795d594fSAndroid Build Coastguard Worker bool NewRegisterInstructions::ExtendPrefix(uint32_t* value1, uint32_t* value2) {
535*795d594fSAndroid Build Coastguard Worker   if (*value1 < 16 && *value2 < 16) {
536*795d594fSAndroid Build Coastguard Worker     return false;
537*795d594fSAndroid Build Coastguard Worker   }
538*795d594fSAndroid Build Coastguard Worker   if ((*value1 >> 4) == 1 && *value2 < 16) {
539*795d594fSAndroid Build Coastguard Worker     InstNibbles(0xE5, {});
540*795d594fSAndroid Build Coastguard Worker     *value1 ^= 1u << 4;
541*795d594fSAndroid Build Coastguard Worker     return true;
542*795d594fSAndroid Build Coastguard Worker   } else if ((*value2 >> 4) == 1 && *value1 < 16) {
543*795d594fSAndroid Build Coastguard Worker     InstNibbles(0xE6, {});
544*795d594fSAndroid Build Coastguard Worker     *value2 ^= 1u << 4;
545*795d594fSAndroid Build Coastguard Worker     return true;
546*795d594fSAndroid Build Coastguard Worker   }
547*795d594fSAndroid Build Coastguard Worker   if (*value1 < 256 && *value2 < 256) {
548*795d594fSAndroid Build Coastguard Worker     // Extend each value by 4 bits.
549*795d594fSAndroid Build Coastguard Worker     CHECK(InstNibbles(0xE3, {*value1 >> 4, *value2 >> 4}));
550*795d594fSAndroid Build Coastguard Worker   } else {
551*795d594fSAndroid Build Coastguard Worker     // Extend each value by 12 bits.
552*795d594fSAndroid Build Coastguard Worker     CHECK(InstNibbles(0xE4, {
553*795d594fSAndroid Build Coastguard Worker         (*value1 >> 12) & 0xF,
554*795d594fSAndroid Build Coastguard Worker         (*value1 >> 8) & 0xF,
555*795d594fSAndroid Build Coastguard Worker         (*value1 >> 4) & 0xF,
556*795d594fSAndroid Build Coastguard Worker         (*value2 >> 12) & 0xF,
557*795d594fSAndroid Build Coastguard Worker         (*value2 >> 8) & 0xF,
558*795d594fSAndroid Build Coastguard Worker         (*value2 >> 4) & 0xF}));
559*795d594fSAndroid Build Coastguard Worker   }
560*795d594fSAndroid Build Coastguard Worker   *value1 &= 0xF;
561*795d594fSAndroid Build Coastguard Worker   *value2 &= 0XF;
562*795d594fSAndroid Build Coastguard Worker   return true;
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker 
InstNibbles(uint8_t opcode,const std::vector<uint32_t> & args)565*795d594fSAndroid Build Coastguard Worker bool NewRegisterInstructions::InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args) {
566*795d594fSAndroid Build Coastguard Worker   if (verbose_level_ >= VerboseLevel::kEverything) {
567*795d594fSAndroid Build Coastguard Worker     std::cout << " ==> " << Instruction::Name(static_cast<Instruction::Code>(opcode)) << " ";
568*795d594fSAndroid Build Coastguard Worker     for (int v : args) {
569*795d594fSAndroid Build Coastguard Worker       std::cout << v << ", ";
570*795d594fSAndroid Build Coastguard Worker     }
571*795d594fSAndroid Build Coastguard Worker   }
572*795d594fSAndroid Build Coastguard Worker   for (int v : args) {
573*795d594fSAndroid Build Coastguard Worker     if (v >= 16) {
574*795d594fSAndroid Build Coastguard Worker       if (verbose_level_ >= VerboseLevel::kEverything) {
575*795d594fSAndroid Build Coastguard Worker         std::cout << "(OUT_OF_RANGE)";
576*795d594fSAndroid Build Coastguard Worker       }
577*795d594fSAndroid Build Coastguard Worker       return false;
578*795d594fSAndroid Build Coastguard Worker     }
579*795d594fSAndroid Build Coastguard Worker   }
580*795d594fSAndroid Build Coastguard Worker   const size_t buffer_start = buffer_.size();
581*795d594fSAndroid Build Coastguard Worker   buffer_.push_back(opcode);
582*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < args.size(); i += 2) {
583*795d594fSAndroid Build Coastguard Worker     buffer_.push_back(args[i] << 4);
584*795d594fSAndroid Build Coastguard Worker     if (i + 1 < args.size()) {
585*795d594fSAndroid Build Coastguard Worker       buffer_.back() |= args[i + 1];
586*795d594fSAndroid Build Coastguard Worker     }
587*795d594fSAndroid Build Coastguard Worker   }
588*795d594fSAndroid Build Coastguard Worker   while (buffer_.size() % alignment_ != 0) {
589*795d594fSAndroid Build Coastguard Worker     buffer_.push_back(0);
590*795d594fSAndroid Build Coastguard Worker   }
591*795d594fSAndroid Build Coastguard Worker   // Register the instruction blob.
592*795d594fSAndroid Build Coastguard Worker   ++instruction_freq_[std::vector<uint8_t>(buffer_.begin() + buffer_start, buffer_.end())];
593*795d594fSAndroid Build Coastguard Worker   return true;
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker 
596*795d594fSAndroid Build Coastguard Worker }  // namespace dexanalyze
597*795d594fSAndroid Build Coastguard Worker }  // namespace art
598