1 /*
2  * Copyright (C) 2014 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 "transaction.h"
18 
19 #include <android-base/logging.h>
20 
21 #include "aot_class_linker.h"
22 #include "base/mutex-inl.h"
23 #include "base/stl_util.h"
24 #include "gc/accounting/card_table-inl.h"
25 #include "gc/heap.h"
26 #include "gc_root-inl.h"
27 #include "intern_table.h"
28 #include "mirror/class-inl.h"
29 #include "mirror/dex_cache-inl.h"
30 #include "mirror/object-inl.h"
31 #include "mirror/object_array-inl.h"
32 #include "obj_ptr-inl.h"
33 #include "runtime.h"
34 
35 #include <list>
36 
37 namespace art {
38 
39 // TODO: remove (only used for debugging purpose).
40 static constexpr bool kEnableTransactionStats = false;
41 
Transaction(bool strict,mirror::Class * root)42 Transaction::Transaction(bool strict, mirror::Class* root)
43     : log_lock_("transaction log lock", kTransactionLogLock),
44       aborted_(false),
45       rolling_back_(false),
46       heap_(Runtime::Current()->GetHeap()),
47       strict_(strict),
48       root_(root),
49       assert_no_new_records_reason_(nullptr) {
50   DCHECK(Runtime::Current()->IsAotCompiler());
51 }
52 
~Transaction()53 Transaction::~Transaction() {
54   if (kEnableTransactionStats) {
55     MutexLock mu(Thread::Current(), log_lock_);
56     size_t objects_count = object_logs_.size();
57     size_t field_values_count = 0;
58     for (const auto& it : object_logs_) {
59       field_values_count += it.second.Size();
60     }
61     size_t array_count = array_logs_.size();
62     size_t array_values_count = 0;
63     for (const auto& it : array_logs_) {
64       array_values_count += it.second.Size();
65     }
66     size_t intern_string_count = intern_string_logs_.size();
67     size_t resolve_string_count = resolve_string_logs_.size();
68     LOG(INFO) << "Transaction::~Transaction"
69               << ": objects_count=" << objects_count
70               << ", field_values_count=" << field_values_count
71               << ", array_count=" << array_count
72               << ", array_values_count=" << array_values_count
73               << ", intern_string_count=" << intern_string_count
74               << ", resolve_string_count=" << resolve_string_count;
75   }
76 }
77 
Abort(const std::string & abort_message)78 void Transaction::Abort(const std::string& abort_message) {
79   MutexLock mu(Thread::Current(), log_lock_);
80   // We may abort more than once if the exception thrown at the time of the
81   // previous abort has been caught during execution of a class initializer.
82   // We just keep the message of the first abort because it will cause the
83   // transaction to be rolled back anyway.
84   if (!aborted_) {
85     aborted_ = true;
86     abort_message_ = abort_message;
87   }
88 }
89 
ThrowAbortError(Thread * self,const std::string * abort_message)90 void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
91   const bool rethrow = (abort_message == nullptr);
92   if (kIsDebugBuild && rethrow) {
93     CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
94                        << " while transaction is not aborted";
95   }
96   if (rethrow) {
97     // Rethrow an exception with the earlier abort message stored in the transaction.
98     self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
99                                    GetAbortMessage().c_str());
100   } else {
101     // Throw an exception with the given abort message.
102     self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
103                                    abort_message->c_str());
104   }
105 }
106 
IsAborted()107 bool Transaction::IsAborted() {
108   MutexLock mu(Thread::Current(), log_lock_);
109   return aborted_;
110 }
111 
IsRollingBack()112 bool Transaction::IsRollingBack() {
113   return rolling_back_;
114 }
115 
GetAbortMessage()116 const std::string& Transaction::GetAbortMessage() {
117   MutexLock mu(Thread::Current(), log_lock_);
118   return abort_message_;
119 }
120 
WriteConstraint(Thread * self,ObjPtr<mirror::Object> obj)121 bool Transaction::WriteConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
122   DCHECK(obj != nullptr);
123   MutexLock mu(self, log_lock_);
124 
125   // Prevent changes in boot image spaces for app or boot image extension.
126   // For boot image there are no boot image spaces and this condition evaluates to false.
127   if (heap_->ObjectIsInBootImageSpace(obj)) {
128     return true;
129   }
130 
131   // For apps, also prevent writing to other classes.
132   return IsStrict() &&
133          obj->IsClass() &&  // no constraint updating instances or arrays
134          obj != root_;  // modifying other classes' static field, fail
135 }
136 
WriteValueConstraint(Thread * self,ObjPtr<mirror::Object> value)137 bool Transaction::WriteValueConstraint(Thread* self, ObjPtr<mirror::Object> value) {
138   if (value == nullptr) {
139     return false;  // We can always store null values.
140   }
141   gc::Heap* heap = Runtime::Current()->GetHeap();
142   MutexLock mu(self, log_lock_);
143   if (IsStrict()) {
144     // TODO: Should we restrict writes the same way as for boot image extension?
145     return false;
146   } else if (heap->GetBootImageSpaces().empty()) {
147     return false;  // No constraints for boot image.
148   } else {
149     // Boot image extension.
150     ObjPtr<mirror::Class> klass = value->IsClass() ? value->AsClass() : value->GetClass();
151     return !AotClassLinker::CanReferenceInBootImageExtension(klass, heap);
152   }
153 }
154 
ReadConstraint(Thread * self,ObjPtr<mirror::Object> obj)155 bool Transaction::ReadConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
156   // Read constraints are checked only for static field reads as there are
157   // no constraints on reading instance fields and array elements.
158   DCHECK(obj->IsClass());
159   MutexLock mu(self, log_lock_);
160   if (IsStrict()) {
161     return obj != root_;  // fail if not self-updating
162   } else {
163     // For boot image and boot image extension, allow reading any field.
164     return false;
165   }
166 }
167 
RecordWriteFieldBoolean(mirror::Object * obj,MemberOffset field_offset,uint8_t value,bool is_volatile)168 void Transaction::RecordWriteFieldBoolean(mirror::Object* obj,
169                                           MemberOffset field_offset,
170                                           uint8_t value,
171                                           bool is_volatile) {
172   DCHECK(obj != nullptr);
173   MutexLock mu(Thread::Current(), log_lock_);
174   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
175   ObjectLog& object_log = object_logs_[obj];
176   object_log.LogBooleanValue(field_offset, value, is_volatile);
177 }
178 
RecordWriteFieldByte(mirror::Object * obj,MemberOffset field_offset,int8_t value,bool is_volatile)179 void Transaction::RecordWriteFieldByte(mirror::Object* obj,
180                                        MemberOffset field_offset,
181                                        int8_t value,
182                                        bool is_volatile) {
183   DCHECK(obj != nullptr);
184   MutexLock mu(Thread::Current(), log_lock_);
185   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
186   ObjectLog& object_log = object_logs_[obj];
187   object_log.LogByteValue(field_offset, value, is_volatile);
188 }
189 
RecordWriteFieldChar(mirror::Object * obj,MemberOffset field_offset,uint16_t value,bool is_volatile)190 void Transaction::RecordWriteFieldChar(mirror::Object* obj,
191                                        MemberOffset field_offset,
192                                        uint16_t value,
193                                        bool is_volatile) {
194   DCHECK(obj != nullptr);
195   MutexLock mu(Thread::Current(), log_lock_);
196   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
197   ObjectLog& object_log = object_logs_[obj];
198   object_log.LogCharValue(field_offset, value, is_volatile);
199 }
200 
201 
RecordWriteFieldShort(mirror::Object * obj,MemberOffset field_offset,int16_t value,bool is_volatile)202 void Transaction::RecordWriteFieldShort(mirror::Object* obj,
203                                         MemberOffset field_offset,
204                                         int16_t value,
205                                         bool is_volatile) {
206   DCHECK(obj != nullptr);
207   MutexLock mu(Thread::Current(), log_lock_);
208   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
209   ObjectLog& object_log = object_logs_[obj];
210   object_log.LogShortValue(field_offset, value, is_volatile);
211 }
212 
213 
RecordWriteField32(mirror::Object * obj,MemberOffset field_offset,uint32_t value,bool is_volatile)214 void Transaction::RecordWriteField32(mirror::Object* obj,
215                                      MemberOffset field_offset,
216                                      uint32_t value,
217                                      bool is_volatile) {
218   DCHECK(obj != nullptr);
219   MutexLock mu(Thread::Current(), log_lock_);
220   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
221   ObjectLog& object_log = object_logs_[obj];
222   object_log.Log32BitsValue(field_offset, value, is_volatile);
223 }
224 
RecordWriteField64(mirror::Object * obj,MemberOffset field_offset,uint64_t value,bool is_volatile)225 void Transaction::RecordWriteField64(mirror::Object* obj,
226                                      MemberOffset field_offset,
227                                      uint64_t value,
228                                      bool is_volatile) {
229   DCHECK(obj != nullptr);
230   MutexLock mu(Thread::Current(), log_lock_);
231   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
232   ObjectLog& object_log = object_logs_[obj];
233   object_log.Log64BitsValue(field_offset, value, is_volatile);
234 }
235 
RecordWriteFieldReference(mirror::Object * obj,MemberOffset field_offset,mirror::Object * value,bool is_volatile)236 void Transaction::RecordWriteFieldReference(mirror::Object* obj,
237                                             MemberOffset field_offset,
238                                             mirror::Object* value,
239                                             bool is_volatile) {
240   DCHECK(obj != nullptr);
241   MutexLock mu(Thread::Current(), log_lock_);
242   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
243   ObjectLog& object_log = object_logs_[obj];
244   object_log.LogReferenceValue(field_offset, value, is_volatile);
245 }
246 
RecordWriteArray(mirror::Array * array,size_t index,uint64_t value)247 void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
248   DCHECK(array != nullptr);
249   DCHECK(array->IsArrayInstance());
250   DCHECK(!array->IsObjectArray());
251   MutexLock mu(Thread::Current(), log_lock_);
252   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
253   auto it = array_logs_.find(array);
254   if (it == array_logs_.end()) {
255     ArrayLog log;
256     it = array_logs_.emplace(array, std::move(log)).first;
257   }
258   it->second.LogValue(index, value);
259 }
260 
RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,dex::StringIndex string_idx)261 void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,
262                                       dex::StringIndex string_idx) {
263   DCHECK(dex_cache != nullptr);
264   DCHECK_LT(string_idx.index_, dex_cache->GetDexFile()->NumStringIds());
265   MutexLock mu(Thread::Current(), log_lock_);
266   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
267   resolve_string_logs_.emplace_back(dex_cache, string_idx);
268 }
269 
RecordStrongStringInsertion(ObjPtr<mirror::String> s)270 void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
271   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
272   LogInternedString(std::move(log));
273 }
274 
RecordWeakStringInsertion(ObjPtr<mirror::String> s)275 void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
276   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
277   LogInternedString(std::move(log));
278 }
279 
RecordStrongStringRemoval(ObjPtr<mirror::String> s)280 void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
281   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
282   LogInternedString(std::move(log));
283 }
284 
RecordWeakStringRemoval(ObjPtr<mirror::String> s)285 void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
286   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
287   LogInternedString(std::move(log));
288 }
289 
LogInternedString(InternStringLog && log)290 void Transaction::LogInternedString(InternStringLog&& log) {
291   Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
292   MutexLock mu(Thread::Current(), log_lock_);
293   DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
294   intern_string_logs_.push_front(std::move(log));
295 }
296 
Rollback()297 void Transaction::Rollback() {
298   Thread* self = Thread::Current();
299   self->AssertNoPendingException();
300   MutexLock mu1(self, *Locks::intern_table_lock_);
301   MutexLock mu2(self, log_lock_);
302   rolling_back_ = true;
303   CHECK(!Runtime::Current()->IsActiveTransaction());
304   UndoObjectModifications();
305   UndoArrayModifications();
306   UndoInternStringTableModifications();
307   UndoResolveStringModifications();
308   rolling_back_ = false;
309 }
310 
UndoObjectModifications()311 void Transaction::UndoObjectModifications() {
312   // TODO we may not need to restore objects allocated during this transaction. Or we could directly
313   // remove them from the heap.
314   for (const auto& it : object_logs_) {
315     it.second.Undo(it.first);
316   }
317   object_logs_.clear();
318 }
319 
UndoArrayModifications()320 void Transaction::UndoArrayModifications() {
321   // TODO we may not need to restore array allocated during this transaction. Or we could directly
322   // remove them from the heap.
323   for (const auto& it : array_logs_) {
324     it.second.Undo(it.first);
325   }
326   array_logs_.clear();
327 }
328 
UndoInternStringTableModifications()329 void Transaction::UndoInternStringTableModifications() {
330   InternTable* const intern_table = Runtime::Current()->GetInternTable();
331   // We want to undo each operation from the most recent to the oldest. List has been filled so the
332   // most recent operation is at list begin so just have to iterate over it.
333   for (const InternStringLog& string_log : intern_string_logs_) {
334     string_log.Undo(intern_table);
335   }
336   intern_string_logs_.clear();
337 }
338 
UndoResolveStringModifications()339 void Transaction::UndoResolveStringModifications() {
340   for (ResolveStringLog& string_log : resolve_string_logs_) {
341     string_log.Undo();
342   }
343   resolve_string_logs_.clear();
344 }
345 
VisitRoots(RootVisitor * visitor)346 void Transaction::VisitRoots(RootVisitor* visitor) {
347   MutexLock mu(Thread::Current(), log_lock_);
348   visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&root_), RootInfo(kRootUnknown));
349   VisitObjectLogs(visitor);
350   VisitArrayLogs(visitor);
351   VisitInternStringLogs(visitor);
352   VisitResolveStringLogs(visitor);
353 }
354 
VisitObjectLogs(RootVisitor * visitor)355 void Transaction::VisitObjectLogs(RootVisitor* visitor) {
356   // List of moving roots.
357   using ObjectPair = std::pair<mirror::Object*, mirror::Object*>;
358   std::list<ObjectPair> moving_roots;
359 
360   // Visit roots.
361   for (auto& it : object_logs_) {
362     it.second.VisitRoots(visitor);
363     mirror::Object* old_root = it.first;
364     mirror::Object* new_root = old_root;
365     visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
366     if (new_root != old_root) {
367       moving_roots.push_back(std::make_pair(old_root, new_root));
368     }
369   }
370 
371   // Update object logs with moving roots.
372   for (const ObjectPair& pair : moving_roots) {
373     mirror::Object* old_root = pair.first;
374     mirror::Object* new_root = pair.second;
375     auto old_root_it = object_logs_.find(old_root);
376     CHECK(old_root_it != object_logs_.end());
377     CHECK(object_logs_.find(new_root) == object_logs_.end());
378     object_logs_.emplace(new_root, std::move(old_root_it->second));
379     object_logs_.erase(old_root_it);
380   }
381 }
382 
VisitArrayLogs(RootVisitor * visitor)383 void Transaction::VisitArrayLogs(RootVisitor* visitor) {
384   // List of moving roots.
385   using ArrayPair = std::pair<mirror::Array*, mirror::Array*>;
386   std::list<ArrayPair> moving_roots;
387 
388   for (auto& it : array_logs_) {
389     mirror::Array* old_root = it.first;
390     CHECK(!old_root->IsObjectArray());
391     mirror::Array* new_root = old_root;
392     visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
393     if (new_root != old_root) {
394       moving_roots.push_back(std::make_pair(old_root, new_root));
395     }
396   }
397 
398   // Update array logs with moving roots.
399   for (const ArrayPair& pair : moving_roots) {
400     mirror::Array* old_root = pair.first;
401     mirror::Array* new_root = pair.second;
402     auto old_root_it = array_logs_.find(old_root);
403     CHECK(old_root_it != array_logs_.end());
404     CHECK(array_logs_.find(new_root) == array_logs_.end());
405     array_logs_.emplace(new_root, std::move(old_root_it->second));
406     array_logs_.erase(old_root_it);
407   }
408 }
409 
VisitInternStringLogs(RootVisitor * visitor)410 void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
411   for (InternStringLog& log : intern_string_logs_) {
412     log.VisitRoots(visitor);
413   }
414 }
415 
VisitResolveStringLogs(RootVisitor * visitor)416 void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
417   for (ResolveStringLog& log : resolve_string_logs_) {
418     log.VisitRoots(visitor);
419   }
420 }
421 
LogBooleanValue(MemberOffset offset,uint8_t value,bool is_volatile)422 void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
423   LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
424 }
425 
LogByteValue(MemberOffset offset,int8_t value,bool is_volatile)426 void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
427   LogValue(ObjectLog::kByte, offset, value, is_volatile);
428 }
429 
LogCharValue(MemberOffset offset,uint16_t value,bool is_volatile)430 void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
431   LogValue(ObjectLog::kChar, offset, value, is_volatile);
432 }
433 
LogShortValue(MemberOffset offset,int16_t value,bool is_volatile)434 void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
435   LogValue(ObjectLog::kShort, offset, value, is_volatile);
436 }
437 
Log32BitsValue(MemberOffset offset,uint32_t value,bool is_volatile)438 void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
439   LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
440 }
441 
Log64BitsValue(MemberOffset offset,uint64_t value,bool is_volatile)442 void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
443   LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
444 }
445 
LogReferenceValue(MemberOffset offset,mirror::Object * obj,bool is_volatile)446 void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset,
447                                                mirror::Object* obj,
448                                                bool is_volatile) {
449   LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
450 }
451 
LogValue(ObjectLog::FieldValueKind kind,MemberOffset offset,uint64_t value,bool is_volatile)452 void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
453                                       MemberOffset offset,
454                                       uint64_t value,
455                                       bool is_volatile) {
456   auto it = field_values_.find(offset.Uint32Value());
457   if (it == field_values_.end()) {
458     ObjectLog::FieldValue field_value;
459     field_value.value = value;
460     field_value.is_volatile = is_volatile;
461     field_value.kind = kind;
462     field_values_.emplace(offset.Uint32Value(), std::move(field_value));
463   }
464 }
465 
Undo(mirror::Object * obj) const466 void Transaction::ObjectLog::Undo(mirror::Object* obj) const {
467   for (auto& it : field_values_) {
468     // Garbage collector needs to access object's class and array's length. So we don't rollback
469     // these values.
470     MemberOffset field_offset(it.first);
471     if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
472       // Skip Object::class field.
473       continue;
474     }
475     if (obj->IsArrayInstance() &&
476         field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
477       // Skip Array::length field.
478       continue;
479     }
480     const FieldValue& field_value = it.second;
481     UndoFieldWrite(obj, field_offset, field_value);
482   }
483 }
484 
UndoFieldWrite(mirror::Object * obj,MemberOffset field_offset,const FieldValue & field_value) const485 void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj,
486                                             MemberOffset field_offset,
487                                             const FieldValue& field_value) const {
488   // TODO We may want to abort a transaction while still being in transaction mode. In this case,
489   // we'd need to disable the check.
490   constexpr bool kCheckTransaction = false;
491   switch (field_value.kind) {
492     case kBoolean:
493       if (UNLIKELY(field_value.is_volatile)) {
494         obj->SetFieldBooleanVolatile<false, kCheckTransaction>(
495             field_offset,
496             field_value.value);
497       } else {
498         obj->SetFieldBoolean<false, kCheckTransaction>(
499             field_offset,
500             field_value.value);
501       }
502       break;
503     case kByte:
504       if (UNLIKELY(field_value.is_volatile)) {
505         obj->SetFieldByteVolatile<false, kCheckTransaction>(
506             field_offset,
507             static_cast<int8_t>(field_value.value));
508       } else {
509         obj->SetFieldByte<false, kCheckTransaction>(
510             field_offset,
511             static_cast<int8_t>(field_value.value));
512       }
513       break;
514     case kChar:
515       if (UNLIKELY(field_value.is_volatile)) {
516         obj->SetFieldCharVolatile<false, kCheckTransaction>(
517             field_offset,
518             static_cast<uint16_t>(field_value.value));
519       } else {
520         obj->SetFieldChar<false, kCheckTransaction>(
521             field_offset,
522             static_cast<uint16_t>(field_value.value));
523       }
524       break;
525     case kShort:
526       if (UNLIKELY(field_value.is_volatile)) {
527         obj->SetFieldShortVolatile<false, kCheckTransaction>(
528             field_offset,
529             static_cast<int16_t>(field_value.value));
530       } else {
531         obj->SetFieldShort<false, kCheckTransaction>(
532             field_offset,
533             static_cast<int16_t>(field_value.value));
534       }
535       break;
536     case k32Bits:
537       if (UNLIKELY(field_value.is_volatile)) {
538         obj->SetField32Volatile<false, kCheckTransaction>(
539             field_offset,
540             static_cast<uint32_t>(field_value.value));
541       } else {
542         obj->SetField32<false, kCheckTransaction>(
543             field_offset,
544             static_cast<uint32_t>(field_value.value));
545       }
546       break;
547     case k64Bits:
548       if (UNLIKELY(field_value.is_volatile)) {
549         obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
550       } else {
551         obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
552       }
553       break;
554     case kReference:
555       if (UNLIKELY(field_value.is_volatile)) {
556         obj->SetFieldObjectVolatile<false, kCheckTransaction>(
557             field_offset,
558             reinterpret_cast<mirror::Object*>(field_value.value));
559       } else {
560         obj->SetFieldObject<false, kCheckTransaction>(
561             field_offset,
562             reinterpret_cast<mirror::Object*>(field_value.value));
563       }
564       break;
565     default:
566       LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
567       UNREACHABLE();
568   }
569 }
570 
VisitRoots(RootVisitor * visitor)571 void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
572   for (auto& it : field_values_) {
573     FieldValue& field_value = it.second;
574     if (field_value.kind == ObjectLog::kReference) {
575       visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
576                                   RootInfo(kRootUnknown));
577     }
578   }
579 }
580 
Undo(InternTable * intern_table) const581 void Transaction::InternStringLog::Undo(InternTable* intern_table) const {
582   DCHECK(intern_table != nullptr);
583   switch (string_op_) {
584     case InternStringLog::kInsert: {
585       switch (string_kind_) {
586         case InternStringLog::kStrongString:
587           intern_table->RemoveStrongFromTransaction(str_.Read());
588           break;
589         case InternStringLog::kWeakString:
590           intern_table->RemoveWeakFromTransaction(str_.Read());
591           break;
592         default:
593           LOG(FATAL) << "Unknown interned string kind";
594           UNREACHABLE();
595       }
596       break;
597     }
598     case InternStringLog::kRemove: {
599       switch (string_kind_) {
600         case InternStringLog::kStrongString:
601           intern_table->InsertStrongFromTransaction(str_.Read());
602           break;
603         case InternStringLog::kWeakString:
604           intern_table->InsertWeakFromTransaction(str_.Read());
605           break;
606         default:
607           LOG(FATAL) << "Unknown interned string kind";
608           UNREACHABLE();
609       }
610       break;
611     }
612     default:
613       LOG(FATAL) << "Unknown interned string op";
614       UNREACHABLE();
615   }
616 }
617 
VisitRoots(RootVisitor * visitor)618 void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
619   str_.VisitRoot(visitor, RootInfo(kRootInternedString));
620 }
621 
Undo() const622 void Transaction::ResolveStringLog::Undo() const {
623   dex_cache_.Read()->ClearString(string_idx_);
624 }
625 
ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,dex::StringIndex string_idx)626 Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
627                                                 dex::StringIndex string_idx)
628     : dex_cache_(dex_cache),
629       string_idx_(string_idx) {
630   DCHECK(dex_cache != nullptr);
631   DCHECK_LT(string_idx_.index_, dex_cache->GetDexFile()->NumStringIds());
632 }
633 
VisitRoots(RootVisitor * visitor)634 void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
635   dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
636 }
637 
InternStringLog(ObjPtr<mirror::String> s,StringKind kind,StringOp op)638 Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
639                                               StringKind kind,
640                                               StringOp op)
641     : str_(s),
642       string_kind_(kind),
643       string_op_(op) {
644   DCHECK(s != nullptr);
645 }
646 
LogValue(size_t index,uint64_t value)647 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
648   auto it = array_values_.find(index);
649   if (it == array_values_.end()) {
650     array_values_.insert(std::make_pair(index, value));
651   }
652 }
653 
Undo(mirror::Array * array) const654 void Transaction::ArrayLog::Undo(mirror::Array* array) const {
655   DCHECK(array != nullptr);
656   DCHECK(array->IsArrayInstance());
657   Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
658   for (auto it : array_values_) {
659     UndoArrayWrite(array, type, it.first, it.second);
660   }
661 }
662 
UndoArrayWrite(mirror::Array * array,Primitive::Type array_type,size_t index,uint64_t value) const663 void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array,
664                                            Primitive::Type array_type,
665                                            size_t index,
666                                            uint64_t value) const {
667   // TODO We may want to abort a transaction while still being in transaction mode. In this case,
668   // we'd need to disable the check.
669   constexpr bool kCheckTransaction = false;
670   switch (array_type) {
671     case Primitive::kPrimBoolean:
672       array->AsBooleanArray()->SetWithoutChecks<false, kCheckTransaction>(
673           index, static_cast<uint8_t>(value));
674       break;
675     case Primitive::kPrimByte:
676       array->AsByteArray()->SetWithoutChecks<false, kCheckTransaction>(
677           index, static_cast<int8_t>(value));
678       break;
679     case Primitive::kPrimChar:
680       array->AsCharArray()->SetWithoutChecks<false, kCheckTransaction>(
681           index, static_cast<uint16_t>(value));
682       break;
683     case Primitive::kPrimShort:
684       array->AsShortArray()->SetWithoutChecks<false, kCheckTransaction>(
685           index, static_cast<int16_t>(value));
686       break;
687     case Primitive::kPrimInt:
688       array->AsIntArray()->SetWithoutChecks<false, kCheckTransaction>(
689           index, static_cast<int32_t>(value));
690       break;
691     case Primitive::kPrimFloat:
692       array->AsFloatArray()->SetWithoutChecks<false, kCheckTransaction>(
693           index, static_cast<float>(value));
694       break;
695     case Primitive::kPrimLong:
696       array->AsLongArray()->SetWithoutChecks<false, kCheckTransaction>(
697           index, static_cast<int64_t>(value));
698       break;
699     case Primitive::kPrimDouble:
700       array->AsDoubleArray()->SetWithoutChecks<false, kCheckTransaction>(
701           index, static_cast<double>(value));
702       break;
703     case Primitive::kPrimNot:
704       LOG(FATAL) << "ObjectArray should be treated as Object";
705       UNREACHABLE();
706     default:
707       LOG(FATAL) << "Unsupported type " << array_type;
708       UNREACHABLE();
709   }
710 }
711 
InstallAssertion(const char * reason)712 Transaction* ScopedAssertNoNewTransactionRecords::InstallAssertion(const char* reason) {
713   Transaction* transaction = nullptr;
714   if (kIsDebugBuild && Runtime::Current()->IsActiveTransaction()) {
715     transaction = Runtime::Current()->GetTransaction().get();
716     if (transaction != nullptr) {
717       MutexLock mu(Thread::Current(), transaction->log_lock_);
718       CHECK(transaction->assert_no_new_records_reason_ == nullptr)
719           << "old: " << transaction->assert_no_new_records_reason_ << " new: " << reason;
720       transaction->assert_no_new_records_reason_ = reason;
721     }
722   }
723   return transaction;
724 }
725 
RemoveAssertion(Transaction * transaction)726 void ScopedAssertNoNewTransactionRecords::RemoveAssertion(Transaction* transaction) {
727   if (kIsDebugBuild) {
728     CHECK(Runtime::Current()->GetTransaction().get() == transaction);
729     MutexLock mu(Thread::Current(), transaction->log_lock_);
730     CHECK(transaction->assert_no_new_records_reason_ != nullptr);
731     transaction->assert_no_new_records_reason_ = nullptr;
732   }
733 }
734 
735 }  // namespace art
736