Merge "ART: Add option to retain lock levels in verifier"
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 8abd592..09d37f8 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -668,14 +668,16 @@
LockTemp(TargetReg(kArg6));
LockTemp(TargetReg(kArg7));
} else {
- LockTemp(TargetReg(kFArg0));
- LockTemp(TargetReg(kFArg1));
- LockTemp(TargetReg(kFArg2));
- LockTemp(TargetReg(kFArg3));
if (fpuIs32Bit_) {
+ LockTemp(TargetReg(kFArg0));
+ LockTemp(TargetReg(kFArg1));
+ LockTemp(TargetReg(kFArg2));
+ LockTemp(TargetReg(kFArg3));
LockTemp(rs_rD6_fr0);
LockTemp(rs_rD7_fr0);
} else {
+ LockTemp(TargetReg(kFArg0));
+ LockTemp(TargetReg(kFArg2));
LockTemp(rs_rD6_fr1);
LockTemp(rs_rD7_fr1);
}
@@ -694,14 +696,16 @@
FreeTemp(TargetReg(kArg6));
FreeTemp(TargetReg(kArg7));
} else {
- FreeTemp(TargetReg(kFArg0));
- FreeTemp(TargetReg(kFArg1));
- FreeTemp(TargetReg(kFArg2));
- FreeTemp(TargetReg(kFArg3));
if (fpuIs32Bit_) {
+ FreeTemp(TargetReg(kFArg0));
+ FreeTemp(TargetReg(kFArg1));
+ FreeTemp(TargetReg(kFArg2));
+ FreeTemp(TargetReg(kFArg3));
FreeTemp(rs_rD6_fr0);
FreeTemp(rs_rD7_fr0);
} else {
+ FreeTemp(TargetReg(kFArg0));
+ FreeTemp(TargetReg(kFArg2));
FreeTemp(rs_rD6_fr1);
FreeTemp(rs_rD7_fr1);
}
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index feaaaf4..075ec1e 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -16,16 +16,12 @@
#include "intrinsics.h"
-#include "art_method.h"
-#include "class_linker.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "invoke_type.h"
-#include "mirror/dex_cache-inl.h"
#include "nodes.h"
#include "quick/inline_method_analyser.h"
-#include "scoped_thread_state_change.h"
#include "utils.h"
namespace art {
@@ -368,34 +364,17 @@
if (inst->IsInvoke()) {
HInvoke* invoke = inst->AsInvoke();
InlineMethod method;
- const DexFile& dex_file = invoke->GetDexFile();
- DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
+ DexFileMethodInliner* inliner =
+ driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
DCHECK(inliner != nullptr);
if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
if (intrinsic != Intrinsics::kNone) {
if (!CheckInvokeType(intrinsic, invoke)) {
- // We might be in a situation where we have inlined a method that calls an intrinsic,
- // but that method is in a different dex file on which we do not have a
- // verified_method that would have helped the compiler driver sharpen the call.
- // We can still ensure the invoke types match by checking whether the called method
- // is final or is in a final class.
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- {
- ScopedObjectAccess soa(Thread::Current());
- ArtMethod* art_method = class_linker->FindDexCache(dex_file)->GetResolvedMethod(
- invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
- DCHECK(art_method != nullptr);
- if (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal()) {
- invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
- } else {
- LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
- << intrinsic << " for "
- << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
- << invoke->DebugName();
- }
- }
+ LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
+ << intrinsic << " for "
+ << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
} else {
invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
}
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 35acd42..084c88e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -141,10 +141,10 @@
#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
art::mirror::Class::AccessFlagsOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
art::mirror::Class::ObjectSizeOffset().Int32Value())
-#define MIRROR_CLASS_STATUS_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
art::mirror::Class::StatusOffset().Int32Value())
@@ -153,7 +153,7 @@
static_cast<uint32_t>(art::mirror::Class::kStatusInitialized))
#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
- static_cast<uint32_t>(kAccClassIsFinalizable))
+ static_cast<uint32_t>(art::kAccClassIsFinalizable))
// Array offsets.
#define MIRROR_ARRAY_LENGTH_OFFSET MIRROR_OBJECT_HEADER_SIZE
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c179c64..b547d07 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -358,9 +358,9 @@
// Setup String.
Handle<mirror::Class> java_lang_String(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
+ java_lang_String->SetStringClass();
mirror::String::SetClass(java_lang_String.Get());
mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self);
- java_lang_String->SetStringClass();
// Setup java.lang.ref.Reference.
Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
@@ -570,16 +570,13 @@
CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
mirror::Reference::ClassSize(image_pointer_size_));
class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
- class_root->SetAccessFlags(class_root->GetAccessFlags() |
- kAccClassIsReference | kAccClassIsFinalizerReference);
+ class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
- class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
- kAccClassIsPhantomReference);
+ class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
- class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference);
+ class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
- class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
- kAccClassIsWeakReference);
+ class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference);
// Setup the ClassLoader, verifying the object_size_.
class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
@@ -2701,6 +2698,11 @@
new_class->SetVTable(java_lang_Object->GetVTable());
new_class->SetPrimitiveType(Primitive::kPrimNot);
new_class->SetClassLoader(component_type->GetClassLoader());
+ if (component_type->IsPrimitive()) {
+ new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields);
+ } else {
+ new_class->SetClassFlags(mirror::kClassFlagObjectArray);
+ }
mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
{
ArtMethod* imt[mirror::Class::kImtSize];
@@ -4385,9 +4387,9 @@
}
// Inherit reference flags (if any) from the superclass.
- int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask);
+ int reference_flags = (super->GetClassFlags() & mirror::kClassFlagReference);
if (reference_flags != 0) {
- klass->SetAccessFlags(klass->GetAccessFlags() | reference_flags);
+ klass->SetClassFlags(klass->GetClassFlags() | reference_flags);
}
// Disallow custom direct subclasses of java.lang.ref.Reference.
if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
@@ -5227,6 +5229,22 @@
*class_size = size;
} else {
klass->SetNumReferenceInstanceFields(num_reference_fields);
+ mirror::Class* super_class = klass->GetSuperClass();
+ if (num_reference_fields == 0 || super_class == nullptr) {
+ // object has one reference field, klass, but we ignore it since we always visit the class.
+ // If the super_class is null then we are java.lang.Object.
+ if (super_class == nullptr ||
+ (super_class->GetClassFlags() & mirror::kClassFlagNoReferenceFields) != 0) {
+ klass->SetClassFlags(klass->GetClassFlags() | mirror::kClassFlagNoReferenceFields);
+ } else if (kIsDebugBuild) {
+ size_t total_reference_instance_fields = 0;
+ while (super_class != nullptr) {
+ total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+ super_class = super_class->GetSuperClass();
+ }
+ CHECK_GT(total_reference_instance_fields, 1u);
+ }
+ }
if (!klass->IsVariableSize()) {
std::string temp;
DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3c84d8f..0d1c875 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -488,6 +488,7 @@
struct ClassOffsets : public CheckOffsets<mirror::Class> {
ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") {
addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags");
addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader");
addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize");
addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId");
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index a3cc831..56edcc9 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -35,10 +35,17 @@
obj->VisitReferences(visitor, ref_visitor);
if (kCountScannedTypes) {
mirror::Class* klass = obj->GetClass<kVerifyNone>();
- if (UNLIKELY(klass == mirror::Class::GetJavaLangClass())) {
+ uint32_t class_flags = klass->GetClassFlags();
+ if ((class_flags & mirror::kClassFlagNoReferenceFields) != 0) {
+ ++no_reference_class_count_;
+ } else if (class_flags == mirror::kClassFlagNormal) {
+ ++normal_count_;
+ } else if (class_flags == mirror::kClassFlagObjectArray) {
+ ++object_array_count_;
+ } else if (class_flags == mirror::kClassFlagClass) {
++class_count_;
- } else if (UNLIKELY(klass->IsArrayClass<kVerifyNone>())) {
- ++array_count_;
+ } else if ((class_flags & mirror::kClassFlagReference) != 0) {
+ ++reference_count_;
} else {
++other_count_;
}
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index b0a8a5b..7ddc7cc 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -70,7 +70,6 @@
static constexpr bool kProfileLargeObjects = false;
static constexpr bool kMeasureOverhead = false;
static constexpr bool kCountTasks = false;
-static constexpr bool kCountJavaLangRefs = false;
static constexpr bool kCountMarkedObjects = false;
// Turn off kCheckLocks when profiling the GC since it slows the GC down by up to 40%.
@@ -114,15 +113,17 @@
mark_stack_ = heap_->GetMarkStack();
DCHECK(mark_stack_ != nullptr);
immune_region_.Reset();
+ no_reference_class_count_.StoreRelaxed(0);
+ normal_count_.StoreRelaxed(0);
class_count_.StoreRelaxed(0);
- array_count_.StoreRelaxed(0);
+ object_array_count_.StoreRelaxed(0);
other_count_.StoreRelaxed(0);
+ reference_count_.StoreRelaxed(0);
large_object_test_.StoreRelaxed(0);
large_object_mark_.StoreRelaxed(0);
overhead_time_ .StoreRelaxed(0);
work_chunks_created_.StoreRelaxed(0);
work_chunks_deleted_.StoreRelaxed(0);
- reference_count_.StoreRelaxed(0);
mark_null_count_.StoreRelaxed(0);
mark_immune_count_.StoreRelaxed(0);
mark_fastpath_count_.StoreRelaxed(0);
@@ -1265,9 +1266,6 @@
// Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been
// marked, put it on the appropriate list in the heap for later processing.
void MarkSweep::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref) {
- if (kCountJavaLangRefs) {
- ++reference_count_;
- }
heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this);
}
@@ -1386,8 +1384,14 @@
void MarkSweep::FinishPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
if (kCountScannedTypes) {
- VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed()
- << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed();
+ VLOG(gc)
+ << "MarkSweep scanned"
+ << " no reference objects=" << no_reference_class_count_.LoadRelaxed()
+ << " normal objects=" << normal_count_.LoadRelaxed()
+ << " classes=" << class_count_.LoadRelaxed()
+ << " object arrays=" << object_array_count_.LoadRelaxed()
+ << " references=" << reference_count_.LoadRelaxed()
+ << " other=" << other_count_.LoadRelaxed();
}
if (kCountTasks) {
VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed();
@@ -1399,9 +1403,6 @@
VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed()
<< " marked " << large_object_mark_.LoadRelaxed();
}
- if (kCountJavaLangRefs) {
- VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed();
- }
if (kCountMarkedObjects) {
VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed()
<< " immune=" << mark_immune_count_.LoadRelaxed()
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 8bd1dc7..371bba5 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -245,7 +245,7 @@
void RevokeAllThreadLocalBuffers();
// Whether or not we count how many of each type of object were scanned.
- static const bool kCountScannedTypes = false;
+ static constexpr bool kCountScannedTypes = false;
// Current space, we check this space first to avoid searching for the appropriate space for an
// object.
@@ -260,18 +260,23 @@
// Parallel finger.
AtomicInteger atomic_finger_;
+
+ AtomicInteger no_reference_class_count_;
+ AtomicInteger normal_count_;
// Number of classes scanned, if kCountScannedTypes.
AtomicInteger class_count_;
- // Number of arrays scanned, if kCountScannedTypes.
- AtomicInteger array_count_;
+ // Number of object arrays scanned, if kCountScannedTypes.
+ AtomicInteger object_array_count_;
// Number of non-class/arrays scanned, if kCountScannedTypes.
AtomicInteger other_count_;
+ // Number of java.lang.ref.Reference instances.
+ AtomicInteger reference_count_;
+
AtomicInteger large_object_test_;
AtomicInteger large_object_mark_;
AtomicInteger overhead_time_;
AtomicInteger work_chunks_created_;
AtomicInteger work_chunks_deleted_;
- AtomicInteger reference_count_;
AtomicInteger mark_null_count_;
AtomicInteger mark_immune_count_;
AtomicInteger mark_fastpath_count_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d7f918b..b8c4478 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3707,7 +3707,7 @@
void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
- (c->IsVariableSize() || c->GetObjectSize() == byte_count));
+ (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags();
CHECK_GE(byte_count, sizeof(mirror::Object));
}
diff --git a/runtime/image.cc b/runtime/image.cc
index 2586959..8df17c6 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '9', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '0', '\0' };
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd678f6..b2c6e4d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -547,6 +547,7 @@
inline String* Class::GetName() {
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_));
}
+
inline void Class::SetName(String* name) {
if (Runtime::Current()->IsActiveTransaction()) {
SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name);
@@ -784,9 +785,17 @@
inline void Class::SetAccessFlags(uint32_t new_access_flags) {
// Called inside a transaction when setting pre-verified flag during boot image compilation.
if (Runtime::Current()->IsActiveTransaction()) {
- SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+ SetField32<true>(AccessFlagsOffset(), new_access_flags);
} else {
- SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+ SetField32<false>(AccessFlagsOffset(), new_access_flags);
+ }
+}
+
+inline void Class::SetClassFlags(uint32_t new_flags) {
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
+ } else {
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
}
}
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 055b3e5..3bea978 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -44,6 +44,7 @@
<< java_lang_Class_.Read()
<< " " << java_lang_Class;
CHECK(java_lang_Class != nullptr);
+ java_lang_Class->SetClassFlags(java_lang_Class->GetClassFlags() | mirror::kClassFlagClass);
java_lang_Class_ = GcRoot<Class>(java_lang_Class);
}
@@ -77,6 +78,12 @@
CHECK_NE(h_this->GetStatus(), kStatusError)
<< "Attempt to set as erroneous an already erroneous class "
<< PrettyClass(h_this.Get());
+ if (VLOG_IS_ON(class_linker)) {
+ LOG(ERROR) << "Setting " << PrettyDescriptor(h_this.Get()) << " to erroneous.";
+ if (self->IsExceptionPending()) {
+ LOG(ERROR) << "Exception: " << self->GetException()->Dump();
+ }
+ }
// Stash current exception.
StackHandleScope<1> hs(self);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 3f375be..cbcb517 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -19,6 +19,7 @@
#include "base/iteration_range.h"
#include "dex_file.h"
+#include "class_flags.h"
#include "gc_root.h"
#include "gc/allocator_type.h"
#include "invoke_type.h"
@@ -201,6 +202,12 @@
return OFFSET_OF_OBJECT_MEMBER(Class, access_flags_);
}
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ ALWAYS_INLINE uint32_t GetClassFlags() SHARED_REQUIRES(Locks::mutator_lock_) {
+ return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_));
+ }
+ void SetClassFlags(uint32_t new_flags) SHARED_REQUIRES(Locks::mutator_lock_);
+
void SetAccessFlags(uint32_t new_access_flags) SHARED_REQUIRES(Locks::mutator_lock_);
// Returns true if the class is an interface.
@@ -228,21 +235,19 @@
}
ALWAYS_INLINE bool IsStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetField32(AccessFlagsOffset()) & kAccClassIsStringClass) != 0;
+ return (GetClassFlags() & kClassFlagString) != 0;
}
ALWAYS_INLINE void SetStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
- SetAccessFlags(flags | kAccClassIsStringClass);
+ SetClassFlags(GetClassFlags() | kClassFlagString | kClassFlagNoReferenceFields);
}
ALWAYS_INLINE bool IsClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetField32(AccessFlagsOffset()) & kAccClassIsClassLoaderClass) != 0;
+ return (GetClassFlags() & kClassFlagClassLoader) != 0;
}
ALWAYS_INLINE void SetClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
- SetAccessFlags(flags | kAccClassIsClassLoaderClass);
+ SetClassFlags(GetClassFlags() | kClassFlagClassLoader);
}
// Returns true if the class is abstract.
@@ -272,27 +277,27 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsTypeOfReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetAccessFlags<kVerifyFlags>() & kAccClassIsReference) != 0;
+ return (GetClassFlags<kVerifyFlags>() & kClassFlagReference) != 0;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsWeakReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetAccessFlags<kVerifyFlags>() & kAccClassIsWeakReference) != 0;
+ return (GetClassFlags<kVerifyFlags>() & kClassFlagWeakReference) != 0;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsSoftReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetAccessFlags<kVerifyFlags>() & kAccReferenceFlagsMask) == kAccClassIsReference;
+ return (GetClassFlags<kVerifyFlags>() & kClassFlagSoftReference) != 0;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsFinalizerReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetAccessFlags<kVerifyFlags>() & kAccClassIsFinalizerReference) != 0;
+ return (GetClassFlags<kVerifyFlags>() & kClassFlagFinalizerReference) != 0;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsPhantomReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return (GetAccessFlags<kVerifyFlags>() & kAccClassIsPhantomReference) != 0;
+ return (GetClassFlags<kVerifyFlags>() & kClassFlagPhantomReference) != 0;
}
// Can references of this type be assigned to by things of another type? For non-array types
@@ -862,7 +867,8 @@
uint32_t NumInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_);
ArtField* GetInstanceField(uint32_t i) SHARED_REQUIRES(Locks::mutator_lock_);
- // Returns the number of instance fields containing reference types.
+ // Returns the number of instance fields containing reference types not counting fields in the
+ // super class.
uint32_t NumReferenceInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_) {
DCHECK(IsResolved() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_));
@@ -1225,6 +1231,9 @@
// length-prefixed array.
uint64_t virtual_methods_;
+ // Class flags to help speed up visiting object references.
+ uint32_t class_flags_;
+
// Total size of the Class instance; used when allocating storage on gc heap.
// See also object_size_.
uint32_t class_size_;
diff --git a/runtime/mirror/class_flags.h b/runtime/mirror/class_flags.h
new file mode 100644
index 0000000..6c15639
--- /dev/null
+++ b/runtime/mirror/class_flags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+#define ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace mirror {
+
+// Object types stored in class to help GC with faster object marking.
+static constexpr uint32_t kClassFlagNormal = 0x00000000;
+// Only normal objects which have no reference fields, e.g. string or primitive array or normal
+// class instance.
+static constexpr uint32_t kClassFlagNoReferenceFields = 0x00000001;
+static constexpr uint32_t kClassFlagString = 0x00000004;
+static constexpr uint32_t kClassFlagObjectArray = 0x00000008;
+static constexpr uint32_t kClassFlagClass = 0x00000010;
+
+// class is ClassLoader or one of its subclasses
+static constexpr uint32_t kClassFlagClassLoader = 0x00000020;
+
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kClassFlagSoftReference = 0x00000040;
+// class is a weak reference
+static constexpr uint32_t kClassFlagWeakReference = 0x00000080;
+// class is a finalizer reference
+static constexpr uint32_t kClassFlagFinalizerReference = 0x00000100;
+// class is a phantom reference
+static constexpr uint32_t kClassFlagPhantomReference = 0x00000200;
+
+static constexpr uint32_t kClassFlagReference =
+ kClassFlagSoftReference |
+ kClassFlagWeakReference |
+ kClassFlagFinalizerReference |
+ kClassFlagPhantomReference;
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 586ae30..702a0f4 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -24,6 +24,7 @@
#include "atomic.h"
#include "array-inl.h"
#include "class.h"
+#include "class_flags.h"
#include "class_linker.h"
#include "class_loader-inl.h"
#include "lock_word-inl.h"
@@ -1010,20 +1011,43 @@
const JavaLangRefVisitor& ref_visitor) {
mirror::Class* klass = GetClass<kVerifyFlags>();
visitor(this, ClassOffset(), false);
- if (klass == Class::GetJavaLangClass()) {
- AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
- } else if (klass->IsArrayClass() || klass->IsStringClass()) {
- if (klass->IsObjectArrayClass<kVerifyNone>()) {
- AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
- }
- } else if (klass->IsClassLoaderClass()) {
- mirror::ClassLoader* class_loader = AsClassLoader<kVerifyFlags>();
- class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
- } else {
+ const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
+ if (LIKELY(class_flags == kClassFlagNormal)) {
DCHECK(!klass->IsVariableSize());
VisitInstanceFieldsReferences(klass, visitor);
- if (UNLIKELY(klass->IsTypeOfReferenceClass<kVerifyNone>())) {
- ref_visitor(klass, AsReference());
+ DCHECK(!klass->IsClassClass());
+ } else {
+ if ((class_flags & kClassFlagNoReferenceFields) == 0) {
+ DCHECK(!klass->IsStringClass());
+ if (class_flags == kClassFlagClass) {
+ DCHECK(klass->IsClassClass());
+ AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
+ } else if (class_flags == kClassFlagObjectArray) {
+ DCHECK(klass->IsObjectArrayClass());
+ AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
+ } else if ((class_flags & kClassFlagReference) != 0) {
+ VisitInstanceFieldsReferences(klass, visitor);
+ ref_visitor(klass, AsReference());
+ } else {
+ mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags>();
+ class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
+ }
+ } else if (kIsDebugBuild) {
+ CHECK(!klass->IsClassClass());
+ CHECK(!klass->IsObjectArrayClass());
+ // String still has instance fields for reflection purposes but these don't exist in
+ // actual string instances.
+ if (!klass->IsStringClass()) {
+ size_t total_reference_instance_fields = 0;
+ mirror::Class* super_class = klass;
+ do {
+ total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+ super_class = super_class->GetSuperClass();
+ } while (super_class != nullptr);
+ // The only reference field should be the object's class. This field is handled at the
+ // beginning of the function.
+ CHECK_EQ(total_reference_instance_fields, 1u);
+ }
}
}
}
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index b6236b1..45610dc 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -55,6 +55,7 @@
void String::SetClass(Class* java_lang_String) {
CHECK(java_lang_String_.IsNull());
CHECK(java_lang_String != nullptr);
+ CHECK(java_lang_String->IsStringClass());
java_lang_String_ = GcRoot<Class>(java_lang_String);
}
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index eb2e1f6..fbee2d7 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -157,10 +157,9 @@
return java_lang_String_.Read();
}
- static void SetClass(Class* java_lang_String);
- static void ResetClass();
- static void VisitRoots(RootVisitor* visitor)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ static void SetClass(Class* java_lang_String) SHARED_REQUIRES(Locks::mutator_lock_);
+ static void ResetClass() SHARED_REQUIRES(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_);
private:
void SetHashCode(int32_t new_hash_code) SHARED_REQUIRES(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 0d9ec29..f7ab10b 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace art {
+
static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
@@ -49,28 +51,8 @@
static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only)
// Special runtime-only flags.
-// Note: if only kAccClassIsReference is set, we have a soft reference.
-
-// class is ClassLoader or one of its subclasses
-static constexpr uint32_t kAccClassIsClassLoaderClass = 0x10000000;
-
// class/ancestor overrides finalize()
static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
-// class is a soft/weak/phantom ref
-static constexpr uint32_t kAccClassIsReference = 0x08000000;
-// class is a weak reference
-static constexpr uint32_t kAccClassIsWeakReference = 0x04000000;
-// class is a finalizer reference
-static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
-// class is a phantom reference
-static constexpr uint32_t kAccClassIsPhantomReference = 0x01000000;
-// class is the string class
-static constexpr uint32_t kAccClassIsStringClass = 0x00800000;
-
-static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
- | kAccClassIsWeakReference
- | kAccClassIsFinalizerReference
- | kAccClassIsPhantomReference);
// Valid (meaningful) bits for a field.
static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
@@ -95,5 +77,7 @@
static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
kAccAbstract | kAccSynthetic | kAccAnnotation;
+} // namespace art
+
#endif // ART_RUNTIME_MODIFIERS_H_
diff --git a/test/004-SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
index 1414715..34e331b 100644
--- a/test/004-SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -93,13 +93,16 @@
char *go_away_compiler = nullptr;
extern "C" JNIEXPORT jint JNICALL Java_Main_testSignal(JNIEnv*, jclass) {
-#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+#if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
// On supported architectures we cause a real SEGV.
*go_away_compiler = 'a';
+#elif defined(__x86_64__)
+ // Cause a SEGV using an instruction known to be 3 bytes long to account for hardcoded jump
+ // in the signal handler
+ asm volatile("movl $0, %%eax;" "movb $1, (%%al);" : : : "%eax");
#else
// On other architectures we simulate SEGV.
kill(getpid(), SIGSEGV);
#endif
return 1234;
}
-
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 04326b3..702e779 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -206,8 +206,9 @@
#if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
*go_away_compiler = 'a';
#elif defined(__x86_64__)
- // Cause a SEGV using an instruction known to be 3 bytes long
- asm volatile("movl $0, %%eax;" "movb $1, (%%eax);" : : : "%eax");
+ // Cause a SEGV using an instruction known to be 3 bytes long to account for hardcoded jump
+ // in the signal handler
+ asm volatile("movl $0, %%eax;" "movb $1, (%%al);" : : : "%eax");
#else
// On other architectures we simulate SEGV.
kill(getpid(), SIGSEGV);