blob: cc0f15f6f2fed4862b079c02186490b658136469 [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"
23#include "mirror/object-inl.h"
24#include "mirror/object_array-inl.h"
25
26#include <list>
27
28namespace art {
29
30// TODO: remove (only used for debugging purpose).
31static constexpr bool kEnableTransactionStats = false;
32
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010033Transaction::Transaction()
34 : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080035 CHECK(Runtime::Current()->IsAotCompiler());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010036}
37
38Transaction::~Transaction() {
39 if (kEnableTransactionStats) {
40 MutexLock mu(Thread::Current(), log_lock_);
41 size_t objects_count = object_logs_.size();
42 size_t field_values_count = 0;
43 for (auto it : object_logs_) {
44 field_values_count += it.second.Size();
45 }
46 size_t array_count = array_logs_.size();
47 size_t array_values_count = 0;
48 for (auto it : array_logs_) {
49 array_values_count += it.second.Size();
50 }
51 size_t string_count = intern_string_logs_.size();
52 LOG(INFO) << "Transaction::~Transaction"
53 << ": objects_count=" << objects_count
54 << ", field_values_count=" << field_values_count
55 << ", array_count=" << array_count
56 << ", array_values_count=" << array_values_count
57 << ", string_count=" << string_count;
58 }
59}
60
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010061void Transaction::Abort(const std::string& abort_message) {
62 MutexLock mu(Thread::Current(), log_lock_);
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020063 // We may abort more than once if the exception thrown at the time of the
64 // previous abort has been caught during execution of a class initializer.
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010065 // We just keep the message of the first abort because it will cause the
66 // transaction to be rolled back anyway.
67 if (!aborted_) {
68 aborted_ = true;
69 abort_message_ = abort_message;
70 }
71}
72
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020073void Transaction::ThrowAbortError(Thread* self, bool rethrow) {
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010074 if (kIsDebugBuild && rethrow) {
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020075 CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
76 << " while transaction is not aborted";
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010077 }
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010078 std::string abort_msg(GetAbortMessage());
Sebastien Hertz64db2392015-04-02 09:09:04 +000079 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature, abort_msg.c_str());
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010080}
81
82bool Transaction::IsAborted() {
83 MutexLock mu(Thread::Current(), log_lock_);
84 return aborted_;
85}
86
87const std::string& Transaction::GetAbortMessage() {
88 MutexLock mu(Thread::Current(), log_lock_);
89 return abort_message_;
90}
91
Fred Shih37f05ef2014-07-16 18:38:08 -070092void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
93 uint8_t value, bool is_volatile) {
94 DCHECK(obj != nullptr);
95 MutexLock mu(Thread::Current(), log_lock_);
96 ObjectLog& object_log = object_logs_[obj];
97 object_log.LogBooleanValue(field_offset, value, is_volatile);
98}
99
100void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
101 int8_t value, bool is_volatile) {
102 DCHECK(obj != nullptr);
103 MutexLock mu(Thread::Current(), log_lock_);
104 ObjectLog& object_log = object_logs_[obj];
105 object_log.LogByteValue(field_offset, value, is_volatile);
106}
107
108void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
109 uint16_t value, bool is_volatile) {
110 DCHECK(obj != nullptr);
111 MutexLock mu(Thread::Current(), log_lock_);
112 ObjectLog& object_log = object_logs_[obj];
113 object_log.LogCharValue(field_offset, value, is_volatile);
114}
115
116
117void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
118 int16_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.LogShortValue(field_offset, value, is_volatile);
123}
124
125
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100126void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
127 bool is_volatile) {
128 DCHECK(obj != nullptr);
129 MutexLock mu(Thread::Current(), log_lock_);
130 ObjectLog& object_log = object_logs_[obj];
131 object_log.Log32BitsValue(field_offset, value, is_volatile);
132}
133
134void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
135 bool is_volatile) {
136 DCHECK(obj != nullptr);
137 MutexLock mu(Thread::Current(), log_lock_);
138 ObjectLog& object_log = object_logs_[obj];
139 object_log.Log64BitsValue(field_offset, value, is_volatile);
140}
141
142void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
143 mirror::Object* value, bool is_volatile) {
144 DCHECK(obj != nullptr);
145 MutexLock mu(Thread::Current(), log_lock_);
146 ObjectLog& object_log = object_logs_[obj];
147 object_log.LogReferenceValue(field_offset, value, is_volatile);
148}
149
150void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
151 DCHECK(array != nullptr);
152 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100153 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100154 MutexLock mu(Thread::Current(), log_lock_);
155 ArrayLog& array_log = array_logs_[array];
156 array_log.LogValue(index, value);
157}
158
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700159void Transaction::RecordStrongStringInsertion(mirror::String* s) {
160 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100161 LogInternedString(log);
162}
163
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700164void Transaction::RecordWeakStringInsertion(mirror::String* s) {
165 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100166 LogInternedString(log);
167}
168
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700169void Transaction::RecordStrongStringRemoval(mirror::String* s) {
170 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100171 LogInternedString(log);
172}
173
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700174void Transaction::RecordWeakStringRemoval(mirror::String* s) {
175 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100176 LogInternedString(log);
177}
178
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700179void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100180 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
181 MutexLock mu(Thread::Current(), log_lock_);
182 intern_string_logs_.push_front(log);
183}
184
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100185void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100186 CHECK(!Runtime::Current()->IsActiveTransaction());
187 Thread* self = Thread::Current();
188 self->AssertNoPendingException();
189 MutexLock mu1(self, *Locks::intern_table_lock_);
190 MutexLock mu2(self, log_lock_);
191 UndoObjectModifications();
192 UndoArrayModifications();
193 UndoInternStringTableModifications();
194}
195
196void Transaction::UndoObjectModifications() {
197 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
198 // remove them from the heap.
199 for (auto it : object_logs_) {
200 it.second.Undo(it.first);
201 }
202 object_logs_.clear();
203}
204
205void Transaction::UndoArrayModifications() {
206 // TODO we may not need to restore array allocated during this transaction. Or we could directly
207 // remove them from the heap.
208 for (auto it : array_logs_) {
209 it.second.Undo(it.first);
210 }
211 array_logs_.clear();
212}
213
214void Transaction::UndoInternStringTableModifications() {
215 InternTable* const intern_table = Runtime::Current()->GetInternTable();
216 // We want to undo each operation from the most recent to the oldest. List has been filled so the
217 // most recent operation is at list begin so just have to iterate over it.
218 for (InternStringLog& string_log : intern_string_logs_) {
219 string_log.Undo(intern_table);
220 }
221 intern_string_logs_.clear();
222}
223
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700224void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100225 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700226 VisitObjectLogs(visitor);
227 VisitArrayLogs(visitor);
228 VisitStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100229}
230
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700231void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100232 // List of moving roots.
233 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
234 std::list<ObjectPair> moving_roots;
235
236 // Visit roots.
237 for (auto it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700238 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100239 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800240 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700241 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100242 if (new_root != old_root) {
243 moving_roots.push_back(std::make_pair(old_root, new_root));
244 }
245 }
246
247 // Update object logs with moving roots.
248 for (const ObjectPair& pair : moving_roots) {
249 mirror::Object* old_root = pair.first;
250 mirror::Object* new_root = pair.second;
251 auto old_root_it = object_logs_.find(old_root);
252 CHECK(old_root_it != object_logs_.end());
253 CHECK(object_logs_.find(new_root) == object_logs_.end());
254 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
255 object_logs_.erase(old_root_it);
256 }
257}
258
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700259void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100260 // List of moving roots.
261 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
262 std::list<ArrayPair> moving_roots;
263
264 for (auto it : array_logs_) {
265 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100266 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800267 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700268 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100269 if (new_root != old_root) {
270 moving_roots.push_back(std::make_pair(old_root, new_root));
271 }
272 }
273
274 // Update array logs with moving roots.
275 for (const ArrayPair& pair : moving_roots) {
276 mirror::Array* old_root = pair.first;
277 mirror::Array* new_root = pair.second;
278 auto old_root_it = array_logs_.find(old_root);
279 CHECK(old_root_it != array_logs_.end());
280 CHECK(array_logs_.find(new_root) == array_logs_.end());
281 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
282 array_logs_.erase(old_root_it);
283 }
284}
285
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700286void Transaction::VisitStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100287 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700288 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100289 }
290}
291
Fred Shih37f05ef2014-07-16 18:38:08 -0700292void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
293 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
294}
295
296void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
297 LogValue(ObjectLog::kByte, offset, value, is_volatile);
298}
299
300void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
301 LogValue(ObjectLog::kChar, offset, value, is_volatile);
302}
303
304void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
305 LogValue(ObjectLog::kShort, offset, value, is_volatile);
306}
307
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100308void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700309 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100310}
311
312void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700313 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
314}
315
316void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
317 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
318}
319
320void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
321 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100322 auto it = field_values_.find(offset.Uint32Value());
323 if (it == field_values_.end()) {
324 ObjectLog::FieldValue field_value;
325 field_value.value = value;
326 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700327 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100328 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
329 }
330}
331
332void Transaction::ObjectLog::Undo(mirror::Object* obj) {
333 for (auto& it : field_values_) {
334 // Garbage collector needs to access object's class and array's length. So we don't rollback
335 // these values.
336 MemberOffset field_offset(it.first);
337 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
338 // Skip Object::class field.
339 continue;
340 }
341 if (obj->IsArrayInstance() &&
342 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
343 // Skip Array::length field.
344 continue;
345 }
346 FieldValue& field_value = it.second;
347 UndoFieldWrite(obj, field_offset, field_value);
348 }
349}
350
351void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
352 const FieldValue& field_value) {
353 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
354 // we'd need to disable the check.
355 constexpr bool kCheckTransaction = true;
356 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700357 case kBoolean:
358 if (UNLIKELY(field_value.is_volatile)) {
359 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
360 static_cast<bool>(field_value.value));
361 } else {
362 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
363 static_cast<bool>(field_value.value));
364 }
365 break;
366 case kByte:
367 if (UNLIKELY(field_value.is_volatile)) {
368 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
369 static_cast<int8_t>(field_value.value));
370 } else {
371 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
372 static_cast<int8_t>(field_value.value));
373 }
374 break;
375 case kChar:
376 if (UNLIKELY(field_value.is_volatile)) {
377 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
378 static_cast<uint16_t>(field_value.value));
379 } else {
380 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
381 static_cast<uint16_t>(field_value.value));
382 }
383 break;
384 case kShort:
385 if (UNLIKELY(field_value.is_volatile)) {
386 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
387 static_cast<int16_t>(field_value.value));
388 } else {
389 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
390 static_cast<int16_t>(field_value.value));
391 }
392 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100393 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700394 if (UNLIKELY(field_value.is_volatile)) {
395 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
396 static_cast<uint32_t>(field_value.value));
397 } else {
398 obj->SetField32<false, kCheckTransaction>(field_offset,
399 static_cast<uint32_t>(field_value.value));
400 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100401 break;
402 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700403 if (UNLIKELY(field_value.is_volatile)) {
404 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
405 } else {
406 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
407 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100408 break;
409 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700410 if (UNLIKELY(field_value.is_volatile)) {
411 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
412 reinterpret_cast<mirror::Object*>(field_value.value));
413 } else {
414 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
415 reinterpret_cast<mirror::Object*>(field_value.value));
416 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100417 break;
418 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700419 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100420 break;
421 }
422}
423
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700424void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100425 for (auto it : field_values_) {
426 FieldValue& field_value = it.second;
427 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700428 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
429 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100430 }
431 }
432}
433
434void Transaction::InternStringLog::Undo(InternTable* intern_table) {
435 DCHECK(intern_table != nullptr);
436 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700437 case InternStringLog::kInsert: {
438 switch (string_kind_) {
439 case InternStringLog::kStrongString:
440 intern_table->RemoveStrongFromTransaction(str_);
441 break;
442 case InternStringLog::kWeakString:
443 intern_table->RemoveWeakFromTransaction(str_);
444 break;
445 default:
446 LOG(FATAL) << "Unknown interned string kind";
447 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100448 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700449 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100450 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700451 case InternStringLog::kRemove: {
452 switch (string_kind_) {
453 case InternStringLog::kStrongString:
454 intern_table->InsertStrongFromTransaction(str_);
455 break;
456 case InternStringLog::kWeakString:
457 intern_table->InsertWeakFromTransaction(str_);
458 break;
459 default:
460 LOG(FATAL) << "Unknown interned string kind";
461 break;
462 }
463 break;
464 }
465 default:
466 LOG(FATAL) << "Unknown interned string op";
467 break;
468 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100469}
470
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700471void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
472 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&str_), RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100473}
474
475void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
476 auto it = array_values_.find(index);
477 if (it == array_values_.end()) {
478 array_values_.insert(std::make_pair(index, value));
479 }
480}
481
482void Transaction::ArrayLog::Undo(mirror::Array* array) {
483 DCHECK(array != nullptr);
484 DCHECK(array->IsArrayInstance());
485 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
486 for (auto it : array_values_) {
487 UndoArrayWrite(array, type, it.first, it.second);
488 }
489}
490
491void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
492 size_t index, uint64_t value) {
493 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
494 // we'd need to disable the check.
495 switch (array_type) {
496 case Primitive::kPrimBoolean:
497 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
498 break;
499 case Primitive::kPrimByte:
500 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
501 break;
502 case Primitive::kPrimChar:
503 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
504 break;
505 case Primitive::kPrimShort:
506 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
507 break;
508 case Primitive::kPrimInt:
509 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
510 break;
511 case Primitive::kPrimFloat:
512 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
513 break;
514 case Primitive::kPrimLong:
515 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
516 break;
517 case Primitive::kPrimDouble:
518 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
519 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100520 case Primitive::kPrimNot:
521 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100522 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100523 default:
524 LOG(FATAL) << "Unsupported type " << array_type;
525 }
526}
527
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100528} // namespace art