Avoid handle-less methods in ClassLinker::LinkInterfaceMethods().
There were some handle-less methods in local variables across
potential GC points.
Bug: 12687968
Change-Id: I786fbaadf7a52e98194080c67c90fc1c35060d59
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f31e273..69db959 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4348,7 +4348,7 @@
return true;
}
}
- StackHandleScope<4> hs(self);
+ StackHandleScope<5> hs(self);
Handle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
if (UNLIKELY(iftable.Get() == NULL)) {
CHECK(self->IsExceptionPending()); // OOME.
@@ -4431,7 +4431,13 @@
}
MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
MethodHelper vtable_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
- std::vector<mirror::ArtMethod*> miranda_list;
+ size_t max_miranda_methods = 0; // The max size of miranda_list.
+ for (size_t i = 0; i < ifcount; ++i) {
+ max_miranda_methods += iftable->GetInterface(i)->NumVirtualMethods();
+ }
+ Handle<mirror::ObjectArray<mirror::ArtMethod>>
+ miranda_list(hs.NewHandle(AllocArtMethodArray(self, max_miranda_methods)));
+ size_t miranda_list_size = 0; // The current size of miranda_list.
for (size_t i = 0; i < ifcount; ++i) {
size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
if (num_methods > 0) {
@@ -4446,8 +4452,7 @@
Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
hs.NewHandle(klass->GetVTableDuringLinking()));
for (size_t j = 0; j < num_methods; ++j) {
- mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
- interface_mh.ChangeMethod(interface_method);
+ interface_mh.ChangeMethod(iftable->GetInterface(i)->GetVirtualMethod(j));
int32_t k;
// For each method listed in the interface's method list, find the
// matching method in our class's method list. We want to favor the
@@ -4458,22 +4463,21 @@
// those don't end up in the virtual method table, so it shouldn't
// matter which direction we go. We walk it backward anyway.)
for (k = vtable->GetLength() - 1; k >= 0; --k) {
- mirror::ArtMethod* vtable_method = vtable->Get(k);
- vtable_mh.ChangeMethod(vtable_method);
+ vtable_mh.ChangeMethod(vtable->Get(k));
if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
- if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
+ if (!vtable_mh.Get()->IsAbstract() && !vtable_mh.Get()->IsPublic()) {
ThrowIllegalAccessError(
klass.Get(),
"Method '%s' implementing interface method '%s' is not public",
- PrettyMethod(vtable_method).c_str(),
- PrettyMethod(interface_method).c_str());
+ PrettyMethod(vtable_mh.Get()).c_str(),
+ PrettyMethod(interface_mh.Get()).c_str());
return false;
}
- method_array->Set<false>(j, vtable_method);
+ method_array->Set<false>(j, vtable_mh.Get());
// Place method in imt if entry is empty, place conflict otherwise.
- uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
+ uint32_t imt_index = interface_mh.Get()->GetDexMethodIndex() % mirror::Class::kImtSize;
if (imtable->Get(imt_index) == NULL) {
- imtable->Set<false>(imt_index, vtable_method);
+ imtable->Set<false>(imt_index, vtable_mh.Get());
imtable_changed = true;
} else {
imtable->Set<false>(imt_index, runtime->GetImtConflictMethod());
@@ -4484,7 +4488,9 @@
if (k < 0) {
StackHandleScope<1> hs(self);
auto miranda_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
- for (mirror::ArtMethod* mir_method : miranda_list) {
+ for (size_t l = 0; l < miranda_list_size; ++l) {
+ mirror::ArtMethod* mir_method = miranda_list->Get(l);
+ DCHECK(mir_method != nullptr);
vtable_mh.ChangeMethod(mir_method);
if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
miranda_method.Assign(mir_method);
@@ -4493,13 +4499,13 @@
}
if (miranda_method.Get() == NULL) {
// Point the interface table at a phantom slot.
- miranda_method.Assign(down_cast<mirror::ArtMethod*>(interface_method->Clone(self)));
+ miranda_method.Assign(down_cast<mirror::ArtMethod*>(interface_mh.Get()->Clone(self)));
if (UNLIKELY(miranda_method.Get() == NULL)) {
CHECK(self->IsExceptionPending()); // OOME.
return false;
}
- // TODO: If a methods move then the miranda_list may hold stale references.
- miranda_list.push_back(miranda_method.Get());
+ DCHECK_LT(miranda_list_size, max_miranda_methods);
+ miranda_list->Set<false>(miranda_list_size++, miranda_method.Get());
}
method_array->Set<false>(j, miranda_method.Get());
}
@@ -4516,9 +4522,9 @@
}
klass->SetImTable(imtable.Get());
}
- if (!miranda_list.empty()) {
+ if (miranda_list_size > 0) {
int old_method_count = klass->NumVirtualMethods();
- int new_method_count = old_method_count + miranda_list.size();
+ int new_method_count = old_method_count + miranda_list_size;
mirror::ObjectArray<mirror::ArtMethod>* virtuals;
if (old_method_count == 0) {
virtuals = AllocArtMethodArray(self, new_method_count);
@@ -4536,14 +4542,14 @@
hs.NewHandle(klass->GetVTableDuringLinking()));
CHECK(vtable.Get() != NULL);
int old_vtable_count = vtable->GetLength();
- int new_vtable_count = old_vtable_count + miranda_list.size();
+ int new_vtable_count = old_vtable_count + miranda_list_size;
vtable.Assign(vtable->CopyOf(self, new_vtable_count));
if (UNLIKELY(vtable.Get() == NULL)) {
CHECK(self->IsExceptionPending()); // OOME.
return false;
}
- for (size_t i = 0; i < miranda_list.size(); ++i) {
- mirror::ArtMethod* method = miranda_list[i];
+ for (size_t i = 0; i < miranda_list_size; ++i) {
+ mirror::ArtMethod* method = miranda_list->Get(i);
// Leave the declaring class alone as type indices are relative to it
method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda);
method->SetMethodIndex(0xFFFF & (old_vtable_count + i));