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