diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/dex/quick/codegen_util.cc | 16 | ||||
| -rw-r--r-- | compiler/dex/quick/gen_common.cc | 49 | ||||
| -rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 11 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 2 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 89 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 127 | ||||
| -rw-r--r-- | compiler/image_writer.cc | 66 |
7 files changed, 308 insertions, 52 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 29554c0977..2ce7ecdecc 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -440,6 +440,20 @@ void Mir2Lir::InstallLiteralPools() { PushPointer(code_buffer_, &id); data_lir = NEXT_LIR(data_lir); } + // Push class literals. + data_lir = class_literal_list_; + while (data_lir != NULL) { + uint32_t target = data_lir->operands[0]; + cu_->compiler_driver->AddClassPatch(cu_->dex_file, + cu_->class_def_idx, + cu_->method_idx, + target, + code_buffer_.size()); + const DexFile::TypeId& id = cu_->dex_file->GetTypeId(target); + // unique value based on target to ensure code deduplication works + PushPointer(code_buffer_, &id); + data_lir = NEXT_LIR(data_lir); + } } /* Write the switch tables to the output stream */ @@ -772,6 +786,7 @@ int Mir2Lir::AssignLiteralOffset(CodeOffset offset) { offset = AssignLiteralOffsetCommon(literal_list_, offset); offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset); offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset); + offset = AssignLiteralPointerOffsetCommon(class_literal_list_, offset); return offset; } @@ -960,6 +975,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena : Backend(arena), literal_list_(NULL), method_literal_list_(NULL), + class_literal_list_(NULL), code_literal_list_(NULL), first_fixup_(NULL), cu_(cu), diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 3bd0298a22..daf21df19d 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -19,6 +19,7 @@ #include "dex/quick/mir_to_lir-inl.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" +#include "mirror/object-inl.h" #include "verifier/method_verifier.h" namespace art { @@ -883,13 +884,53 @@ void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { // alloc will always check for resolution, do we also need to verify // access because the verifier was unable to? ThreadOffset func_offset(-1); - if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks( - cu_->method_idx, *cu_->dex_file, type_idx)) { - func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject); + const DexFile* dex_file = cu_->dex_file; + CompilerDriver* driver = cu_->compiler_driver; + if (driver->CanAccessInstantiableTypeWithoutChecks( + cu_->method_idx, *dex_file, type_idx)) { + bool is_type_initialized; + bool use_direct_type_ptr; + uintptr_t direct_type_ptr; + if (kEmbedClassInCode && + driver->CanEmbedTypeInCode(*dex_file, type_idx, + &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) { + // The fast path. + if (!use_direct_type_ptr) { + // Use the literal pool and a PC-relative load from a data word. + LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0); + if (data_target == nullptr) { + data_target = AddWordData(&class_literal_list_, type_idx); + } + LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target); + AppendLIR(load_pc_rel); + if (!is_type_initialized) { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved); + CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true); + } else { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized); + CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true); + } + } else { + // Use the direct pointer. + if (!is_type_initialized) { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved); + CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true); + } else { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized); + CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true); + } + } + } else { + // The slow path. + DCHECK_EQ(func_offset.Int32Value(), -1); + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject); + CallRuntimeHelperImmMethod(func_offset, type_idx, true); + } + DCHECK_NE(func_offset.Int32Value(), -1); } else { func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectWithAccessCheck); + CallRuntimeHelperImmMethod(func_offset, type_idx, true); } - CallRuntimeHelperImmMethod(func_offset, type_idx, true); RegLocation rl_result = GetReturn(false); StoreValue(rl_dest, rl_result); } diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index d942a24a18..f865207fc7 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -142,6 +142,17 @@ void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, b CallHelper(r_tgt, helper_offset, safepoint_pc); } +void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) { + int r_tgt = CallHelperSetup(helper_offset); + DCHECK_NE(TargetReg(kArg1), arg0); + if (TargetReg(kArg0) != arg0) { + OpRegCopy(TargetReg(kArg0), arg0); + } + LoadCurrMethodDirect(TargetReg(kArg1)); + ClobberCallerSave(); + CallHelper(r_tgt, helper_offset, safepoint_pc); +} + void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0, RegLocation arg1, bool safepoint_pc) { int r_tgt = CallHelperSetup(helper_offset); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index c157327109..f9d9e9e2f4 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -529,6 +529,7 @@ class Mir2Lir : public Backend { bool safepoint_pc); void CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc); + void CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc); void CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0, RegLocation arg1, bool safepoint_pc); @@ -855,6 +856,7 @@ class Mir2Lir : public Backend { // TODO: add accessors for these. LIR* literal_list_; // Constants. LIR* method_literal_list_; // Method literals requiring patching. + LIR* class_literal_list_; // Class literals requiring patching. LIR* code_literal_list_; // Code literals requiring patching. LIR* first_fixup_; // Doubly-linked list of LIR nodes requiring fixups. diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index f713151dc5..f390b4143f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -439,6 +439,10 @@ CompilerDriver::~CompilerDriver() { MutexLock mu(self, compiled_methods_lock_); STLDeleteElements(&methods_to_patch_); } + { + MutexLock mu(self, compiled_methods_lock_); + STLDeleteElements(&classes_to_patch_); + } CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key"); typedef void (*UninitCompilerContextFn)(CompilerDriver&); UninitCompilerContextFn uninit_compiler_context; @@ -906,6 +910,51 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id return result; } +bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr) { + ScopedObjectAccess soa(Thread::Current()); + mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); + if (resolved_class == nullptr) { + return false; + } + const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot(); + if (compiling_boot) { + // boot -> boot class pointers. + // True if the class is in the image at boot compiling time. + const bool is_image_class = IsImage() && IsImageClass( + dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_)); + // True if pc relative load works. + const bool support_boot_image_fixup = GetSupportBootImageFixup(); + if (is_image_class && support_boot_image_fixup) { + *is_type_initialized = resolved_class->IsInitialized(); + *use_direct_type_ptr = false; + *direct_type_ptr = 0; + return true; + } else { + return false; + } + } else { + // True if the class is in the image at app compiling time. + const bool class_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace(); + if (class_in_image) { + // boot -> app class pointers. + *is_type_initialized = resolved_class->IsInitialized(); + *use_direct_type_ptr = true; + *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class); + return true; + } else { + // app -> app class pointers. + // Give up because app does not have an image and class + // isn't created at compile time. TODO: implement this + // if/when each app gets an image. + return false; + } + } +} + static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa, SirtRef<mirror::DexCache>& dex_cache, const DexCompilationUnit* mUnit) @@ -1291,13 +1340,13 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file, InvokeType target_invoke_type, size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); - code_to_patch_.push_back(new PatchInformation(dex_file, - referrer_class_def_idx, - referrer_method_idx, - referrer_invoke_type, - target_method_idx, - target_invoke_type, - literal_offset)); + code_to_patch_.push_back(new CallPatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + referrer_invoke_type, + target_method_idx, + target_invoke_type, + literal_offset)); } void CompilerDriver::AddMethodPatch(const DexFile* dex_file, uint16_t referrer_class_def_idx, @@ -1307,13 +1356,25 @@ void CompilerDriver::AddMethodPatch(const DexFile* dex_file, InvokeType target_invoke_type, size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); - methods_to_patch_.push_back(new PatchInformation(dex_file, - referrer_class_def_idx, - referrer_method_idx, - referrer_invoke_type, - target_method_idx, - target_invoke_type, - literal_offset)); + methods_to_patch_.push_back(new CallPatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + referrer_invoke_type, + target_method_idx, + target_invoke_type, + literal_offset)); +} +void CompilerDriver::AddClassPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_type_idx, + size_t literal_offset) { + MutexLock mu(Thread::Current(), compiled_methods_lock_); + classes_to_patch_.push_back(new TypePatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + target_type_idx, + literal_offset)); } class ParallelCompilationManager { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 9e316242ba..eef94a1fc1 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -189,6 +189,10 @@ class CompilerDriver { uint32_t type_idx) LOCKS_EXCLUDED(Locks::mutator_lock_); + bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr); + // Can we fast path instance field access? Computes field's offset and volatility. bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, int* field_offset, bool* is_volatile) @@ -228,6 +232,12 @@ class CompilerDriver { InvokeType target_invoke_type, size_t literal_offset) LOCKS_EXCLUDED(compiled_methods_lock_); + void AddClassPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_method_idx, + size_t literal_offset) + LOCKS_EXCLUDED(compiled_methods_lock_); void SetBitcodeFileName(std::string const& filename); @@ -267,6 +277,8 @@ class CompilerDriver { return thread_count_; } + class CallPatchInformation; + class TypePatchInformation; class PatchInformation { public: const DexFile& GetDexFile() const { @@ -278,55 +290,127 @@ class CompilerDriver { uint32_t GetReferrerMethodIdx() const { return referrer_method_idx_; } - InvokeType GetReferrerInvokeType() const { - return referrer_invoke_type_; + size_t GetLiteralOffset() const { + return literal_offset_; } - uint32_t GetTargetMethodIdx() const { - return target_method_idx_; + + virtual bool IsCall() const { + return false; } - InvokeType GetTargetInvokeType() const { - return target_invoke_type_; + virtual bool IsType() const { + return false; } - size_t GetLiteralOffset() const {; - return literal_offset_; + virtual const CallPatchInformation* AsCall() const { + LOG(FATAL) << "Unreachable"; + return nullptr; + } + virtual const TypePatchInformation* AsType() const { + LOG(FATAL) << "Unreachable"; + return nullptr; } - private: + protected: PatchInformation(const DexFile* dex_file, uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, size_t literal_offset) : dex_file_(dex_file), referrer_class_def_idx_(referrer_class_def_idx), referrer_method_idx_(referrer_method_idx), - referrer_invoke_type_(referrer_invoke_type), - target_method_idx_(target_method_idx), - target_invoke_type_(target_invoke_type), literal_offset_(literal_offset) { CHECK(dex_file_ != NULL); } + virtual ~PatchInformation() {} const DexFile* const dex_file_; const uint16_t referrer_class_def_idx_; const uint32_t referrer_method_idx_; + const size_t literal_offset_; + + friend class CompilerDriver; + }; + + class CallPatchInformation : public PatchInformation { + public: + InvokeType GetReferrerInvokeType() const { + return referrer_invoke_type_; + } + uint32_t GetTargetMethodIdx() const { + return target_method_idx_; + } + InvokeType GetTargetInvokeType() const { + return target_invoke_type_; + } + + const CallPatchInformation* AsCall() const { + return this; + } + bool IsCall() const { + return true; + } + + private: + CallPatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) + : PatchInformation(dex_file, referrer_class_def_idx, + referrer_method_idx, literal_offset), + referrer_invoke_type_(referrer_invoke_type), + target_method_idx_(target_method_idx), + target_invoke_type_(target_invoke_type) { + } + const InvokeType referrer_invoke_type_; const uint32_t target_method_idx_; const InvokeType target_invoke_type_; - const size_t literal_offset_; friend class CompilerDriver; - DISALLOW_COPY_AND_ASSIGN(PatchInformation); + DISALLOW_COPY_AND_ASSIGN(CallPatchInformation); }; - const std::vector<const PatchInformation*>& GetCodeToPatch() const { + class TypePatchInformation : public PatchInformation { + public: + uint32_t GetTargetTypeIdx() const { + return target_type_idx_; + } + + bool IsType() const { + return true; + } + const TypePatchInformation* AsType() const { + return this; + } + + private: + TypePatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_type_idx, + size_t literal_offset) + : PatchInformation(dex_file, referrer_class_def_idx, + referrer_method_idx, literal_offset), + target_type_idx_(target_type_idx) { + } + + const uint32_t target_type_idx_; + + friend class CompilerDriver; + DISALLOW_COPY_AND_ASSIGN(TypePatchInformation); + }; + + const std::vector<const CallPatchInformation*>& GetCodeToPatch() const { return code_to_patch_; } - const std::vector<const PatchInformation*>& GetMethodsToPatch() const { + const std::vector<const CallPatchInformation*>& GetMethodsToPatch() const { return methods_to_patch_; } + const std::vector<const TypePatchInformation*>& GetClassesToPatch() const { + return classes_to_patch_; + } // Checks if class specified by type_idx is one of the image_classes_ bool IsImageClass(const char* descriptor) const; @@ -398,8 +482,9 @@ class CompilerDriver { static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_); - std::vector<const PatchInformation*> code_to_patch_; - std::vector<const PatchInformation*> methods_to_patch_; + std::vector<const CallPatchInformation*> code_to_patch_; + std::vector<const CallPatchInformation*> methods_to_patch_; + std::vector<const TypePatchInformation*> classes_to_patch_; VerifiedMethodsData* verified_methods_data_; DexFileToMethodInlinerMap* method_inliner_map_; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 556dec25ad..09bb70cd2f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -734,7 +734,7 @@ void ImageWriter::FixupFields(const Object* orig, } } -static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) +static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Thread* self = Thread::Current(); @@ -757,15 +757,34 @@ static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) return method; } +static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Thread* self = Thread::Current(); + SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(patch->GetDexFile())); + SirtRef<mirror::ClassLoader> class_loader(self, nullptr); + Class* klass = class_linker->ResolveType(patch->GetDexFile(), + patch->GetTargetTypeIdx(), + dex_cache, + class_loader); + CHECK(klass != NULL) + << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx(); + CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass) + << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " " + << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " " + << PrettyClass(klass); + return klass; +} + void ImageWriter::PatchOatCodeAndMethods() { Thread* self = Thread::Current(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); - typedef std::vector<const CompilerDriver::PatchInformation*> Patches; - const Patches& code_to_patch = compiler_driver_.GetCodeToPatch(); + typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches; + const CallPatches& code_to_patch = compiler_driver_.GetCodeToPatch(); for (size_t i = 0; i < code_to_patch.size(); i++) { - const CompilerDriver::PatchInformation* patch = code_to_patch[i]; + const CompilerDriver::CallPatchInformation* patch = code_to_patch[i]; ArtMethod* target = GetTargetMethod(patch); uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target)); uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader()); @@ -773,13 +792,21 @@ void ImageWriter::PatchOatCodeAndMethods() { SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset))); } - const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); + const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); for (size_t i = 0; i < methods_to_patch.size(); i++) { - const CompilerDriver::PatchInformation* patch = methods_to_patch[i]; + const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; ArtMethod* target = GetTargetMethod(patch); SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); } + const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = + compiler_driver_.GetClassesToPatch(); + for (size_t i = 0; i < classes_to_patch.size(); i++) { + const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i]; + Class* target = GetTargetType(patch); + SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); + } + // Update the image header with the new checksum after patching ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum()); @@ -796,13 +823,26 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(oat_code) & ~0x1); uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset()); if (kIsDebugBuild) { - const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx()); - uint32_t expected = reinterpret_cast<uint32_t>(&id); - uint32_t actual = *patch_location; - CHECK(actual == expected || actual == value) << std::hex - << "actual=" << actual - << "expected=" << expected - << "value=" << value; + if (patch->IsCall()) { + const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall(); + const DexFile::MethodId& id = cpatch->GetDexFile().GetMethodId(cpatch->GetTargetMethodIdx()); + uint32_t expected = reinterpret_cast<uint32_t>(&id); + uint32_t actual = *patch_location; + CHECK(actual == expected || actual == value) << std::hex + << "actual=" << actual + << "expected=" << expected + << "value=" << value; + } + if (patch->IsType()) { + const CompilerDriver::TypePatchInformation* tpatch = patch->AsType(); + const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx()); + uint32_t expected = reinterpret_cast<uint32_t>(&id); + uint32_t actual = *patch_location; + CHECK(actual == expected || actual == value) << std::hex + << "actual=" << actual + << "expected=" << expected + << "value=" << value; + } } *patch_location = value; oat_header.UpdateChecksum(patch_location, sizeof(value)); |