Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save 3Nigma/eded1949ca36f51c6bc8 to your computer and use it in GitHub Desktop.
Save 3Nigma/eded1949ca36f51c6bc8 to your computer and use it in GitHub Desktop.
Method used to analyze the triggering of the new "return-void-barrier" opcode in Google's Android ART distribution
static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager,
size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
ATRACE_CALL();
Thread* self = Thread::Current();
jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
ClassLinker* class_linker = manager->GetClassLinker();
// If an instance field is final then we need to have a barrier on the return, static final
// fields are assigned within the lock held for class initialization. Conservatively assume
// constructor barriers are always required.
bool requires_constructor_barrier = true;
// Method and Field are the worst. We can't resolve without either
// context from the code use (to disambiguate virtual vs direct
// method and instance vs static field) or from class
// definitions. While the compiler will resolve what it can as it
// needs it, here we try to resolve fields and methods used in class
// definitions, since many of them many never be referenced by
// generated code.
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
if (!SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
ScopedObjectAccess soa(self);
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
// Resolve the class.
mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
class_loader);
bool resolve_fields_and_methods;
if (klass == NULL) {
// Class couldn't be resolved, for example, super-class is in a different dex file. Don't
// attempt to resolve methods and fields when there is no declaring class.
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
resolve_fields_and_methods = false;
} else {
resolve_fields_and_methods = manager->GetCompiler()->IsImage();
}
// Note the class_data pointer advances through the headers,
// static fields, instance fields, direct methods, and virtual
// methods.
const byte* class_data = dex_file.GetClassData(class_def);
if (class_data == NULL) {
// Empty class such as a marker interface.
requires_constructor_barrier = false;
} else {
ClassDataItemIterator it(dex_file, class_data);
while (it.HasNextStaticField()) {
if (resolve_fields_and_methods) {
mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
dex_cache, class_loader, true);
if (field == NULL) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
}
}
it.Next();
}
// We require a constructor barrier if there are final instance fields.
requires_constructor_barrier = false;
while (it.HasNextInstanceField()) {
if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
requires_constructor_barrier = true;
}
if (resolve_fields_and_methods) {
mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
dex_cache, class_loader, false);
if (field == NULL) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
}
}
it.Next();
}
if (resolve_fields_and_methods) {
while (it.HasNextDirectMethod()) {
mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
if (method == NULL) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
}
it.Next();
}
while (it.HasNextVirtualMethod()) {
mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
if (method == NULL) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
}
it.Next();
}
DCHECK(!it.HasNext());
}
}
}
if (requires_constructor_barrier) {
manager->GetCompiler()->AddRequiresConstructorBarrier(self, &dex_file, class_def_index);
}
}
@3Nigma
Copy link
Author

3Nigma commented Jun 11, 2014

requires_constructor_barrier gets TRUE only in 2 situations:

  • SkipClass(class_linker, jclass_loader, dex_file, class_def) is FALSE
  • Class is not empty as it is the case for marker classes AND Class has instance fields AND Member access is final (it.GetMemberAccessFlags() & kAccFinal) != 0

@3Nigma
Copy link
Author

3Nigma commented Jun 11, 2014

Running grep -rnw ./ -e "kAccFinal" inside the android art-platform source tree (v4.4.3) yeilded the following occurances:

./compiler/driver/compiler_driver.cc:1530:        if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
./runtime/class_linker.cc:2195:  primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
./runtime/class_linker.cc:2324:  access_flags |= kAccAbstract | kAccFinal;
./runtime/class_linker.cc:2826:  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
./runtime/class_linker.cc:2853:  interfaces_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
./runtime/class_linker.cc:2863:  throws_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
./runtime/class_linker.cc:3041:  method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
./runtime/class_linker_test.cc:93:    EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
./runtime/class_linker_test.cc:107:    EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
./runtime/dex_file_verifier.cc:342:      kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
./runtime/dex_file_verifier.cc:368:      kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract |
./runtime/mirror/art_field.h:61:    return (GetAccessFlags() & kAccFinal) != 0;
./runtime/mirror/art_method.h:107:    return (GetAccessFlags() & kAccFinal) != 0;
./runtime/mirror/class.h:206:    return (GetAccessFlags() & kAccFinal) != 0;
./runtime/modifiers.h:26:static const uint32_t kAccFinal = 0x0010;  // class, field, method, ic

Further analysis of these results concluded:

  • class_linker.cc:2324 referes to class declarations
  • class_linker.cc:2826 referes to classes (resides in a method called CreateProxyClass
  • class_linker.cc:2853 resides in the same area as line 2826
  • class_linker.cc:2863 lays still in the CreateProxyClass method
  • class_linker.cc:3041 referes to a method declaration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment