We now have an invariant where we never allocate finalizable
objects with the Initialized or Resolved entrypoints. This speeds up
allocation by only doing the check in the slow path.
Before:
MemAllocTest: 3625, 3707, 3641
EvaluateAndApplyChanges: 3448, 3421, 3413
After:
MemAllocTest: 3164, 3109, 3135
EvaluateAndApplyChanges: 3272, 3299, 3353
Bug:
14078487
Change-Id: I2b0534af3e7c75ea5e5257cf3647744f7abfb74e
bool is_type_initialized; // Ignored as an array does not have an initializer.
bool use_direct_type_ptr;
uintptr_t direct_type_ptr;
+ bool is_finalizable;
if (kEmbedClassInCode &&
- driver->CanEmbedTypeInCode(*dex_file, type_idx,
- &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+ &direct_type_ptr, &is_finalizable)) {
// The fast path.
if (!use_direct_type_ptr) {
LoadClassType(type_idx, kArg0);
bool is_type_initialized;
bool use_direct_type_ptr;
uintptr_t direct_type_ptr;
+ bool is_finalizable;
if (kEmbedClassInCode &&
- driver->CanEmbedTypeInCode(*dex_file, type_idx,
- &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+ &direct_type_ptr, &is_finalizable) &&
+ !is_finalizable) {
// The fast path.
if (!use_direct_type_ptr) {
LoadClassType(type_idx, kArg0);
bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
bool* is_type_initialized, bool* use_direct_type_ptr,
- uintptr_t* direct_type_ptr) {
+ uintptr_t* direct_type_ptr, bool* out_is_finalizable) {
ScopedObjectAccess soa(Thread::Current());
mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == nullptr) {
return false;
}
+ *out_is_finalizable = resolved_class->IsFinalizable();
const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
if (compiling_boot) {
// boot -> boot class pointers.
bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
bool* is_type_initialized, bool* use_direct_type_ptr,
- uintptr_t* direct_type_ptr);
+ uintptr_t* direct_type_ptr, bool* out_is_finalizable);
// Get the DexCache for the
mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit)
if (klass == nullptr) {
return nullptr;
}
- gc::Heap* heap = Runtime::Current()->GetHeap();
- return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+ return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
DCHECK(klass != nullptr);
return klass->Alloc<kInstrumented>(self, allocator_type);
return nullptr;
}
gc::Heap* heap = Runtime::Current()->GetHeap();
- return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
}
- return klass->Alloc<kInstrumented>(self, allocator_type);
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, allocator_type);
}
// Given the context of a calling Method and an initialized class, create an instance.
gc::AllocatorType allocator_type)
NO_THREAD_SAFETY_ANALYSIS {
DCHECK(klass != nullptr);
- return klass->Alloc<kInstrumented>(self, allocator_type);
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, allocator_type);
}
non_moving_space_->ClearGrowthLimit();
}
-void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
+void Heap::AddFinalizerReference(Thread* self, mirror::Object** object) {
ScopedObjectAccess soa(self);
- ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(object));
+ ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(*object));
jvalue args[1];
args[0].l = arg.get();
InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
+ // Restore object in case it gets moved.
+ *object = soa.Decode<mirror::Object*>(arg.get());
}
void Heap::EnqueueClearedReferences() {
return card_table_.get();
}
- void AddFinalizerReference(Thread* self, mirror::Object* object);
+ void AddFinalizerReference(Thread* self, mirror::Object** object);
// Returns the number of bytes currently allocated.
size_t GetBytesAllocated() const {
DCHECK_GE(this->object_size_, sizeof(Object));
}
-template <bool kIsInstrumented>
+template<bool kIsInstrumented, bool kCheckAddFinalizer>
inline Object* Class::Alloc(Thread* self, gc::AllocatorType allocator_type) {
CheckObjectAlloc();
gc::Heap* heap = Runtime::Current()->GetHeap();
- return heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
- allocator_type, VoidFunctor());
+ const bool add_finalizer = kCheckAddFinalizer && IsFinalizable();
+ if (!kCheckAddFinalizer) {
+ DCHECK(!IsFinalizable());
+ }
+ mirror::Object* obj =
+ heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
+ allocator_type, VoidFunctor());
+ if (add_finalizer && LIKELY(obj != nullptr)) {
+ heap->AddFinalizerReference(self, &obj);
+ }
+ return obj;
}
inline Object* Class::AllocObject(Thread* self) {
}
// Creates a raw object instance but does not invoke the default constructor.
- template <bool kIsInstrumented>
+ template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
ALWAYS_INLINE Object* Alloc(Thread* self, gc::AllocatorType allocator_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
heap->WriteBarrierEveryFieldOf(dest);
}
if (c->IsFinalizable()) {
- SirtRef<Object> sirt_dest(self, dest);
- heap->AddFinalizerReference(self, dest);
- return sirt_dest.get();
+ heap->AddFinalizerReference(self, &dest);
}
return dest;
}
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '2', '2', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '2', '3', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));