// Perform logical OR on two bit vectors and assign back to LHS, i.e. `to_update |= other`. // Size of the two vectors must be equal. // Size of `other` must be equal to size of `to_update`. staticinlinevoid BitVectorOr(std::vector<bool>& to_update, const std::vector<bool>& other) {
DCHECK_EQ(to_update.size(), other.size());
std::transform(
other.begin(), other.end(), to_update.begin(), to_update.begin(), std::logical_or<bool>());
}
void VerifierDeps::MergeWith(std::unique_ptr<VerifierDeps> other, const std::vector<const DexFile*>& dex_files) {
DCHECK(other != nullptr);
DCHECK_EQ(dex_deps_.size(), other->dex_deps_.size()); for (const DexFile* dex_file : dex_files) {
DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
DexFileDeps& other_deps = *other->GetDexFileDeps(*dex_file); // We currently collect extra strings only on the main `VerifierDeps`, // which should be the one passed as `this` in this method.
DCHECK(other_deps.strings_.empty()); // Size is the number of class definitions in the dex file, and must be the // same between the two `VerifierDeps`.
DCHECK_EQ(my_deps->assignable_types_.size(), other_deps.assignable_types_.size()); for (uint32_t i = 0; i < my_deps->assignable_types_.size(); ++i) {
my_deps->assignable_types_[i].merge(other_deps.assignable_types_[i]);
}
BitVectorOr(my_deps->verified_classes_, other_deps.verified_classes_);
}
}
VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) { auto it = dex_deps_.find(&dex_file); return (it == dex_deps_.end()) ? nullptr : it->second.get();
}
const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) const { auto it = dex_deps_.find(&dex_file); return (it == dex_deps_.end()) ? nullptr : it->second.get();
}
dex::StringIndex VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
ObjPtr<mirror::Class> klass) {
DCHECK(klass != nullptr);
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache(); // Array and proxy classes do not have a dex cache. if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
DCHECK(dex_cache != nullptr) << klass->PrettyClass(); if (dex_cache->GetDexFile() == &dex_file) { // FindStringId is slow, try to go through the class def if we have one. const dex::ClassDef* class_def = klass->GetClassDef();
DCHECK(class_def != nullptr) << klass->PrettyClass(); const dex::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_); if (kIsDebugBuild) {
std::string temp;
CHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
} return type_id.descriptor_idx_;
}
}
std::string temp; return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
}
staticinline VerifierDeps* GetMainVerifierDeps(VerifierDeps* local_deps) { // The main VerifierDeps is the one set in the compiler callbacks, which at the // end of verification will have all the per-thread VerifierDeps merged into it.
CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks(); if (callbacks == nullptr) {
DCHECK(!Runtime::Current()->IsAotCompiler()); return local_deps;
}
DCHECK(Runtime::Current()->IsAotCompiler()); return callbacks->GetVerifierDeps();
}
staticbool FindExistingStringId(const std::vector<std::string>& strings, const std::string& str,
uint32_t* found_id) {
uint32_t num_extra_ids = strings.size(); for (size_t i = 0; i < num_extra_ids; ++i) { if (strings[i] == str) {
*found_id = i; returntrue;
}
} returnfalse;
}
dex::StringIndex VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) { const dex::StringId* string_id = dex_file.FindStringId(str.c_str()); if (string_id != nullptr) { // String is in the DEX file. Return its ID. return dex_file.GetIndexForStringId(*string_id);
}
// String is not in the DEX file. Assign a new ID to it which is higher than // the number of strings in the DEX file.
// We use the main `VerifierDeps` for adding new strings to simplify // synchronization/merging of these entries between threads.
VerifierDeps* singleton = GetMainVerifierDeps(this);
DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
DCHECK(deps != nullptr);
void VerifierDeps::AddAssignability(const DexFile& dex_file, const dex::ClassDef& class_def,
ObjPtr<mirror::Class> destination,
ObjPtr<mirror::Class> source) { // Test that the method is only called on reference types. // Note that concurrent verification of `destination` and `source` may have // set their status to erroneous. However, the tests performed below rely // merely on no issues with linking (valid access flags, superclass and // implemented interfaces). If the class at any point reached the IsResolved // status, the requirement holds. This is guaranteed by RegTypeCache::ResolveClass.
DCHECK(destination != nullptr);
DCHECK(source != nullptr);
if (destination->IsPrimitive() || source->IsPrimitive()) { // Primitive types are trivially non-assignable to anything else. // We do not need to record trivial assignability, as it will // not change across releases. return;
}
if (destination == source || destination->IsObjectClass()) { // Cases when `destination` is trivially assignable from `source`. return;
}
if (destination->IsArrayClass() && source->IsArrayClass()) { // Both types are arrays. Break down to component types and add recursively. // This helps filter out destinations from compiled DEX files (see below) // and deduplicate entries with the same canonical component type.
ObjPtr<mirror::Class> destination_component = destination->GetComponentType();
ObjPtr<mirror::Class> source_component = source->GetComponentType();
// Only perform the optimization if both types are resolved which guarantees // that they linked successfully, as required at the top of this method. if (destination_component->IsResolved() && source_component->IsResolved()) {
AddAssignability(dex_file, class_def, destination_component, source_component); return;
}
}
DexFileDeps* dex_deps = GetDexFileDeps(dex_file); if (dex_deps == nullptr) { // This invocation is from verification of a DEX file which is not being compiled. return;
}
// Get string IDs for both descriptors and store in the appropriate set.
dex::StringIndex destination_id = GetClassDescriptorStringId(dex_file, destination);
dex::StringIndex source_id = GetClassDescriptorStringId(dex_file, source);
uint16_t index = dex_file.GetIndexForClassDef(class_def);
dex_deps->assignable_types_[index].emplace(TypeAssignability(destination_id, source_id));
}
void VerifierDeps::AddAssignability(const DexFile& dex_file, const dex::ClassDef& class_def, const RegType& destination, const RegType& source) {
DexFileDeps* dex_deps = GetDexFileDeps(dex_file); if (dex_deps == nullptr) { // This invocation is from verification of a DEX file which is not being compiled. return;
}
template <typename T> staticvoid EncodeSetVector(std::vector<uint8_t>* out, const std::vector<std::set<T>>& vector, const std::vector<bool>& verified_classes) {
uint32_t offsets_index = out->size(); // Make room for offsets for each class, +1 for marking the end of the // assignability types data.
out->resize(out->size() + (vector.size() + 1) * sizeof(uint32_t));
uint32_t class_def_index = 0; for (const std::set<T>& set : vector) { if (verified_classes[class_def_index]) { // Store the offset of the set for this class.
SetUint32InUint8Array(out, offsets_index, class_def_index, out->size()); for (const T& entry : set) {
EncodeTuple(out, entry);
}
} else {
SetUint32InUint8Array(out, offsets_index, class_def_index, VerifierDeps::kNotVerifiedMarker);
}
class_def_index++;
}
SetUint32InUint8Array(out, offsets_index, class_def_index, out->size());
}
template <bool kFillSet, typename T> staticbool DecodeSetVector(const uint8_t** cursor, const uint8_t* start, const uint8_t* end,
std::vector<std::set<T>>* vector,
std::vector<bool>* verified_classes,
size_t num_class_defs) { const uint32_t* offsets = reinterpret_cast<const uint32_t*>(*cursor);
uint32_t next_valid_offset_index = 1; // Put the cursor after the offsets of each class, +1 for the offset of the // end of the assignable types data.
*cursor += (num_class_defs + 1) * sizeof(uint32_t); for (uint32_t i = 0; i < num_class_defs; ++i) {
uint32_t offset = offsets[i]; if (offset == VerifierDeps::kNotVerifiedMarker) {
(*verified_classes)[i] = false; continue;
}
(*verified_classes)[i] = true;
*cursor = start + offset; // Fetch the assignability checks.
std::set<T>& set = (*vector)[i]; // Find the offset of the next entry. This will tell us where to stop when // reading the checks. Note that the last entry in the `offsets` array points // to the end of the assignability types data, so the loop will terminate correctly. while (next_valid_offset_index <= i ||
offsets[next_valid_offset_index] == VerifierDeps::kNotVerifiedMarker) {
next_valid_offset_index++;
} const uint8_t* set_end = start + offsets[next_valid_offset_index]; // Decode each check. while (*cursor < set_end) {
T tuple; if (UNLIKELY(!DecodeTuple(cursor, end, &tuple))) { returnfalse;
} if (kFillSet) {
set.emplace(tuple);
}
}
} // Align the cursor to start decoding the strings.
*cursor = AlignUp(*cursor, sizeof(uint32_t)); returntrue;
}
staticinlinevoid EncodeStringVector(std::vector<uint8_t>* out, const std::vector<std::string>& strings) {
uint32_t offsets_index = out->size(); // Make room for offsets for each string, +1 for putting the number of // strings.
out->resize(out->size() + (strings.size() + 1) * sizeof(uint32_t));
(reinterpret_cast<uint32_t*>(out->data() + offsets_index))[0] = strings.size();
uint32_t string_index = 1; for (const std::string& str : strings) { // Store the offset of the string.
(reinterpret_cast<uint32_t*>(out->data() + offsets_index))[string_index++] = out->size();
// Store the string data. const uint8_t* data = reinterpret_cast<const uint8_t*>(str.c_str());
size_t length = str.length() + 1;
out->insert(out->end(), data, data + length);
DCHECK_EQ(0u, out->back());
}
}
bool VerifierDeps::ParseStoredData(const std::vector<const DexFile*>& dex_files,
ArrayRef<const uint8_t> data) { if (data.empty()) { // Return eagerly, as the first thing we expect from VerifierDeps data is // the number of created strings, even if there is no dependency. // Currently, only the boot image does not have any VerifierDeps data. returntrue;
} const uint8_t* data_start = data.data(); const uint8_t* data_end = data_start + data.size(); const uint8_t* cursor = data_start;
uint32_t dex_file_index = 0; for (const DexFile* dex_file : dex_files) {
DexFileDeps* deps = GetDexFileDeps(*dex_file); // Fetch the offset of this dex file's verifier data.
cursor = data_start + reinterpret_cast<const uint32_t*>(data_start)[dex_file_index++];
size_t num_class_defs = dex_file->NumClassDefs(); if (UNLIKELY(!DecodeDexFileDeps</*kOnlyVerifiedClasses=*/false>(
*deps, &cursor, data_start, data_end, num_class_defs))) {
LOG(ERROR) << "Failed to parse dex file dependencies for " << dex_file->GetLocation(); returnfalse;
}
} // TODO: We should check that `data_start == data_end`. Why are we passing excessive data? returntrue;
}
// TODO: share that helper with other parts of the compiler that have // the same lookup pattern. static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
Thread* self, constchar* descriptor,
size_t descriptor_length,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Class> result =
class_linker->FindClass(self, descriptor, descriptor_length, class_loader); if (result == nullptr) {
DCHECK(self->IsExceptionPending());
self->ClearException();
} return result;
}
if (destination == nullptr || source == nullptr) {
deps.verified_classes_[class_def_index] = false; // We currently don't use assignability information for unresolved // types, as the status of the class using unresolved types will be soft // fail in the vdex. continue;
}
DCHECK(destination->IsResolved() && source->IsResolved()); if (!destination->IsAssignableFrom(source.Get())) {
deps.verified_classes_[class_def_index] = false;
all_validated = false; if (number_of_warnings++ < kMaxWarnings) {
LOG(WARNING) << "Class "
<< dex_file.PrettyType(dex_file.GetClassDef(class_def_index).class_idx_)
<< " could not be fast verified because one of its methods wrongly expected "
<< destination_desc << " to be assignable from " << source_desc;
} break;
}
}
class_def_index++;
} return all_validated;
}
} // namespace verifier
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.