Merge "Remove DEBUG_JIT from Zygote flags."
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/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 3b78264..0d05c49 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -614,23 +614,36 @@
}
bool is_exact = a.IsExact() && b.IsExact();
- Handle<mirror::Class> type_handle;
+ ReferenceTypeInfo::TypeHandle result_type_handle;
+ ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
+ ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
+ bool a_is_interface = a_type_handle->IsInterface();
+ bool b_is_interface = b_type_handle->IsInterface();
if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
- type_handle = a.GetTypeHandle();
+ result_type_handle = a_type_handle;
} else if (a.IsSupertypeOf(b)) {
- type_handle = a.GetTypeHandle();
+ result_type_handle = a_type_handle;
is_exact = false;
} else if (b.IsSupertypeOf(a)) {
- type_handle = b.GetTypeHandle();
+ result_type_handle = b_type_handle;
+ is_exact = false;
+ } else if (!a_is_interface && !b_is_interface) {
+ result_type_handle = handles_->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
is_exact = false;
} else {
- // TODO: Find the first common super class.
- type_handle = object_class_handle_;
+ // This can happen if:
+ // - both types are interfaces. TODO(calin): implement
+ // - one is an interface, the other a class, and the type does not implement the interface
+ // e.g:
+ // void foo(Interface i, boolean cond) {
+ // Object o = cond ? i : new Object();
+ // }
+ result_type_handle = object_class_handle_;
is_exact = false;
}
- return ReferenceTypeInfo::Create(type_handle, is_exact);
+ return ReferenceTypeInfo::Create(result_type_handle, is_exact);
}
static void UpdateArrayGet(HArrayGet* instr,
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/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6eacac1..463c9cf 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -788,7 +788,106 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
+DEFINE_FUNCTION art_quick_alloc_object_rosalloc
+ // Fast path rosalloc allocation.
+ // eax: uint32_t type_idx/return value, ecx: ArtMethod*
+ // ebx, edx: free
+ PUSH edi
+ movl ART_METHOD_DEX_CACHE_TYPES_OFFSET_32(%ecx), %edx // Load dex cache resolved types array
+ // Load the class (edx)
+ movl 0(%edx, %eax, COMPRESSED_REFERENCE_SIZE), %edx
+ testl %edx, %edx // Check null class
+ jz .Lart_quick_alloc_object_rosalloc_slow_path
+ // Check class status
+ cmpl LITERAL(MIRROR_CLASS_STATUS_INITIALIZED), MIRROR_CLASS_STATUS_OFFSET(%edx)
+ jne .Lart_quick_alloc_object_rosalloc_slow_path
+ // No fake dependence needed on x86
+ // between status and flags load,
+ // since each load is a load-acquire,
+ // no loads reordering.
+ // Check access flags has
+ // kAccClassIsFinalizable
+ testl LITERAL(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), MIRROR_CLASS_ACCESS_FLAGS_OFFSET(%edx)
+ jnz .Lart_quick_alloc_object_rosalloc_slow_path
+
+ movl %fs:THREAD_SELF_OFFSET, %ebx // ebx = thread
+ // Check if the thread local allocation
+ // stack has room
+ movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %edi
+ cmpl THREAD_LOCAL_ALLOC_STACK_END_OFFSET(%ebx), %edi
+ jae .Lart_quick_alloc_object_rosalloc_slow_path
+
+ movl MIRROR_CLASS_OBJECT_SIZE_OFFSET(%edx), %edi // Load the object size (edi)
+ // Check if the size is for a thread
+ // local allocation
+ cmpl LITERAL(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE), %edi
+ ja .Lart_quick_alloc_object_rosalloc_slow_path
+ decl %edi
+ shrl LITERAL(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT), %edi // Calculate the rosalloc bracket index
+ // from object size.
+ // Align up the size by the rosalloc
+ // bracket quantum size and divide
+ // by the quantum size and subtract
+ // by 1. This code is a shorter but
+ // equivalent version.
+ // Load thread local rosalloc run (ebx)
+ movl THREAD_ROSALLOC_RUNS_OFFSET(%ebx, %edi, __SIZEOF_POINTER__), %ebx
+ // Load free_list head (edi),
+ // this will be the return value.
+ movl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx), %edi
+ test %edi, %edi
+ jz .Lart_quick_alloc_object_rosalloc_slow_path
+ // Point of no slow path. Won't go to
+ // the slow path from here on. Ok to
+ // clobber eax and ecx.
+ movl %edi, %eax
+ // Load the next pointer of the head
+ // and update head of free list with
+ // next pointer
+ movl ROSALLOC_SLOT_NEXT_OFFSET(%eax), %edi
+ movl %edi, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx)
+ // Decrement size of free list by 1
+ decl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)(%ebx)
+ // Store the class pointer in the
+ // header. This also overwrites the
+ // next pointer. The offsets are
+ // asserted to match.
+#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
+#error "Class pointer needs to overwrite next pointer."
+#endif
+ POISON_HEAP_REF edx
+ movl %edx, MIRROR_OBJECT_CLASS_OFFSET(%eax)
+ movl %fs:THREAD_SELF_OFFSET, %ebx // ebx = thread
+ // Push the new object onto the thread
+ // local allocation stack and
+ // increment the thread local
+ // allocation stack top.
+ movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %edi
+ movl %eax, (%edi)
+ addl LITERAL(COMPRESSED_REFERENCE_SIZE), %edi
+ movl %edi, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx)
+ // No fence needed for x86.
+ POP edi
+ ret
+.Lart_quick_alloc_object_rosalloc_slow_path:
+ POP edi
+ SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx // save ref containing registers for GC
+ // Outgoing argument set up
+ PUSH eax // alignment padding
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ CFI_ADJUST_CFA_OFFSET(4)
+ PUSH ecx
+ PUSH eax
+ call SYMBOL(artAllocObjectFromCodeRosAlloc) // cxx_name(arg0, arg1, Thread*)
+ addl LITERAL(16), %esp // pop arguments
+ CFI_ADJUST_CFA_OFFSET(-16)
+ RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // resotre frame up to return address
+ RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
+END_FUNCTION art_quick_alloc_object_rosalloc
+
+
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 13d0b84..32e77b7 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2684,26 +2684,26 @@
case JDWP::JT_BOOLEAN:
case JDWP::JT_BYTE:
CHECK_EQ(width, 1U);
- if (!visitor.SetVRegFromDebugger(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+ if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
}
break;
case JDWP::JT_SHORT:
case JDWP::JT_CHAR:
CHECK_EQ(width, 2U);
- if (!visitor.SetVRegFromDebugger(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+ if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
}
break;
case JDWP::JT_INT:
CHECK_EQ(width, 4U);
- if (!visitor.SetVRegFromDebugger(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+ if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
}
break;
case JDWP::JT_FLOAT:
CHECK_EQ(width, 4U);
- if (!visitor.SetVRegFromDebugger(m, vreg, static_cast<uint32_t>(value), kFloatVReg)) {
+ if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kFloatVReg)) {
return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
}
break;
@@ -2721,7 +2721,7 @@
VLOG(jdwp) << tag << " object " << o << " is an invalid object";
return JDWP::ERR_INVALID_OBJECT;
}
- if (!visitor.SetVRegFromDebugger(m, vreg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)),
+ if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)),
kReferenceVReg)) {
return FailSetLocalValue(visitor, vreg, tag, reinterpret_cast<uintptr_t>(o));
}
@@ -2729,14 +2729,14 @@
}
case JDWP::JT_DOUBLE: {
CHECK_EQ(width, 8U);
- if (!visitor.SetVRegPairFromDebugger(m, vreg, value, kDoubleLoVReg, kDoubleHiVReg)) {
+ if (!visitor.SetVRegPair(m, vreg, value, kDoubleLoVReg, kDoubleHiVReg)) {
return FailSetLocalValue(visitor, vreg, tag, value);
}
break;
}
case JDWP::JT_LONG: {
CHECK_EQ(width, 8U);
- if (!visitor.SetVRegPairFromDebugger(m, vreg, value, kLongLoVReg, kLongHiVReg)) {
+ if (!visitor.SetVRegPair(m, vreg, value, kLongLoVReg, kLongHiVReg)) {
return FailSetLocalValue(visitor, vreg, tag, value);
}
break;
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.cc b/runtime/mirror/class.cc
index 3590586..05a9039 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -802,6 +802,18 @@
}
}
+mirror::Class* Class::GetCommonSuperClass(Handle<Class> klass) {
+ DCHECK(klass.Get() != nullptr);
+ DCHECK(!klass->IsInterface());
+ DCHECK(!IsInterface());
+ mirror::Class* common_super_class = this;
+ while (!common_super_class->IsAssignableFrom(klass.Get())) {
+ common_super_class = common_super_class->GetSuperClass();
+ }
+ DCHECK(common_super_class != nullptr);
+ return common_super_class;
+}
+
const char* Class::GetSourceFile() {
const DexFile& dex_file = GetDexFile();
const DexFile::ClassDef* dex_class_def = GetClassDef();
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 80e136c..0ab5b97 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -657,6 +657,10 @@
ALWAYS_INLINE Class* GetSuperClass() SHARED_REQUIRES(Locks::mutator_lock_);
+ // Get first common super class. It will never return null.
+ // `This` and `klass` must be classes.
+ Class* GetCommonSuperClass(Handle<Class> klass) SHARED_REQUIRES(Locks::mutator_lock_);
+
void SetSuperClass(Class *new_super_class) SHARED_REQUIRES(Locks::mutator_lock_) {
// Super class is assigned once, except during class linker initialization.
Class* old_super_class = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_));
@@ -1157,6 +1161,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_));
}
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 88978bf..9098d38 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -265,7 +265,12 @@
}
} else {
DCHECK(cur_shadow_frame_ != nullptr);
- *val = cur_shadow_frame_->GetVReg(vreg);
+ if (kind == kReferenceVReg) {
+ *val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(
+ cur_shadow_frame_->GetVRegReference(vreg)));
+ } else {
+ *val = cur_shadow_frame_->GetVReg(vreg);
+ }
return true;
}
}
@@ -481,52 +486,10 @@
return true;
}
-bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value,
+bool StackVisitor::SetVReg(ArtMethod* m,
+ uint16_t vreg,
+ uint32_t new_value,
VRegKind kind) {
- if (cur_quick_frame_ != nullptr) {
- DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
- DCHECK(m == GetMethod());
- if (cur_oat_quick_method_header_->IsOptimized()) {
- return false;
- } else {
- return SetVRegFromQuickCode(m, vreg, new_value, kind);
- }
- } else {
- cur_shadow_frame_->SetVReg(vreg, new_value);
- return true;
- }
-}
-
-bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t new_value,
- VRegKind kind) {
- DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
- DCHECK(m == GetMethod());
- const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
- QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
- const VmapTable vmap_table(method_header->GetVmapTable());
- uint32_t vmap_offset;
- // TODO: IsInContext stops before spotting floating point registers.
- if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
- bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
- uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
- uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
- return SetRegisterIfAccessible(reg, new_value, kind);
- } else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile
- // its instructions?
- uint32_t* addr = GetVRegAddrFromQuickCode(
- cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
- frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
- *addr = new_value;
- return true;
- }
-}
-
-bool StackVisitor::SetVRegFromDebugger(ArtMethod* m,
- uint16_t vreg,
- uint32_t new_value,
- VRegKind kind) {
const DexFile::CodeItem* code_item = m->GetCodeItem();
if (code_item == nullptr) {
return false;
@@ -551,93 +514,11 @@
return true;
}
-bool StackVisitor::SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind) {
- const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
- if (!IsAccessibleRegister(reg, is_float)) {
- return false;
- }
- const bool target64 = Is64BitInstructionSet(kRuntimeISA);
-
- // Create a new value that can hold both low 32 and high 32 bits, in
- // case we are running 64 bits.
- uintptr_t full_new_value = new_value;
- // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
- if (target64) {
- bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
- bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
- if (wide_lo || wide_hi) {
- uintptr_t old_reg_val = GetRegister(reg, is_float);
- uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
- uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
- uint64_t mask = 0xffffffff;
- if (wide_lo) {
- mask = mask << 32;
- } else {
- new_vreg_portion = new_vreg_portion << 32;
- }
- full_new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
- }
- }
- SetRegister(reg, full_new_value, is_float);
- return true;
-}
-
-bool StackVisitor::SetVRegPair(ArtMethod* m, uint16_t vreg, uint64_t new_value,
- VRegKind kind_lo, VRegKind kind_hi) {
- if (kind_lo == kLongLoVReg) {
- DCHECK_EQ(kind_hi, kLongHiVReg);
- } else if (kind_lo == kDoubleLoVReg) {
- DCHECK_EQ(kind_hi, kDoubleHiVReg);
- } else {
- LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
- }
- if (cur_quick_frame_ != nullptr) {
- DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
- DCHECK(m == GetMethod());
- if (cur_oat_quick_method_header_->IsOptimized()) {
- return false;
- } else {
- return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi);
- }
- } else {
- DCHECK(cur_shadow_frame_ != nullptr);
- cur_shadow_frame_->SetVRegLong(vreg, new_value);
- return true;
- }
-}
-
-bool StackVisitor::SetVRegPairFromQuickCode(
- ArtMethod* m, uint16_t vreg, uint64_t new_value, VRegKind kind_lo, VRegKind kind_hi) {
- DCHECK_EQ(m, GetMethod());
- const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
- QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
- const VmapTable vmap_table(method_header->GetVmapTable());
- uint32_t vmap_offset_lo, vmap_offset_hi;
- // TODO: IsInContext stops before spotting floating point registers.
- if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
- vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
- bool is_float = (kind_lo == kDoubleLoVReg);
- uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
- uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
- uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
- return SetRegisterPairIfAccessible(reg_lo, reg_hi, new_value, is_float);
- } else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile
- // its instructions?
- uint32_t* addr = GetVRegAddrFromQuickCode(
- cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
- frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
- *reinterpret_cast<uint64_t*>(addr) = new_value;
- return true;
- }
-}
-
-bool StackVisitor::SetVRegPairFromDebugger(ArtMethod* m,
- uint16_t vreg,
- uint64_t new_value,
- VRegKind kind_lo,
- VRegKind kind_hi) {
+bool StackVisitor::SetVRegPair(ArtMethod* m,
+ uint16_t vreg,
+ uint64_t new_value,
+ VRegKind kind_lo,
+ VRegKind kind_hi) {
if (kind_lo == kLongLoVReg) {
DCHECK_EQ(kind_hi, kLongHiVReg);
} else if (kind_lo == kDoubleLoVReg) {
@@ -666,25 +547,6 @@
return true;
}
-bool StackVisitor::SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi,
- uint64_t new_value, bool is_float) {
- if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
- return false;
- }
- uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF);
- uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32);
- bool target64 = Is64BitInstructionSet(kRuntimeISA);
- // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
- if (target64) {
- DCHECK_EQ(reg_lo, reg_hi);
- SetRegister(reg_lo, new_value, is_float);
- } else {
- SetRegister(reg_lo, new_value_lo, is_float);
- SetRegister(reg_hi, new_value_hi, is_float);
- }
- return true;
-}
-
bool StackVisitor::IsAccessibleGPR(uint32_t reg) const {
DCHECK(context_ != nullptr);
return context_->IsAccessibleGPR(reg);
@@ -702,12 +564,6 @@
return context_->GetGPR(reg);
}
-void StackVisitor::SetGPR(uint32_t reg, uintptr_t value) {
- DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine";
- DCHECK(context_ != nullptr);
- context_->SetGPR(reg, value);
-}
-
bool StackVisitor::IsAccessibleFPR(uint32_t reg) const {
DCHECK(context_ != nullptr);
return context_->IsAccessibleFPR(reg);
@@ -719,12 +575,6 @@
return context_->GetFPR(reg);
}
-void StackVisitor::SetFPR(uint32_t reg, uintptr_t value) {
- DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine";
- DCHECK(context_ != nullptr);
- context_->SetFPR(reg, value);
-}
-
uintptr_t StackVisitor::GetReturnPc() const {
uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
DCHECK(sp != nullptr);
diff --git a/runtime/stack.h b/runtime/stack.h
index aa7b616..a0c44cb 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -600,22 +600,18 @@
uint64_t* val) const
SHARED_REQUIRES(Locks::mutator_lock_);
+ // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
+ // is triggered to make the values effective.
bool SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
SHARED_REQUIRES(Locks::mutator_lock_);
// Values will be set in debugger shadow frames. Debugger will make sure deoptimization
// is triggered to make the values effective.
- bool SetVRegFromDebugger(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- bool SetVRegPair(ArtMethod* m, uint16_t vreg, uint64_t new_value,
- VRegKind kind_lo, VRegKind kind_hi)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
- // is triggered to make the values effective.
- bool SetVRegPairFromDebugger(ArtMethod* m, uint16_t vreg, uint64_t new_value,
- VRegKind kind_lo, VRegKind kind_hi)
+ bool SetVRegPair(ArtMethod* m,
+ uint16_t vreg,
+ uint64_t new_value,
+ VRegKind kind_lo,
+ VRegKind kind_hi)
SHARED_REQUIRES(Locks::mutator_lock_);
uintptr_t* GetGPRAddress(uint32_t reg) const;
@@ -749,22 +745,12 @@
DCHECK(IsAccessibleRegister(reg, is_float));
return is_float ? GetFPR(reg) : GetGPR(reg);
}
- void SetRegister(uint32_t reg, uintptr_t value, bool is_float) {
- DCHECK(IsAccessibleRegister(reg, is_float));
- if (is_float) {
- SetFPR(reg, value);
- } else {
- SetGPR(reg, value);
- }
- }
bool IsAccessibleGPR(uint32_t reg) const;
uintptr_t GetGPR(uint32_t reg) const;
- void SetGPR(uint32_t reg, uintptr_t value);
bool IsAccessibleFPR(uint32_t reg) const;
uintptr_t GetFPR(uint32_t reg) const;
- void SetFPR(uint32_t reg, uintptr_t value);
bool GetVRegFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind, uint32_t* val) const
SHARED_REQUIRES(Locks::mutator_lock_);
@@ -789,19 +775,6 @@
uint64_t* val) const
SHARED_REQUIRES(Locks::mutator_lock_);
- bool SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t new_value,
- VRegKind kind)
- SHARED_REQUIRES(Locks::mutator_lock_);
- bool SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- bool SetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, uint64_t new_value,
- VRegKind kind_lo, VRegKind kind_hi)
- SHARED_REQUIRES(Locks::mutator_lock_);
- bool SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, uint64_t new_value,
- bool is_float)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
void SanityCheckFrame() const SHARED_REQUIRES(Locks::mutator_lock_);
InlineInfo GetCurrentInlineInfo() const SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index cd5e5a7..ec63057 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -14,17 +14,22 @@
* limitations under the License.
*/
-interface Interface {
+interface SuperInterface {
+ void superInterfaceMethod();
+}
+
+interface OtherInterface extends SuperInterface {
+}
+
+interface Interface extends SuperInterface {
void $noinline$f();
}
class Super implements Interface {
+ public void superInterfaceMethod() {}
public void $noinline$f() {
throw new RuntimeException();
}
-
- public int instanceField;
-
}
class SubclassA extends Super {
@@ -551,40 +556,30 @@
private void argumentCheck(Super s, double d, SubclassA a, Final f) {
}
- /// CHECK-START: Main Main.getMain(boolean) reference_type_propagation (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:Main
- /// CHECK: Return [<<Phi>>]
- private Main getMain(boolean cond) {
- return cond ? null : new Main();
- }
-
- /// CHECK-START: Super Main.getSuper(boolean, SubclassA, SubclassB) reference_type_propagation (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
- /// CHECK: Return [<<Phi>>]
- private Super getSuper(boolean cond, SubclassA a, SubclassB b) {
- return cond ? a : b;
- }
-
private Main getNull() {
return null;
}
private int mainField = 0;
- /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, SubclassA, SubclassB) inliner (before)
- /// CHECK: <<Int:i\d+>> IntConstant 0
- /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:Super
- /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:Super exact:false
- /// CHECK: InstanceFieldSet [<<NullCheck>>,<<Int>>]
-
- /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, SubclassA, SubclassB) inliner (after)
- /// CHECK: <<Int:i\d+>> IntConstant 0
+ /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) reference_type_propagation (after)
/// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
- /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:Super exact:false
- /// CHECK: InstanceFieldSet [<<NullCheck>>,<<Int>>]
- private void testInlinerWidensReturnType(boolean cond, SubclassA a, SubclassB b) {
- Super o = getSuper(cond, a, b);
- o.instanceField = 0;
+ /// CHECK: Return [<<Phi>>]
+ private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) {
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (before)
+ /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:SuperInterface
+ /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:SuperInterface exact:false
+ /// CHECK: InvokeInterface [<<NullCheck>>]
+
+ /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:SuperInterface exact:false
+ /// CHECK: InvokeInterface [<<NullCheck>>]
+ private void testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b) {
+ getWiderType(cond, a, b).superInterfaceMethod();
}
/// CHECK-START: void Main.testInlinerReturnsNull() inliner (before)
diff --git a/test/455-set-vreg/expected.txt b/test/455-set-vreg/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/455-set-vreg/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/455-set-vreg/info.txt b/test/455-set-vreg/info.txt
deleted file mode 100644
index e8c57b5..0000000
--- a/test/455-set-vreg/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tests for setting DEX registers in a Java method.
diff --git a/test/455-set-vreg/set_vreg_jni.cc b/test/455-set-vreg/set_vreg_jni.cc
deleted file mode 100644
index 21149f6..0000000
--- a/test/455-set-vreg/set_vreg_jni.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 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 "arch/context.h"
-#include "art_method-inl.h"
-#include "jni.h"
-#include "scoped_thread_state_change.h"
-#include "stack.h"
-#include "thread.h"
-
-namespace art {
-
-namespace {
-
-class TestVisitor : public StackVisitor {
- public:
- TestVisitor(Thread* thread, Context* context, mirror::Object* this_value)
- SHARED_REQUIRES(Locks::mutator_lock_)
- : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- this_value_(this_value) {}
-
- bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
-
- if (m_name.compare("testIntVReg") == 0) {
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
-
- CHECK(SetVReg(m, 2, 5, kIntVReg));
- CHECK(SetVReg(m, 3, 4, kIntVReg));
- CHECK(SetVReg(m, 4, 3, kIntVReg));
- CHECK(SetVReg(m, 5, 2, kIntVReg));
- CHECK(SetVReg(m, 6, 1, kIntVReg));
- } else if (m_name.compare("testLongVReg") == 0) {
- uint32_t value = 0;
- CHECK(GetVReg(m, 3, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
-
- CHECK(SetVRegPair(m, 4, std::numeric_limits<int64_t>::max(), kLongLoVReg, kLongHiVReg));
- CHECK(SetVRegPair(m, 6, 4, kLongLoVReg, kLongHiVReg));
- CHECK(SetVRegPair(m, 8, 3, kLongLoVReg, kLongHiVReg));
- CHECK(SetVRegPair(m, 10, 2, kLongLoVReg, kLongHiVReg));
- CHECK(SetVRegPair(m, 12, 1, kLongLoVReg, kLongHiVReg));
- } else if (m_name.compare("testFloatVReg") == 0) {
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
-
- CHECK(SetVReg(m, 2, bit_cast<uint32_t, float>(5.0f), kFloatVReg));
- CHECK(SetVReg(m, 3, bit_cast<uint32_t, float>(4.0f), kFloatVReg));
- CHECK(SetVReg(m, 4, bit_cast<uint32_t, float>(3.0f), kFloatVReg));
- CHECK(SetVReg(m, 5, bit_cast<uint32_t, float>(2.0f), kFloatVReg));
- CHECK(SetVReg(m, 6, bit_cast<uint32_t, float>(1.0f), kFloatVReg));
- } else if (m_name.compare("testDoubleVReg") == 0) {
- uint32_t value = 0;
- CHECK(GetVReg(m, 3, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
-
- CHECK(SetVRegPair(m, 4, bit_cast<uint64_t, double>(5.0), kDoubleLoVReg, kDoubleHiVReg));
- CHECK(SetVRegPair(m, 6, bit_cast<uint64_t, double>(4.0), kDoubleLoVReg, kDoubleHiVReg));
- CHECK(SetVRegPair(m, 8, bit_cast<uint64_t, double>(3.0), kDoubleLoVReg, kDoubleHiVReg));
- CHECK(SetVRegPair(m, 10, bit_cast<uint64_t, double>(2.0), kDoubleLoVReg, kDoubleHiVReg));
- CHECK(SetVRegPair(m, 12, bit_cast<uint64_t, double>(1.0), kDoubleLoVReg, kDoubleHiVReg));
- }
-
- return true;
- }
-
- mirror::Object* this_value_;
-};
-
-extern "C" JNIEXPORT void JNICALL Java_Main_doNativeCallSetVReg(JNIEnv*, jobject value) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
- visitor.WalkStack();
-}
-
-} // namespace
-
-} // namespace art
diff --git a/test/455-set-vreg/src/Main.java b/test/455-set-vreg/src/Main.java
deleted file mode 100644
index 4db9d66..0000000
--- a/test/455-set-vreg/src/Main.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-public class Main {
- public Main() {
- }
-
- int testIntVReg(int a, int b, int c, int d, int e) {
- doNativeCallSetVReg();
- return a - b - c - d - e;
- }
-
- long testLongVReg(long a, long b, long c, long d, long e) {
- doNativeCallSetVReg();
- return a - b - c - d - e;
- }
-
- float testFloatVReg(float a, float b, float c, float d, float e) {
- doNativeCallSetVReg();
- return a - b - c - d - e;
- }
-
- double testDoubleVReg(double a, double b, double c, double d, double e) {
- doNativeCallSetVReg();
- return a - b - c - d - e;
- }
-
- native void doNativeCallSetVReg();
-
- public static void main(String[] args) {
- System.loadLibrary(args[0]);
- Main rm = new Main();
- int intExpected = 5 - 4 - 3 - 2 - 1;
- int intResult = rm.testIntVReg(0, 0, 0, 0, 0);
- if (intResult != intExpected) {
- throw new Error("Expected " + intExpected + ", got " + intResult);
- }
-
- long longExpected = Long.MAX_VALUE - 4 - 3 - 2 - 1;
- long longResult = rm.testLongVReg(0, 0, 0, 0, 0);
- if (longResult != longExpected) {
- throw new Error("Expected " + longExpected + ", got " + longResult);
- }
-
- float floatExpected = 5.0f - 4.0f - 3.0f - 2.0f - 1.0f;
- float floatResult = rm.testFloatVReg(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- if (floatResult != floatExpected) {
- throw new Error("Expected " + floatExpected + ", got " + floatResult);
- }
-
- double doubleExpected = 5.0 - 4.0 - 3.0 - 2.0 - 1.0;
- double doubleResult = rm.testDoubleVReg(0.0, 0.0, 0.0, 0.0, 0.0);
- if (doubleResult != doubleExpected) {
- throw new Error("Expected " + doubleExpected + ", got " + doubleResult);
- }
- }
-}
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index 64b2336..79fa8b0 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -68,7 +68,7 @@
CHECK(!success);
}
- CHECK(GetVReg(m, 3, kReferenceVReg, &value));
+ CHECK(GetVReg(m, 3, kIntVReg, &value));
CHECK_EQ(value, 1u);
CHECK(GetVReg(m, 4, kFloatVReg, &value));
diff --git a/test/549-checker-types-merge/expected.txt b/test/549-checker-types-merge/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/549-checker-types-merge/expected.txt
diff --git a/test/549-checker-types-merge/info.txt b/test/549-checker-types-merge/info.txt
new file mode 100644
index 0000000..f174e20
--- /dev/null
+++ b/test/549-checker-types-merge/info.txt
@@ -0,0 +1 @@
+Checker test for testing the type merge during reference type propagation.
diff --git a/test/549-checker-types-merge/src/Main.java b/test/549-checker-types-merge/src/Main.java
new file mode 100644
index 0000000..dc27f10
--- /dev/null
+++ b/test/549-checker-types-merge/src/Main.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+// To make it easier to follow the tests:
+// - all interfaces defined in this file extend InterfaceSuper (except InterfaceOtherSuper)
+// - all classes defined in this file extend ClassSuper (except ClassOtherSuper)
+
+interface InterfaceSuper {}
+interface InterfaceOtherSuper {}
+
+interface InterfaceA extends InterfaceSuper {}
+interface InterfaceB extends InterfaceSuper {}
+interface InterfaceExtendsA extends InterfaceA {}
+interface InterfaceExtendsB extends InterfaceB {}
+
+class ClassSuper {}
+class ClassOtherSuper {}
+
+class ClassA extends ClassSuper {}
+class ClassB extends ClassSuper {}
+class ClassExtendsA extends ClassA {}
+class ClassExtendsB extends ClassB {}
+
+class ClassImplementsInterfaceA extends ClassSuper implements InterfaceA {}
+
+public class Main {
+
+ /// CHECK-START: java.lang.Object Main.testMergeNullContant(boolean) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:Main
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeNullContant(boolean cond) {
+ return cond ? null : new Main();
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassExtendsB) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassExtendsB b) {
+ // Different classes, have a common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassSuper b) {
+ // Different classes, one is the super type of the other.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassSuper, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassSuper a, ClassSuper b) {
+ // Same classes.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassOtherSuper, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassOtherSuper a, ClassSuper b) {
+ // Different classes, have Object as the common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassImplementsInterfaceA, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClassWithInterface(boolean cond, ClassImplementsInterfaceA a, InterfaceSuper b) {
+ // Class implements interface.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassSuper, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClassWithInterface(boolean cond, ClassSuper a, InterfaceSuper b) {
+ // Class doesn't implement interface.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceSuper b) {
+ // Different Interfaces, one implements the other.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceSuper b) {
+ // Same interfaces.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceExtendsB) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceExtendsB b) {
+ // Different Interfaces, have a common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceOtherSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceOtherSuper b) {
+ // Different interfaces.
+ return cond ? a : b;
+ }
+
+ public static void main(String[] args) {
+ }
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index bffd0e0..7a22e1b 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -34,7 +34,6 @@
139-register-natives/regnative.cc \
141-class-unload/jni_unload.cc \
454-get-vreg/get_vreg_jni.cc \
- 455-set-vreg/set_vreg_jni.cc \
457-regs/regs_jni.cc \
461-get-reference-vreg/get_reference_vreg_jni.cc \
466-get-live-vreg/get_live_vreg_jni.cc \
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 3e97b86..c830ad4 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -464,18 +464,6 @@
TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS :=
-# Known broken tests for the optimizing compiler.
-TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS := \
- 455-set-vreg \
-
-ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
- ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
- optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
- $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
-endif
-
-TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS :=
-
# Tests that should fail when the optimizing compiler compiles them non-debuggable.
TEST_ART_BROKEN_OPTIMIZING_NONDEBUGGABLE_RUN_TESTS := \
454-get-vreg \