Clinits may not have the kAccConstructor flag.
Bug: 11157540
Set the clinit access flag when we load the method and warn about badly
formed access flags.
Change-Id: I515c692095051f84f98510722ab764591185918e
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f0a7202..28c9a56 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1866,47 +1866,54 @@
const char* old_cause = self->StartAssertNoThreadSuspension("LoadMethod");
dst->SetDexMethodIndex(dex_method_idx);
dst->SetDeclaringClass(klass.get());
-
- if (method_name == "finalize") {
- // Create the prototype for a signature of "()V"
- const DexFile::StringId* void_string_id = dex_file.FindStringId("V");
- if (void_string_id != NULL) {
- const DexFile::TypeId* void_type_id =
- dex_file.FindTypeId(dex_file.GetIndexForStringId(*void_string_id));
- if (void_type_id != NULL) {
- std::vector<uint16_t> no_args;
- const DexFile::ProtoId* finalizer_proto =
- dex_file.FindProtoId(dex_file.GetIndexForTypeId(*void_type_id), no_args);
- if (finalizer_proto != NULL) {
- // We have the prototype in the dex file
- if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged
- klass->SetFinalizable();
- } else {
- ClassHelper kh(klass.get());
- StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece());
- // 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_descriptor != "Ljava/lang/Object;" &&
- klass_descriptor != "Ljava/lang/Enum;") {
- klass->SetFinalizable();
- }
- }
- }
- }
- }
- }
dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
- dst->SetAccessFlags(it.GetMemberAccessFlags());
dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
- CHECK(dst->IsArtMethod());
+ uint32_t access_flags = it.GetMemberAccessFlags();
+
+ if (UNLIKELY(method_name == "finalize")) {
+ // Set finalizable flag on declaring class.
+ const DexFile::ProtoId& proto = dex_file.GetProtoId(method_id.proto_idx_);
+ if (dex_file.GetProtoParameters(proto) == NULL) { // No arguments
+ const DexFile::TypeId& return_type = dex_file.GetTypeId(proto.return_type_idx_);
+ if (dex_file.StringDataAsStringPieceByIdx(return_type.descriptor_idx_) == "V") {
+ // Void return type.
+ if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged
+ klass->SetFinalizable();
+ } else {
+ ClassHelper kh(klass.get());
+ StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece());
+ // 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_descriptor != "Ljava/lang/Object;" &&
+ klass_descriptor != "Ljava/lang/Enum;") {
+ klass->SetFinalizable();
+ }
+ }
+ }
+ }
+ } else if (method_name[0] == '<') {
+ // Fix broken access flags for initializers. Bug 11157540.
+ bool is_init = (method_name == "<init>");
+ bool is_clinit = !is_init && (method_name == "<clinit>");
+ if (UNLIKELY(!is_init && !is_clinit)) {
+ LOG(WARNING) << "Unexpected '<' at start of method name " << method_name;
+ } else {
+ if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
+ LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
+ << PrettyDescriptor(klass.get()) << " in dex file " << dex_file.GetLocation();
+ access_flags |= kAccConstructor;
+ }
+ }
+ }
+ dst->SetAccessFlags(access_flags);
self->EndAssertNoThreadSuspension(old_cause);
return dst;