From c7f832061fea59fd6abd125f26c8ca1faec695a5 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Fri, 24 Jan 2014 17:55:18 +0000 Subject: Refactor verification results. Rename VerificationMethodsData to VerificationResults. Create new class VerifiedMethod to hold all the data for a given method. Change-Id: Ife1ac67cede20f3a2f9c7f5345f08a851cf1ed20 --- compiler/Android.mk | 3 +- compiler/dex/quick/codegen_util.cc | 4 +- compiler/dex/verification_results.cc | 128 ++++++++++ compiler/dex/verification_results.h | 80 ++++++ compiler/dex/verified_method.cc | 312 +++++++++++++++++++++++ compiler/dex/verified_method.h | 98 ++++++++ compiler/dex/verified_methods_data.cc | 454 ---------------------------------- compiler/dex/verified_methods_data.h | 117 --------- compiler/driver/compiler_driver.cc | 14 +- compiler/driver/compiler_driver.h | 10 +- compiler/llvm/compiler_llvm.cc | 4 +- compiler/oat_test.cc | 6 +- compiler/oat_writer.cc | 6 +- dex2oat/dex2oat.cc | 20 +- runtime/common_test.h | 26 +- runtime/method_reference.h | 2 + 16 files changed, 667 insertions(+), 617 deletions(-) create mode 100644 compiler/dex/verification_results.cc create mode 100644 compiler/dex/verification_results.h create mode 100644 compiler/dex/verified_method.cc create mode 100644 compiler/dex/verified_method.h delete mode 100644 compiler/dex/verified_methods_data.cc delete mode 100644 compiler/dex/verified_methods_data.h diff --git a/compiler/Android.mk b/compiler/Android.mk index 25dfb0a..c6662c2 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -59,7 +59,8 @@ LIBART_COMPILER_SRC_FILES := \ dex/frontend.cc \ dex/mir_graph.cc \ dex/mir_analysis.cc \ - dex/verified_methods_data.cc \ + dex/verified_method.cc \ + dex/verification_results.cc \ dex/vreg_analysis.cc \ dex/ssa_transformation.cc \ driver/compiler_driver.cc \ diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 1eb79c9..cb36813 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -21,7 +21,7 @@ #include "mir_to_lir-inl.h" #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" -#include "dex/verified_methods_data.h" +#include "dex/verification_results.h" #include "verifier/dex_gc_map.h" #include "verifier/method_verifier.h" @@ -764,7 +764,7 @@ void Mir2Lir::CreateNativeGcMap() { } MethodReference method_ref(cu_->dex_file, cu_->method_idx); const std::vector* gc_map_raw = - cu_->compiler_driver->GetVerifiedMethodsData()->GetDexGcMap(method_ref); + cu_->compiler_driver->GetVerificationResults()->GetDexGcMap(method_ref); verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[0]); DCHECK_EQ(gc_map_raw->size(), dex_gc_map.RawSize()); // Compute native offset to references size. diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc new file mode 100644 index 0000000..8b4fa1a --- /dev/null +++ b/compiler/dex/verification_results.cc @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2013 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 "verification_results.h" + +#include "base/stl_util.h" +#include "base/mutex.h" +#include "base/mutex-inl.h" +#include "thread.h" +#include "thread-inl.h" +#include "verified_method.h" +#include "verifier/method_verifier.h" +#include "verifier/method_verifier-inl.h" + +namespace art { + +VerificationResults::VerificationResults() + : verified_methods_lock_("compiler verified methods lock"), + verified_methods_(), + rejected_classes_lock_("compiler rejected classes lock"), + rejected_classes_() { +} + +VerificationResults::~VerificationResults() { + Thread* self = Thread::Current(); + { + WriterMutexLock mu(self, verified_methods_lock_); + STLDeleteValues(&verified_methods_); + } +} + +bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { + MethodReference ref = method_verifier->GetMethodReference(); + bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags()); + // TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization. + if (!compile && !method_verifier->HasCheckCasts()) { + return true; + } + + const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile); + if (verified_method == nullptr) { + DCHECK(method_verifier->HasFailures()); + return false; + } + + WriterMutexLock mu(Thread::Current(), verified_methods_lock_); + auto it = verified_methods_.find(ref); + if (it != verified_methods_.end()) { + // TODO: Investigate why are we doing the work again for this method and try to avoid it. + LOG(WARNING) << "Method processed more than once: " + << PrettyMethod(ref.dex_method_index, *ref.dex_file); + DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size()); + DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size()); + DCHECK_EQ(it->second->GetDexGcMap().size(), verified_method->GetDexGcMap().size()); + delete it->second; + verified_methods_.erase(it); + } + verified_methods_.Put(ref, verified_method); + DCHECK(verified_methods_.find(ref) != verified_methods_.end()); + return true; +} + +const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) { + ReaderMutexLock mu(Thread::Current(), verified_methods_lock_); + auto it = verified_methods_.find(ref); + return (it != verified_methods_.end()) ? it->second : nullptr; +} + +const std::vector* VerificationResults::GetDexGcMap(MethodReference ref) { + const VerifiedMethod* verified_method = GetVerifiedMethod(ref); + CHECK(verified_method != nullptr) + << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file); + return &verified_method->GetDexGcMap(); +} + +const MethodReference* VerificationResults::GetDevirtMap(const MethodReference& ref, + uint32_t dex_pc) { + const VerifiedMethod* verified_method = GetVerifiedMethod(ref); + return (verified_method != nullptr) ? verified_method->GetDevirtTarget(dex_pc) : nullptr; +} + +bool VerificationResults::IsSafeCast(MethodReference ref, uint32_t pc) { + const VerifiedMethod* verified_method = GetVerifiedMethod(ref); + return (verified_method != nullptr) && (verified_method->IsSafeCast(pc)); +} + +void VerificationResults::AddRejectedClass(ClassReference ref) { + { + WriterMutexLock mu(Thread::Current(), rejected_classes_lock_); + rejected_classes_.insert(ref); + } + DCHECK(IsClassRejected(ref)); +} + +bool VerificationResults::IsClassRejected(ClassReference ref) { + ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_); + return (rejected_classes_.find(ref) != rejected_classes_.end()); +} + +bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref, + const uint32_t access_flags) { +#ifdef ART_SEA_IR_MODE + bool use_sea = Runtime::Current()->IsSeaIRMode(); + use_sea = use_sea && (std::string::npos != PrettyMethod( + method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci")); + if (use_sea) return true; +#endif + // Don't compile class initializers, ever. + if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { + return false; + } + return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly); +} + +} // namespace art diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h new file mode 100644 index 0000000..e9cdb53 --- /dev/null +++ b/compiler/dex/verification_results.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ART_COMPILER_DEX_VERIFICATION_RESULTS_H_ +#define ART_COMPILER_DEX_VERIFICATION_RESULTS_H_ + +#include +#include +#include + +#include "base/macros.h" +#include "base/mutex.h" +#include "class_reference.h" +#include "method_reference.h" +#include "safe_map.h" + +namespace art { + +namespace verifier { +class MethodVerifier; +} // namespace verifier + +class VerifiedMethod; + +class VerificationResults { + public: + VerificationResults(); + ~VerificationResults(); + + bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + LOCKS_EXCLUDED(verified_methods_lock_); + + const VerifiedMethod* GetVerifiedMethod(MethodReference ref) + LOCKS_EXCLUDED(verified_methods_lock_); + + const std::vector* GetDexGcMap(MethodReference ref) + LOCKS_EXCLUDED(verified_methods_lock_); + + const MethodReference* GetDevirtMap(const MethodReference& ref, uint32_t dex_pc) + LOCKS_EXCLUDED(verified_methods_lock_); + + // Returns true if the cast can statically be verified to be redundant + // by using the check-cast elision peephole optimization in the verifier. + bool IsSafeCast(MethodReference ref, uint32_t pc) LOCKS_EXCLUDED(safecast_map_lock_); + + void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); + bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); + + static bool IsCandidateForCompilation(MethodReference& method_ref, + const uint32_t access_flags); + + private: + // Verified methods. + typedef SafeMap VerifiedMethodMap; + ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + VerifiedMethodMap verified_methods_; + + // Rejected classes. + ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + std::set rejected_classes_ GUARDED_BY(rejected_classes_lock_); +}; + +} // namespace art + +#endif // ART_COMPILER_DEX_VERIFICATION_RESULTS_H_ diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc new file mode 100644 index 0000000..0f812a4 --- /dev/null +++ b/compiler/dex/verified_method.cc @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2014 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 "verified_method.h" + +#include +#include + +#include "base/logging.h" +#include "base/stl_util.h" +#include "dex_file.h" +#include "dex_instruction.h" +#include "dex_instruction-inl.h" +#include "base/mutex.h" +#include "base/mutex-inl.h" +#include "mirror/art_method.h" +#include "mirror/art_method-inl.h" +#include "mirror/class.h" +#include "mirror/class-inl.h" +#include "mirror/dex_cache.h" +#include "mirror/dex_cache-inl.h" +#include "mirror/object.h" +#include "mirror/object-inl.h" +#include "UniquePtr.h" +#include "verifier/dex_gc_map.h" +#include "verifier/method_verifier.h" +#include "verifier/method_verifier-inl.h" +#include "verifier/register_line.h" +#include "verifier/register_line-inl.h" + +namespace art { + +const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier, + bool compile) { + UniquePtr verified_method(new VerifiedMethod); + if (compile) { + /* Generate a register map. */ + if (!verified_method->GenerateGcMap(method_verifier)) { + CHECK(method_verifier->HasFailures()); + return nullptr; // Not a real failure, but a failure to encode. + } + if (kIsDebugBuild) { + VerifyGcMap(method_verifier, verified_method->dex_gc_map_); + } + + // TODO: move this out when DEX-to-DEX supports devirtualization. + if (method_verifier->HasVirtualOrInterfaceInvokes()) { + verified_method->GenerateDevirtMap(method_verifier); + } + } + + if (method_verifier->HasCheckCasts()) { + verified_method->GenerateSafeCastSet(method_verifier); + } + return verified_method.release(); +} + +const MethodReference* VerifiedMethod::GetDevirtTarget(uint32_t dex_pc) const { + auto it = devirt_map_.find(dex_pc); + return (it != devirt_map_.end()) ? &it->second : nullptr; +} + +bool VerifiedMethod::IsSafeCast(uint32_t pc) const { + return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc); +} + +bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) { + DCHECK(dex_gc_map_.empty()); + size_t num_entries, ref_bitmap_bits, pc_bits; + ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits); + // There's a single byte to encode the size of each bitmap. + if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) { + // TODO: either a better GC map format or per method failures + method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) + << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers"; + return false; + } + size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8; + // There are 2 bytes to encode the number of entries. + if (num_entries >= 65536) { + // TODO: Either a better GC map format or per method failures. + method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) + << "Cannot encode GC map for method with " << num_entries << " entries"; + return false; + } + size_t pc_bytes; + verifier::RegisterMapFormat format; + if (pc_bits <= 8) { + format = verifier::kRegMapFormatCompact8; + pc_bytes = 1; + } else if (pc_bits <= 16) { + format = verifier::kRegMapFormatCompact16; + pc_bytes = 2; + } else { + // TODO: Either a better GC map format or per method failures. + method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) + << "Cannot encode GC map for method with " + << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)"; + return false; + } + size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4; + dex_gc_map_.reserve(table_size); + // Write table header. + dex_gc_map_.push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5)); + dex_gc_map_.push_back(ref_bitmap_bytes & 0xFF); + dex_gc_map_.push_back(num_entries & 0xFF); + dex_gc_map_.push_back((num_entries >> 8) & 0xFF); + // Write table data. + const DexFile::CodeItem* code_item = method_verifier->CodeItem(); + for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { + if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { + dex_gc_map_.push_back(i & 0xFF); + if (pc_bytes == 2) { + dex_gc_map_.push_back((i >> 8) & 0xFF); + } + verifier::RegisterLine* line = method_verifier->GetRegLine(i); + line->WriteReferenceBitMap(dex_gc_map_, ref_bitmap_bytes); + } + } + DCHECK_EQ(dex_gc_map_.size(), table_size); + return true; +} + +void VerifiedMethod::VerifyGcMap(verifier::MethodVerifier* method_verifier, + const std::vector& data) { + // Check that for every GC point there is a map entry, there aren't entries for non-GC points, + // that the table data is well formed and all references are marked (or not) in the bitmap. + verifier::DexPcToReferenceMap map(&data[0]); + DCHECK_EQ(data.size(), map.RawSize()); + size_t map_index = 0; + const DexFile::CodeItem* code_item = method_verifier->CodeItem(); + for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { + const uint8_t* reg_bitmap = map.FindBitMap(i, false); + if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { + DCHECK_LT(map_index, map.NumEntries()); + DCHECK_EQ(map.GetDexPc(map_index), i); + DCHECK_EQ(map.GetBitMap(map_index), reg_bitmap); + map_index++; + verifier::RegisterLine* line = method_verifier->GetRegLine(i); + for (size_t j = 0; j < code_item->registers_size_; j++) { + if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) { + DCHECK_LT(j / 8, map.RegWidth()); + DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1); + } else if ((j / 8) < map.RegWidth()) { + DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0); + } else { + // If a register doesn't contain a reference then the bitmap may be shorter than the line. + } + } + } else { + DCHECK(reg_bitmap == NULL); + } + } +} + +void VerifiedMethod::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier, + size_t* gc_points, size_t* ref_bitmap_bits, + size_t* log2_max_gc_pc) { + size_t local_gc_points = 0; + size_t max_insn = 0; + size_t max_ref_reg = -1; + const DexFile::CodeItem* code_item = method_verifier->CodeItem(); + for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { + if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { + local_gc_points++; + max_insn = i; + verifier::RegisterLine* line = method_verifier->GetRegLine(i); + max_ref_reg = line->GetMaxNonZeroReferenceReg(max_ref_reg); + } + } + *gc_points = local_gc_points; + *ref_bitmap_bits = max_ref_reg + 1; // If max register is 0 we need 1 bit to encode (ie +1). + size_t i = 0; + while ((1U << i) <= max_insn) { + i++; + } + *log2_max_gc_pc = i; +} + +void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) { + // It is risky to rely on reg_types for sharpening in cases of soft + // verification, we might end up sharpening to a wrong implementation. Just abort. + if (method_verifier->HasFailures()) { + return; + } + + const DexFile::CodeItem* code_item = method_verifier->CodeItem(); + const uint16_t* insns = code_item->insns_; + const Instruction* inst = Instruction::At(insns); + const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_); + + for (; inst < end; inst = inst->Next()) { + bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) || + (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); + bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) || + (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE); + + if (!is_interface && !is_virtual) { + continue; + } + // Get reg type for register holding the reference to the object that will be dispatched upon. + uint32_t dex_pc = inst->GetDexPc(insns); + verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); + bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) || + (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE); + const verifier::RegType& + reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c())); + + if (!reg_type.HasClass()) { + // We will compute devirtualization information only when we know the Class of the reg type. + continue; + } + mirror::Class* reg_class = reg_type.GetClass(); + if (reg_class->IsInterface()) { + // We can't devirtualize when the known type of the register is an interface. + continue; + } + if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) { + // We can't devirtualize abstract classes except on arrays of abstract classes. + continue; + } + mirror::ArtMethod* abstract_method = method_verifier->GetDexCache()->GetResolvedMethod( + is_range ? inst->VRegB_3rc() : inst->VRegB_35c()); + if (abstract_method == NULL) { + // If the method is not found in the cache this means that it was never found + // by ResolveMethodAndCheckAccess() called when verifying invoke_*. + continue; + } + // Find the concrete method. + mirror::ArtMethod* concrete_method = NULL; + if (is_interface) { + concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method); + } + if (is_virtual) { + concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method); + } + if (concrete_method == NULL || concrete_method->IsAbstract()) { + // In cases where concrete_method is not found, or is abstract, continue to the next invoke. + continue; + } + if (reg_type.IsPreciseReference() || concrete_method->IsFinal() || + concrete_method->GetDeclaringClass()->IsFinal()) { + // If we knew exactly the class being dispatched upon, or if the target method cannot be + // overridden record the target to be used in the compiler driver. + MethodReference concrete_ref( + concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(), + concrete_method->GetDexMethodIndex()); + devirt_map_.Put(dex_pc, concrete_ref); + } + } +} + +void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) { + /* + * Walks over the method code and adds any cast instructions in which + * the type cast is implicit to a set, which is used in the code generation + * to elide these casts. + */ + if (method_verifier->HasFailures()) { + return; + } + const DexFile::CodeItem* code_item = method_verifier->CodeItem(); + const Instruction* inst = Instruction::At(code_item->insns_); + const Instruction* end = Instruction::At(code_item->insns_ + + code_item->insns_size_in_code_units_); + + for (; inst < end; inst = inst->Next()) { + Instruction::Code code = inst->Opcode(); + if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) { + uint32_t dex_pc = inst->GetDexPc(code_item->insns_); + const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); + bool is_safe_cast = false; + if (code == Instruction::CHECK_CAST) { + const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c())); + const verifier::RegType& cast_type = + method_verifier->ResolveCheckedClass(inst->VRegB_21c()); + is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type); + } else { + const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x())); + // We only know its safe to assign to an array if the array type is precise. For example, + // an Object[] can have any type of object stored in it, but it may also be assigned a + // String[] in which case the stores need to be of Strings. + if (array_type.IsPreciseReference()) { + const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x())); + const verifier::RegType& component_type = method_verifier->GetRegTypeCache() + ->GetComponentType(array_type, method_verifier->GetClassLoader()); + is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type); + } + } + if (is_safe_cast) { + // Verify ordering for push_back() to the sorted vector. + DCHECK(safe_cast_set_.empty() || safe_cast_set_.back() < dex_pc); + safe_cast_set_.push_back(dex_pc); + } + } + } +} + +} // namespace art diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h new file mode 100644 index 0000000..aa0e72a --- /dev/null +++ b/compiler/dex/verified_method.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ART_COMPILER_DEX_VERIFIED_METHOD_H_ +#define ART_COMPILER_DEX_VERIFIED_METHOD_H_ + +#include + +#include "method_reference.h" +#include "safe_map.h" + +namespace art { + +namespace verifier { +class MethodVerifier; +} // namespace verifier + +class VerifiedMethod { + public: + // Cast elision set type. + // Since we're adding the dex PCs to the set in increasing order, a sorted vector + // is better for performance (not just memory usage), especially for large sets. + typedef std::vector SafeCastSet; + + // Devirtualization map type maps dex offset to concrete method reference. + typedef SafeMap DevirtualizationMap; + + static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier, bool compile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ~VerifiedMethod() = default; + + const std::vector& GetDexGcMap() const { + return dex_gc_map_; + } + + const DevirtualizationMap& GetDevirtMap() const { + return devirt_map_; + } + + const SafeCastSet& GetSafeCastSet() const { + return safe_cast_set_; + } + + // Returns the devirtualization target method, or nullptr if none. + const MethodReference* GetDevirtTarget(uint32_t dex_pc) const; + + // Returns true if the cast can statically be verified to be redundant + // by using the check-cast elision peephole optimization in the verifier. + bool IsSafeCast(uint32_t pc) const; + + private: + VerifiedMethod() = default; + + /* + * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of + * verification). For type-precise determination we have all the data we need, so we just need to + * encode it in some clever fashion. + * Stores the data in dex_gc_map_, returns true on success and false on failure. + */ + bool GenerateGcMap(verifier::MethodVerifier* method_verifier); + + // Verify that the GC map associated with method_ is well formed. + static void VerifyGcMap(verifier::MethodVerifier* method_verifier, + const std::vector& data); + + // Compute sizes for GC map data. + static void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier, + size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc); + + // Generate devirtualizaion map into devirt_map_. + void GenerateDevirtMap(verifier::MethodVerifier* method_verifier) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Generate safe case set into safe_cast_set_. + void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + std::vector dex_gc_map_; + DevirtualizationMap devirt_map_; + SafeCastSet safe_cast_set_; +}; + +} // namespace art + +#endif // ART_COMPILER_DEX_VERIFIED_METHOD_H_ diff --git a/compiler/dex/verified_methods_data.cc b/compiler/dex/verified_methods_data.cc deleted file mode 100644 index e6c4dda..0000000 --- a/compiler/dex/verified_methods_data.cc +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (C) 2013 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 "base/stl_util.h" -#include "dex_file.h" -#include "dex_instruction.h" -#include "dex_instruction-inl.h" -#include "base/mutex.h" -#include "base/mutex-inl.h" -#include "mirror/art_method.h" -#include "mirror/art_method-inl.h" -#include "mirror/class.h" -#include "mirror/class-inl.h" -#include "mirror/dex_cache.h" -#include "mirror/dex_cache-inl.h" -#include "mirror/object.h" -#include "mirror/object-inl.h" -#include "verified_methods_data.h" -#include "verifier/dex_gc_map.h" -#include "verifier/method_verifier.h" -#include "verifier/method_verifier-inl.h" -#include "verifier/register_line.h" -#include "verifier/register_line-inl.h" - -namespace art { - -VerifiedMethodsData::VerifiedMethodsData() - : dex_gc_maps_lock_("compiler GC maps lock"), - dex_gc_maps_(), - safecast_map_lock_("compiler Cast Elision lock"), - safecast_map_(), - devirt_maps_lock_("compiler Devirtualization lock"), - devirt_maps_(), - rejected_classes_lock_("compiler rejected classes lock"), - rejected_classes_() { -} - -VerifiedMethodsData::~VerifiedMethodsData() { - Thread* self = Thread::Current(); - { - WriterMutexLock mu(self, dex_gc_maps_lock_); - STLDeleteValues(&dex_gc_maps_); - } - { - WriterMutexLock mu(self, safecast_map_lock_); - STLDeleteValues(&safecast_map_); - } - { - WriterMutexLock mu(self, devirt_maps_lock_); - STLDeleteValues(&devirt_maps_); - } -} - -bool VerifiedMethodsData::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { - MethodReference ref = method_verifier->GetMethodReference(); - bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags()); - if (compile) { - /* Generate a register map and add it to the method. */ - const std::vector* dex_gc_map = GenerateGcMap(method_verifier); - if (dex_gc_map == NULL) { - DCHECK(method_verifier->HasFailures()); - return false; // Not a real failure, but a failure to encode - } - if (kIsDebugBuild) { - VerifyGcMap(method_verifier, *dex_gc_map); - } - SetDexGcMap(ref, dex_gc_map); - - // TODO: move this out when DEX-to-DEX supports devirtualization. - if (method_verifier->HasVirtualOrInterfaceInvokes()) { - PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap(method_verifier); - if (pc_to_concrete_method != NULL) { - SetDevirtMap(ref, pc_to_concrete_method); - } - } - } - - if (method_verifier->HasCheckCasts()) { - MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet(method_verifier); - if (method_to_safe_casts != NULL) { - SetSafeCastMap(ref, method_to_safe_casts); - } - } - return true; -} - -const std::vector* VerifiedMethodsData::GetDexGcMap(MethodReference ref) { - ReaderMutexLock mu(Thread::Current(), dex_gc_maps_lock_); - DexGcMapTable::const_iterator it = dex_gc_maps_.find(ref); - CHECK(it != dex_gc_maps_.end()) - << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file); - CHECK(it->second != NULL); - return it->second; -} - -const MethodReference* VerifiedMethodsData::GetDevirtMap(const MethodReference& ref, - uint32_t dex_pc) { - ReaderMutexLock mu(Thread::Current(), devirt_maps_lock_); - DevirtualizationMapTable::const_iterator it = devirt_maps_.find(ref); - if (it == devirt_maps_.end()) { - return NULL; - } - - // Look up the PC in the map, get the concrete method to execute and return its reference. - PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc); - if (pc_to_concrete_method != it->second->end()) { - return &(pc_to_concrete_method->second); - } else { - return NULL; - } -} - -bool VerifiedMethodsData::IsSafeCast(MethodReference ref, uint32_t pc) { - ReaderMutexLock mu(Thread::Current(), safecast_map_lock_); - SafeCastMap::const_iterator it = safecast_map_.find(ref); - if (it == safecast_map_.end()) { - return false; - } - - // Look up the cast address in the set of safe casts - // Use binary_search for lookup in the sorted vector. - return std::binary_search(it->second->begin(), it->second->end(), pc); -} - -void VerifiedMethodsData::AddRejectedClass(ClassReference ref) { - { - WriterMutexLock mu(Thread::Current(), rejected_classes_lock_); - rejected_classes_.insert(ref); - } - DCHECK(IsClassRejected(ref)); -} - -bool VerifiedMethodsData::IsClassRejected(ClassReference ref) { - ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_); - return (rejected_classes_.find(ref) != rejected_classes_.end()); -} - -bool VerifiedMethodsData::IsCandidateForCompilation(MethodReference& method_ref, - const uint32_t access_flags) { -#ifdef ART_SEA_IR_MODE - bool use_sea = Runtime::Current()->IsSeaIRMode(); - use_sea = use_sea && (std::string::npos != PrettyMethod( - method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci")); - if (use_sea) return true; -#endif - // Don't compile class initializers, ever. - if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { - return false; - } - return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly); -} - -const std::vector* VerifiedMethodsData::GenerateGcMap( - verifier::MethodVerifier* method_verifier) { - size_t num_entries, ref_bitmap_bits, pc_bits; - ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits); - // There's a single byte to encode the size of each bitmap - if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) { - // TODO: either a better GC map format or per method failures - method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) - << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers"; - return NULL; - } - size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8; - // There are 2 bytes to encode the number of entries - if (num_entries >= 65536) { - // TODO: either a better GC map format or per method failures - method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) - << "Cannot encode GC map for method with " << num_entries << " entries"; - return NULL; - } - size_t pc_bytes; - verifier::RegisterMapFormat format; - if (pc_bits <= 8) { - format = verifier::kRegMapFormatCompact8; - pc_bytes = 1; - } else if (pc_bits <= 16) { - format = verifier::kRegMapFormatCompact16; - pc_bytes = 2; - } else { - // TODO: either a better GC map format or per method failures - method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) - << "Cannot encode GC map for method with " - << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)"; - return NULL; - } - size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4; - std::vector* table = new std::vector; - if (table == NULL) { - method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD) - << "Failed to encode GC map (size=" << table_size << ")"; - return NULL; - } - table->reserve(table_size); - // Write table header - table->push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5)); - table->push_back(ref_bitmap_bytes & 0xFF); - table->push_back(num_entries & 0xFF); - table->push_back((num_entries >> 8) & 0xFF); - // Write table data - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { - if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { - table->push_back(i & 0xFF); - if (pc_bytes == 2) { - table->push_back((i >> 8) & 0xFF); - } - verifier::RegisterLine* line = method_verifier->GetRegLine(i); - line->WriteReferenceBitMap(*table, ref_bitmap_bytes); - } - } - DCHECK_EQ(table->size(), table_size); - return table; -} - -void VerifiedMethodsData::VerifyGcMap(verifier::MethodVerifier* method_verifier, - const std::vector& data) { - // Check that for every GC point there is a map entry, there aren't entries for non-GC points, - // that the table data is well formed and all references are marked (or not) in the bitmap - verifier::DexPcToReferenceMap map(&data[0]); - DCHECK_EQ(data.size(), map.RawSize()); - size_t map_index = 0; - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { - const uint8_t* reg_bitmap = map.FindBitMap(i, false); - if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { - CHECK_LT(map_index, map.NumEntries()); - CHECK_EQ(map.GetDexPc(map_index), i); - CHECK_EQ(map.GetBitMap(map_index), reg_bitmap); - map_index++; - verifier::RegisterLine* line = method_verifier->GetRegLine(i); - for (size_t j = 0; j < code_item->registers_size_; j++) { - if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) { - CHECK_LT(j / 8, map.RegWidth()); - CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1); - } else if ((j / 8) < map.RegWidth()) { - CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0); - } else { - // If a register doesn't contain a reference then the bitmap may be shorter than the line - } - } - } else { - CHECK(reg_bitmap == NULL); - } - } -} - -void VerifiedMethodsData::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier, - size_t* gc_points, size_t* ref_bitmap_bits, - size_t* log2_max_gc_pc) { - size_t local_gc_points = 0; - size_t max_insn = 0; - size_t max_ref_reg = -1; - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) { - if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) { - local_gc_points++; - max_insn = i; - verifier::RegisterLine* line = method_verifier->GetRegLine(i); - max_ref_reg = line->GetMaxNonZeroReferenceReg(max_ref_reg); - } - } - *gc_points = local_gc_points; - *ref_bitmap_bits = max_ref_reg + 1; // if max register is 0 we need 1 bit to encode (ie +1) - size_t i = 0; - while ((1U << i) <= max_insn) { - i++; - } - *log2_max_gc_pc = i; -} - -void VerifiedMethodsData::SetDexGcMap(MethodReference ref, const std::vector* gc_map) { - DCHECK(Runtime::Current()->IsCompiler()); - { - WriterMutexLock mu(Thread::Current(), dex_gc_maps_lock_); - DexGcMapTable::iterator it = dex_gc_maps_.find(ref); - if (it != dex_gc_maps_.end()) { - delete it->second; - dex_gc_maps_.erase(it); - } - dex_gc_maps_.Put(ref, gc_map); - } - DCHECK(GetDexGcMap(ref) != NULL); -} - -VerifiedMethodsData::MethodSafeCastSet* VerifiedMethodsData::GenerateSafeCastSet( - verifier::MethodVerifier* method_verifier) { - /* - * Walks over the method code and adds any cast instructions in which - * the type cast is implicit to a set, which is used in the code generation - * to elide these casts. - */ - if (method_verifier->HasFailures()) { - return NULL; - } - UniquePtr mscs; - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - const Instruction* inst = Instruction::At(code_item->insns_); - const Instruction* end = Instruction::At(code_item->insns_ + - code_item->insns_size_in_code_units_); - - for (; inst < end; inst = inst->Next()) { - Instruction::Code code = inst->Opcode(); - if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) { - uint32_t dex_pc = inst->GetDexPc(code_item->insns_); - const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); - bool is_safe_cast = false; - if (code == Instruction::CHECK_CAST) { - const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c())); - const verifier::RegType& cast_type = - method_verifier->ResolveCheckedClass(inst->VRegB_21c()); - is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type); - } else { - const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x())); - // We only know its safe to assign to an array if the array type is precise. For example, - // an Object[] can have any type of object stored in it, but it may also be assigned a - // String[] in which case the stores need to be of Strings. - if (array_type.IsPreciseReference()) { - const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x())); - const verifier::RegType& component_type = method_verifier->GetRegTypeCache() - ->GetComponentType(array_type, method_verifier->GetClassLoader()); - is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type); - } - } - if (is_safe_cast) { - if (mscs.get() == nullptr) { - mscs.reset(new MethodSafeCastSet()); - } else { - DCHECK_LT(mscs->back(), dex_pc); // Verify ordering for push_back() to the sorted vector. - } - mscs->push_back(dex_pc); - } - } - } - return mscs.release(); -} - -void VerifiedMethodsData::SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* cast_set) { - WriterMutexLock mu(Thread::Current(), safecast_map_lock_); - SafeCastMap::iterator it = safecast_map_.find(ref); - if (it != safecast_map_.end()) { - delete it->second; - safecast_map_.erase(it); - } - safecast_map_.Put(ref, cast_set); - DCHECK(safecast_map_.find(ref) != safecast_map_.end()); -} - -VerifiedMethodsData::PcToConcreteMethodMap* VerifiedMethodsData::GenerateDevirtMap( - verifier::MethodVerifier* method_verifier) { - // It is risky to rely on reg_types for sharpening in cases of soft - // verification, we might end up sharpening to a wrong implementation. Just abort. - if (method_verifier->HasFailures()) { - return NULL; - } - - UniquePtr pc_to_concrete_method_map; - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - const uint16_t* insns = code_item->insns_; - const Instruction* inst = Instruction::At(insns); - const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_); - - for (; inst < end; inst = inst->Next()) { - bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) || - (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); - bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) || - (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE); - - if (!is_interface && !is_virtual) { - continue; - } - // Get reg type for register holding the reference to the object that will be dispatched upon. - uint32_t dex_pc = inst->GetDexPc(insns); - verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); - bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) || - (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE); - const verifier::RegType& - reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c())); - - if (!reg_type.HasClass()) { - // We will compute devirtualization information only when we know the Class of the reg type. - continue; - } - mirror::Class* reg_class = reg_type.GetClass(); - if (reg_class->IsInterface()) { - // We can't devirtualize when the known type of the register is an interface. - continue; - } - if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) { - // We can't devirtualize abstract classes except on arrays of abstract classes. - continue; - } - mirror::ArtMethod* abstract_method = method_verifier->GetDexCache()->GetResolvedMethod( - is_range ? inst->VRegB_3rc() : inst->VRegB_35c()); - if (abstract_method == NULL) { - // If the method is not found in the cache this means that it was never found - // by ResolveMethodAndCheckAccess() called when verifying invoke_*. - continue; - } - // Find the concrete method. - mirror::ArtMethod* concrete_method = NULL; - if (is_interface) { - concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method); - } - if (is_virtual) { - concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method); - } - if (concrete_method == NULL || concrete_method->IsAbstract()) { - // In cases where concrete_method is not found, or is abstract, continue to the next invoke. - continue; - } - if (reg_type.IsPreciseReference() || concrete_method->IsFinal() || - concrete_method->GetDeclaringClass()->IsFinal()) { - // If we knew exactly the class being dispatched upon, or if the target method cannot be - // overridden record the target to be used in the compiler driver. - if (pc_to_concrete_method_map.get() == NULL) { - pc_to_concrete_method_map.reset(new PcToConcreteMethodMap()); - } - MethodReference concrete_ref( - concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(), - concrete_method->GetDexMethodIndex()); - pc_to_concrete_method_map->Put(dex_pc, concrete_ref); - } - } - return pc_to_concrete_method_map.release(); -} - -void VerifiedMethodsData::SetDevirtMap(MethodReference ref, - const PcToConcreteMethodMap* devirt_map) { - WriterMutexLock mu(Thread::Current(), devirt_maps_lock_); - DevirtualizationMapTable::iterator it = devirt_maps_.find(ref); - if (it != devirt_maps_.end()) { - delete it->second; - devirt_maps_.erase(it); - } - - devirt_maps_.Put(ref, devirt_map); - DCHECK(devirt_maps_.find(ref) != devirt_maps_.end()); -} - -} // namespace art diff --git a/compiler/dex/verified_methods_data.h b/compiler/dex/verified_methods_data.h deleted file mode 100644 index d495dff..0000000 --- a/compiler/dex/verified_methods_data.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_ -#define ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_ - -#include -#include -#include - -#include "base/macros.h" -#include "base/mutex.h" -#include "class_reference.h" -#include "method_reference.h" -#include "safe_map.h" - -namespace art { - -namespace verifier { -class MethodVerifier; -} // namespace verifier - -class VerifiedMethodsData { - public: - VerifiedMethodsData(); - ~VerifiedMethodsData(); - - bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - LOCKS_EXCLUDED(dex_gc_maps_lock_, devirt_maps_lock_, safecast_map_lock_); - - const std::vector* GetDexGcMap(MethodReference ref) - LOCKS_EXCLUDED(dex_gc_maps_lock_); - - const MethodReference* GetDevirtMap(const MethodReference& ref, uint32_t dex_pc) - LOCKS_EXCLUDED(devirt_maps_lock_); - - // Returns true if the cast can statically be verified to be redundant - // by using the check-cast elision peephole optimization in the verifier - bool IsSafeCast(MethodReference ref, uint32_t pc) LOCKS_EXCLUDED(safecast_map_lock_); - - void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); - bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); - - static bool IsCandidateForCompilation(MethodReference& method_ref, - const uint32_t access_flags); - - private: - /* - * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of - * verification). For type-precise determination we have all the data we need, so we just need to - * encode it in some clever fashion. - * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure. - */ - const std::vector* GenerateGcMap(verifier::MethodVerifier* method_verifier); - - // Verify that the GC map associated with method_ is well formed - void VerifyGcMap(verifier::MethodVerifier* method_verifier, const std::vector& data); - - // Compute sizes for GC map data - void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier, - size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc); - - // All the GC maps that the verifier has created - typedef SafeMap*, - MethodReferenceComparator> DexGcMapTable; - ReaderWriterMutex dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - DexGcMapTable dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_); - void SetDexGcMap(MethodReference ref, const std::vector* dex_gc_map) - LOCKS_EXCLUDED(dex_gc_maps_lock_); - - // Cast elision types. - // Since we're adding the dex PCs to the set in increasing order, a sorted vector - // is better for performance (not just memory usage), especially for large sets. - typedef std::vector MethodSafeCastSet; - typedef SafeMap SafeCastMap; - MethodSafeCastSet* GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* mscs) - LOCKS_EXCLUDED(safecast_map_lock_); - ReaderWriterMutex safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - SafeCastMap safecast_map_ GUARDED_BY(safecast_map_lock_); - - // Devirtualization map. - typedef SafeMap PcToConcreteMethodMap; - typedef SafeMap DevirtualizationMapTable; - PcToConcreteMethodMap* GenerateDevirtMap(verifier::MethodVerifier* method_verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ReaderWriterMutex devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - DevirtualizationMapTable devirt_maps_ GUARDED_BY(devirt_maps_lock_); - void SetDevirtMap(MethodReference ref, const PcToConcreteMethodMap* pc_method_map) - LOCKS_EXCLUDED(devirt_maps_lock_); - - // Rejected classes - typedef std::set RejectedClassesTable; - ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - RejectedClassesTable rejected_classes_ GUARDED_BY(rejected_classes_lock_); -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_ diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index f390b41..f84e01f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -27,7 +27,7 @@ #include "class_linker.h" #include "dex_compilation_unit.h" #include "dex_file-inl.h" -#include "dex/verified_methods_data.h" +#include "dex/verification_results.h" #include "jni_internal.h" #include "object_utils.h" #include "runtime.h" @@ -336,13 +336,13 @@ extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& co extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver, std::string const& filename); -CompilerDriver::CompilerDriver(VerifiedMethodsData* verified_methods_data, +CompilerDriver::CompilerDriver(VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, CompilerBackend compiler_backend, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, bool image, DescriptorSet* image_classes, size_t thread_count, bool dump_stats) - : verified_methods_data_(verified_methods_data), + : verification_results_(verification_results), method_inliner_map_(method_inliner_map), compiler_backend_(compiler_backend), instruction_set_(instruction_set), @@ -1274,7 +1274,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // Did the verifier record a more precise invoke target based on its type information? const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex()); const MethodReference* devirt_map_target = - verified_methods_data_->GetDevirtMap(caller_method, dex_pc); + verification_results_->GetDevirtMap(caller_method, dex_pc); if (devirt_map_target != NULL) { SirtRef target_dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file)); SirtRef class_loader(soa.Self(), soa.Decode(mUnit->GetClassLoader())); @@ -1322,7 +1322,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui } bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) { - bool result = verified_methods_data_->IsSafeCast(mr, dex_pc); + bool result = verification_results_->IsSafeCast(mr, dex_pc); if (result) { stats_->SafeCast(); } else { @@ -2268,7 +2268,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz } ClassReference ref(&dex_file, class_def_index); // Skip compiling classes with generic verifier failures since they will still fail at runtime - if (manager->GetCompiler()->verified_methods_data_->IsClassRejected(ref)) { + if (manager->GetCompiler()->verification_results_->IsClassRejected(ref)) { return; } const byte* class_data = dex_file.GetClassData(class_def); @@ -2351,7 +2351,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else if ((access_flags & kAccAbstract) != 0) { } else { MethodReference method_ref(&dex_file, method_idx); - bool compile = VerifiedMethodsData::IsCandidateForCompilation(method_ref, access_flags); + bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags); if (compile) { CompilerFn compiler = compiler_; diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index eef94a1..f8aa868 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -44,7 +44,7 @@ class DexCompilationUnit; class DexFileToMethodInlinerMap; class OatWriter; class TimingLogger; -class VerifiedMethodsData; +class VerificationResults; enum CompilerBackend { kQuick, @@ -92,7 +92,7 @@ class CompilerDriver { // enabled. "image_classes" lets the compiler know what classes it // can assume will be in the image, with NULL implying all available // classes. - explicit CompilerDriver(VerifiedMethodsData* verified_methods_data, + explicit CompilerDriver(VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, CompilerBackend compiler_backend, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, @@ -109,8 +109,8 @@ class CompilerDriver { void CompileOne(const mirror::ArtMethod* method, TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - VerifiedMethodsData* GetVerifiedMethodsData() const { - return verified_methods_data_; + VerificationResults* GetVerificationResults() const { + return verification_results_; } DexFileToMethodInlinerMap* GetMethodInlinerMap() const { @@ -486,7 +486,7 @@ class CompilerDriver { std::vector methods_to_patch_; std::vector classes_to_patch_; - VerifiedMethodsData* verified_methods_data_; + VerificationResults* verification_results_; DexFileToMethodInlinerMap* method_inliner_map_; CompilerBackend compiler_backend_; diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 35d1ecd..8f996fa 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -20,7 +20,7 @@ #include "base/stl_util.h" #include "class_linker.h" #include "compiled_method.h" -#include "dex/verified_methods_data.h" +#include "dex/verification_results.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" #include "globals.h" @@ -157,7 +157,7 @@ CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_typ dex_compilation_unit->GetDexMethodIndex()); return new CompiledMethod(*compiler_driver_, compiler_driver_->GetInstructionSet(), cunit->GetElfObject(), - *compiler_driver_->GetVerifiedMethodsData()->GetDexGcMap(mref), + *compiler_driver_->GetVerificationResults()->GetDexGcMap(mref), cunit->GetDexCompilationUnit()->GetSymbol()); } diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 2434262..fc45412 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -79,10 +79,10 @@ TEST_F(OatTest, WriteRead) { InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; InstructionSetFeatures insn_features; - verified_methods_data_.reset(new VerifiedMethodsData); + verification_results_.reset(new VerificationResults); method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr); - callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get()); - compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(), + callbacks_.Reset(verification_results_.get(), method_inliner_map_.get()); + compiler_driver_.reset(new CompilerDriver(verification_results_.get(), method_inliner_map_.get(), compiler_backend, insn_set, insn_features, false, NULL, 2, true)); diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 199a2b8..7a902d8 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -23,7 +23,7 @@ #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "dex_file-inl.h" -#include "dex/verified_methods_data.h" +#include "dex/verification_results.h" #include "gc/space/space.h" #include "mirror/art_method-inl.h" #include "mirror/array.h" @@ -218,7 +218,7 @@ size_t OatWriter::InitOatClasses(size_t offset) { mirror::Class::Status status; if (compiled_class != NULL) { status = compiled_class->GetStatus(); - } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) { + } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) { status = mirror::Class::kStatusError; } else { status = mirror::Class::kStatusNotReady; @@ -433,7 +433,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, mirror::Class::Status status; if (compiled_class != NULL) { status = compiled_class->GetStatus(); - } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) { + } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) { status = mirror::Class::kStatusError; } else { status = mirror::Class::kStatusNotReady; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 26fac23..97df199 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -32,7 +32,7 @@ #include "class_linker.h" #include "compiler_callbacks.h" #include "dex_file-inl.h" -#include "dex/verified_methods_data.h" +#include "dex/verification_results.h" #include "driver/compiler_driver.h" #include "elf_fixup.h" #include "elf_stripper.h" @@ -268,7 +268,7 @@ class Dex2Oat { Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files); } - UniquePtr driver(new CompilerDriver(verified_methods_data_.get(), + UniquePtr driver(new CompilerDriver(verification_results_.get(), method_inliner_map_.get(), compiler_backend_, instruction_set_, @@ -348,15 +348,15 @@ class Dex2Oat { private: class Dex2OatCompilerCallbacks : public CompilerCallbacks { public: - Dex2OatCompilerCallbacks(VerifiedMethodsData* verified_methods_data, + Dex2OatCompilerCallbacks(VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map) - : verified_methods_data_(verified_methods_data), + : verification_results_(verification_results), method_inliner_map_(method_inliner_map) { } virtual ~Dex2OatCompilerCallbacks() { } virtual bool MethodVerified(verifier::MethodVerifier* verifier) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - bool result = verified_methods_data_->ProcessVerifiedMethod(verifier); + bool result = verification_results_->ProcessVerifiedMethod(verifier); if (result && method_inliner_map_ != nullptr) { MethodReference ref = verifier->GetMethodReference(); method_inliner_map_->GetMethodInliner(ref.dex_file) @@ -365,11 +365,11 @@ class Dex2Oat { return result; } virtual void ClassRejected(ClassReference ref) { - verified_methods_data_->AddRejectedClass(ref); + verification_results_->AddRejectedClass(ref); } private: - VerifiedMethodsData* verified_methods_data_; + VerificationResults* verification_results_; DexFileToMethodInlinerMap* method_inliner_map_; }; @@ -380,9 +380,9 @@ class Dex2Oat { : compiler_backend_(compiler_backend), instruction_set_(instruction_set), instruction_set_features_(instruction_set_features), - verified_methods_data_(new VerifiedMethodsData), + verification_results_(new VerificationResults), method_inliner_map_(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr), - callbacks_(verified_methods_data_.get(), method_inliner_map_.get()), + callbacks_(verification_results_.get(), method_inliner_map_.get()), runtime_(nullptr), thread_count_(thread_count), start_ns_(NanoTime()) { @@ -446,7 +446,7 @@ class Dex2Oat { const InstructionSet instruction_set_; const InstructionSetFeatures instruction_set_features_; - UniquePtr verified_methods_data_; + UniquePtr verification_results_; UniquePtr method_inliner_map_; Dex2OatCompilerCallbacks callbacks_; Runtime* runtime_; diff --git a/runtime/common_test.h b/runtime/common_test.h index ee95d5b..5e6354e 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -26,7 +26,7 @@ #include "../../external/icu4c/common/unicode/uvernum.h" #include "../compiler/dex/quick/dex_file_to_method_inliner_map.h" -#include "../compiler/dex/verified_methods_data.h" +#include "../compiler/dex/verification_results.h" #include "../compiler/driver/compiler_driver.h" #include "base/macros.h" #include "base/stl_util.h" @@ -425,9 +425,9 @@ class CommonTest : public testing::Test { CompilerBackend compiler_backend = kQuick; #endif - verified_methods_data_.reset(new VerifiedMethodsData); + verification_results_.reset(new VerificationResults); method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr); - callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get()); + callbacks_.Reset(verification_results_.get(), method_inliner_map_.get()); Runtime::Options options; options.push_back(std::make_pair("compilercallbacks", static_cast(&callbacks_))); options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); @@ -474,7 +474,7 @@ class CommonTest : public testing::Test { } } class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); - compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(), + compiler_driver_.reset(new CompilerDriver(verification_results_.get(), method_inliner_map_.get(), compiler_backend, instruction_set, instruction_set_features, @@ -526,7 +526,7 @@ class CommonTest : public testing::Test { compiler_driver_.reset(); callbacks_.Reset(nullptr, nullptr); method_inliner_map_.reset(); - verified_methods_data_.reset(); + verification_results_.reset(); STLDeleteElements(&opened_dex_files_); Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test @@ -654,18 +654,18 @@ class CommonTest : public testing::Test { class TestCompilerCallbacks : public CompilerCallbacks { public: - TestCompilerCallbacks() : verified_methods_data_(nullptr), method_inliner_map_(nullptr) { } + TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) { } - void Reset(VerifiedMethodsData* verified_methods_data, + void Reset(VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map) { - verified_methods_data_ = verified_methods_data; + verification_results_ = verification_results; method_inliner_map_ = method_inliner_map; } virtual bool MethodVerified(verifier::MethodVerifier* verifier) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(verified_methods_data_); - bool result = verified_methods_data_->ProcessVerifiedMethod(verifier); + CHECK(verification_results_); + bool result = verification_results_->ProcessVerifiedMethod(verifier); if (result && method_inliner_map_ != nullptr) { MethodReference ref = verifier->GetMethodReference(); method_inliner_map_->GetMethodInliner(ref.dex_file) @@ -674,11 +674,11 @@ class CommonTest : public testing::Test { return result; } virtual void ClassRejected(ClassReference ref) { - verified_methods_data_->AddRejectedClass(ref); + verification_results_->AddRejectedClass(ref); } private: - VerifiedMethodsData* verified_methods_data_; + VerificationResults* verification_results_; DexFileToMethodInlinerMap* method_inliner_map_; }; @@ -689,7 +689,7 @@ class CommonTest : public testing::Test { UniquePtr runtime_; // Owned by the runtime ClassLinker* class_linker_; - UniquePtr verified_methods_data_; + UniquePtr verification_results_; UniquePtr method_inliner_map_; TestCompilerCallbacks callbacks_; UniquePtr compiler_driver_; diff --git a/runtime/method_reference.h b/runtime/method_reference.h index 1ff4ea0..8e46d7e 100644 --- a/runtime/method_reference.h +++ b/runtime/method_reference.h @@ -17,6 +17,8 @@ #ifndef ART_RUNTIME_METHOD_REFERENCE_H_ #define ART_RUNTIME_METHOD_REFERENCE_H_ +#include + namespace art { class DexFile; -- cgit v1.1