blob: eba64d760f3b3f30cc74f18bee29e453875d0101 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mir_annotations.h"
#include <string.h>
#include "base/logging.h"
#include "class_linker.h"
#include "compiler_ir.h"
#include "driver/dex_compilation_unit.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/art_field.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
#include "scoped_thread_state_change.h"
namespace art {
void IFieldAnnotation::Resolve(const DexCompilationUnit* mUnit,
IFieldAnnotation* annotations, size_t count) {
if (kIsDebugBuild) {
DCHECK(annotations != nullptr);
DCHECK_NE(count, 0u);
for (auto it = annotations, end = annotations + count; it != end; ++it) {
IFieldAnnotation unresolved(it->field_idx_);
DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
}
}
const DexFile* dex_file = mUnit->GetDexFile();
ClassLinker* class_linker = mUnit->GetClassLinker();
uint32_t referrer_class_idx = dex_file->GetMethodId(mUnit->GetDexMethodIndex()).class_idx_;
// We're going to resolve fields and check access in a tight loop. It's better to hold
// the lock and needed references once than re-acquiring them again and again.
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(*dex_file));
SirtRef<mirror::ClassLoader> class_loader(
soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
SirtRef<mirror::Class> referrer_class(soa.Self(),
class_linker->ResolveType(*dex_file, referrer_class_idx, dex_cache, class_loader));
if (UNLIKELY(referrer_class.get() == nullptr)) {
// Clean up any exception left by type resolution
DCHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
// We're compiling a method without class definition. We may still resolve fields
// and update annotations, so fall through and check again in the loop.
}
for (auto it = annotations, end = annotations + count; it != end; ++it) {
uint32_t field_idx = it->field_idx_;
mirror::ArtField* resolved_field =
class_linker->ResolveField(*dex_file, field_idx, dex_cache, class_loader, false);
if (UNLIKELY(resolved_field == nullptr)) {
DCHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
continue;
}
DCHECK(!soa.Self()->IsExceptionPending());
if (UNLIKELY(resolved_field->IsStatic())) {
continue;
}
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
it->is_volatile_ = resolved_field->IsVolatile() ? 1u : 0u;
it->field_offset_ = resolved_field->GetOffset();
it->declaring_dex_file_ = fields_class->GetDexCache()->GetDexFile();
it->declaring_class_idx_ = fields_class->GetDexTypeIndex();
it->declaring_field_idx_ = resolved_field->GetDexFieldIndex();
if (UNLIKELY(referrer_class.get() == nullptr)) {
continue;
}
if (referrer_class->CanAccessResolvedField(fields_class, resolved_field,
dex_cache.get(), field_idx)) {
it->fast_get_ = 1u;
if (!resolved_field->IsFinal() || fields_class == referrer_class.get()) {
it->fast_put_ = 1u;
}
}
}
}
void SFieldAnnotation::Resolve(const DexCompilationUnit* mUnit,
SFieldAnnotation* annotations, size_t count) {
if (kIsDebugBuild) {
DCHECK(annotations != nullptr);
DCHECK_NE(count, 0u);
for (auto it = annotations, end = annotations + count; it != end; ++it) {
SFieldAnnotation unresolved(it->field_idx_);
DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
}
}
const DexFile* dex_file = mUnit->GetDexFile();
ClassLinker* class_linker = mUnit->GetClassLinker();
uint32_t referrer_class_idx = dex_file->GetMethodId(mUnit->GetDexMethodIndex()).class_idx_;
// We're going to resolve fields and check access in a tight loop. It's better to hold
// the lock and needed references once than re-acquiring them again and again.
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(*dex_file));
SirtRef<mirror::ClassLoader> class_loader(
soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
SirtRef<mirror::Class> referrer_class(soa.Self(),
class_linker->ResolveType(*dex_file, referrer_class_idx, dex_cache, class_loader));
if (UNLIKELY(referrer_class.get() == nullptr)) {
DCHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
// We're compiling a method without class definition. We may still resolve fields
// and update annotations, so fall through and check again in the loop.
}
for (auto it = annotations, end = annotations + count; it != end; ++it) {
uint32_t field_idx = it->field_idx_;
mirror::ArtField* resolved_field =
class_linker->ResolveField(*dex_file, field_idx, dex_cache, class_loader, true);
if (UNLIKELY(resolved_field == nullptr)) {
// Clean up the exception left by field resolution
DCHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
continue;
}
DCHECK(!soa.Self()->IsExceptionPending());
if (UNLIKELY(!resolved_field->IsStatic())) {
continue;
}
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
it->is_volatile_ = resolved_field->IsVolatile() ? 1u : 0u;
it->field_offset_ = resolved_field->GetOffset();
it->declaring_dex_file_ = fields_class->GetDexCache()->GetDexFile();
it->declaring_class_idx_ = fields_class->GetDexTypeIndex();
it->declaring_field_idx_ = resolved_field->GetDexFieldIndex();
if (UNLIKELY(referrer_class.get() == nullptr)) {
continue;
}
if (fields_class == referrer_class.get()) {
it->fast_get_ = 1u;
it->fast_put_ = 1u;
it->is_referrers_class_ = 1u; // implies no worrying about class initialization
it->is_initialized_ = 1u;
it->storage_index_ = fields_class->GetDexTypeIndex();
continue;
}
if (referrer_class->CanAccessResolvedField(fields_class, resolved_field,
dex_cache.get(), field_idx)) {
// We have the resolved field, we must make it into a index for the referrer
// in its static storage (which may fail if it doesn't have a slot for it)
// TODO: for images we can elide the static storage base null check
// if we know there's a non-null entry in the image
if (LIKELY(fields_class->GetDexCache() == dex_cache.get())) {
// common case where the dex cache of both the referrer and the field are the same,
// no need to search the dex file
it->storage_index_ = fields_class->GetDexTypeIndex();
} else {
// Search dex file for localized ssb index, may fail if field's class is a parent
// of the class mentioned in the dex file and there is no dex cache entry.
const DexFile::StringId* string_id =
dex_file->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
if (string_id == nullptr) {
continue;
}
const DexFile::TypeId* type_id =
dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
if (type_id == nullptr) {
continue;
}
// medium path, needs check of static storage base being initialized
it->storage_index_ = dex_file->GetIndexForTypeId(*type_id);
}
it->fast_get_ = 1u;
it->fast_put_ = resolved_field->IsFinal() ? 0u : 1u;
DCHECK_EQ(it->is_referrers_class_, 0u);
it->is_initialized_ = fields_class->IsInitialized() &&
mUnit->GetCompilationUnit()->compiler_driver->CanAssumeTypeIsPresentInDexCache(
*dex_file, it->storage_index_);
}
}
}
} // namespace art