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