diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/assembler_x86.cc | 2 | ||||
| -rw-r--r-- | src/class_linker.cc | 33 | ||||
| -rw-r--r-- | src/class_linker_test.cc | 33 | ||||
| -rw-r--r-- | src/jni_compiler.cc | 2 | ||||
| -rw-r--r-- | src/object.cc | 23 | ||||
| -rw-r--r-- | src/object.h | 30 |
6 files changed, 101 insertions, 22 deletions
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc index 5df87047df..c7b2bb5a66 100644 --- a/src/assembler_x86.cc +++ b/src/assembler_x86.cc @@ -1797,7 +1797,7 @@ void X86ExceptionSlowPath::Emit(Assembler *sasm) { X86Assembler* sp_asm = down_cast<X86Assembler*>(sasm); #define __ sp_asm-> __ Bind(&entry_); - // NB the return value is dead + // Note: the return value is dead // Pass exception as argument in EAX __ fs()->movl(EAX, Address::Absolute(Thread::ExceptionOffset())); __ fs()->call(Address::Absolute(OFFSETOF_MEMBER(Thread, pDeliverException))); diff --git a/src/class_linker.cc b/src/class_linker.cc index 1049107d67..6ebc6384d5 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -470,7 +470,7 @@ void ClassLinker::FinishInit() { } // Let the heap know some key offsets into java.lang.ref instances - // NB we hard code the field indexes here rather than using FindInstanceField + // Note: we hard code the field indexes here rather than using FindInstanceField // as the types of the field can't be resolved prior to the runtime being // fully initialized Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;"); @@ -1053,16 +1053,32 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, Method* dst) { const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_); dst->SetDeclaringClass(klass); + String* method_name = ResolveString(dex_file, method_id.name_idx_, klass->GetDexCache()); dst->SetName(method_name); if (method_name->Equals("<init>")) { dst->SetClass(GetClassRoot(kJavaLangReflectConstructor)); } - { - int32_t utf16_length; - std::string utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_, &utf16_length)); - dst->SetSignature(intern_table_->InternStrong(utf16_length, utf8.c_str())); + + int32_t utf16_length; + std::string signature(dex_file.CreateMethodDescriptor(method_id.proto_idx_, &utf16_length)); + dst->SetSignature(intern_table_->InternStrong(utf16_length, signature.c_str())); + + if (method_name->Equals("finalize") && signature == "()V") { + /* + * The Enum class declares a "final" finalize() method to prevent subclasses from introducing + * a finalizer. We don't want to set the finalizable flag for Enum or its subclasses, so we + * exclude it here. + * + * We also want to avoid setting the flag on Object, where we know that finalize() is empty. + */ + if (klass->GetClassLoader() != NULL || + (!klass->GetDescriptor()->Equals("Ljava/lang/Object;") && + !klass->GetDescriptor()->Equals("Ljava/lang/Enum;"))) { + klass->SetFinalizable(); + } } + dst->SetProtoIdx(method_id.proto_idx_); dst->SetCodeItemOffset(src.code_off_); const char* shorty = dex_file.GetShorty(method_id.proto_idx_); @@ -1771,7 +1787,6 @@ bool ClassLinker::LinkSuperClass(Class* klass) { "java.lang.Object must not have a superclass"); return false; } - // TODO: clear finalize attribute return true; } if (super == NULL) { @@ -1795,6 +1810,12 @@ bool ClassLinker::LinkSuperClass(Class* klass) { PrettyDescriptor(klass->GetDescriptor()).c_str()); return false; } + + // Inherit kAccClassIsFinalizable from the superclass in case this class doesn't override finalize. + if (super->IsFinalizable()) { + klass->SetFinalizable(); + } + #ifndef NDEBUG // Ensure super classes are fully resolved prior to resolving fields.. while (super != NULL) { diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index 18a3f928ff..8be1b905dd 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -969,4 +969,37 @@ TEST_F(ClassLinkerTest, InitializeStaticStorageFromCode) { EXPECT_EQ(init, clinit->GetDexCacheInitializedStaticStorage()->Get(type_idx)); } +TEST_F(ClassLinkerTest, FinalizableBit) { + Class* c; + + // Object has a finalize method, but we know it's empty. + c = class_linker_->FindSystemClass("Ljava/lang/Object;"); + EXPECT_FALSE(c->IsFinalizable()); + + // Enum has a finalize method to prevent its subclasses from implementing one. + c = class_linker_->FindSystemClass("Ljava/lang/Enum;"); + EXPECT_FALSE(c->IsFinalizable()); + + // RoundingMode is an enum. + c = class_linker_->FindSystemClass("Ljava/math/RoundingMode;"); + EXPECT_FALSE(c->IsFinalizable()); + + // RandomAccessFile extends Object and overrides finalize. + c = class_linker_->FindSystemClass("Ljava/io/RandomAccessFile;"); + EXPECT_TRUE(c->IsFinalizable()); + + // FileInputStream is finalizable and extends InputStream which isn't. + c = class_linker_->FindSystemClass("Ljava/io/InputStream;"); + EXPECT_FALSE(c->IsFinalizable()); + c = class_linker_->FindSystemClass("Ljava/io/FileInputStream;"); + EXPECT_TRUE(c->IsFinalizable()); + + // ScheduledThreadPoolExecutor doesn't have a finalize method but + // extends ThreadPoolExecutor which does. + c = class_linker_->FindSystemClass("Ljava/util/concurrent/ThreadPoolExecutor;"); + EXPECT_TRUE(c->IsFinalizable()); + c = class_linker_->FindSystemClass("Ljava/util/concurrent/ScheduledThreadPoolExecutor;"); + EXPECT_TRUE(c->IsFinalizable()); +} + } // namespace art diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc index c8cfc66f8e..83be88a226 100644 --- a/src/jni_compiler.cc +++ b/src/jni_compiler.cc @@ -219,7 +219,7 @@ void JniCompiler::Compile(Method* native_method) { // to the convention required for a native call (shuffling). For references // place an index/pointer to the reference after checking whether it is // NULL (which must be encoded as NULL). - // NB. we do this prior to materializing the JNIEnv* and static's jclass to + // Note: we do this prior to materializing the JNIEnv* and static's jclass to // give as many free registers for the shuffle as possible mr_conv->ResetIterator(FrameOffset(frame_size+out_arg_size)); uint32_t args_count = 0; diff --git a/src/object.cc b/src/object.cc index 49d689c850..4950077a5b 100644 --- a/src/object.cc +++ b/src/object.cc @@ -22,6 +22,20 @@ namespace art { +void Object::AddFinalizerReference() { + Thread* self = Thread::Current(); + + // TODO: cache these somewhere. + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Class* java_lang_ref_FinalizerReference = class_linker->FindSystemClass("Ljava/lang/ref/FinalizerReference;"); + CHECK(java_lang_ref_FinalizerReference != NULL); + Method* m = java_lang_ref_FinalizerReference->FindDirectMethod("add", "(Ljava/lang/Object;)V"); + CHECK(m != NULL); + + LOG(INFO) << "Object::AddFinalizerReference invoking FinalizerReference.add for " << (void*) this; + m->Invoke(self, NULL, reinterpret_cast<byte*>(this), NULL); +} + Object* Object::Clone() { Class* c = GetClass(); DCHECK(!c->IsClassClass()); @@ -41,10 +55,9 @@ Object* Object::Clone() { size_t offset = sizeof(Object); memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset); - // TODO: Mark the clone as finalizable if appropriate. -// if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) { -// dvmSetFinalizable(copy); -// } + if (c->IsFinalizable()) { + copy->AddFinalizerReference(); + } return copy; } @@ -1384,7 +1397,7 @@ bool String::Equals(const String* that) const { // Quick length inequality test return false; } else { - // NB don't short circuit on hash code as we're presumably here as the + // Note: don't short circuit on hash code as we're presumably here as the // hash code was already equal for (int32_t i = 0; i < that->GetLength(); ++i) { if (this->CharAt(i) != that->CharAt(i)) { diff --git a/src/object.h b/src/object.h index 205d7c08f0..ce1d1443b7 100644 --- a/src/object.h +++ b/src/object.h @@ -133,11 +133,13 @@ static const uint32_t kAccMethodFlagsMask = (kAccPublic | kAccConstructor | kAccDeclaredSynchronized); -// if only kAccClassIsReference is set, we have a soft reference -static const uint32_t kAccClassIsReference = 0x8000000; // class is a soft/weak/phantom ref -static const uint32_t kAccClassIsWeakReference = 0x4000000; // class is a weak reference -static const uint32_t kAccClassIsFinalizerReference = 0x2000000; // class is a finalizer reference -static const uint32_t kAccClassIsPhantomReference = 0x1000000; // class is a phantom reference +// Special runtime-only flags. +// Note: if only kAccClassIsReference is set, we have a soft reference. +static const uint32_t kAccClassIsFinalizable = 0x80000000; // class/ancestor overrides finalize() +static const uint32_t kAccClassIsReference = 0x08000000; // class is a soft/weak/phantom ref +static const uint32_t kAccClassIsWeakReference = 0x04000000; // class is a weak reference +static const uint32_t kAccClassIsFinalizerReference = 0x02000000; // class is a finalizer reference +static const uint32_t kAccClassIsPhantomReference = 0x01000000; // class is a phantom reference static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference | kAccClassIsWeakReference @@ -296,6 +298,9 @@ class MANAGED Object { return down_cast<const Field*>(this); } + // If you're looking for SetFinalizable, this is the moral equivalent. + void AddFinalizerReference(); + bool IsReferenceInstance() const; bool IsWeakReferenceInstance() const; @@ -425,8 +430,7 @@ class MANAGED Field : public AccessibleObject { uint32_t GetAccessFlags() const; void SetAccessFlags(uint32_t new_access_flags) { - SetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), new_access_flags, - false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), new_access_flags, false); } bool IsPublic() const { @@ -602,8 +606,7 @@ class MANAGED Method : public AccessibleObject { uint32_t GetAccessFlags() const; void SetAccessFlags(uint32_t new_access_flags) { - SetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), new_access_flags, - false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), new_access_flags, false); } // Returns true if the method is declared public. @@ -1327,6 +1330,15 @@ class MANAGED Class : public StaticStorageBase { return (GetAccessFlags() & kAccFinal) != 0; } + bool IsFinalizable() const { + return (GetAccessFlags() & kAccClassIsFinalizable) != 0; + } + + void SetFinalizable() { + uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false); + SetAccessFlags(flags | kAccClassIsFinalizable); + } + // Returns true if the class is abstract. bool IsAbstract() const { return (GetAccessFlags() & kAccAbstract) != 0; |