Merge "ARM: Fix JNI MacroAssembler after VIXL update."
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 8a3b12c..a706697 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -838,64 +838,19 @@
return true;
}
-class ImageWriter::PruneClassesVisitor : public ClassVisitor {
+class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
public:
- PruneClassesVisitor(ImageWriter* image_writer, ObjPtr<mirror::ClassLoader> class_loader)
- : image_writer_(image_writer),
- class_loader_(class_loader),
- classes_to_prune_(),
- defined_class_count_(0u) { }
+ explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
- bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool operator()(ObjPtr<Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (!image_writer_->KeepClass(klass.Ptr())) {
classes_to_prune_.insert(klass.Ptr());
- if (klass->GetClassLoader() == class_loader_) {
- ++defined_class_count_;
- }
}
return true;
}
- size_t Prune() REQUIRES_SHARED(Locks::mutator_lock_) {
- ClassTable* class_table =
- Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader_);
- for (mirror::Class* klass : classes_to_prune_) {
- std::string storage;
- const char* descriptor = klass->GetDescriptor(&storage);
- bool result = class_table->Remove(descriptor);
- DCHECK(result);
- }
- return defined_class_count_;
- }
-
- private:
- ImageWriter* const image_writer_;
- const ObjPtr<mirror::ClassLoader> class_loader_;
std::unordered_set<mirror::Class*> classes_to_prune_;
- size_t defined_class_count_;
-};
-
-class ImageWriter::PruneClassLoaderClassesVisitor : public ClassLoaderVisitor {
- public:
- explicit PruneClassLoaderClassesVisitor(ImageWriter* image_writer)
- : image_writer_(image_writer), removed_class_count_(0) {}
-
- virtual void Visit(ObjPtr<mirror::ClassLoader> class_loader) OVERRIDE
- REQUIRES_SHARED(Locks::mutator_lock_) {
- PruneClassesVisitor classes_visitor(image_writer_, class_loader);
- ClassTable* class_table =
- Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader);
- class_table->Visit(classes_visitor);
- removed_class_count_ += classes_visitor.Prune();
- }
-
- size_t GetRemovedClassCount() const {
- return removed_class_count_;
- }
-
- private:
ImageWriter* const image_writer_;
- size_t removed_class_count_;
};
void ImageWriter::PruneNonImageClasses() {
@@ -907,13 +862,21 @@
// path dex caches.
class_linker->ClearClassTableStrongRoots();
+ // Make a list of classes we would like to prune.
+ NonImageClassesVisitor visitor(this);
+ class_linker->VisitClasses(&visitor);
+
// Remove the undesired classes from the class roots.
- {
- ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- PruneClassLoaderClassesVisitor class_loader_visitor(this);
- class_loader_visitor.Visit(nullptr); // Visit boot class loader.
- class_linker->VisitClassLoaders(&class_loader_visitor);
- VLOG(compiler) << "Pruned " << class_loader_visitor.GetRemovedClassCount() << " classes";
+ VLOG(compiler) << "Pruning " << visitor.classes_to_prune_.size() << " classes";
+ for (mirror::Class* klass : visitor.classes_to_prune_) {
+ std::string temp;
+ const char* name = klass->GetDescriptor(&temp);
+ VLOG(compiler) << "Pruning class " << name;
+ if (!compile_app_image_) {
+ DCHECK(IsBootClassLoaderClass(klass));
+ }
+ bool result = class_linker->RemoveClass(name, klass->GetClassLoader());
+ DCHECK(result);
}
// Clear references to removed classes from the DexCaches.
@@ -1141,26 +1104,7 @@
DCHECK_NE(as_klass->GetStatus(), mirror::Class::kStatusError);
if (compile_app_image_) {
// Extra sanity, no boot loader classes should be left!
- struct ImageRanges {
- std::string Dump() const {
- std::ostringstream oss;
- const char* separator = "";
- gc::Heap* const heap = Runtime::Current()->GetHeap();
- for (gc::space::ImageSpace* boot_image_space : heap->GetBootImageSpaces()) {
- const uint8_t* image_begin = boot_image_space->Begin();
- // Real image end including ArtMethods and ArtField sections.
- const uint8_t* image_end =
- image_begin + boot_image_space->GetImageHeader().GetImageSize();
- oss << separator << static_cast<const void*>(image_begin)
- << "-" << static_cast<const void*>(image_end);
- separator = ":";
- }
- return oss.str();
- }
- };
- CHECK(!IsBootClassLoaderClass(as_klass)) << as_klass->PrettyClass()
- << " " << static_cast<const void*>(as_klass)
- << " " << ImageRanges().Dump();
+ CHECK(!IsBootClassLoaderClass(as_klass)) << as_klass->PrettyClass();
}
LengthPrefixedArray<ArtField>* fields[] = {
as_klass->GetSFieldsPtr(), as_klass->GetIFieldsPtr(),
@@ -1563,10 +1507,8 @@
}
// Calculate the size of the class table.
ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u);
- mirror::ClassLoader* class_loader = compile_app_image_ ? *class_loaders_.begin() : nullptr;
- DCHECK_EQ(image_info.class_table_->NumZygoteClasses(class_loader), 0u);
- if (image_info.class_table_->NumNonZygoteClasses(class_loader) != 0u) {
+ DCHECK_EQ(image_info.class_table_->NumZygoteClasses(), 0u);
+ if (image_info.class_table_->NumNonZygoteClasses() != 0u) {
image_info.class_table_bytes_ += image_info.class_table_->WriteToMemory(nullptr);
}
}
@@ -1911,10 +1853,8 @@
// above comment for intern tables.
ClassTable temp_class_table;
temp_class_table.ReadFromMemory(class_table_memory_ptr);
- CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u);
- mirror::ClassLoader* class_loader = compile_app_image_ ? *class_loaders_.begin() : nullptr;
- CHECK_EQ(temp_class_table.NumZygoteClasses(class_loader),
- table->NumNonZygoteClasses(class_loader) + table->NumZygoteClasses(class_loader));
+ CHECK_EQ(temp_class_table.NumZygoteClasses(), table->NumNonZygoteClasses() +
+ table->NumZygoteClasses());
BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&root_visitor,
RootInfo(kRootUnknown));
temp_class_table.VisitRoots(buffered_visitor);
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index ad6ffd8..24fad46 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -588,8 +588,7 @@
class FixupVisitor;
class GetRootsVisitor;
class NativeLocationVisitor;
- class PruneClassesVisitor;
- class PruneClassLoaderClassesVisitor;
+ class NonImageClassesVisitor;
class VisitReferencesVisitor;
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index fa86bf4..db2fdca 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -107,7 +107,28 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
.endm
+.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_TLAB_ALLOCATOR
+// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
+.endm
+
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_TLAB_ALLOCATORS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_TLAB_ALLOCATOR
+.endm
+
+.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc)
@@ -187,20 +208,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer_instrumented, BumpPointerInstrumented)
-// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
-
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab_instrumented, TLABInstrumented)
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index fb405fa..6fbc954 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1085,15 +1085,12 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB). May be called
+// for CC if the GC is not marking.
DEFINE_FUNCTION art_quick_alloc_object_tlab
// Fast path tlab allocation.
// EAX: uint32_t type_idx/return value, ECX: ArtMethod*.
// EBX, EDX: free.
-#if defined(USE_READ_BARRIER)
- int3
- int3
-#endif
PUSH esi
PUSH edi
movl ART_METHOD_DEX_CACHE_TYPES_OFFSET_32(%ecx), %edx // Load dex cache resolved types array
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 860b77e..f8066e4 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -18,6 +18,13 @@
#include "arch/quick_alloc_entrypoints.S"
+MACRO0(ASSERT_USE_READ_BARRIER)
+#if !defined(USE_READ_BARRIER)
+ int3
+ int3
+#endif
+END_MACRO
+
MACRO0(SETUP_FP_CALLEE_SAVE_FRAME)
// Create space for ART FP callee-saved registers
subq MACRO_LITERAL(4 * 8), %rsp
@@ -972,8 +979,10 @@
END_MACRO
// Generate the allocation entrypoints for each allocator.
-GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_TLAB_ALLOCATORS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
+
// Comment out allocators that have x86_64 specific asm.
+// Region TLAB:
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
@@ -986,6 +995,19 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
+// Normal TLAB:
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
DEFINE_FUNCTION art_quick_alloc_object_rosalloc
@@ -1162,16 +1184,11 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB). May be
+// called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_tlab
- // Fast path tlab allocation.
// RDI: uint32_t type_idx, RSI: ArtMethod*
// RDX, RCX, R8, R9: free. RAX: return val.
-#if defined(USE_READ_BARRIER)
- int3
- int3
-#endif
- // Might need a special macro since rsi and edx is 32b/64b mismatched.
movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rsi), %rdx // Load dex cache resolved types array
// Might need to break down into multiple instructions to get the base address in a register.
// Load the class
@@ -1181,29 +1198,69 @@
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeTLAB
END_FUNCTION art_quick_alloc_object_tlab
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB). May be
+// called with CC if the GC is not active.
+DEFINE_FUNCTION art_quick_alloc_object_resolved_tlab
+ // RDI: mirror::Class* klass, RSI: ArtMethod*
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ movq %rdi, %rdx
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_tlab_slow_path
+.Lart_quick_alloc_object_resolved_tlab_slow_path:
+ ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedTLAB
+END_FUNCTION art_quick_alloc_object_resolved_tlab
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB).
+// May be called with CC if the GC is not active.
+DEFINE_FUNCTION art_quick_alloc_object_initialized_tlab
+ // RDI: mirror::Class* klass, RSI: ArtMethod*
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ movq %rdi, %rdx
+ ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_tlab_slow_path
+.Lart_quick_alloc_object_initialized_tlab_slow_path:
+ ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedTLAB
+END_FUNCTION art_quick_alloc_object_initialized_tlab
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB).
+DEFINE_FUNCTION art_quick_alloc_array_tlab
+ // RDI: uint32_t type_idx, RSI: int32_t component_count, RDX: ArtMethod*
+ // RCX: klass, R8, R9: free. RAX: return val.
+ movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rdx), %rcx // Load dex cache resolved types array
+ movl 0(%rcx, %rdi, COMPRESSED_REFERENCE_SIZE), %ecx // Load the class
+ testl %ecx, %ecx
+ jz .Lart_quick_alloc_array_tlab_slow_path
+ ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_tlab_slow_path
+.Lart_quick_alloc_array_tlab_slow_path:
+ ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeTLAB
+END_FUNCTION art_quick_alloc_array_tlab
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB).
+DEFINE_FUNCTION art_quick_alloc_array_resolved_tlab
+ // RDI: mirror::Class* klass, RSI: int32_t component_count, RDX: ArtMethod*
+ // RCX: mirror::Class* klass, R8, R9: free. RAX: return val.
+ movq %rdi, %rcx
+ // Already resolved, no null check.
+ ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_resolved_tlab_slow_path
+.Lart_quick_alloc_array_resolved_tlab_slow_path:
+ ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeResolvedTLAB
+END_FUNCTION art_quick_alloc_array_resolved_tlab
+
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_array_region_tlab
// Fast path region tlab allocation.
// RDI: uint32_t type_idx, RSI: int32_t component_count, RDX: ArtMethod*
// RCX: klass, R8, R9: free. RAX: return val.
-#if !defined(USE_READ_BARRIER)
- int3
- int3
-#endif
+ ASSERT_USE_READ_BARRIER
movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rdx), %rcx // Load dex cache resolved types array
movl 0(%rcx, %rdi, COMPRESSED_REFERENCE_SIZE), %ecx // Load the class
// Null check so that we can load the lock word.
testl %ecx, %ecx
jz .Lart_quick_alloc_array_region_tlab_slow_path
-
- cmpl LITERAL(0), %gs:THREAD_IS_GC_MARKING_OFFSET
- jne .Lart_quick_alloc_array_region_tlab_class_load_read_barrier_marking
+ // Since we have allocation entrypoint switching, we know the GC is marking.
+ // Check the mark bit, if it is 0, do the read barrier mark.
+ testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%ecx)
+ jz .Lart_quick_alloc_array_region_tlab_class_load_read_barrier_slow_path
.Lart_quick_alloc_array_region_tlab_class_load_read_barrier_slow_path_exit:
ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_region_tlab_slow_path
-.Lart_quick_alloc_array_region_tlab_class_load_read_barrier_marking:
- // Check the mark bit, if it is 1 return.
- testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%ecx)
- jnz .Lart_quick_alloc_array_region_tlab_class_load_read_barrier_slow_path_exit
.Lart_quick_alloc_array_region_tlab_class_load_read_barrier_slow_path:
// The read barrier slow path. Mark the class.
PUSH rdi
@@ -1226,33 +1283,11 @@
// Fast path region tlab allocation.
// RDI: mirror::Class* klass, RSI: int32_t component_count, RDX: ArtMethod*
// RCX: mirror::Class* klass, R8, R9: free. RAX: return val.
-#if !defined(USE_READ_BARRIER)
- int3
- int3
-#endif
+ ASSERT_USE_READ_BARRIER
movq %rdi, %rcx
+ // Caller is responsible for read barrier.
// Already resolved, no null check.
- cmpl LITERAL(0), %gs:THREAD_IS_GC_MARKING_OFFSET
- jne .Lart_quick_alloc_array_resolved_region_tlab_class_load_read_barrier_marking
-.Lart_quick_alloc_array_resolved_region_tlab_class_load_read_barrier_slow_path_exit:
ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_resolved_region_tlab_slow_path
-.Lart_quick_alloc_array_resolved_region_tlab_class_load_read_barrier_marking:
- // Check the mark bit, if it is 1 return.
- testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%ecx)
- jnz .Lart_quick_alloc_array_region_tlab_class_load_read_barrier_slow_path_exit
-.Lart_quick_alloc_array_resolved_region_tlab_class_load_read_barrier_slow_path:
- // The read barrier slow path. Mark the class.
- PUSH rdi
- PUSH rsi
- PUSH rdx
- // Outgoing argument set up
- movq %rcx, %rdi // Pass the class as the first param.
- call SYMBOL(artReadBarrierMark) // cxx_name(mirror::Object* obj)
- movq %rax, %rcx
- POP rdx
- POP rsi
- POP rdi
- jmp .Lart_quick_alloc_array_resolved_region_tlab_class_load_read_barrier_slow_path_exit
.Lart_quick_alloc_array_resolved_region_tlab_slow_path:
ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeResolvedRegionTLAB
END_FUNCTION art_quick_alloc_array_resolved_region_tlab
@@ -1262,24 +1297,19 @@
// Fast path region tlab allocation.
// RDI: uint32_t type_idx, RSI: ArtMethod*
// RDX, RCX, R8, R9: free. RAX: return val.
-#if !defined(USE_READ_BARRIER)
- int3
- int3
-#endif
+ ASSERT_USE_READ_BARRIER
movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rsi), %rdx // Load dex cache resolved types array
movl 0(%rdx, %rdi, COMPRESSED_REFERENCE_SIZE), %edx // Load the class
// Null check so that we can load the lock word.
testl %edx, %edx
jz .Lart_quick_alloc_object_region_tlab_slow_path
- // Test if the GC is marking.
- cmpl LITERAL(0), %gs:THREAD_IS_GC_MARKING_OFFSET
- jne .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_marking
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_marking:
- // Check the mark bit, if it is 1 avoid the read barrier.
+ // Since we have allocation entrypoint switching, we know the GC is marking.
+ // Check the mark bit, if it is 0, do the read barrier mark.
testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%edx)
- jnz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
+ jz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path
+.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
+ // Use resolved one since we already did the null check.
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path:
// The read barrier slow path. Mark the class.
PUSH rdi
@@ -1302,10 +1332,7 @@
// Fast path region tlab allocation.
// RDI: mirror::Class* klass, RSI: ArtMethod*
// RDX, RCX, R8, R9: free. RAX: return val.
-#if !defined(USE_READ_BARRIER)
- int3
- int3
-#endif
+ ASSERT_USE_READ_BARRIER
// No read barrier since the caller is responsible for that.
movq %rdi, %rdx
ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_region_tlab_slow_path
@@ -1318,10 +1345,7 @@
// Fast path region tlab allocation.
// RDI: mirror::Class* klass, RSI: ArtMethod*
// RDX, RCX, R8, R9: free. RAX: return val.
-#if !defined(USE_READ_BARRIER)
- int3
- int3
-#endif
+ ASSERT_USE_READ_BARRIER
movq %rdi, %rdx
// No read barrier since the caller is responsible for that.
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_region_tlab_slow_path
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 216ec9e..f3aba97 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1949,36 +1949,13 @@
void Visit(ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
ClassTable* const class_table = class_loader->GetClassTable();
- if (!done_ && class_table != nullptr) {
- DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_);
- if (!class_table->Visit(visitor)) {
- // If the visitor ClassTable returns false it means that we don't need to continue.
- done_ = true;
- }
+ if (!done_ && class_table != nullptr && !class_table->Visit(*visitor_)) {
+ // If the visitor ClassTable returns false it means that we don't need to continue.
+ done_ = true;
}
}
private:
- // Class visitor that limits the class visits from a ClassTable to the classes with
- // the provided defining class loader. This filter is used to avoid multiple visits
- // of the same class which can be recorded for multiple initiating class loaders.
- class DefiningClassLoaderFilterVisitor : public ClassVisitor {
- public:
- DefiningClassLoaderFilterVisitor(ObjPtr<mirror::ClassLoader> defining_class_loader,
- ClassVisitor* visitor)
- : defining_class_loader_(defining_class_loader), visitor_(visitor) { }
-
- bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- if (klass->GetClassLoader() != defining_class_loader_) {
- return true;
- }
- return (*visitor_)(klass);
- }
-
- ObjPtr<mirror::ClassLoader> const defining_class_loader_;
- ClassVisitor* const visitor_;
- };
-
ClassVisitor* const visitor_;
// If done is true then we don't need to do any more visiting.
bool done_;
@@ -2563,109 +2540,56 @@
}
} else {
ScopedObjectAccessUnchecked soa(self);
- ObjPtr<mirror::Class> result_ptr;
- bool descriptor_equals;
- bool known_hierarchy =
- FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
- if (result_ptr != nullptr) {
- // The chain was understood and we found the class. We still need to add the class to
- // the class table to protect from racy programs that can try and redefine the path list
- // which would change the Class<?> returned for subsequent evaluation of const-class.
- DCHECK(known_hierarchy);
- DCHECK(result_ptr->DescriptorEquals(descriptor));
- descriptor_equals = true;
- } else {
- // Either the chain wasn't understood or the class wasn't found.
- //
- // If the chain was understood but we did not find the class, let the Java-side
- // rediscover all this and throw the exception with the right stack trace. Note that
- // the Java-side could still succeed for racy programs if another thread is actively
- // modifying the class loader's path list.
+ ObjPtr<mirror::Class> cp_klass;
+ if (FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
+ // The chain was understood. So the value in cp_klass is either the class we were looking
+ // for, or not found.
+ if (cp_klass != nullptr) {
+ return cp_klass.Ptr();
+ }
+ // TODO: We handle the boot classpath loader in FindClassInBaseDexClassLoader. Try to unify
+ // this and the branch above. TODO: throw the right exception here.
- if (Runtime::Current()->IsAotCompiler()) {
- // Oops, compile-time, can't run actual class-loader code.
- ObjPtr<mirror::Throwable> pre_allocated =
- Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
- self->SetException(pre_allocated);
- return nullptr;
- }
-
- ScopedLocalRef<jobject> class_loader_object(
- soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
- std::string class_name_string(DescriptorToDot(descriptor));
- ScopedLocalRef<jobject> result(soa.Env(), nullptr);
- {
- ScopedThreadStateChange tsc(self, kNative);
- ScopedLocalRef<jobject> class_name_object(
- soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str()));
- if (class_name_object.get() == nullptr) {
- DCHECK(self->IsExceptionPending()); // OOME.
- return nullptr;
- }
- CHECK(class_loader_object.get() != nullptr);
- result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
- WellKnownClasses::java_lang_ClassLoader_loadClass,
- class_name_object.get()));
- }
- if (self->IsExceptionPending()) {
- // If the ClassLoader threw, pass that exception up.
- // However, to comply with the RI behavior, first check if another thread succeeded.
- result_ptr = LookupClass(self, descriptor, hash, class_loader.Get());
- if (result_ptr != nullptr && !result_ptr->IsErroneous()) {
- self->ClearException();
- return EnsureResolved(self, descriptor, result_ptr);
- }
- return nullptr;
- } else if (result.get() == nullptr) {
- // broken loader - throw NPE to be compatible with Dalvik
- ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
- class_name_string.c_str()).c_str());
- return nullptr;
- }
- result_ptr = soa.Decode<mirror::Class>(result.get());
- // Check the name of the returned class.
- descriptor_equals = result_ptr->DescriptorEquals(descriptor);
+ // We'll let the Java-side rediscover all this and throw the exception with the right stack
+ // trace.
}
- // Try to insert the class to the class table, checking for mismatch.
- ObjPtr<mirror::Class> old;
- {
- ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
- old = class_table->Lookup(descriptor, hash);
- if (old == nullptr) {
- old = result_ptr; // For the comparison below, after releasing the lock.
- if (descriptor_equals) {
- class_table->InsertWithHash(result_ptr.Ptr(), hash);
- Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
- } // else throw below, after releasing the lock.
- }
- }
- if (UNLIKELY(old != result_ptr)) {
- // Return `old` (even if `!descriptor_equals`) to mimic the RI behavior for parallel
- // capable class loaders. (All class loaders are considered parallel capable on Android.)
- mirror::Class* loader_class = class_loader->GetClass();
- const char* loader_class_name =
- loader_class->GetDexFile().StringByTypeIdx(loader_class->GetDexTypeIndex());
- LOG(WARNING) << "Initiating class loader of type " << DescriptorToDot(loader_class_name)
- << " is not well-behaved; it returned a different Class for racing loadClass(\""
- << DescriptorToDot(descriptor) << "\").";
- return EnsureResolved(self, descriptor, old);
- }
- if (UNLIKELY(!descriptor_equals)) {
- std::string result_storage;
- const char* result_name = result_ptr->GetDescriptor(&result_storage);
- std::string loader_storage;
- const char* loader_class_name = class_loader->GetClass()->GetDescriptor(&loader_storage);
- ThrowNoClassDefFoundError(
- "Initiating class loader of type %s returned class %s instead of %s.",
- DescriptorToDot(loader_class_name).c_str(),
- DescriptorToDot(result_name).c_str(),
- DescriptorToDot(descriptor).c_str());
+ if (Runtime::Current()->IsAotCompiler()) {
+ // Oops, compile-time, can't run actual class-loader code.
+ ObjPtr<mirror::Throwable> pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
return nullptr;
}
- // success, return mirror::Class*
- return result_ptr.Ptr();
+
+ ScopedLocalRef<jobject> class_loader_object(soa.Env(),
+ soa.AddLocalReference<jobject>(class_loader.Get()));
+ std::string class_name_string(DescriptorToDot(descriptor));
+ ScopedLocalRef<jobject> result(soa.Env(), nullptr);
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ ScopedLocalRef<jobject> class_name_object(soa.Env(),
+ soa.Env()->NewStringUTF(class_name_string.c_str()));
+ if (class_name_object.get() == nullptr) {
+ DCHECK(self->IsExceptionPending()); // OOME.
+ return nullptr;
+ }
+ CHECK(class_loader_object.get() != nullptr);
+ result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
+ WellKnownClasses::java_lang_ClassLoader_loadClass,
+ class_name_object.get()));
+ }
+ if (self->IsExceptionPending()) {
+ // If the ClassLoader threw, pass that exception up.
+ return nullptr;
+ } else if (result.get() == nullptr) {
+ // broken loader - throw NPE to be compatible with Dalvik
+ ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
+ class_name_string.c_str()).c_str());
+ return nullptr;
+ } else {
+ // success, return mirror::Class*
+ return soa.Decode<mirror::Class>(result.get()).Ptr();
+ }
}
UNREACHABLE();
}
@@ -3746,6 +3670,12 @@
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass);
}
+bool ClassLinker::RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader) {
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ClassTable* const class_table = ClassTableForClassLoader(class_loader);
+ return class_table != nullptr && class_table->Remove(descriptor);
+}
+
mirror::Class* ClassLinker::LookupClass(Thread* self,
const char* descriptor,
size_t hash,
@@ -3796,8 +3726,7 @@
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
ClassTable* const class_table = class_loader->GetClassTable();
ObjPtr<mirror::Class> klass = class_table->Lookup(descriptor_, hash_);
- // Add `klass` only if `class_loader` is its defining (not just initiating) class loader.
- if (klass != nullptr && klass->GetClassLoader() == class_loader) {
+ if (klass != nullptr) {
result_->push_back(klass);
}
}
@@ -3816,7 +3745,6 @@
const size_t hash = ComputeModifiedUtf8Hash(descriptor);
ObjPtr<mirror::Class> klass = boot_class_table_.Lookup(descriptor, hash);
if (klass != nullptr) {
- DCHECK(klass->GetClassLoader() == nullptr);
result.push_back(klass);
}
LookupClassesVisitor visitor(descriptor, hash, &result);
@@ -8124,8 +8052,8 @@
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
ClassTable* const class_table = class_loader->GetClassTable();
if (class_table != nullptr) {
- num_zygote_classes += class_table->NumZygoteClasses(class_loader);
- num_non_zygote_classes += class_table->NumNonZygoteClasses(class_loader);
+ num_zygote_classes += class_table->NumZygoteClasses();
+ num_non_zygote_classes += class_table->NumNonZygoteClasses();
}
}
@@ -8136,13 +8064,13 @@
size_t ClassLinker::NumZygoteClasses() const {
CountClassesVisitor visitor;
VisitClassLoaders(&visitor);
- return visitor.num_zygote_classes + boot_class_table_.NumZygoteClasses(nullptr);
+ return visitor.num_zygote_classes + boot_class_table_.NumZygoteClasses();
}
size_t ClassLinker::NumNonZygoteClasses() const {
CountClassesVisitor visitor;
VisitClassLoaders(&visitor);
- return visitor.num_non_zygote_classes + boot_class_table_.NumNonZygoteClasses(nullptr);
+ return visitor.num_non_zygote_classes + boot_class_table_.NumNonZygoteClasses();
}
size_t ClassLinker::NumLoadedClasses() {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 88028ea..9563448 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -218,6 +218,12 @@
mirror::Class* FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
+ // General class unloading is not supported, this is used to prune
+ // unwanted classes during image writing.
+ bool RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES(!Locks::classlinker_classes_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
void DumpAllClasses(int flags)
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 81cdce5..0fcce6b 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -83,29 +83,18 @@
#pragma clang diagnostic pop // http://b/31104323
-size_t ClassTable::CountDefiningLoaderClasses(ObjPtr<mirror::ClassLoader> defining_loader,
- const ClassSet& set) const {
- size_t count = 0;
- for (const GcRoot<mirror::Class>& klass : set) {
- if (klass.Read()->GetClassLoader() == defining_loader) {
- ++count;
- }
- }
- return count;
-}
-
-size_t ClassTable::NumZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const {
+size_t ClassTable::NumZygoteClasses() const {
ReaderMutexLock mu(Thread::Current(), lock_);
size_t sum = 0;
for (size_t i = 0; i < classes_.size() - 1; ++i) {
- sum += CountDefiningLoaderClasses(defining_loader, classes_[i]);
+ sum += classes_[i].Size();
}
return sum;
}
-size_t ClassTable::NumNonZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const {
+size_t ClassTable::NumNonZygoteClasses() const {
ReaderMutexLock mu(Thread::Current(), lock_);
- return CountDefiningLoaderClasses(defining_loader, classes_.back());
+ return classes_.back().Size();
}
mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) {
@@ -113,7 +102,7 @@
for (ClassSet& class_set : classes_) {
auto it = class_set.FindWithHash(descriptor, hash);
if (it != class_set.end()) {
- return it->Read();
+ return it->Read();
}
}
return nullptr;
@@ -153,6 +142,7 @@
bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
const GcRoot<mirror::Class>& b) const {
+ DCHECK_EQ(a.Read()->GetClassLoader(), b.Read()->GetClassLoader());
std::string temp;
return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp));
}
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 92634a4..558c144 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -84,14 +84,10 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the number of classes in previous snapshots.
- size_t NumZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const
- REQUIRES(!lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ size_t NumZygoteClasses() const REQUIRES(!lock_);
// Returns all off the classes in the lastest snapshot.
- size_t NumNonZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const
- REQUIRES(!lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ size_t NumNonZygoteClasses() const REQUIRES(!lock_);
// Update a class in the table with the new class. Returns the existing class which was replaced.
mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash)
@@ -177,11 +173,6 @@
private:
void InsertWithoutLocks(ObjPtr<mirror::Class> klass) NO_THREAD_SAFETY_ANALYSIS;
- size_t CountDefiningLoaderClasses(ObjPtr<mirror::ClassLoader> defining_loader,
- const ClassSet& set) const
- REQUIRES(lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Return true if we inserted the oat file, false if it already exists.
bool InsertOatFileLocked(const OatFile* oat_file)
REQUIRES(lock_)
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 397655a..d2fee9a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -292,7 +292,7 @@
entry_points_instrumented = instrumented;
}
-void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
+void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints, bool is_marking) {
#if !defined(__APPLE__) || !defined(__LP64__)
switch (entry_points_allocator) {
case gc::kAllocatorTypeDlMalloc: {
@@ -320,7 +320,12 @@
}
case gc::kAllocatorTypeRegionTLAB: {
CHECK(kMovingCollector);
- SetQuickAllocEntryPoints_region_tlab(qpoints, entry_points_instrumented);
+ if (is_marking) {
+ SetQuickAllocEntryPoints_region_tlab(qpoints, entry_points_instrumented);
+ } else {
+ // Not marking means we need no read barriers and can just use the normal TLAB case.
+ SetQuickAllocEntryPoints_tlab(qpoints, entry_points_instrumented);
+ }
return;
}
default:
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.h b/runtime/entrypoints/quick/quick_alloc_entrypoints.h
index 14a8e04..bd1e295 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.h
@@ -23,7 +23,9 @@
namespace art {
-void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
+// is_marking is only used for CC, if the GC is marking the allocation entrypoint is the marking
+// one.
+void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints, bool is_marking);
// Runtime shutdown lock is necessary to prevent races in thread initialization. When the thread is
// starting it doesn't hold the mutator lock until after it has been added to the thread list.
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index df23f94..78dad94 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -31,7 +31,7 @@
jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
// Alloc
- ResetQuickAllocEntryPoints(qpoints);
+ ResetQuickAllocEntryPoints(qpoints, /* is_marking */ true);
// DexCache
qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage;
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 97129e8..54f2210 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -247,7 +247,7 @@
if (allocator_type != kAllocatorTypeTLAB &&
allocator_type != kAllocatorTypeRegionTLAB &&
allocator_type != kAllocatorTypeRosAlloc &&
- UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type, alloc_size))) {
+ UNLIKELY(IsOutOfMemoryOnAllocation(allocator_type, alloc_size, kGrow))) {
return nullptr;
}
mirror::Object* ret;
@@ -267,8 +267,9 @@
if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
// If running on valgrind or asan, we should be using the instrumented path.
size_t max_bytes_tl_bulk_allocated = rosalloc_space_->MaxBytesBulkAllocatedFor(alloc_size);
- if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type,
- max_bytes_tl_bulk_allocated))) {
+ if (UNLIKELY(IsOutOfMemoryOnAllocation(allocator_type,
+ max_bytes_tl_bulk_allocated,
+ kGrow))) {
return nullptr;
}
ret = rosalloc_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
@@ -277,14 +278,18 @@
DCHECK(!is_running_on_memory_tool_);
size_t max_bytes_tl_bulk_allocated =
rosalloc_space_->MaxBytesBulkAllocatedForNonvirtual(alloc_size);
- if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type,
- max_bytes_tl_bulk_allocated))) {
+ if (UNLIKELY(IsOutOfMemoryOnAllocation(allocator_type,
+ max_bytes_tl_bulk_allocated,
+ kGrow))) {
return nullptr;
}
if (!kInstrumented) {
DCHECK(!rosalloc_space_->CanAllocThreadLocal(self, alloc_size));
}
- ret = rosalloc_space_->AllocNonvirtual(self, alloc_size, bytes_allocated, usable_size,
+ ret = rosalloc_space_->AllocNonvirtual(self,
+ alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
}
break;
@@ -292,22 +297,34 @@
case kAllocatorTypeDlMalloc: {
if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
// If running on valgrind, we should be using the instrumented path.
- ret = dlmalloc_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
+ ret = dlmalloc_space_->Alloc(self,
+ alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
} else {
DCHECK(!is_running_on_memory_tool_);
- ret = dlmalloc_space_->AllocNonvirtual(self, alloc_size, bytes_allocated, usable_size,
+ ret = dlmalloc_space_->AllocNonvirtual(self,
+ alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
}
break;
}
case kAllocatorTypeNonMoving: {
- ret = non_moving_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
+ ret = non_moving_space_->Alloc(self,
+ alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
break;
}
case kAllocatorTypeLOS: {
- ret = large_object_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
+ ret = large_object_space_->Alloc(self,
+ alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
// Note that the bump pointer spaces aren't necessarily next to
// the other continuous spaces like the non-moving alloc space or
@@ -315,80 +332,38 @@
DCHECK(ret == nullptr || large_object_space_->Contains(ret));
break;
}
- case kAllocatorTypeTLAB: {
- DCHECK_ALIGNED(alloc_size, space::BumpPointerSpace::kAlignment);
- if (UNLIKELY(self->TlabSize() < alloc_size)) {
- const size_t new_tlab_size = alloc_size + kDefaultTLABSize;
- if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type, new_tlab_size))) {
- return nullptr;
- }
- // Try allocating a new thread local buffer, if the allocaiton fails the space must be
- // full so return null.
- if (!bump_pointer_space_->AllocNewTlab(self, new_tlab_size)) {
- return nullptr;
- }
- *bytes_tl_bulk_allocated = new_tlab_size;
- } else {
- *bytes_tl_bulk_allocated = 0;
- }
- // The allocation can't fail.
- ret = self->AllocTlab(alloc_size);
- DCHECK(ret != nullptr);
- *bytes_allocated = alloc_size;
- *usable_size = alloc_size;
- break;
- }
case kAllocatorTypeRegion: {
DCHECK(region_space_ != nullptr);
alloc_size = RoundUp(alloc_size, space::RegionSpace::kAlignment);
- ret = region_space_->AllocNonvirtual<false>(alloc_size, bytes_allocated, usable_size,
+ ret = region_space_->AllocNonvirtual<false>(alloc_size,
+ bytes_allocated,
+ usable_size,
bytes_tl_bulk_allocated);
break;
}
+ case kAllocatorTypeTLAB:
+ FALLTHROUGH_INTENDED;
case kAllocatorTypeRegionTLAB: {
- DCHECK(region_space_ != nullptr);
- DCHECK_ALIGNED(alloc_size, space::RegionSpace::kAlignment);
+ DCHECK_ALIGNED(alloc_size, kObjectAlignment);
+ static_assert(space::RegionSpace::kAlignment == space::BumpPointerSpace::kAlignment,
+ "mismatched alignments");
+ static_assert(kObjectAlignment == space::BumpPointerSpace::kAlignment,
+ "mismatched alignments");
if (UNLIKELY(self->TlabSize() < alloc_size)) {
- if (space::RegionSpace::kRegionSize >= alloc_size) {
- // Non-large. Check OOME for a tlab.
- if (LIKELY(!IsOutOfMemoryOnAllocation<kGrow>(allocator_type, space::RegionSpace::kRegionSize))) {
- // Try to allocate a tlab.
- if (!region_space_->AllocNewTlab(self)) {
- // Failed to allocate a tlab. Try non-tlab.
- ret = region_space_->AllocNonvirtual<false>(alloc_size, bytes_allocated, usable_size,
- bytes_tl_bulk_allocated);
- return ret;
- }
- *bytes_tl_bulk_allocated = space::RegionSpace::kRegionSize;
- // Fall-through.
- } else {
- // Check OOME for a non-tlab allocation.
- if (!IsOutOfMemoryOnAllocation<kGrow>(allocator_type, alloc_size)) {
- ret = region_space_->AllocNonvirtual<false>(alloc_size, bytes_allocated, usable_size,
- bytes_tl_bulk_allocated);
- return ret;
- } else {
- // Neither tlab or non-tlab works. Give up.
- return nullptr;
- }
- }
- } else {
- // Large. Check OOME.
- if (LIKELY(!IsOutOfMemoryOnAllocation<kGrow>(allocator_type, alloc_size))) {
- ret = region_space_->AllocNonvirtual<false>(alloc_size, bytes_allocated, usable_size,
- bytes_tl_bulk_allocated);
- return ret;
- } else {
- return nullptr;
- }
- }
- } else {
- *bytes_tl_bulk_allocated = 0; // Allocated in an existing buffer.
+ // kAllocatorTypeTLAB may be the allocator for region space TLAB if the GC is not marking,
+ // that is why the allocator is not passed down.
+ return AllocWithNewTLAB(self,
+ alloc_size,
+ kGrow,
+ bytes_allocated,
+ usable_size,
+ bytes_tl_bulk_allocated);
}
// The allocation can't fail.
ret = self->AllocTlab(alloc_size);
DCHECK(ret != nullptr);
*bytes_allocated = alloc_size;
+ *bytes_tl_bulk_allocated = 0; // Allocated in an existing buffer.
*usable_size = alloc_size;
break;
}
@@ -408,15 +383,16 @@
return byte_count >= large_object_threshold_ && (c->IsPrimitiveArray() || c->IsStringClass());
}
-template <bool kGrow>
-inline bool Heap::IsOutOfMemoryOnAllocation(AllocatorType allocator_type, size_t alloc_size) {
+inline bool Heap::IsOutOfMemoryOnAllocation(AllocatorType allocator_type,
+ size_t alloc_size,
+ bool grow) {
size_t new_footprint = num_bytes_allocated_.LoadSequentiallyConsistent() + alloc_size;
if (UNLIKELY(new_footprint > max_allowed_footprint_)) {
if (UNLIKELY(new_footprint > growth_limit_)) {
return true;
}
if (!AllocatorMayHaveConcurrentGC(allocator_type) || !IsGcConcurrent()) {
- if (!kGrow) {
+ if (!grow) {
return true;
}
// TODO: Grow for allocation is racy, fix it.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f0e619d..ae9741f 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1819,7 +1819,7 @@
break;
}
// Try to transition the heap if the allocation failure was due to the space being full.
- if (!IsOutOfMemoryOnAllocation<false>(allocator, alloc_size)) {
+ if (!IsOutOfMemoryOnAllocation(allocator, alloc_size, /*grow*/ false)) {
// If we aren't out of memory then the OOM was probably from the non moving space being
// full. Attempt to disable compaction and turn the main space into a non moving space.
DisableMovingGc();
@@ -4225,5 +4225,72 @@
gc_pause_listener_.StoreRelaxed(nullptr);
}
+mirror::Object* Heap::AllocWithNewTLAB(Thread* self,
+ size_t alloc_size,
+ bool grow,
+ size_t* bytes_allocated,
+ size_t* usable_size,
+ size_t* bytes_tl_bulk_allocated) {
+ const AllocatorType allocator_type = GetCurrentAllocator();
+ if (allocator_type == kAllocatorTypeTLAB) {
+ DCHECK(bump_pointer_space_ != nullptr);
+ const size_t new_tlab_size = alloc_size + kDefaultTLABSize;
+ if (UNLIKELY(IsOutOfMemoryOnAllocation(allocator_type, new_tlab_size, grow))) {
+ return nullptr;
+ }
+ // Try allocating a new thread local buffer, if the allocation fails the space must be
+ // full so return null.
+ if (!bump_pointer_space_->AllocNewTlab(self, new_tlab_size)) {
+ return nullptr;
+ }
+ *bytes_tl_bulk_allocated = new_tlab_size;
+ } else {
+ DCHECK(allocator_type == kAllocatorTypeRegionTLAB);
+ DCHECK(region_space_ != nullptr);
+ if (space::RegionSpace::kRegionSize >= alloc_size) {
+ // Non-large. Check OOME for a tlab.
+ if (LIKELY(!IsOutOfMemoryOnAllocation(allocator_type,
+ space::RegionSpace::kRegionSize,
+ grow))) {
+ // Try to allocate a tlab.
+ if (!region_space_->AllocNewTlab(self)) {
+ // Failed to allocate a tlab. Try non-tlab.
+ return region_space_->AllocNonvirtual<false>(alloc_size,
+ bytes_allocated,
+ usable_size,
+ bytes_tl_bulk_allocated);
+ }
+ *bytes_tl_bulk_allocated = space::RegionSpace::kRegionSize;
+ // Fall-through to using the TLAB below.
+ } else {
+ // Check OOME for a non-tlab allocation.
+ if (!IsOutOfMemoryOnAllocation(allocator_type, alloc_size, grow)) {
+ return region_space_->AllocNonvirtual<false>(alloc_size,
+ bytes_allocated,
+ usable_size,
+ bytes_tl_bulk_allocated);
+ }
+ // Neither tlab or non-tlab works. Give up.
+ return nullptr;
+ }
+ } else {
+ // Large. Check OOME.
+ if (LIKELY(!IsOutOfMemoryOnAllocation(allocator_type, alloc_size, grow))) {
+ return region_space_->AllocNonvirtual<false>(alloc_size,
+ bytes_allocated,
+ usable_size,
+ bytes_tl_bulk_allocated);
+ }
+ return nullptr;
+ }
+ }
+ // Refilled TLAB, return.
+ mirror::Object* ret = self->AllocTlab(alloc_size);
+ DCHECK(ret != nullptr);
+ *bytes_allocated = alloc_size;
+ *usable_size = alloc_size;
+ return ret;
+}
+
} // namespace gc
} // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 0c671d2..3a8e29b 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -854,6 +854,10 @@
allocator_type != kAllocatorTypeRegionTLAB;
}
static ALWAYS_INLINE bool AllocatorMayHaveConcurrentGC(AllocatorType allocator_type) {
+ if (kUseReadBarrier) {
+ // Read barrier may have the TLAB allocator but is always concurrent. TODO: clean this up.
+ return true;
+ }
return
allocator_type != kAllocatorTypeBumpPointer &&
allocator_type != kAllocatorTypeTLAB;
@@ -923,11 +927,20 @@
size_t* bytes_tl_bulk_allocated)
REQUIRES_SHARED(Locks::mutator_lock_);
+ mirror::Object* AllocWithNewTLAB(Thread* self,
+ size_t alloc_size,
+ bool grow,
+ size_t* bytes_allocated,
+ size_t* usable_size,
+ size_t* bytes_tl_bulk_allocated)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
void ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_);
- template <bool kGrow>
- ALWAYS_INLINE bool IsOutOfMemoryOnAllocation(AllocatorType allocator_type, size_t alloc_size);
+ ALWAYS_INLINE bool IsOutOfMemoryOnAllocation(AllocatorType allocator_type,
+ size_t alloc_size,
+ bool grow);
// Run the finalizers. If timeout is non zero, then we use the VMRuntime version.
void RunFinalization(JNIEnv* env, uint64_t timeout);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d4c322e..870d1ae 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -630,7 +630,7 @@
}
static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg ATTRIBUTE_UNUSED) {
- thread->ResetQuickAllocEntryPointsForThread();
+ thread->ResetQuickAllocEntryPointsForThread(kUseReadBarrier && thread->GetIsGcMarking());
}
void Instrumentation::SetEntrypointsInstrumented(bool instrumented) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 65c8681..c92e38b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -122,21 +122,27 @@
CHECK(kUseReadBarrier);
tls32_.is_gc_marking = is_marking;
UpdateReadBarrierEntrypoints(&tlsPtr_.quick_entrypoints, is_marking);
+ if (kRuntimeISA == kX86_64) {
+ // Entrypoint switching is only implemented for X86_64.
+ ResetQuickAllocEntryPointsForThread(is_marking);
+ }
}
void Thread::InitTlsEntryPoints() {
// Insert a placeholder so we can easily tell if we call an unimplemented entry point.
uintptr_t* begin = reinterpret_cast<uintptr_t*>(&tlsPtr_.jni_entrypoints);
- uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(&tlsPtr_.quick_entrypoints) +
- sizeof(tlsPtr_.quick_entrypoints));
+ uintptr_t* end = reinterpret_cast<uintptr_t*>(
+ reinterpret_cast<uint8_t*>(&tlsPtr_.quick_entrypoints) + sizeof(tlsPtr_.quick_entrypoints));
for (uintptr_t* it = begin; it != end; ++it) {
*it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
}
InitEntryPoints(&tlsPtr_.jni_entrypoints, &tlsPtr_.quick_entrypoints);
}
-void Thread::ResetQuickAllocEntryPointsForThread() {
- ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints);
+void Thread::ResetQuickAllocEntryPointsForThread(bool is_marking) {
+ // Entrypoint switching is currnetly only faster for X86_64 since other archs don't have TLAB
+ // fast path for non region space entrypoints.
+ ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints, is_marking);
}
class DeoptimizationContextRecord {
diff --git a/runtime/thread.h b/runtime/thread.h
index 97093a6..35226f2 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1007,7 +1007,7 @@
tls32_.state_and_flags.as_atomic_int.FetchAndAndSequentiallyConsistent(-1 ^ flag);
}
- void ResetQuickAllocEntryPointsForThread();
+ void ResetQuickAllocEntryPointsForThread(bool is_marking);
// Returns the remaining space in the TLAB.
size_t TlabSize() const;
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
deleted file mode 100644
index 7e312d5..0000000
--- a/test/626-const-class-linking/clear_dex_cache_types.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 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 "jni.h"
-#include "object_lock.h"
-#include "scoped_thread_state_change-inl.h"
-
-namespace art {
-
-namespace {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_nativeClearResolvedTypes(JNIEnv*, jclass, jclass cls) {
- ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
- for (size_t i = 0, num_types = dex_cache->NumResolvedTypes(); i != num_types; ++i) {
- dex_cache->SetResolvedType(dex::TypeIndex(i), ObjPtr<mirror::Class>(nullptr));
- }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_Main_nativeSkipVerification(JNIEnv*, jclass, jclass cls) {
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- Handle<mirror::Class> klass = hs.NewHandle(soa.Decode<mirror::Class>(cls));
- mirror::Class::Status status = klass->GetStatus();
- if (status == mirror::Class::kStatusResolved) {
- ObjectLock<mirror::Class> lock(soa.Self(), klass);
- klass->SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
- } else {
- LOG(ERROR) << klass->PrettyClass() << " has unexpected status: " << status;
- }
-}
-
-} // namespace
-
-} // namespace art
diff --git a/test/626-const-class-linking/expected.txt b/test/626-const-class-linking/expected.txt
deleted file mode 100644
index 1243226..0000000
--- a/test/626-const-class-linking/expected.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-JNI_OnLoad called
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-testClearDexCache done
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-first: Helper2 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-testMultiDex done
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyLoader done
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper3 class loader: RacyLoader
-second: Test3 class loader: DefiningLoader
-first: Helper3 class loader: RacyLoader
-second: Test3 class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (2 unique)
-testRacyLoader2 done
-java.lang.NoClassDefFoundError: Initiating class loader of type MisbehavingLoader returned class Helper2 instead of Test.
-testMisbehavingLoader done
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyMisbehavingLoader done
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyMisbehavingLoader2 done
diff --git a/test/626-const-class-linking/info.txt b/test/626-const-class-linking/info.txt
deleted file mode 100644
index 9c19a46..0000000
--- a/test/626-const-class-linking/info.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Test that once a const-class instruction is linked, it will keep referring
-to the same class even in the presence of custom class loaders even after
-clearing the dex cache type array.
diff --git a/test/626-const-class-linking/multidex.jpp b/test/626-const-class-linking/multidex.jpp
deleted file mode 100644
index c7a6648..0000000
--- a/test/626-const-class-linking/multidex.jpp
+++ /dev/null
@@ -1,27 +0,0 @@
-ClassPair:
- @@com.android.jack.annotations.ForceInMainDex
- class ClassPair
-DefiningLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class DefiningLoader
-DelegatingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class DelegatingLoader
-Helper1:
- @@com.android.jack.annotations.ForceInMainDex
- class Helper1
-Main:
- @@com.android.jack.annotations.ForceInMainDex
- class Main
-MisbehavingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class MisbehavingLoader
-RacyLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyLoader
-RacyMisbehavingHelper:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyMisbehavingHelper
-RacyMisbehavingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyMisbehavingLoader
diff --git a/test/626-const-class-linking/src-multidex/Helper2.java b/test/626-const-class-linking/src-multidex/Helper2.java
deleted file mode 100644
index 5bb31ee..0000000
--- a/test/626-const-class-linking/src-multidex/Helper2.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 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 Helper2 {
- public static ClassPair get() {
- Class<?> helper2_class = Helper2.class;
- Class<?> test_class = Test.class;
- return new ClassPair(helper2_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src-multidex/Helper3.java b/test/626-const-class-linking/src-multidex/Helper3.java
deleted file mode 100644
index af996de..0000000
--- a/test/626-const-class-linking/src-multidex/Helper3.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 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 Helper3 {
- public static ClassPair get() {
- Class<?> helper3_class = Helper3.class;
- Class<?> test3_class = Test3.class;
- return new ClassPair(helper3_class, test3_class);
- }
-}
diff --git a/test/626-const-class-linking/src-multidex/Test.java b/test/626-const-class-linking/src-multidex/Test.java
deleted file mode 100644
index 1b0cc2a..0000000
--- a/test/626-const-class-linking/src-multidex/Test.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 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 Test {
-}
diff --git a/test/626-const-class-linking/src-multidex/Test3.java b/test/626-const-class-linking/src-multidex/Test3.java
deleted file mode 100644
index c4b134d..0000000
--- a/test/626-const-class-linking/src-multidex/Test3.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 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 Test3 {
-}
diff --git a/test/626-const-class-linking/src/ClassPair.java b/test/626-const-class-linking/src/ClassPair.java
deleted file mode 100644
index b07036c..0000000
--- a/test/626-const-class-linking/src/ClassPair.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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 ClassPair {
- public Class<?> first;
- public Class<?> second;
-
- public ClassPair(Class<?> first, Class<?> second) {
- this.first = first;
- this.second = second;
- }
-
- public void print() {
- String first_loader_name = first.getClassLoader().getClass().getName();
- System.out.println("first: " + first.getName() + " class loader: " + first_loader_name);
- String second_loader_name = second.getClassLoader().getClass().getName();
- System.out.println("second: " + second.getName() + " class loader: " + second_loader_name);
- }
-}
diff --git a/test/626-const-class-linking/src/DefiningLoader.java b/test/626-const-class-linking/src/DefiningLoader.java
deleted file mode 100644
index b17ab77..0000000
--- a/test/626-const-class-linking/src/DefiningLoader.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * A class loader with atypical behavior: we try to load a private
- * class implementation before asking the system or boot loader. This
- * is used to create multiple classes with identical names in a single VM.
- *
- * If DexFile is available, we use that; if not, we assume we're not in
- * Dalvik and instantiate the class with defineClass().
- *
- * The location of the DEX files and class data is dependent upon the
- * test framework.
- */
-public class DefiningLoader extends ClassLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- /* this is where the .class files live */
- static final String CLASS_PATH1 = "classes/";
- static final String CLASS_PATH2 = "classes2/";
-
- /* this is the DEX/Jar file */
- static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/626-const-class-linking.jar";
-
- /* on Dalvik, this is a DexFile; otherwise, it's null */
- private Class<?> mDexClass;
-
- private Object mDexFile;
-
- /**
- * Construct DefiningLoader, grabbing a reference to the DexFile class
- * if we're running under Dalvik.
- */
- public DefiningLoader(ClassLoader parent) {
- super(parent);
-
- try {
- mDexClass = parent.loadClass("dalvik.system.DexFile");
- } catch (ClassNotFoundException cnfe) {
- // ignore -- not running Dalvik
- }
- }
-
- /**
- * Finds the class with the specified binary name.
- *
- * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
- * If we don't find a match, we throw an exception.
- */
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (mDexClass != null) {
- return findClassDalvik(name);
- } else {
- return findClassNonDalvik(name);
- }
- }
-
- /**
- * Finds the class with the specified binary name, from a DEX file.
- */
- private Class<?> findClassDalvik(String name)
- throws ClassNotFoundException {
-
- if (mDexFile == null) {
- synchronized (DefiningLoader.class) {
- Constructor<?> ctor;
- /*
- * Construct a DexFile object through reflection.
- */
- try {
- ctor = mDexClass.getConstructor(String.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getConstructor failed",
- nsme);
- }
-
- try {
- mDexFile = ctor.newInstance(DEX_FILE);
- } catch (InstantiationException ie) {
- throw new ClassNotFoundException("newInstance failed", ie);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("newInstance failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("newInstance failed", ite);
- }
- }
- }
-
- /*
- * Call DexFile.loadClass(String, ClassLoader).
- */
- Method meth;
-
- try {
- meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getMethod failed", nsme);
- }
-
- try {
- meth.invoke(mDexFile, name, this);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("loadClass failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("loadClass failed",
- ite.getCause());
- }
-
- return null;
- }
-
- /**
- * Finds the class with the specified binary name, from .class files.
- */
- private Class<?> findClassNonDalvik(String name)
- throws ClassNotFoundException {
-
- String[] pathNames = { CLASS_PATH1 + name + ".class", CLASS_PATH2 + name + ".class" };
-
- String pathName = null;
- RandomAccessFile raf = null;
-
- for (String pn : pathNames) {
- pathName = pn;
- try {
- //System.out.println("--- Defining: looking for " + pathName);
- raf = new RandomAccessFile(new File(pathName), "r");
- break;
- } catch (FileNotFoundException fnfe) {
- }
- }
- if (raf == null) {
- throw new ClassNotFoundException("Not found: " + pathNames[0] + ":" + pathNames[1]);
- }
-
- /* read the entire file in */
- byte[] fileData;
- try {
- fileData = new byte[(int) raf.length()];
- raf.readFully(fileData);
- } catch (IOException ioe) {
- throw new ClassNotFoundException("Read error: " + pathName);
- } finally {
- try {
- raf.close();
- } catch (IOException ioe) {
- // drop
- }
- }
-
- /* create the class */
- //System.out.println("--- Defining: defining " + name);
- try {
- return defineClass(name, fileData, 0, fileData.length);
- } catch (Throwable th) {
- throw new ClassNotFoundException("defineClass failed", th);
- }
- }
-
- /**
- * Load a class.
- *
- * Normally a class loader wouldn't override this, but we want our
- * version of the class to take precedence over an already-loaded
- * version.
- *
- * We still want the system classes (e.g. java.lang.Object) from the
- * bootstrap class loader.
- */
- synchronized protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- Class<?> res;
-
- /*
- * 1. Invoke findLoadedClass(String) to check if the class has
- * already been loaded.
- *
- * This doesn't change.
- */
- res = findLoadedClass(name);
- if (res != null) {
- // System.out.println("FancyLoader.loadClass: " + name + " already loaded");
- if (resolve)
- resolveClass(res);
- return res;
- }
-
- /*
- * 3. Invoke the findClass(String) method to find the class.
- */
- try {
- res = findClass(name);
- if (resolve)
- resolveClass(res);
- }
- catch (ClassNotFoundException e) {
- // we couldn't find it, so eat the exception and keep going
- }
-
- /*
- * 2. Invoke the loadClass method on the parent class loader. If
- * the parent loader is null the class loader built-in to the
- * virtual machine is used, instead.
- *
- * (Since we're not in java.lang, we can't actually invoke the
- * parent's loadClass() method, but we passed our parent to the
- * super-class which can take care of it for us.)
- */
- res = super.loadClass(name, resolve); // returns class or throws
- return res;
- }
-}
diff --git a/test/626-const-class-linking/src/DelegatingLoader.java b/test/626-const-class-linking/src/DelegatingLoader.java
deleted file mode 100644
index 49955d4..0000000
--- a/test/626-const-class-linking/src/DelegatingLoader.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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 DelegatingLoader extends DefiningLoader {
- private DefiningLoader defining_loader;
-
- public DelegatingLoader(ClassLoader parent, DefiningLoader defining_loader) {
- super(parent);
- this.defining_loader = defining_loader;
- }
-
- public void resetDefiningLoader(DefiningLoader defining_loader) {
- this.defining_loader = defining_loader;
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- throw new Error("Unexpected DelegatingLoader.findClass(\"Test\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- return defining_loader.loadClass(name, resolve);
- }
- return super.loadClass(name, resolve);
- }
-}
diff --git a/test/626-const-class-linking/src/Helper1.java b/test/626-const-class-linking/src/Helper1.java
deleted file mode 100644
index ff9cd1a..0000000
--- a/test/626-const-class-linking/src/Helper1.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 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 Helper1 {
- public static ClassPair get() {
- Class<?> helper1_class = Helper1.class;
- Class<?> test_class = Test.class;
- return new ClassPair(helper1_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src/Main.java b/test/626-const-class-linking/src/Main.java
deleted file mode 100644
index 8d8f6b6..0000000
--- a/test/626-const-class-linking/src/Main.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- try {
- System.loadLibrary(args[0]);
- } catch (UnsatisfiedLinkError ule) {
- usingRI = true;
- // Add expected JNI_OnLoad log line to match expected.txt.
- System.out.println("JNI_OnLoad called");
- }
-
- testClearDexCache();
- testMultiDex();
- testRacyLoader();
- testRacyLoader2();
- testMisbehavingLoader();
- testRacyMisbehavingLoader();
- testRacyMisbehavingLoader2();
- }
-
- private static void testClearDexCache() throws Exception {
- DelegatingLoader delegating_loader = createDelegatingLoader();
- Class<?> helper = delegating_loader.loadClass("Helper1");
-
- WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper);
- changeInner(delegating_loader);
- clearResolvedTypes(helper);
- Runtime.getRuntime().gc();
- WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper);
- Runtime.getRuntime().gc();
-
- Class<?> test1 = weak_test1.get();
- if (test1 == null) {
- System.out.println("test1 disappeared");
- }
- Class<?> test2 = weak_test2.get();
- if (test2 == null) {
- System.out.println("test2 disappeared");
- }
- if (test1 != test2) {
- System.out.println("test1 != test2");
- }
-
- System.out.println("testClearDexCache done");
- }
-
- private static void testMultiDex() throws Exception {
- DelegatingLoader delegating_loader = createDelegatingLoader();
-
- Class<?> helper1 = delegating_loader.loadClass("Helper1");
- WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1);
-
- changeInner(delegating_loader);
-
- Class<?> helper2 = delegating_loader.loadClass("Helper2");
- WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2);
-
- Runtime.getRuntime().gc();
-
- Class<?> test1 = weak_test1.get();
- if (test1 == null) {
- System.out.println("test1 disappeared");
- }
- Class<?> test2 = weak_test2.get();
- if (test2 == null) {
- System.out.println("test2 disappeared");
- }
- if (test1 != test2) {
- System.out.println("test1 != test2");
- }
-
- System.out.println("testMultiDex done");
- }
-
- private static void testMisbehavingLoader() throws Exception {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- MisbehavingLoader misbehaving_loader =
- new MisbehavingLoader(system_loader, defining_loader);
- Class<?> helper = misbehaving_loader.loadClass("Helper1");
-
- try {
- WeakReference<Class<?>> weak_test = wrapHelperGet(helper);
- } catch (InvocationTargetException ite) {
- String message = ite.getCause().getMessage();
- if (usingRI && "Test".equals(message)) {
- // Replace RI message with dalvik message to match expected.txt.
- message = "Initiating class loader of type " +
- misbehaving_loader.getClass().getName() +
- " returned class Helper2 instead of Test.";
- }
- System.out.println(ite.getCause().getClass().getName() + ": " + message);
- }
- System.out.println("testMisbehavingLoader done");
- }
-
- private static void testRacyLoader() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
- final Class<?> helper1 = racy_loader.loadClass("Helper1");
- skipVerification(helper1); // Avoid class loading during verification.
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyLoader done");
- }
-
- private static void testRacyLoader2() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
- final Class<?> helper1 = racy_loader.loadClass("Helper1");
- skipVerification(helper1); // Avoid class loading during verification.
- final Class<?> helper3 = racy_loader.loadClass("Helper3");
- skipVerification(helper3); // Avoid class loading during verification.
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3;
- Method get = helper.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyLoader2 done");
- }
-
- private static void dumpResultStats(Object[] results) throws Exception {
- int throwables = 0;
- int class_weaks = 0;
- int unique_class_weaks = 0;
- for (int i = 0; i != results.length; ++i) {
- Object r = results[i];
- if (r instanceof Throwable) {
- ++throwables;
- System.out.println(((Throwable) r).getMessage());
- } else if (isClassPair(r)) {
- printPair(r);
- Object ref = getSecond(r);
- ++class_weaks;
- ++unique_class_weaks;
- for (int j = 0; j != i; ++j) {
- Object rj = results[j];
- if (isClassPair(results[j]) && getSecond(results[j]) == ref) {
- --unique_class_weaks;
- break;
- }
- }
- }
- }
- System.out.println("total: " + results.length);
- System.out.println(" throwables: " + throwables);
- System.out.println(" class_weaks: " + class_weaks
- + " (" + unique_class_weaks + " unique)");
- }
-
- private static void testRacyMisbehavingLoader() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyMisbehavingLoader racy_loader =
- new RacyMisbehavingLoader(system_loader, threads.length, false);
- final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
- skipVerification(helper1); // Avoid class loading during verification.
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyMisbehavingLoader done");
- }
-
- private static void testRacyMisbehavingLoader2() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyMisbehavingLoader racy_loader =
- new RacyMisbehavingLoader(system_loader, threads.length, true);
- final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
- skipVerification(helper1); // Avoid class loading during verification.
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyMisbehavingLoader2 done");
- }
-
- private static DelegatingLoader createDelegatingLoader() {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- return new DelegatingLoader(system_loader, defining_loader);
- }
-
- private static void changeInner(DelegatingLoader delegating_loader) {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- delegating_loader.resetDefiningLoader(defining_loader);
- }
-
- private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception {
- Method get = helper.getDeclaredMethod("get");
- Object pair = get.invoke(null);
- printPair(pair);
- return new WeakReference<Class<?>>(getSecond(pair));
- }
-
- private static void printPair(Object pair) throws Exception {
- Method print = pair.getClass().getDeclaredMethod("print");
- print.invoke(pair);
- }
-
- private static Class<?> getSecond(Object pair) throws Exception {
- Field second = pair.getClass().getDeclaredField("second");
- return (Class<?>) second.get(pair);
- }
-
- private static boolean isClassPair(Object r) {
- return r != null && r.getClass().getName().equals("ClassPair");
- }
-
- public static void clearResolvedTypes(Class<?> c) {
- if (!usingRI) {
- nativeClearResolvedTypes(c);
- }
- }
-
- // Skip verification of a class on ART. Verification can cause classes to be loaded
- // while holding a lock on the class being verified and holding that lock can interfere
- // with the intent of the "racy" tests. In these tests we're waiting in the loadClass()
- // for all the tested threads to synchronize and they cannot reach that point if they
- // are waiting for the class lock on ClassLinker::InitializeClass(Helper1/Helper3).
- public static void skipVerification(Class<?> c) {
- if (!usingRI) {
- nativeSkipVerification(c);
- }
- }
-
- public static native void nativeClearResolvedTypes(Class<?> c);
- public static native void nativeSkipVerification(Class<?> c);
-
- static boolean usingRI = false;
-}
diff --git a/test/626-const-class-linking/src/MisbehavingLoader.java b/test/626-const-class-linking/src/MisbehavingLoader.java
deleted file mode 100644
index ca9783e..0000000
--- a/test/626-const-class-linking/src/MisbehavingLoader.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Class loader that returns Helper2.class when asked to load "Test".
-public class MisbehavingLoader extends DefiningLoader {
- private DefiningLoader defining_loader;
-
- public MisbehavingLoader(ClassLoader parent, DefiningLoader defining_loader) {
- super(parent);
- this.defining_loader = defining_loader;
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Helper1") || name.equals("Helper2")) {
- return super.findClass(name);
- } else if (name.equals("Test")) {
- throw new Error("Unexpected MisbehavingLoader.findClass(\"Test\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Helper1") || name.equals("Helper2")) {
- return super.loadClass(name, resolve);
- } else if (name.equals("Test")) {
- // Ask for a different class.
- return defining_loader.loadClass("Helper2", resolve);
- }
- return super.loadClass(name, resolve);
- }
-}
diff --git a/test/626-const-class-linking/src/RacyLoader.java b/test/626-const-class-linking/src/RacyLoader.java
deleted file mode 100644
index 9c164a3..0000000
--- a/test/626-const-class-linking/src/RacyLoader.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2016 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 RacyLoader extends DefiningLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- private Object lock = new Object();
- private int index = 0;
- private int count;
-
- private DefiningLoader[] defining_loaders;
-
- public RacyLoader(ClassLoader parent, int count) {
- super(parent);
- this.count = count;
- defining_loaders = new DefiningLoader[2];
- for (int i = 0; i != defining_loaders.length; ++i) {
- defining_loaders[i] = new DefiningLoader(parent);
- }
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test") || name.equals("Test3")) {
- throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test") || name.equals("Test3")) {
- int my_index = syncWithOtherInstances(count);
- Class<?> result = defining_loaders[my_index & 1].loadClass(name, resolve);
- syncWithOtherInstances(2 * count);
- return result;
- }
- return super.loadClass(name, resolve);
- }
-
- private int syncWithOtherInstances(int limit) {
- int my_index;
- synchronized (lock) {
- my_index = index;
- ++index;
- if (index != limit) {
- do {
- try {
- lock.wait();
- } catch (InterruptedException ie) {
- throw new Error(ie);
- }
- } while (index < limit);
- } else {
- lock.notifyAll();
- }
- }
- return my_index;
- }
-}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingHelper.java b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
deleted file mode 100644
index 4525278..0000000
--- a/test/626-const-class-linking/src/RacyMisbehavingHelper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-import java.lang.reflect.Method;
-
-public class RacyMisbehavingHelper {
- public static ClassPair get() {
- Class<?> helper1_class = Helper1.class;
- Class<?> test_class = Test.class;
- try {
- // After loading the correct class, allow loading the incorrect class.
- ClassLoader loader = helper1_class.getClassLoader();
- Method reportAfterLoading = loader.getClass().getDeclaredMethod("reportAfterLoading");
- reportAfterLoading.invoke(loader);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return new ClassPair(helper1_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingLoader.java b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
deleted file mode 100644
index f5bcb4c..0000000
--- a/test/626-const-class-linking/src/RacyMisbehavingLoader.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 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 RacyMisbehavingLoader extends DefiningLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- private Object lock = new Object();
- private int index = 0;
- private int count;
- private boolean throw_error;
-
- private DefiningLoader[] defining_loaders;
-
- public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
- super(parent);
- this.count = count;
- this.throw_error = throw_error;
- defining_loaders = new DefiningLoader[2];
- for (int i = 0; i != defining_loaders.length; ++i) {
- defining_loaders[i] = new DefiningLoader(parent);
- }
- }
-
- public void reportAfterLoading() {
- synchronized (lock) {
- ++index;
- if (index == 2 * count) {
- lock.notifyAll();
- }
- }
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- int my_index = syncWithOtherInstances(count);
- Class<?> result;
- if ((my_index & 1) == 0) {
- // Do not delay loading the correct class.
- result = defining_loaders[my_index & 1].loadClass(name, resolve);
- } else {
- // Delay loading the wrong class.
- syncWithOtherInstances(2 * count);
- if (throw_error) {
- throw new Error("RacyMisbehavingLoader throw_error=true");
- }
- result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
- }
- return result;
- }
- return super.loadClass(name, resolve);
- }
-
- private int syncWithOtherInstances(int limit) {
- int my_index;
- synchronized (lock) {
- my_index = index;
- ++index;
- if (index != limit) {
- do {
- try {
- lock.wait();
- } catch (InterruptedException ie) {
- throw new Error(ie);
- }
- } while (index < limit);
- } else {
- lock.notifyAll();
- }
- }
- return my_index;
- }
-}
diff --git a/test/Android.bp b/test/Android.bp
index 39a4059..fe20f29 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -314,7 +314,6 @@
"595-profile-saving/profile-saving.cc",
"596-app-images/app_images.cc",
"597-deopt-new-string/deopt.cc",
- "626-const-class-linking/clear_dex_cache_types.cc",
],
shared_libs: [
"libbacktrace",
diff --git a/test/etc/default-build b/test/etc/default-build
index 408dcfd..e663496 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -273,10 +273,8 @@
fi
# Create a single jar with two dex files for multidex.
-if [ ${NEED_DEX} = "true" ]; then
- if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
- zip $TEST_NAME.jar classes.dex classes2.dex
- else
- zip $TEST_NAME.jar classes.dex
- fi
+if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
+ zip $TEST_NAME.jar classes.dex classes2.dex
+elif [ ${NEED_DEX} = "true" ]; then
+ zip $TEST_NAME.jar classes.dex
fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index f0abb44..bb3a3ad 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -316,8 +316,7 @@
if [ "$USE_JVM" = "y" ]; then
export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64
# Xmx is necessary since we don't pass down the ART flags to JVM.
- # We pass the classes2 path whether it's used (src-multidex) or not.
- cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes:classes2 ${FLAGS} $MAIN $@ ${ARGS}"
+ cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes ${FLAGS} $MAIN $@ ${ARGS}"
if [ "$DEV_MODE" = "y" ]; then
echo $cmdline
fi