blob: d91860bd836138860093d0219e39cd8238363dc8 [file] [log] [blame]
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +01001/*
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"
Mathieu Chartiere401d142015-04-22 13:56:20 -070023#include "mirror/class-inl.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010024#include "mirror/object-inl.h"
25#include "mirror/object_array-inl.h"
26
27#include <list>
28
29namespace art {
30
31// TODO: remove (only used for debugging purpose).
32static constexpr bool kEnableTransactionStats = false;
33
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010034Transaction::Transaction()
35 : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080036 CHECK(Runtime::Current()->IsAotCompiler());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010037}
38
39Transaction::~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 (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 (auto it : array_logs_) {
50 array_values_count += it.second.Size();
51 }
52 size_t string_count = intern_string_logs_.size();
53 LOG(INFO) << "Transaction::~Transaction"
54 << ": objects_count=" << objects_count
55 << ", field_values_count=" << field_values_count
56 << ", array_count=" << array_count
57 << ", array_values_count=" << array_values_count
58 << ", string_count=" << string_count;
59 }
60}
61
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010062void Transaction::Abort(const std::string& abort_message) {
63 MutexLock mu(Thread::Current(), log_lock_);
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020064 // We may abort more than once if the exception thrown at the time of the
65 // previous abort has been caught during execution of a class initializer.
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010066 // We just keep the message of the first abort because it will cause the
67 // transaction to be rolled back anyway.
68 if (!aborted_) {
69 aborted_ = true;
70 abort_message_ = abort_message;
71 }
72}
73
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020074void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
75 const bool rethrow = (abort_message == nullptr);
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010076 if (kIsDebugBuild && rethrow) {
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020077 CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
78 << " while transaction is not aborted";
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010079 }
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020080 if (rethrow) {
81 // Rethrow an exception with the earlier abort message stored in the transaction.
82 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
83 GetAbortMessage().c_str());
84 } else {
85 // Throw an exception with the given abort message.
86 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
87 abort_message->c_str());
88 }
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010089}
90
91bool Transaction::IsAborted() {
92 MutexLock mu(Thread::Current(), log_lock_);
93 return aborted_;
94}
95
96const std::string& Transaction::GetAbortMessage() {
97 MutexLock mu(Thread::Current(), log_lock_);
98 return abort_message_;
99}
100
Fred Shih37f05ef2014-07-16 18:38:08 -0700101void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
102 uint8_t value, bool is_volatile) {
103 DCHECK(obj != nullptr);
104 MutexLock mu(Thread::Current(), log_lock_);
105 ObjectLog& object_log = object_logs_[obj];
106 object_log.LogBooleanValue(field_offset, value, is_volatile);
107}
108
109void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
110 int8_t value, bool is_volatile) {
111 DCHECK(obj != nullptr);
112 MutexLock mu(Thread::Current(), log_lock_);
113 ObjectLog& object_log = object_logs_[obj];
114 object_log.LogByteValue(field_offset, value, is_volatile);
115}
116
117void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
118 uint16_t value, bool is_volatile) {
119 DCHECK(obj != nullptr);
120 MutexLock mu(Thread::Current(), log_lock_);
121 ObjectLog& object_log = object_logs_[obj];
122 object_log.LogCharValue(field_offset, value, is_volatile);
123}
124
125
126void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
127 int16_t value, bool is_volatile) {
128 DCHECK(obj != nullptr);
129 MutexLock mu(Thread::Current(), log_lock_);
130 ObjectLog& object_log = object_logs_[obj];
131 object_log.LogShortValue(field_offset, value, is_volatile);
132}
133
134
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100135void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
136 bool is_volatile) {
137 DCHECK(obj != nullptr);
138 MutexLock mu(Thread::Current(), log_lock_);
139 ObjectLog& object_log = object_logs_[obj];
140 object_log.Log32BitsValue(field_offset, value, is_volatile);
141}
142
143void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
144 bool is_volatile) {
145 DCHECK(obj != nullptr);
146 MutexLock mu(Thread::Current(), log_lock_);
147 ObjectLog& object_log = object_logs_[obj];
148 object_log.Log64BitsValue(field_offset, value, is_volatile);
149}
150
151void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
152 mirror::Object* value, bool is_volatile) {
153 DCHECK(obj != nullptr);
154 MutexLock mu(Thread::Current(), log_lock_);
155 ObjectLog& object_log = object_logs_[obj];
156 object_log.LogReferenceValue(field_offset, value, is_volatile);
157}
158
159void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
160 DCHECK(array != nullptr);
161 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100162 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100163 MutexLock mu(Thread::Current(), log_lock_);
164 ArrayLog& array_log = array_logs_[array];
165 array_log.LogValue(index, value);
166}
167
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700168void Transaction::RecordStrongStringInsertion(mirror::String* s) {
169 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100170 LogInternedString(log);
171}
172
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700173void Transaction::RecordWeakStringInsertion(mirror::String* s) {
174 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100175 LogInternedString(log);
176}
177
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700178void Transaction::RecordStrongStringRemoval(mirror::String* s) {
179 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100180 LogInternedString(log);
181}
182
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700183void Transaction::RecordWeakStringRemoval(mirror::String* s) {
184 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100185 LogInternedString(log);
186}
187
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700188void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100189 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
190 MutexLock mu(Thread::Current(), log_lock_);
191 intern_string_logs_.push_front(log);
192}
193
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100194void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100195 CHECK(!Runtime::Current()->IsActiveTransaction());
196 Thread* self = Thread::Current();
197 self->AssertNoPendingException();
198 MutexLock mu1(self, *Locks::intern_table_lock_);
199 MutexLock mu2(self, log_lock_);
200 UndoObjectModifications();
201 UndoArrayModifications();
202 UndoInternStringTableModifications();
203}
204
205void Transaction::UndoObjectModifications() {
206 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
207 // remove them from the heap.
208 for (auto it : object_logs_) {
209 it.second.Undo(it.first);
210 }
211 object_logs_.clear();
212}
213
214void Transaction::UndoArrayModifications() {
215 // TODO we may not need to restore array allocated during this transaction. Or we could directly
216 // remove them from the heap.
217 for (auto it : array_logs_) {
218 it.second.Undo(it.first);
219 }
220 array_logs_.clear();
221}
222
223void Transaction::UndoInternStringTableModifications() {
224 InternTable* const intern_table = Runtime::Current()->GetInternTable();
225 // We want to undo each operation from the most recent to the oldest. List has been filled so the
226 // most recent operation is at list begin so just have to iterate over it.
227 for (InternStringLog& string_log : intern_string_logs_) {
228 string_log.Undo(intern_table);
229 }
230 intern_string_logs_.clear();
231}
232
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700233void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100234 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700235 VisitObjectLogs(visitor);
236 VisitArrayLogs(visitor);
237 VisitStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100238}
239
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700240void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100241 // List of moving roots.
242 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
243 std::list<ObjectPair> moving_roots;
244
245 // Visit roots.
246 for (auto it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700247 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100248 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800249 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700250 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100251 if (new_root != old_root) {
252 moving_roots.push_back(std::make_pair(old_root, new_root));
253 }
254 }
255
256 // Update object logs with moving roots.
257 for (const ObjectPair& pair : moving_roots) {
258 mirror::Object* old_root = pair.first;
259 mirror::Object* new_root = pair.second;
260 auto old_root_it = object_logs_.find(old_root);
261 CHECK(old_root_it != object_logs_.end());
262 CHECK(object_logs_.find(new_root) == object_logs_.end());
263 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
264 object_logs_.erase(old_root_it);
265 }
266}
267
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700268void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100269 // List of moving roots.
270 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
271 std::list<ArrayPair> moving_roots;
272
273 for (auto it : array_logs_) {
274 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100275 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800276 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700277 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100278 if (new_root != old_root) {
279 moving_roots.push_back(std::make_pair(old_root, new_root));
280 }
281 }
282
283 // Update array logs with moving roots.
284 for (const ArrayPair& pair : moving_roots) {
285 mirror::Array* old_root = pair.first;
286 mirror::Array* new_root = pair.second;
287 auto old_root_it = array_logs_.find(old_root);
288 CHECK(old_root_it != array_logs_.end());
289 CHECK(array_logs_.find(new_root) == array_logs_.end());
290 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
291 array_logs_.erase(old_root_it);
292 }
293}
294
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700295void Transaction::VisitStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100296 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700297 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100298 }
299}
300
Fred Shih37f05ef2014-07-16 18:38:08 -0700301void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
302 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
303}
304
305void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
306 LogValue(ObjectLog::kByte, offset, value, is_volatile);
307}
308
309void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
310 LogValue(ObjectLog::kChar, offset, value, is_volatile);
311}
312
313void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
314 LogValue(ObjectLog::kShort, offset, value, is_volatile);
315}
316
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100317void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700318 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100319}
320
321void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700322 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
323}
324
325void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
326 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
327}
328
329void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
330 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100331 auto it = field_values_.find(offset.Uint32Value());
332 if (it == field_values_.end()) {
333 ObjectLog::FieldValue field_value;
334 field_value.value = value;
335 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700336 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100337 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
338 }
339}
340
341void Transaction::ObjectLog::Undo(mirror::Object* obj) {
342 for (auto& it : field_values_) {
343 // Garbage collector needs to access object's class and array's length. So we don't rollback
344 // these values.
345 MemberOffset field_offset(it.first);
346 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
347 // Skip Object::class field.
348 continue;
349 }
350 if (obj->IsArrayInstance() &&
351 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
352 // Skip Array::length field.
353 continue;
354 }
355 FieldValue& field_value = it.second;
356 UndoFieldWrite(obj, field_offset, field_value);
357 }
358}
359
360void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
361 const FieldValue& field_value) {
362 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
363 // we'd need to disable the check.
364 constexpr bool kCheckTransaction = true;
365 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700366 case kBoolean:
367 if (UNLIKELY(field_value.is_volatile)) {
368 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
369 static_cast<bool>(field_value.value));
370 } else {
371 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
372 static_cast<bool>(field_value.value));
373 }
374 break;
375 case kByte:
376 if (UNLIKELY(field_value.is_volatile)) {
377 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
378 static_cast<int8_t>(field_value.value));
379 } else {
380 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
381 static_cast<int8_t>(field_value.value));
382 }
383 break;
384 case kChar:
385 if (UNLIKELY(field_value.is_volatile)) {
386 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
387 static_cast<uint16_t>(field_value.value));
388 } else {
389 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
390 static_cast<uint16_t>(field_value.value));
391 }
392 break;
393 case kShort:
394 if (UNLIKELY(field_value.is_volatile)) {
395 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
396 static_cast<int16_t>(field_value.value));
397 } else {
398 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
399 static_cast<int16_t>(field_value.value));
400 }
401 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100402 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700403 if (UNLIKELY(field_value.is_volatile)) {
404 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
405 static_cast<uint32_t>(field_value.value));
406 } else {
407 obj->SetField32<false, kCheckTransaction>(field_offset,
408 static_cast<uint32_t>(field_value.value));
409 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100410 break;
411 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700412 if (UNLIKELY(field_value.is_volatile)) {
413 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
414 } else {
415 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
416 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100417 break;
418 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700419 if (UNLIKELY(field_value.is_volatile)) {
420 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
421 reinterpret_cast<mirror::Object*>(field_value.value));
422 } else {
423 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
424 reinterpret_cast<mirror::Object*>(field_value.value));
425 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100426 break;
427 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700428 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100429 break;
430 }
431}
432
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700433void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100434 for (auto it : field_values_) {
435 FieldValue& field_value = it.second;
436 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700437 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
438 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100439 }
440 }
441}
442
443void Transaction::InternStringLog::Undo(InternTable* intern_table) {
444 DCHECK(intern_table != nullptr);
445 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700446 case InternStringLog::kInsert: {
447 switch (string_kind_) {
448 case InternStringLog::kStrongString:
449 intern_table->RemoveStrongFromTransaction(str_);
450 break;
451 case InternStringLog::kWeakString:
452 intern_table->RemoveWeakFromTransaction(str_);
453 break;
454 default:
455 LOG(FATAL) << "Unknown interned string kind";
456 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100457 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700458 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100459 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700460 case InternStringLog::kRemove: {
461 switch (string_kind_) {
462 case InternStringLog::kStrongString:
463 intern_table->InsertStrongFromTransaction(str_);
464 break;
465 case InternStringLog::kWeakString:
466 intern_table->InsertWeakFromTransaction(str_);
467 break;
468 default:
469 LOG(FATAL) << "Unknown interned string kind";
470 break;
471 }
472 break;
473 }
474 default:
475 LOG(FATAL) << "Unknown interned string op";
476 break;
477 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100478}
479
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700480void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
481 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&str_), RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100482}
483
484void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
485 auto it = array_values_.find(index);
486 if (it == array_values_.end()) {
487 array_values_.insert(std::make_pair(index, value));
488 }
489}
490
491void Transaction::ArrayLog::Undo(mirror::Array* array) {
492 DCHECK(array != nullptr);
493 DCHECK(array->IsArrayInstance());
494 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
495 for (auto it : array_values_) {
496 UndoArrayWrite(array, type, it.first, it.second);
497 }
498}
499
500void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
501 size_t index, uint64_t value) {
502 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
503 // we'd need to disable the check.
504 switch (array_type) {
505 case Primitive::kPrimBoolean:
506 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
507 break;
508 case Primitive::kPrimByte:
509 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
510 break;
511 case Primitive::kPrimChar:
512 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
513 break;
514 case Primitive::kPrimShort:
515 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
516 break;
517 case Primitive::kPrimInt:
518 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
519 break;
520 case Primitive::kPrimFloat:
521 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
522 break;
523 case Primitive::kPrimLong:
524 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
525 break;
526 case Primitive::kPrimDouble:
527 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
528 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100529 case Primitive::kPrimNot:
530 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100531 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100532 default:
533 LOG(FATAL) << "Unsupported type " << array_type;
534 }
535}
536
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100537} // namespace art