xref: /aosp_15_r20/art/dex2oat/aot_class_linker.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "aot_class_linker.h"
18 
19 #include "base/stl_util.h"
20 #include "class_status.h"
21 #include "compiler_callbacks.h"
22 #include "dex/class_reference.h"
23 #include "gc/heap.h"
24 #include "handle_scope-inl.h"
25 #include "interpreter/interpreter_switch_impl.h"
26 #include "mirror/class-inl.h"
27 #include "runtime.h"
28 #include "scoped_thread_state_change-inl.h"
29 #include "transaction.h"
30 #include "verifier/verifier_enums.h"
31 
32 namespace art HIDDEN {
33 
AotClassLinker(InternTable * intern_table)34 AotClassLinker::AotClassLinker(InternTable* intern_table)
35     : ClassLinker(intern_table, /*fast_class_not_found_exceptions=*/ false),
36       preinitialization_transactions_() {}
37 
~AotClassLinker()38 AotClassLinker::~AotClassLinker() {}
39 
CanAllocClass()40 bool AotClassLinker::CanAllocClass() {
41   // AllocClass doesn't work under transaction, so we abort.
42   if (IsActiveTransaction()) {
43     AbortTransactionF(Thread::Current(), "Can't resolve type within transaction.");
44     return false;
45   }
46   return ClassLinker::CanAllocClass();
47 }
48 
49 // Wrap the original InitializeClass with creation of transaction when in strict mode.
InitializeClass(Thread * self,Handle<mirror::Class> klass,bool can_init_statics,bool can_init_parents)50 bool AotClassLinker::InitializeClass(Thread* self,
51                                      Handle<mirror::Class> klass,
52                                      bool can_init_statics,
53                                      bool can_init_parents) {
54   bool strict_mode = IsActiveStrictTransactionMode();
55 
56   DCHECK(klass != nullptr);
57   if (klass->IsInitialized() || klass->IsInitializing()) {
58     return ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents);
59   }
60 
61   // When compiling a boot image extension, do not initialize a class defined
62   // in a dex file belonging to the boot image we're compiling against.
63   // However, we must allow the initialization of TransactionAbortError,
64   // VerifyError, etc. outside of a transaction.
65   if (!strict_mode &&
66       Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass->GetDexCache())) {
67     if (IsActiveTransaction()) {
68       AbortTransactionF(self,
69                         "Can't initialize %s because it is defined in a boot image dex file.",
70                         klass->PrettyTypeOf().c_str());
71       return false;
72     }
73     CHECK(klass->IsThrowableClass()) << klass->PrettyDescriptor();
74   }
75 
76   // When in strict_mode, don't initialize a class if it belongs to boot but not initialized.
77   if (strict_mode && klass->IsBootStrapClassLoaded()) {
78     AbortTransactionF(self,
79                       "Can't resolve %s because it is an uninitialized boot class.",
80                       klass->PrettyTypeOf().c_str());
81     return false;
82   }
83 
84   // Don't initialize klass if it's superclass is not initialized, because superclass might abort
85   // the transaction and rolled back after klass's change is commited.
86   if (strict_mode && !klass->IsInterface() && klass->HasSuperClass()) {
87     if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) {
88       AbortTransactionF(self,
89                         "Can't resolve %s because it's superclass is not initialized.",
90                         klass->PrettyTypeOf().c_str());
91       return false;
92     }
93   }
94 
95   if (strict_mode) {
96     EnterTransactionMode(/*strict=*/ true, klass.Get());
97   }
98   bool success = ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents);
99 
100   if (strict_mode) {
101     if (success) {
102       // Exit Transaction if success.
103       ExitTransactionMode();
104     } else {
105       // If not successfully initialized, don't rollback immediately, leave the cleanup to compiler
106       // driver which needs abort message and exception.
107       DCHECK(self->IsExceptionPending());
108     }
109   }
110   return success;
111 }
112 
PerformClassVerification(Thread * self,verifier::VerifierDeps * verifier_deps,Handle<mirror::Class> klass,verifier::HardFailLogMode log_level,std::string * error_msg)113 verifier::FailureKind AotClassLinker::PerformClassVerification(
114     Thread* self,
115     verifier::VerifierDeps* verifier_deps,
116     Handle<mirror::Class> klass,
117     verifier::HardFailLogMode log_level,
118     std::string* error_msg) {
119   Runtime* const runtime = Runtime::Current();
120   CompilerCallbacks* callbacks = runtime->GetCompilerCallbacks();
121   ClassStatus old_status = callbacks->GetPreviousClassState(
122       ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex()));
123   // Was it verified? Report no failure.
124   if (old_status >= ClassStatus::kVerified) {
125     return verifier::FailureKind::kNoFailure;
126   }
127   if (old_status >= ClassStatus::kVerifiedNeedsAccessChecks) {
128     return verifier::FailureKind::kAccessChecksFailure;
129   }
130   // Does it need to be verified at runtime? Report soft failure.
131   if (old_status >= ClassStatus::kRetryVerificationAtRuntime) {
132     // Error messages from here are only reported through -verbose:class. It is not worth it to
133     // create a message.
134     return verifier::FailureKind::kSoftFailure;
135   }
136   // Do the actual work.
137   return ClassLinker::PerformClassVerification(self, verifier_deps, klass, log_level, error_msg);
138 }
139 
140 static const std::vector<const DexFile*>* gAppImageDexFiles = nullptr;
141 
SetAppImageDexFiles(const std::vector<const DexFile * > * app_image_dex_files)142 void AotClassLinker::SetAppImageDexFiles(const std::vector<const DexFile*>* app_image_dex_files) {
143   gAppImageDexFiles = app_image_dex_files;
144 }
145 
CanReferenceInBootImageExtensionOrAppImage(ObjPtr<mirror::Class> klass,gc::Heap * heap)146 bool AotClassLinker::CanReferenceInBootImageExtensionOrAppImage(
147     ObjPtr<mirror::Class> klass, gc::Heap* heap) {
148   // Do not allow referencing a class or instance of a class defined in a dex file
149   // belonging to the boot image we're compiling against but not itself in the boot image;
150   // or a class referencing such classes as component type, superclass or interface.
151   // Allowing this could yield duplicate class objects from multiple images.
152 
153   if (heap->ObjectIsInBootImageSpace(klass)) {
154     return true;  // Already included in the boot image we're compiling against.
155   }
156 
157   // Treat arrays and primitive types specially because they do not have a DexCache that we
158   // can use to check whether the dex file belongs to the boot image we're compiling against.
159   DCHECK(!klass->IsPrimitive());  // Primitive classes must be in the primary boot image.
160   if (klass->IsArrayClass()) {
161     DCHECK(heap->ObjectIsInBootImageSpace(klass->GetIfTable()));  // IfTable is OK.
162     // Arrays of all dimensions are tied to the dex file of the non-array component type.
163     do {
164       klass = klass->GetComponentType();
165     } while (klass->IsArrayClass());
166     if (klass->IsPrimitive()) {
167       return false;
168     }
169     // Do not allow arrays of erroneous classes (the array class is not itself erroneous).
170     if (klass->IsErroneous()) {
171       return false;
172     }
173   }
174 
175   auto can_reference_dex_cache = [&](ObjPtr<mirror::DexCache> dex_cache)
176       REQUIRES_SHARED(Locks::mutator_lock_) {
177     // We cannot reference a boot image dex cache for classes
178     // that were not themselves in the boot image.
179     if (heap->ObjectIsInBootImageSpace(dex_cache)) {
180       return false;
181     }
182     // App image compilation can pull in dex files from parent or library class loaders.
183     // Classes from such dex files cannot be included or referenced in the current app image
184     // to avoid conflicts with classes in the parent or library class loader's app image.
185     if (gAppImageDexFiles != nullptr &&
186         !ContainsElement(*gAppImageDexFiles, dex_cache->GetDexFile())) {
187       return false;
188     }
189     return true;
190   };
191 
192   // Check the class itself.
193   if (!can_reference_dex_cache(klass->GetDexCache())) {
194     return false;
195   }
196 
197   // Check superclasses.
198   ObjPtr<mirror::Class> superclass = klass->GetSuperClass();
199   while (!heap->ObjectIsInBootImageSpace(superclass)) {
200     DCHECK(superclass != nullptr);  // Cannot skip Object which is in the primary boot image.
201     if (!can_reference_dex_cache(superclass->GetDexCache())) {
202       return false;
203     }
204     superclass = superclass->GetSuperClass();
205   }
206 
207   // Check IfTable. This includes direct and indirect interfaces.
208   ObjPtr<mirror::IfTable> if_table = klass->GetIfTable();
209   for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
210     ObjPtr<mirror::Class> interface = if_table->GetInterface(i);
211     DCHECK(interface != nullptr);
212     if (!heap->ObjectIsInBootImageSpace(interface) &&
213         !can_reference_dex_cache(interface->GetDexCache())) {
214       return false;
215     }
216   }
217 
218   if (kIsDebugBuild) {
219     // All virtual methods must come from classes we have already checked above.
220     PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
221     ObjPtr<mirror::Class> k = klass;
222     while (!heap->ObjectIsInBootImageSpace(k)) {
223       for (auto& m : k->GetVirtualMethods(pointer_size)) {
224         ObjPtr<mirror::Class> declaring_class = m.GetDeclaringClass();
225         CHECK(heap->ObjectIsInBootImageSpace(declaring_class) ||
226               can_reference_dex_cache(declaring_class->GetDexCache()));
227       }
228       k = k->GetSuperClass();
229     }
230   }
231 
232   return true;
233 }
234 
SetSdkChecker(std::unique_ptr<SdkChecker> && sdk_checker)235 void AotClassLinker::SetSdkChecker(std::unique_ptr<SdkChecker>&& sdk_checker) {
236   sdk_checker_ = std::move(sdk_checker);
237 }
238 
GetSdkChecker() const239 const SdkChecker* AotClassLinker::GetSdkChecker() const {
240   return sdk_checker_.get();
241 }
242 
DenyAccessBasedOnPublicSdk(ArtMethod * art_method) const243 bool AotClassLinker::DenyAccessBasedOnPublicSdk(ArtMethod* art_method) const {
244   return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(art_method);
245 }
DenyAccessBasedOnPublicSdk(ArtField * art_field) const246 bool AotClassLinker::DenyAccessBasedOnPublicSdk(ArtField* art_field) const {
247   return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(art_field);
248 }
DenyAccessBasedOnPublicSdk(std::string_view type_descriptor) const249 bool AotClassLinker::DenyAccessBasedOnPublicSdk(std::string_view type_descriptor) const {
250   return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(type_descriptor);
251 }
252 
SetEnablePublicSdkChecks(bool enabled)253 void AotClassLinker::SetEnablePublicSdkChecks(bool enabled) {
254   if (sdk_checker_ != nullptr) {
255     sdk_checker_->SetEnabled(enabled);
256   }
257 }
258 
259 // Transaction support.
260 
IsActiveTransaction() const261 bool AotClassLinker::IsActiveTransaction() const {
262   bool result = Runtime::Current()->IsActiveTransaction();
263   DCHECK_EQ(result, !preinitialization_transactions_.empty() && !GetTransaction()->IsRollingBack());
264   return result;
265 }
266 
EnterTransactionMode(bool strict,mirror::Class * root)267 void AotClassLinker::EnterTransactionMode(bool strict, mirror::Class* root) {
268   Runtime* runtime = Runtime::Current();
269   ArenaPool* arena_pool = nullptr;
270   ArenaStack* arena_stack = nullptr;
271   if (preinitialization_transactions_.empty()) {  // Top-level transaction?
272     // Make initialized classes visibly initialized now. If that happened during the transaction
273     // and then the transaction was aborted, we would roll back the status update but not the
274     // ClassLinker's bookkeeping structures, so these classes would never be visibly initialized.
275     {
276       Thread* self = Thread::Current();
277       StackHandleScope<1> hs(self);
278       HandleWrapper<mirror::Class> h(hs.NewHandleWrapper(&root));
279       ScopedThreadSuspension sts(self, ThreadState::kNative);
280       MakeInitializedClassesVisiblyInitialized(Thread::Current(), /*wait=*/ true);
281     }
282     // Pass the runtime `ArenaPool` to the transaction.
283     arena_pool = runtime->GetArenaPool();
284   } else {
285     // Pass the `ArenaStack` from previous transaction to the new one.
286     arena_stack = preinitialization_transactions_.front().GetArenaStack();
287   }
288   preinitialization_transactions_.emplace_front(strict, root, arena_stack, arena_pool);
289   runtime->SetActiveTransaction();
290 }
291 
ExitTransactionMode()292 void AotClassLinker::ExitTransactionMode() {
293   DCHECK(IsActiveTransaction());
294   preinitialization_transactions_.pop_front();
295   if (preinitialization_transactions_.empty()) {
296     Runtime::Current()->ClearActiveTransaction();
297   } else {
298     DCHECK(IsActiveTransaction());  // Trigger the DCHECK() in `IsActiveTransaction()`.
299   }
300 }
301 
RollbackAllTransactions()302 void AotClassLinker::RollbackAllTransactions() {
303   // If transaction is aborted, all transactions will be kept in the list.
304   // Rollback and exit all of them.
305   while (IsActiveTransaction()) {
306     RollbackAndExitTransactionMode();
307   }
308 }
309 
RollbackAndExitTransactionMode()310 void AotClassLinker::RollbackAndExitTransactionMode() {
311   DCHECK(IsActiveTransaction());
312   Runtime::Current()->ClearActiveTransaction();
313   preinitialization_transactions_.front().Rollback();
314   preinitialization_transactions_.pop_front();
315   if (!preinitialization_transactions_.empty()) {
316     Runtime::Current()->SetActiveTransaction();
317   }
318 }
319 
GetTransaction() const320 const Transaction* AotClassLinker::GetTransaction() const {
321   DCHECK(!preinitialization_transactions_.empty());
322   return &preinitialization_transactions_.front();
323 }
324 
GetTransaction()325 Transaction* AotClassLinker::GetTransaction() {
326   DCHECK(!preinitialization_transactions_.empty());
327   return &preinitialization_transactions_.front();
328 }
329 
IsActiveStrictTransactionMode() const330 bool AotClassLinker::IsActiveStrictTransactionMode() const {
331   return IsActiveTransaction() && GetTransaction()->IsStrict();
332 }
333 
TransactionWriteConstraint(Thread * self,ObjPtr<mirror::Object> obj)334 bool AotClassLinker::TransactionWriteConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
335   DCHECK(IsActiveTransaction());
336   if (GetTransaction()->WriteConstraint(obj)) {
337     Runtime* runtime = Runtime::Current();
338     DCHECK(runtime->GetHeap()->ObjectIsInBootImageSpace(obj) || obj->IsClass());
339     const char* extra = runtime->GetHeap()->ObjectIsInBootImageSpace(obj) ? "boot image " : "";
340     AbortTransactionF(
341         self, "Can't set fields of %s%s", extra, obj->PrettyTypeOf().c_str());
342     return true;
343   }
344   return false;
345 }
346 
TransactionWriteValueConstraint(Thread * self,ObjPtr<mirror::Object> value)347 bool AotClassLinker::TransactionWriteValueConstraint(Thread* self, ObjPtr<mirror::Object> value) {
348   DCHECK(IsActiveTransaction());
349   if (GetTransaction()->WriteValueConstraint(value)) {
350     DCHECK(value != nullptr);
351     const char* description = value->IsClass() ? "class" : "instance of";
352     ObjPtr<mirror::Class> klass = value->IsClass() ? value->AsClass() : value->GetClass();
353     AbortTransactionF(
354         self, "Can't store reference to %s %s", description, klass->PrettyDescriptor().c_str());
355     return true;
356   }
357   return false;
358 }
359 
TransactionReadConstraint(Thread * self,ObjPtr<mirror::Object> obj)360 bool AotClassLinker::TransactionReadConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
361   DCHECK(obj->IsClass());
362   if (GetTransaction()->ReadConstraint(obj)) {
363     AbortTransactionF(self,
364                       "Can't read static fields of %s since it does not belong to clinit's class.",
365                       obj->PrettyTypeOf().c_str());
366     return true;
367   }
368   return false;
369 }
370 
TransactionAllocationConstraint(Thread * self,ObjPtr<mirror::Class> klass)371 bool AotClassLinker::TransactionAllocationConstraint(Thread* self, ObjPtr<mirror::Class> klass) {
372   DCHECK(IsActiveTransaction());
373   if (klass->IsFinalizable()) {
374     AbortTransactionF(self,
375                       "Allocating finalizable object in transaction: %s",
376                       klass->PrettyDescriptor().c_str());
377     return true;
378   }
379   return false;
380 }
381 
RecordWriteFieldBoolean(mirror::Object * obj,MemberOffset field_offset,uint8_t value,bool is_volatile)382 void AotClassLinker::RecordWriteFieldBoolean(mirror::Object* obj,
383                                              MemberOffset field_offset,
384                                              uint8_t value,
385                                              bool is_volatile) {
386   DCHECK(IsActiveTransaction());
387   GetTransaction()->RecordWriteFieldBoolean(obj, field_offset, value, is_volatile);
388 }
389 
RecordWriteFieldByte(mirror::Object * obj,MemberOffset field_offset,int8_t value,bool is_volatile)390 void AotClassLinker::RecordWriteFieldByte(mirror::Object* obj,
391                                           MemberOffset field_offset,
392                                           int8_t value,
393                                           bool is_volatile) {
394   DCHECK(IsActiveTransaction());
395   GetTransaction()->RecordWriteFieldByte(obj, field_offset, value, is_volatile);
396 }
397 
RecordWriteFieldChar(mirror::Object * obj,MemberOffset field_offset,uint16_t value,bool is_volatile)398 void AotClassLinker::RecordWriteFieldChar(mirror::Object* obj,
399                                           MemberOffset field_offset,
400                                           uint16_t value,
401                                           bool is_volatile) {
402   DCHECK(IsActiveTransaction());
403   GetTransaction()->RecordWriteFieldChar(obj, field_offset, value, is_volatile);
404 }
405 
RecordWriteFieldShort(mirror::Object * obj,MemberOffset field_offset,int16_t value,bool is_volatile)406 void AotClassLinker::RecordWriteFieldShort(mirror::Object* obj,
407                                            MemberOffset field_offset,
408                                            int16_t value,
409                                            bool is_volatile) {
410   DCHECK(IsActiveTransaction());
411   GetTransaction()->RecordWriteFieldShort(obj, field_offset, value, is_volatile);
412 }
413 
RecordWriteField32(mirror::Object * obj,MemberOffset field_offset,uint32_t value,bool is_volatile)414 void AotClassLinker::RecordWriteField32(mirror::Object* obj,
415                                         MemberOffset field_offset,
416                                         uint32_t value,
417                                         bool is_volatile) {
418   DCHECK(IsActiveTransaction());
419   GetTransaction()->RecordWriteField32(obj, field_offset, value, is_volatile);
420 }
421 
RecordWriteField64(mirror::Object * obj,MemberOffset field_offset,uint64_t value,bool is_volatile)422 void AotClassLinker::RecordWriteField64(mirror::Object* obj,
423                                         MemberOffset field_offset,
424                                         uint64_t value,
425                                         bool is_volatile) {
426   DCHECK(IsActiveTransaction());
427   GetTransaction()->RecordWriteField64(obj, field_offset, value, is_volatile);
428 }
429 
RecordWriteFieldReference(mirror::Object * obj,MemberOffset field_offset,ObjPtr<mirror::Object> value,bool is_volatile)430 void AotClassLinker::RecordWriteFieldReference(mirror::Object* obj,
431                                                MemberOffset field_offset,
432                                                ObjPtr<mirror::Object> value,
433                                                bool is_volatile) {
434   DCHECK(IsActiveTransaction());
435   GetTransaction()->RecordWriteFieldReference(obj, field_offset, value.Ptr(), is_volatile);
436 }
437 
RecordWriteArray(mirror::Array * array,size_t index,uint64_t value)438 void AotClassLinker::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
439   DCHECK(IsActiveTransaction());
440   GetTransaction()->RecordWriteArray(array, index, value);
441 }
442 
RecordStrongStringInsertion(ObjPtr<mirror::String> s)443 void AotClassLinker::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
444   DCHECK(IsActiveTransaction());
445   GetTransaction()->RecordStrongStringInsertion(s);
446 }
447 
RecordWeakStringInsertion(ObjPtr<mirror::String> s)448 void AotClassLinker::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
449   DCHECK(IsActiveTransaction());
450   GetTransaction()->RecordWeakStringInsertion(s);
451 }
452 
RecordStrongStringRemoval(ObjPtr<mirror::String> s)453 void AotClassLinker::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
454   DCHECK(IsActiveTransaction());
455   GetTransaction()->RecordStrongStringRemoval(s);
456 }
457 
RecordWeakStringRemoval(ObjPtr<mirror::String> s)458 void AotClassLinker::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
459   DCHECK(IsActiveTransaction());
460   GetTransaction()->RecordWeakStringRemoval(s);
461 }
462 
RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,dex::StringIndex string_idx)463 void AotClassLinker::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,
464                                          dex::StringIndex string_idx) {
465   DCHECK(IsActiveTransaction());
466   GetTransaction()->RecordResolveString(dex_cache, string_idx);
467 }
468 
RecordResolveMethodType(ObjPtr<mirror::DexCache> dex_cache,dex::ProtoIndex proto_idx)469 void AotClassLinker::RecordResolveMethodType(ObjPtr<mirror::DexCache> dex_cache,
470                                              dex::ProtoIndex proto_idx) {
471   DCHECK(IsActiveTransaction());
472   GetTransaction()->RecordResolveMethodType(dex_cache, proto_idx);
473 }
474 
ThrowTransactionAbortError(Thread * self)475 void AotClassLinker::ThrowTransactionAbortError(Thread* self) {
476   DCHECK(IsActiveTransaction());
477   // Passing nullptr means we rethrow an exception with the earlier transaction abort message.
478   GetTransaction()->ThrowAbortError(self, nullptr);
479 }
480 
AbortTransactionF(Thread * self,const char * fmt,...)481 void AotClassLinker::AbortTransactionF(Thread* self, const char* fmt, ...) {
482   va_list args;
483   va_start(args, fmt);
484   AbortTransactionV(self, fmt, args);
485   va_end(args);
486 }
487 
AbortTransactionV(Thread * self,const char * fmt,va_list args)488 void AotClassLinker::AbortTransactionV(Thread* self, const char* fmt, va_list args) {
489   CHECK(IsActiveTransaction());
490   // Constructs abort message.
491   std::string abort_message;
492   android::base::StringAppendV(&abort_message, fmt, args);
493   // Throws an exception so we can abort the transaction and rollback every change.
494   //
495   // Throwing an exception may cause its class initialization. If we mark the transaction
496   // aborted before that, we may warn with a false alarm. Throwing the exception before
497   // marking the transaction aborted avoids that.
498   // But now the transaction can be nested, and abort the transaction will relax the constraints
499   // for constructing stack trace.
500   GetTransaction()->Abort(abort_message);
501   GetTransaction()->ThrowAbortError(self, &abort_message);
502 }
503 
IsTransactionAborted() const504 bool AotClassLinker::IsTransactionAborted() const {
505   DCHECK(IsActiveTransaction());
506   return GetTransaction()->IsAborted();
507 }
508 
VisitTransactionRoots(RootVisitor * visitor)509 void AotClassLinker::VisitTransactionRoots(RootVisitor* visitor) {
510   for (Transaction& transaction : preinitialization_transactions_) {
511     transaction.VisitRoots(visitor);
512   }
513 }
514 
GetTransactionalInterpreter()515 const void* AotClassLinker::GetTransactionalInterpreter() {
516   return reinterpret_cast<const void*>(
517       &interpreter::ExecuteSwitchImplCpp</*transaction_active=*/ true>);
518 }
519 
520 }  // namespace art
521