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