Refactor some patching logic
Reduce duplication since app images in-place relocation will require
this code also.
Bug: 22858531
Change-Id: Ibb901b67267e27ef3bc2a0baff77189d4dcd018a
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 3777015..3d9e7e7 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1441,34 +1441,28 @@
: reinterpret_cast<T*>(image_begin_ + NativeOffsetInImage(obj));
}
-void ImageWriter::FixupClass(mirror::Class* orig, mirror::Class* copy) {
- // Update the field arrays.
- copy->SetSFieldsPtrUnchecked(NativeLocationInImage(orig->GetSFieldsPtr()));
- copy->SetIFieldsPtrUnchecked(NativeLocationInImage(orig->GetIFieldsPtr()));
- // Update direct and virtual method arrays.
- copy->SetDirectMethodsPtrUnchecked(NativeLocationInImage(orig->GetDirectMethodsPtr()));
- copy->SetVirtualMethodsPtr(NativeLocationInImage(orig->GetVirtualMethodsPtr()));
- // Update dex cache strings.
- copy->SetDexCacheStrings(NativeLocationInImage(orig->GetDexCacheStrings()));
- // Fix up embedded tables.
- if (!orig->IsTemp()) {
- // TODO: Why do we have temp classes in some cases?
- if (orig->ShouldHaveEmbeddedImtAndVTable()) {
- for (int32_t i = 0; i < orig->GetEmbeddedVTableLength(); ++i) {
- ArtMethod* orig_method = orig->GetEmbeddedVTableEntry(i, target_ptr_size_);
- copy->SetEmbeddedVTableEntryUnchecked(
- i,
- NativeLocationInImage(orig_method),
- target_ptr_size_);
- }
- for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
- copy->SetEmbeddedImTableEntry(
- i,
- NativeLocationInImage(orig->GetEmbeddedImTableEntry(i, target_ptr_size_)),
- target_ptr_size_);
- }
- }
+template <typename T>
+T* ImageWriter::NativeCopyLocation(T* obj) {
+ return (obj == nullptr || IsInBootImage(obj))
+ ? obj
+ : reinterpret_cast<T*>(image_->Begin() + NativeOffsetInImage(obj));
+}
+
+class NativeLocationVisitor {
+ public:
+ explicit NativeLocationVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
+
+ template <typename T>
+ T* operator()(T* ptr) const {
+ return image_writer_->NativeLocationInImage(ptr);
}
+
+ private:
+ ImageWriter* const image_writer_;
+};
+
+void ImageWriter::FixupClass(mirror::Class* orig, mirror::Class* copy) {
+ orig->FixupNativePointers(copy, target_ptr_size_, NativeLocationVisitor(this));
FixupClassVisitor visitor(this, copy);
static_cast<mirror::Object*>(orig)->VisitReferences(visitor, visitor);
}
@@ -1528,6 +1522,21 @@
}
}
+
+class ImageAddressVisitor {
+ public:
+ explicit ImageAddressVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
+
+ template <typename T>
+ T* operator()(T* ptr) const SHARED_REQUIRES(Locks::mutator_lock_) {
+ return image_writer_->GetImageAddress(ptr);
+ }
+
+ private:
+ ImageWriter* const image_writer_;
+};
+
+
void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache,
mirror::DexCache* copy_dex_cache) {
// Though the DexCache array fields are usually treated as native pointers, we set the full
@@ -1536,52 +1545,39 @@
// static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + offset))).
GcRoot<mirror::String>* orig_strings = orig_dex_cache->GetStrings();
if (orig_strings != nullptr) {
- uintptr_t copy_strings_offset = NativeOffsetInImage(orig_strings);
- copy_dex_cache->SetField64<false>(
- mirror::DexCache::StringsOffset(),
- static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + copy_strings_offset)));
- GcRoot<mirror::String>* copy_strings =
- reinterpret_cast<GcRoot<mirror::String>*>(image_->Begin() + copy_strings_offset);
- for (size_t i = 0, num = orig_dex_cache->NumStrings(); i != num; ++i) {
- copy_strings[i] = GcRoot<mirror::String>(GetImageAddress(orig_strings[i].Read()));
- }
+ copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::StringsOffset(),
+ NativeLocationInImage(orig_strings),
+ /*pointer size*/8u);
+ orig_dex_cache->FixupStrings(NativeCopyLocation(orig_strings), ImageAddressVisitor(this));
}
GcRoot<mirror::Class>* orig_types = orig_dex_cache->GetResolvedTypes();
if (orig_types != nullptr) {
- uintptr_t copy_types_offset = NativeOffsetInImage(orig_types);
- copy_dex_cache->SetField64<false>(
- mirror::DexCache::ResolvedTypesOffset(),
- static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + copy_types_offset)));
- GcRoot<mirror::Class>* copy_types =
- reinterpret_cast<GcRoot<mirror::Class>*>(image_->Begin() + copy_types_offset);
- for (size_t i = 0, num = orig_dex_cache->NumResolvedTypes(); i != num; ++i) {
- copy_types[i] = GcRoot<mirror::Class>(GetImageAddress(orig_types[i].Read()));
- }
+ copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedTypesOffset(),
+ NativeLocationInImage(orig_types),
+ /*pointer size*/8u);
+ orig_dex_cache->FixupResolvedTypes(NativeCopyLocation(orig_types), ImageAddressVisitor(this));
}
ArtMethod** orig_methods = orig_dex_cache->GetResolvedMethods();
if (orig_methods != nullptr) {
- uintptr_t copy_methods_offset = NativeOffsetInImage(orig_methods);
- copy_dex_cache->SetField64<false>(
- mirror::DexCache::ResolvedMethodsOffset(),
- static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + copy_methods_offset)));
- ArtMethod** copy_methods =
- reinterpret_cast<ArtMethod**>(image_->Begin() + copy_methods_offset);
+ copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedMethodsOffset(),
+ NativeLocationInImage(orig_methods),
+ /*pointer size*/8u);
+ ArtMethod** copy_methods = NativeCopyLocation(orig_methods);
for (size_t i = 0, num = orig_dex_cache->NumResolvedMethods(); i != num; ++i) {
ArtMethod* orig = mirror::DexCache::GetElementPtrSize(orig_methods, i, target_ptr_size_);
- ArtMethod* copy = IsInBootImage(orig) ? orig : NativeLocationInImage(orig);
+ ArtMethod* copy = NativeLocationInImage(orig);
mirror::DexCache::SetElementPtrSize(copy_methods, i, copy, target_ptr_size_);
}
}
ArtField** orig_fields = orig_dex_cache->GetResolvedFields();
if (orig_fields != nullptr) {
- uintptr_t copy_fields_offset = NativeOffsetInImage(orig_fields);
- copy_dex_cache->SetField64<false>(
- mirror::DexCache::ResolvedFieldsOffset(),
- static_cast<int64_t>(reinterpret_cast<uintptr_t>(image_begin_ + copy_fields_offset)));
- ArtField** copy_fields = reinterpret_cast<ArtField**>(image_->Begin() + copy_fields_offset);
+ copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedFieldsOffset(),
+ NativeLocationInImage(orig_fields),
+ /*pointer size*/8u);
+ ArtField** copy_fields = NativeCopyLocation(orig_fields);
for (size_t i = 0, num = orig_dex_cache->NumResolvedFields(); i != num; ++i) {
ArtField* orig = mirror::DexCache::GetElementPtrSize(orig_fields, i, target_ptr_size_);
- ArtField* copy = IsInBootImage(orig) ? orig : NativeLocationInImage(orig);
+ ArtField* copy = NativeLocationInImage(orig);
mirror::DexCache::SetElementPtrSize(copy_fields, i, copy, target_ptr_size_);
}
}
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index a0a785e..22cb91a 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -347,9 +347,14 @@
uintptr_t NativeOffsetInImage(void* obj);
+ // Location of where the object will be when the image is loaded at runtime.
template <typename T>
T* NativeLocationInImage(T* obj);
+ // Location of where the temporary copy of the object currently is.
+ template <typename T>
+ T* NativeCopyLocation(T* obj);
+
// Return true of obj is inside of the boot image space. This may only return true if we are
// compiling an app image.
bool IsInBootImage(const void* obj) const;
@@ -446,6 +451,7 @@
friend class FixupClassVisitor;
friend class FixupRootVisitor;
friend class FixupVisitor;
+ friend class NativeLocationVisitor;
friend class NonImageClassesVisitor;
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
};
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index c587f68..3d9f7dc 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -526,13 +526,26 @@
temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots);
}
+class RelocatedPointerVisitor {
+ public:
+ explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
+
+ template <typename T>
+ T* operator()(T* ptr) const {
+ return patch_oat_->RelocatedAddressOfPointer(ptr);
+ }
+
+ private:
+ PatchOat* const patch_oat_;
+};
+
void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) {
auto* dex_caches = down_cast<mirror::ObjectArray<mirror::DexCache>*>(
img_roots->Get(ImageHeader::kDexCaches));
+ const size_t pointer_size = InstructionSetPointerSize(isa_);
for (size_t i = 0, count = dex_caches->GetLength(); i < count; ++i) {
auto* orig_dex_cache = dex_caches->GetWithoutChecks(i);
auto* copy_dex_cache = RelocatedCopyOf(orig_dex_cache);
- const size_t pointer_size = InstructionSetPointerSize(isa_);
// Though the DexCache array fields are usually treated as native pointers, we set the full
// 64-bit values here, clearing the top 32 bits for 32-bit targets. The zero-extension is
// done by casting to the unsigned type uintptr_t before casting to int64_t, i.e.
@@ -543,10 +556,7 @@
mirror::DexCache::StringsOffset(),
static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_strings)));
if (orig_strings != nullptr) {
- GcRoot<mirror::String>* copy_strings = RelocatedCopyOf(orig_strings);
- for (size_t j = 0, num = orig_dex_cache->NumStrings(); j != num; ++j) {
- copy_strings[j] = GcRoot<mirror::String>(RelocatedAddressOfPointer(orig_strings[j].Read()));
- }
+ orig_dex_cache->FixupStrings(RelocatedCopyOf(orig_strings), RelocatedPointerVisitor(this));
}
GcRoot<mirror::Class>* orig_types = orig_dex_cache->GetResolvedTypes();
GcRoot<mirror::Class>* relocated_types = RelocatedAddressOfPointer(orig_types);
@@ -554,10 +564,8 @@
mirror::DexCache::ResolvedTypesOffset(),
static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_types)));
if (orig_types != nullptr) {
- GcRoot<mirror::Class>* copy_types = RelocatedCopyOf(orig_types);
- for (size_t j = 0, num = orig_dex_cache->NumResolvedTypes(); j != num; ++j) {
- copy_types[j] = GcRoot<mirror::Class>(RelocatedAddressOfPointer(orig_types[j].Read()));
- }
+ orig_dex_cache->FixupResolvedTypes(RelocatedCopyOf(orig_types),
+ RelocatedPointerVisitor(this));
}
ArtMethod** orig_methods = orig_dex_cache->GetResolvedMethods();
ArtMethod** relocated_methods = RelocatedAddressOfPointer(orig_methods);
@@ -588,25 +596,6 @@
}
}
-void PatchOat::FixupNativePointerArray(mirror::PointerArray* object) {
- if (object->IsIntArray()) {
- mirror::IntArray* arr = object->AsIntArray();
- mirror::IntArray* copy_arr = down_cast<mirror::IntArray*>(RelocatedCopyOf(arr));
- for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) {
- copy_arr->SetWithoutChecks<false>(
- j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j)));
- }
- } else {
- CHECK(object->IsLongArray());
- mirror::LongArray* arr = object->AsLongArray();
- mirror::LongArray* copy_arr = down_cast<mirror::LongArray*>(RelocatedCopyOf(arr));
- for (size_t j = 0, count2 = arr->GetLength(); j < count2; ++j) {
- copy_arr->SetWithoutChecks<false>(
- j, RelocatedAddressOfIntPointer(arr->GetWithoutChecks(j)));
- }
- }
-}
-
bool PatchOat::PatchImage() {
ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
CHECK_GT(image_->Size(), sizeof(ImageHeader));
@@ -674,17 +663,14 @@
PatchOat::PatchVisitor visitor(this, copy);
object->VisitReferences<kVerifyNone>(visitor, visitor);
if (object->IsClass<kVerifyNone>()) {
- auto* klass = object->AsClass();
- auto* copy_klass = down_cast<mirror::Class*>(copy);
- copy_klass->SetDexCacheStrings(RelocatedAddressOfPointer(klass->GetDexCacheStrings()));
- copy_klass->SetSFieldsPtrUnchecked(RelocatedAddressOfPointer(klass->GetSFieldsPtr()));
- copy_klass->SetIFieldsPtrUnchecked(RelocatedAddressOfPointer(klass->GetIFieldsPtr()));
- copy_klass->SetDirectMethodsPtrUnchecked(
- RelocatedAddressOfPointer(klass->GetDirectMethodsPtr()));
- copy_klass->SetVirtualMethodsPtr(RelocatedAddressOfPointer(klass->GetVirtualMethodsPtr()));
+ const size_t pointer_size = InstructionSetPointerSize(isa_);
+ mirror::Class* klass = object->AsClass();
+ mirror::Class* copy_klass = down_cast<mirror::Class*>(copy);
+ RelocatedPointerVisitor native_visitor(this);
+ klass->FixupNativePointers(copy_klass, pointer_size, native_visitor);
auto* vtable = klass->GetVTable();
if (vtable != nullptr) {
- FixupNativePointerArray(vtable);
+ vtable->Fixup(RelocatedCopyOf(vtable), pointer_size, native_visitor);
}
auto* iftable = klass->GetIfTable();
if (iftable != nullptr) {
@@ -692,24 +678,12 @@
if (iftable->GetMethodArrayCount(i) > 0) {
auto* method_array = iftable->GetMethodArray(i);
CHECK(method_array != nullptr);
- FixupNativePointerArray(method_array);
+ method_array->Fixup(RelocatedCopyOf(method_array), pointer_size, native_visitor);
}
}
}
- if (klass->ShouldHaveEmbeddedImtAndVTable()) {
- const size_t pointer_size = InstructionSetPointerSize(isa_);
- for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) {
- copy_klass->SetEmbeddedVTableEntryUnchecked(i, RelocatedAddressOfPointer(
- klass->GetEmbeddedVTableEntry(i, pointer_size)), pointer_size);
- }
- for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
- copy_klass->SetEmbeddedImTableEntry(i, RelocatedAddressOfPointer(
- klass->GetEmbeddedImTableEntry(i, pointer_size)), pointer_size);
- }
- }
- }
- if (object->GetClass() == mirror::Method::StaticClass() ||
- object->GetClass() == mirror::Constructor::StaticClass()) {
+ } else if (object->GetClass() == mirror::Method::StaticClass() ||
+ object->GetClass() == mirror::Constructor::StaticClass()) {
// Need to go update the ArtMethod.
auto* dest = down_cast<mirror::AbstractMethod*>(copy);
auto* src = down_cast<mirror::AbstractMethod*>(object);
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 87ecc61..0915014 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -102,8 +102,6 @@
SHARED_REQUIRES(Locks::mutator_lock_);
void FixupMethod(ArtMethod* object, ArtMethod* copy)
SHARED_REQUIRES(Locks::mutator_lock_);
- void FixupNativePointerArray(mirror::PointerArray* object)
- SHARED_REQUIRES(Locks::mutator_lock_);
bool InHeap(mirror::Object*);
// Patches oat in place, modifying the oat_file given to the constructor.
@@ -200,6 +198,7 @@
TimingLogger* timings_;
friend class FixupRootVisitor;
+ friend class RelocatedPointerVisitor;
friend class PatchOatArtFieldVisitor;
friend class PatchOatArtMethodVisitor;
DISALLOW_IMPLICIT_CONSTRUCTORS(PatchOat);
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index ec7d758..b6f424b 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -394,6 +394,19 @@
}
}
+template <typename Visitor>
+inline void PointerArray::Fixup(mirror::PointerArray* dest,
+ size_t pointer_size,
+ const Visitor& visitor) {
+ for (size_t i = 0, count = GetLength(); i < count; ++i) {
+ void* ptr = GetElementPtrSize<void*>(i, pointer_size);
+ void* new_ptr = visitor(ptr);
+ if (ptr != new_ptr) {
+ dest->SetElementPtrSize<false, true>(i, new_ptr, pointer_size);
+ }
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 7458424..50d77eb 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -190,6 +190,12 @@
template<bool kTransactionActive = false, bool kUnchecked = false, typename T>
void SetElementPtrSize(uint32_t idx, T element, size_t ptr_size)
SHARED_REQUIRES(Locks::mutator_lock_);
+
+ // Fixup the pointers in the dest arrays by passing our pointers through the visitor. Only copies
+ // to dest if visitor(source_ptr) != source_ptr.
+ template <typename Visitor>
+ void Fixup(mirror::PointerArray* dest, size_t pointer_size, const Visitor& visitor)
+ SHARED_REQUIRES(Locks::mutator_lock_);
};
} // namespace mirror
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 174de0e..9e416dc 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -937,6 +937,57 @@
return arr != nullptr ? arr->size() : 0u;
}
+template <typename Visitor>
+inline void Class::FixupNativePointers(mirror::Class* dest,
+ size_t pointer_size,
+ const Visitor& visitor) {
+ // Update the field arrays.
+ LengthPrefixedArray<ArtField>* const sfields = GetSFieldsPtr();
+ LengthPrefixedArray<ArtField>* const new_sfields = visitor(sfields);
+ if (sfields != new_sfields) {
+ dest->SetSFieldsPtrUnchecked(new_sfields);
+ }
+ LengthPrefixedArray<ArtField>* const ifields = GetIFieldsPtr();
+ LengthPrefixedArray<ArtField>* const new_ifields = visitor(ifields);
+ if (ifields != new_ifields) {
+ dest->SetIFieldsPtrUnchecked(new_ifields);
+ }
+ // Update direct and virtual method arrays.
+ LengthPrefixedArray<ArtMethod>* direct_methods = GetDirectMethodsPtr();
+ LengthPrefixedArray<ArtMethod>* new_direct_methods = visitor(direct_methods);
+ if (direct_methods != new_direct_methods) {
+ dest->SetDirectMethodsPtrUnchecked(new_direct_methods);
+ }
+ LengthPrefixedArray<ArtMethod>* virtual_methods = GetVirtualMethodsPtr();
+ LengthPrefixedArray<ArtMethod>* new_virtual_methods = visitor(virtual_methods);
+ if (virtual_methods != new_virtual_methods) {
+ dest->SetVirtualMethodsPtr(new_virtual_methods);
+ }
+ // Update dex cache strings.
+ GcRoot<mirror::String>* strings = GetDexCacheStrings();
+ GcRoot<mirror::String>* new_strings = visitor(strings);
+ if (strings != new_strings) {
+ dest->SetDexCacheStrings(new_strings);
+ }
+ // Fix up embedded tables.
+ if (!IsTemp() && ShouldHaveEmbeddedImtAndVTable()) {
+ for (int32_t i = 0, count = GetEmbeddedVTableLength(); i < count; ++i) {
+ ArtMethod* method = GetEmbeddedVTableEntry(i, pointer_size);
+ ArtMethod* new_method = visitor(method);
+ if (method != new_method) {
+ dest->SetEmbeddedVTableEntryUnchecked(i, new_method, pointer_size);
+ }
+ }
+ for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
+ ArtMethod* method = GetEmbeddedImTableEntry(i, pointer_size);
+ ArtMethod* new_method = visitor(method);
+ if (method != new_method) {
+ dest->SetEmbeddedImTableEntry(i, new_method, pointer_size);
+ }
+ }
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 80e136c..19a84f2 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1157,6 +1157,13 @@
ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetVirtualMethodsPtrUnchecked()
SHARED_REQUIRES(Locks::mutator_lock_);
+ // Fix up all of the native pointers in the class by running them through the visitor. Only sets
+ // the corresponding entry in dest if visitor(obj) != obj to prevent dirty memory. Dest should be
+ // initialized to a copy of *this to prevent issues.
+ template <typename Visitor>
+ void FixupNativePointers(mirror::Class* dest, size_t pointer_size, const Visitor& visitor)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
private:
void SetVerifyError(Object* klass) SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index f8ccfb1..975af61 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -137,6 +137,32 @@
}
}
+template <typename Visitor>
+inline void DexCache::FixupStrings(GcRoot<mirror::String>* dest, const Visitor& visitor) {
+ GcRoot<mirror::String>* src = GetStrings();
+ for (size_t i = 0, count = NumStrings(); i < count; ++i) {
+ // TODO: Probably don't need read barrier for most callers.
+ mirror::String* source = src[i].Read();
+ mirror::String* new_source = visitor(source);
+ if (source != new_source) {
+ dest[i] = GcRoot<mirror::String>(new_source);
+ }
+ }
+}
+
+template <typename Visitor>
+inline void DexCache::FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visitor& visitor) {
+ GcRoot<mirror::Class>* src = GetResolvedTypes();
+ for (size_t i = 0, count = NumResolvedTypes(); i < count; ++i) {
+ // TODO: Probably don't need read barrier for most callers.
+ mirror::Class* source = src[i].Read();
+ mirror::Class* new_source = visitor(source);
+ if (source != new_source) {
+ dest[i] = GcRoot<mirror::Class>(new_source);
+ }
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 3144553..32eb595 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -61,6 +61,14 @@
void Fixup(ArtMethod* trampoline, size_t pointer_size)
SHARED_REQUIRES(Locks::mutator_lock_);
+ template <typename Visitor>
+ void FixupStrings(GcRoot<mirror::String>* dest, const Visitor& visitor)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
+ template <typename Visitor>
+ void FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visitor& visitor)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
String* GetLocation() SHARED_REQUIRES(Locks::mutator_lock_) {
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_));
}