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