summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc79
1 files changed, 54 insertions, 25 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d98e0b2c54c..45d1381297e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -270,9 +270,13 @@ static void WrapExceptionInInitializer(Handle<mirror::Class> klass)
// cannot in general be guaranteed, but in all likelihood leads to breakage down the line.
if (klass->GetClassLoader() == nullptr && !Runtime::Current()->IsAotCompiler()) {
std::string tmp;
- LOG(kIsDebugBuild ? FATAL : WARNING) << klass->GetDescriptor(&tmp)
- << " failed initialization: "
- << self->GetException()->Dump();
+ // We want to LOG(FATAL) on debug builds since this really shouldn't be happening but we need to
+ // make sure to only do it if we don't have AsyncExceptions being thrown around since those
+ // could have caused the error.
+ bool known_impossible = kIsDebugBuild && !Runtime::Current()->AreAsyncExceptionsThrown();
+ LOG(known_impossible ? FATAL : WARNING) << klass->GetDescriptor(&tmp)
+ << " failed initialization: "
+ << self->GetException()->Dump();
}
env->ExceptionClear();
@@ -1828,21 +1832,6 @@ bool ClassLinker::AddImageSpace(
header.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_);
}
- if (!app_image) {
- // Make the string intern table and class table immutable for boot image.
- // PIC app oat files may mmap a read-only copy into their own .bss section,
- // so enforce that the data in the boot image tables remains unchanged.
- //
- // We cannot do that for app image even after the fixup as some interned
- // String references may actually end up pointing to moveable Strings.
- uint8_t* const_section_begin = space->Begin() + header.GetBootImageConstantTablesOffset();
- CheckedCall(mprotect,
- "protect constant tables",
- const_section_begin,
- header.GetBootImageConstantTablesSize(),
- PROT_READ);
- }
-
ClassTable* class_table = nullptr;
{
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
@@ -3390,9 +3379,10 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
CHECK_EQ(dex_cache_location, dex_file_suffix);
const OatFile* oat_file =
(dex_file.GetOatDexFile() != nullptr) ? dex_file.GetOatDexFile()->GetOatFile() : nullptr;
- // Clean up pass to remove null dex caches. Also check if we need to initialize OatFile .bss.
- // Null dex caches can occur due to class unloading and we are lazily removing null entries.
- bool initialize_oat_file_bss = (oat_file != nullptr);
+ // Clean up pass to remove null dex caches; null dex caches can occur due to class unloading
+ // and we are lazily removing null entries. Also check if we need to initialize OatFile data
+ // (.data.bimg.rel.ro and .bss sections) needed for code execution.
+ bool initialize_oat_file_data = (oat_file != nullptr) && oat_file->IsExecutable();
JavaVMExt* const vm = self->GetJniEnv()->GetVm();
for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) {
DexCacheData data = *it;
@@ -3400,15 +3390,36 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
vm->DeleteWeakGlobalRef(self, data.weak_root);
it = dex_caches_.erase(it);
} else {
- if (initialize_oat_file_bss &&
+ if (initialize_oat_file_data &&
it->dex_file->GetOatDexFile() != nullptr &&
it->dex_file->GetOatDexFile()->GetOatFile() == oat_file) {
- initialize_oat_file_bss = false; // Already initialized.
+ initialize_oat_file_data = false; // Already initialized.
}
++it;
}
}
- if (initialize_oat_file_bss) {
+ if (initialize_oat_file_data) {
+ // Initialize the .data.bimg.rel.ro section.
+ if (!oat_file->GetBootImageRelocations().empty()) {
+ uint8_t* reloc_begin = const_cast<uint8_t*>(oat_file->DataBimgRelRoBegin());
+ CheckedCall(mprotect,
+ "un-protect boot image relocations",
+ reloc_begin,
+ oat_file->DataBimgRelRoSize(),
+ PROT_READ | PROT_WRITE);
+ uint32_t boot_image_begin = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(
+ Runtime::Current()->GetHeap()->GetBootImageSpaces().front()->Begin()));
+ for (const uint32_t& relocation : oat_file->GetBootImageRelocations()) {
+ const_cast<uint32_t&>(relocation) += boot_image_begin;
+ }
+ CheckedCall(mprotect,
+ "protect boot image relocations",
+ reloc_begin,
+ oat_file->DataBimgRelRoSize(),
+ PROT_READ);
+ }
+
+ // Initialize the .bss section.
// TODO: Pre-initialize from boot/app image?
ArtMethod* resolution_method = Runtime::Current()->GetResolutionMethod();
for (ArtMethod*& entry : oat_file->GetBssMethods()) {
@@ -6169,7 +6180,7 @@ ArtMethod* ClassLinker::AddMethodToConflictTable(ObjPtr<mirror::Class> klass,
// Note that there is a race in the presence of multiple threads and we may leak
// memory from the LinearAlloc, but that's a tradeoff compared to using
// atomic operations.
- QuasiAtomic::ThreadFenceRelease();
+ std::atomic_thread_fence(std::memory_order_release);
new_conflict_method->SetImtConflictTable(new_table, image_pointer_size_);
return new_conflict_method;
}
@@ -8225,29 +8236,34 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
DexFile::MethodHandleType handle_type =
static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_);
mirror::MethodHandle::Kind kind;
+ bool is_put;
bool is_static;
int32_t num_params;
switch (handle_type) {
case DexFile::MethodHandleType::kStaticPut: {
kind = mirror::MethodHandle::Kind::kStaticPut;
+ is_put = true;
is_static = true;
num_params = 1;
break;
}
case DexFile::MethodHandleType::kStaticGet: {
kind = mirror::MethodHandle::Kind::kStaticGet;
+ is_put = false;
is_static = true;
num_params = 0;
break;
}
case DexFile::MethodHandleType::kInstancePut: {
kind = mirror::MethodHandle::Kind::kInstancePut;
+ is_put = true;
is_static = false;
num_params = 2;
break;
}
case DexFile::MethodHandleType::kInstanceGet: {
kind = mirror::MethodHandle::Kind::kInstanceGet;
+ is_put = false;
is_static = false;
num_params = 1;
break;
@@ -8269,6 +8285,10 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
ThrowIllegalAccessErrorField(referring_class, target_field);
return nullptr;
}
+ if (UNLIKELY(is_put && target_field->IsFinal())) {
+ ThrowIllegalAccessErrorField(referring_class, target_field);
+ return nullptr;
+ }
} else {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8849,6 +8869,15 @@ void ClassLinker::VisitClassLoaders(ClassLoaderVisitor* visitor) const {
}
}
+void ClassLinker::VisitAllocators(AllocatorVisitor* visitor) const {
+ for (const ClassLoaderData& data : class_loaders_) {
+ LinearAlloc* alloc = data.allocator;
+ if (alloc != nullptr && !visitor->Visit(alloc)) {
+ break;
+ }
+ }
+}
+
void ClassLinker::InsertDexFileInToClassLoader(ObjPtr<mirror::Object> dex_file,
ObjPtr<mirror::ClassLoader> class_loader) {
DCHECK(dex_file != nullptr);