bool AotClassLinker::CanAllocClass() { // AllocClass doesn't work under transaction, so we abort. if (IsActiveTransaction()) {
AbortTransactionF(Thread::Current(), "Can't resolve type within transaction."); returnfalse;
} return ClassLinker::CanAllocClass();
}
// Wrap the original InitializeClass with creation of transaction when in strict mode. bool AotClassLinker::InitializeClass(Thread* self,
Handle<mirror::Class> klass, bool can_init_statics, bool can_init_parents) { bool strict_mode = IsActiveStrictTransactionMode();
// When compiling a boot image extension, do not initialize a class defined // in a dex file belonging to the boot image we're compiling against. // However, we must allow the initialization of TransactionAbortError, // VerifyError, etc. outside of a transaction. if (!strict_mode &&
Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass->GetDexCache())) { if (IsActiveTransaction()) {
AbortTransactionF(self, "Can't initialize %s because it is defined in a boot image dex file.",
klass->PrettyTypeOf().c_str()); returnfalse;
}
CHECK(klass->IsThrowableClass()) << klass->PrettyDescriptor();
}
// When in strict_mode, don't initialize a class if it belongs to boot but not initialized. if (strict_mode && klass->IsBootStrapClassLoaded()) {
AbortTransactionF(self, "Can't resolve %s because it is an uninitialized boot class.",
klass->PrettyTypeOf().c_str()); returnfalse;
}
// Don't initialize klass if it's superclass is not initialized, because superclass might abort // the transaction and rolled back after klass's change is commited. if (strict_mode && !klass->IsInterface() && klass->HasSuperClass()) { if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) {
AbortTransactionF(self, "Can't resolve %s because it's superclass is not initialized.",
klass->PrettyTypeOf().c_str()); returnfalse;
}
}
if (strict_mode) { if (success) { // Exit Transaction if success.
ExitTransactionMode();
} else { // If not successfully initialized, don't rollback immediately, leave the cleanup to compiler // driver which needs abort message and exception.
DCHECK(self->IsExceptionPending());
}
} return success;
}
verifier::FailureKind AotClassLinker::PerformClassVerification(
Thread* self,
verifier::VerifierDeps* verifier_deps,
Handle<mirror::Class> klass,
verifier::HardFailLogMode log_level,
std::string* error_msg) {
Runtime* const runtime = Runtime::Current();
CompilerCallbacks* callbacks = runtime->GetCompilerCallbacks();
ClassStatus old_status = callbacks->GetPreviousClassState(
ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex())); // Was it verified? Report no failure. if (old_status >= ClassStatus::kVerified) { return verifier::FailureKind::kNoFailure;
} if (old_status >= ClassStatus::kVerifiedNeedsAccessChecks) { return verifier::FailureKind::kAccessChecksFailure;
} // Does it need to be verified at runtime? Report soft failure. if (old_status >= ClassStatus::kRetryVerificationAtRuntime) { // Error messages from here are only reported through -verbose:class. It is not worth it to // create a message. return verifier::FailureKind::kSoftFailure;
} // Do the actual work. return ClassLinker::PerformClassVerification(self, verifier_deps, klass, log_level, error_msg);
}
bool AotClassLinker::CanReferenceInBootImageExtensionOrAppImage(
ObjPtr<mirror::Class> klass, gc::Heap* heap) { // Do not allow referencing a class or instance of a class defined in a dex file // belonging to the boot image we're compiling against but not itself in the boot image; // or a class referencing such classes as component type, superclass or interface. // Allowing this could yield duplicate class objects from multiple images.
if (heap->ObjectIsInBootImageSpace(klass)) { returntrue; // Already included in the boot image we're compiling against.
}
// Treat arrays and primitive types specially because they do not have a DexCache that we // can use to check whether the dex file belongs to the boot image we're compiling against.
DCHECK(!klass->IsPrimitive()); // Primitive classes must be in the primary boot image. if (klass->IsArrayClass()) {
DCHECK(heap->ObjectIsInBootImageSpace(klass->GetIfTable())); // IfTable is OK. // Arrays of all dimensions are tied to the dex file of the non-array component type. do {
klass = klass->GetComponentType();
} while (klass->IsArrayClass()); if (klass->IsPrimitive()) { returnfalse;
} // Do not allow arrays of erroneous classes (the array class is not itself erroneous). if (klass->IsErroneous()) { returnfalse;
}
}
auto can_reference_dex_cache = [&](ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) { // We cannot reference a boot image dex cache for classes // that were not themselves in the boot image. if (heap->ObjectIsInBootImageSpace(dex_cache)) { returnfalse;
} // App image compilation can pull in dex files from parent or library class loaders. // Classes from such dex files cannot be included or referenced in the current app image // to avoid conflicts with classes in the parent or library class loader's app image. if (gAppImageDexFiles != nullptr &&
!ContainsElement(*gAppImageDexFiles, dex_cache->GetDexFile())) { returnfalse;
} returntrue;
};
// Check the class itself. if (!can_reference_dex_cache(klass->GetDexCache())) { returnfalse;
}
// Check superclasses.
ObjPtr<mirror::Class> superclass = klass->GetSuperClass(); while (!heap->ObjectIsInBootImageSpace(superclass)) {
DCHECK(superclass != nullptr); // Cannot skip Object which is in the primary boot image. if (!can_reference_dex_cache(superclass->GetDexCache())) { returnfalse;
}
superclass = superclass->GetSuperClass();
}
// Check IfTable. This includes direct and indirect interfaces.
ObjPtr<mirror::IfTable> if_table = klass->GetIfTable(); for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
ObjPtr<mirror::Class> interface = if_table->GetInterface(i);
DCHECK(interface != nullptr); if (!heap->ObjectIsInBootImageSpace(interface) &&
!can_reference_dex_cache(interface->GetDexCache())) { returnfalse;
}
}
if (kIsDebugBuild) { // All virtual methods must come from classes we have already checked above.
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
ObjPtr<mirror::Class> k = klass; while (!heap->ObjectIsInBootImageSpace(k)) { for (auto& m : k->GetMethods(pointer_size)) { if (m.IsVirtual()) {
ObjPtr<mirror::Class> declaring_class = m.GetDeclaringClass();
CHECK(heap->ObjectIsInBootImageSpace(declaring_class) ||
can_reference_dex_cache(declaring_class->GetDexCache()));
}
}
k = k->GetSuperClass();
}
}
void AotClassLinker::EnterTransactionMode(bool strict, mirror::Class* root) {
Runtime* runtime = Runtime::Current();
ArenaPool* arena_pool = nullptr;
ArenaStack* arena_stack = nullptr; if (preinitialization_transactions_.empty()) { // Top-level transaction? // Make initialized classes visibly initialized now. If that happened during the transaction // and then the transaction was aborted, we would roll back the status update but not the // ClassLinker's bookkeeping structures, so these classes would never be visibly initialized.
{
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
HandleWrapper<mirror::Class> h(hs.NewHandleWrapper(&root));
ScopedThreadSuspension sts(self, ThreadState::kNative);
MakeInitializedClassesVisiblyInitialized(Thread::Current(), /*wait=*/ true);
} // Pass the runtime `ArenaPool` to the transaction.
arena_pool = runtime->GetArenaPool();
} else { // Pass the `ArenaStack` from previous transaction to the new one.
arena_stack = preinitialization_transactions_.front().GetArenaStack();
}
preinitialization_transactions_.emplace_front(strict, root, arena_stack, arena_pool);
runtime->SetActiveTransaction();
}
void AotClassLinker::ExitTransactionMode() {
DCHECK(IsActiveTransaction());
preinitialization_transactions_.pop_front(); if (preinitialization_transactions_.empty()) {
Runtime::Current()->ClearActiveTransaction();
} else {
DCHECK(IsActiveTransaction()); // Trigger the DCHECK() in `IsActiveTransaction()`.
}
}
void AotClassLinker::RollbackAllTransactions() { // If transaction is aborted, all transactions will be kept in the list. // Rollback and exit all of them. while (IsActiveTransaction()) {
RollbackAndExitTransactionMode();
}
}
bool AotClassLinker::TransactionReadConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
DCHECK(obj->IsClass()); if (GetTransaction()->ReadConstraint(obj)) {
AbortTransactionF(self, "Can't read static fields of %s since it does not belong to clinit's class.",
obj->PrettyTypeOf().c_str()); returntrue;
} returnfalse;
}
void AotClassLinker::ThrowTransactionAbortError(Thread* self) {
DCHECK(IsActiveTransaction()); // Passing nullptr means we rethrow an exception with the earlier transaction abort message.
GetTransaction()->ThrowAbortError(self, nullptr);
}
void AotClassLinker::AbortTransactionV(Thread* self, constchar* fmt, va_list args) {
CHECK(IsActiveTransaction()); // Constructs abort message.
std::string abort_message;
android::base::StringAppendV(&abort_message, fmt, args); // Throws an exception so we can abort the transaction and rollback every change. // // Throwing an exception may cause its class initialization. If we mark the transaction // aborted before that, we may warn with a false alarm. Throwing the exception before // marking the transaction aborted avoids that. // But now the transaction can be nested, and abort the transaction will relax the constraints // for constructing stack trace.
GetTransaction()->Abort(abort_message);
GetTransaction()->ThrowAbortError(self, &abort_message);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.