blob: e1f119df59a2689bacef36848e6b63a128d9e054 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dexanalyze_experiments.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_instruction-inl.h"
#include "dex/standard_dex_file.h"
namespace art {
void CountDexIndices::ProcessDexFile(const DexFile& dex_file) {
num_string_ids_ += dex_file.NumStringIds();
num_method_ids_ += dex_file.NumMethodIds();
num_field_ids_ += dex_file.NumFieldIds();
num_type_ids_ += dex_file.NumTypeIds();
num_class_defs_ += dex_file.NumClassDefs();
for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); ++class_def_index) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
const uint8_t* class_data = dex_file.GetClassData(class_def);
if (class_data == nullptr) {
continue;
}
ClassDataItemIterator it(dex_file, class_data);
it.SkipAllFields();
std::set<size_t> unique_method_ids;
std::set<size_t> unique_string_ids;
while (it.HasNextMethod()) {
const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
if (code_item != nullptr) {
CodeItemInstructionAccessor instructions(dex_file, code_item);
const uint16_t* code_ptr = instructions.Insns();
dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]);
for (const DexInstructionPcPair& inst : instructions) {
switch (inst->Opcode()) {
case Instruction::CONST_STRING: {
const dex::StringIndex string_index(inst->VRegB_21c());
unique_string_ids.insert(string_index.index_);
++num_string_ids_from_code_;
break;
}
case Instruction::CONST_STRING_JUMBO: {
const dex::StringIndex string_index(inst->VRegB_31c());
unique_string_ids.insert(string_index.index_);
++num_string_ids_from_code_;
break;
}
// Invoke cases.
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) {
++same_class_virtual_;
} else {
++other_class_virtual_;
unique_method_ids.insert(method_idx);
}
break;
}
case Instruction::INVOKE_DIRECT:
case Instruction::INVOKE_DIRECT_RANGE: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) {
++same_class_direct_;
} else {
++other_class_direct_;
unique_method_ids.insert(method_idx);
}
break;
}
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_STATIC_RANGE: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) {
++same_class_static_;
} else {
++other_class_static_;
unique_method_ids.insert(method_idx);
}
break;
}
default:
break;
}
}
}
it.Next();
}
DCHECK(!it.HasNext());
total_unique_method_idx_ += unique_method_ids.size();
total_unique_string_ids_ += unique_string_ids.size();
}
}
void CountDexIndices::Dump(std::ostream& os) const {
os << "Num string ids: " << num_string_ids_ << "\n";
os << "Num method ids: " << num_method_ids_ << "\n";
os << "Num field ids: " << num_field_ids_ << "\n";
os << "Num type ids: " << num_type_ids_ << "\n";
os << "Num class defs: " << num_class_defs_ << "\n";
os << "Same class direct: " << same_class_direct_ << "\n";
os << "Other class direct: " << other_class_direct_ << "\n";
os << "Same class virtual: " << same_class_virtual_ << "\n";
os << "Other class virtual: " << other_class_virtual_ << "\n";
os << "Same class static: " << same_class_static_ << "\n";
os << "Other class static: " << other_class_static_ << "\n";
os << "Num strings accessed from code: " << num_string_ids_from_code_ << "\n";
os << "Unique(per class) method ids accessed from code: " << total_unique_method_idx_ << "\n";
os << "Unique(per class) string ids accessed from code: " << total_unique_string_ids_ << "\n";
size_t same_class_total = same_class_direct_ + same_class_virtual_ + same_class_static_;
size_t other_class_total = other_class_direct_ + other_class_virtual_ + other_class_static_;
os << "Same class invoke: " << same_class_total << "\n";
os << "Other class invoke: " << other_class_total << "\n";
os << "Invokes from code: " << (same_class_total + other_class_total) << "\n";
}
} // namespace art