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