blob: 5b8d23b70fc1bebafdc442111c13fdece67f6ec7 [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());
Andreas Gampe328dd442015-04-01 14:28:09 -070079 // Temporary workaround for b/20019689.
80 if (self->IsExceptionPending()) {
81 self->ClearException();
82 }
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020083 self->ThrowNewException(Transaction::kAbortExceptionSignature, abort_msg.c_str());
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010084}
85
86bool Transaction::IsAborted() {
87 MutexLock mu(Thread::Current(), log_lock_);
88 return aborted_;
89}
90
91const std::string& Transaction::GetAbortMessage() {
92 MutexLock mu(Thread::Current(), log_lock_);
93 return abort_message_;
94}
95
Fred Shih37f05ef2014-07-16 18:38:08 -070096void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
97 uint8_t value, bool is_volatile) {
98 DCHECK(obj != nullptr);
99 MutexLock mu(Thread::Current(), log_lock_);
100 ObjectLog& object_log = object_logs_[obj];
101 object_log.LogBooleanValue(field_offset, value, is_volatile);
102}
103
104void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
105 int8_t value, bool is_volatile) {
106 DCHECK(obj != nullptr);
107 MutexLock mu(Thread::Current(), log_lock_);
108 ObjectLog& object_log = object_logs_[obj];
109 object_log.LogByteValue(field_offset, value, is_volatile);
110}
111
112void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
113 uint16_t value, bool is_volatile) {
114 DCHECK(obj != nullptr);
115 MutexLock mu(Thread::Current(), log_lock_);
116 ObjectLog& object_log = object_logs_[obj];
117 object_log.LogCharValue(field_offset, value, is_volatile);
118}
119
120
121void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
122 int16_t value, bool is_volatile) {
123 DCHECK(obj != nullptr);
124 MutexLock mu(Thread::Current(), log_lock_);
125 ObjectLog& object_log = object_logs_[obj];
126 object_log.LogShortValue(field_offset, value, is_volatile);
127}
128
129
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100130void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
131 bool is_volatile) {
132 DCHECK(obj != nullptr);
133 MutexLock mu(Thread::Current(), log_lock_);
134 ObjectLog& object_log = object_logs_[obj];
135 object_log.Log32BitsValue(field_offset, value, is_volatile);
136}
137
138void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_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.Log64BitsValue(field_offset, value, is_volatile);
144}
145
146void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
147 mirror::Object* value, bool is_volatile) {
148 DCHECK(obj != nullptr);
149 MutexLock mu(Thread::Current(), log_lock_);
150 ObjectLog& object_log = object_logs_[obj];
151 object_log.LogReferenceValue(field_offset, value, is_volatile);
152}
153
154void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
155 DCHECK(array != nullptr);
156 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100157 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100158 MutexLock mu(Thread::Current(), log_lock_);
159 ArrayLog& array_log = array_logs_[array];
160 array_log.LogValue(index, value);
161}
162
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700163void Transaction::RecordStrongStringInsertion(mirror::String* s) {
164 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100165 LogInternedString(log);
166}
167
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700168void Transaction::RecordWeakStringInsertion(mirror::String* s) {
169 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100170 LogInternedString(log);
171}
172
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700173void Transaction::RecordStrongStringRemoval(mirror::String* s) {
174 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100175 LogInternedString(log);
176}
177
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700178void Transaction::RecordWeakStringRemoval(mirror::String* s) {
179 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100180 LogInternedString(log);
181}
182
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700183void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100184 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
185 MutexLock mu(Thread::Current(), log_lock_);
186 intern_string_logs_.push_front(log);
187}
188
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100189void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100190 CHECK(!Runtime::Current()->IsActiveTransaction());
191 Thread* self = Thread::Current();
192 self->AssertNoPendingException();
193 MutexLock mu1(self, *Locks::intern_table_lock_);
194 MutexLock mu2(self, log_lock_);
195 UndoObjectModifications();
196 UndoArrayModifications();
197 UndoInternStringTableModifications();
198}
199
200void Transaction::UndoObjectModifications() {
201 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
202 // remove them from the heap.
203 for (auto it : object_logs_) {
204 it.second.Undo(it.first);
205 }
206 object_logs_.clear();
207}
208
209void Transaction::UndoArrayModifications() {
210 // TODO we may not need to restore array allocated during this transaction. Or we could directly
211 // remove them from the heap.
212 for (auto it : array_logs_) {
213 it.second.Undo(it.first);
214 }
215 array_logs_.clear();
216}
217
218void Transaction::UndoInternStringTableModifications() {
219 InternTable* const intern_table = Runtime::Current()->GetInternTable();
220 // We want to undo each operation from the most recent to the oldest. List has been filled so the
221 // most recent operation is at list begin so just have to iterate over it.
222 for (InternStringLog& string_log : intern_string_logs_) {
223 string_log.Undo(intern_table);
224 }
225 intern_string_logs_.clear();
226}
227
228void Transaction::VisitRoots(RootCallback* callback, void* arg) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100229 MutexLock mu(Thread::Current(), log_lock_);
230 VisitObjectLogs(callback, arg);
231 VisitArrayLogs(callback, arg);
232 VisitStringLogs(callback, arg);
233}
234
235void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
236 // List of moving roots.
237 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
238 std::list<ObjectPair> moving_roots;
239
240 // Visit roots.
241 for (auto it : object_logs_) {
242 it.second.VisitRoots(callback, arg);
243 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800244 mirror::Object* new_root = old_root;
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800245 callback(&new_root, arg, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100246 if (new_root != old_root) {
247 moving_roots.push_back(std::make_pair(old_root, new_root));
248 }
249 }
250
251 // Update object logs with moving roots.
252 for (const ObjectPair& pair : moving_roots) {
253 mirror::Object* old_root = pair.first;
254 mirror::Object* new_root = pair.second;
255 auto old_root_it = object_logs_.find(old_root);
256 CHECK(old_root_it != object_logs_.end());
257 CHECK(object_logs_.find(new_root) == object_logs_.end());
258 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
259 object_logs_.erase(old_root_it);
260 }
261}
262
263void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
264 // List of moving roots.
265 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
266 std::list<ArrayPair> moving_roots;
267
268 for (auto it : array_logs_) {
269 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100270 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800271 mirror::Array* new_root = old_root;
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800272 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100273 if (new_root != old_root) {
274 moving_roots.push_back(std::make_pair(old_root, new_root));
275 }
276 }
277
278 // Update array logs with moving roots.
279 for (const ArrayPair& pair : moving_roots) {
280 mirror::Array* old_root = pair.first;
281 mirror::Array* new_root = pair.second;
282 auto old_root_it = array_logs_.find(old_root);
283 CHECK(old_root_it != array_logs_.end());
284 CHECK(array_logs_.find(new_root) == array_logs_.end());
285 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
286 array_logs_.erase(old_root_it);
287 }
288}
289
290void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
291 for (InternStringLog& log : intern_string_logs_) {
292 log.VisitRoots(callback, arg);
293 }
294}
295
Fred Shih37f05ef2014-07-16 18:38:08 -0700296void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
297 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
298}
299
300void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
301 LogValue(ObjectLog::kByte, offset, value, is_volatile);
302}
303
304void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
305 LogValue(ObjectLog::kChar, offset, value, is_volatile);
306}
307
308void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
309 LogValue(ObjectLog::kShort, offset, value, is_volatile);
310}
311
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100312void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700313 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100314}
315
316void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700317 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
318}
319
320void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
321 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
322}
323
324void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
325 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100326 auto it = field_values_.find(offset.Uint32Value());
327 if (it == field_values_.end()) {
328 ObjectLog::FieldValue field_value;
329 field_value.value = value;
330 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700331 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100332 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
333 }
334}
335
336void Transaction::ObjectLog::Undo(mirror::Object* obj) {
337 for (auto& it : field_values_) {
338 // Garbage collector needs to access object's class and array's length. So we don't rollback
339 // these values.
340 MemberOffset field_offset(it.first);
341 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
342 // Skip Object::class field.
343 continue;
344 }
345 if (obj->IsArrayInstance() &&
346 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
347 // Skip Array::length field.
348 continue;
349 }
350 FieldValue& field_value = it.second;
351 UndoFieldWrite(obj, field_offset, field_value);
352 }
353}
354
355void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
356 const FieldValue& field_value) {
357 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
358 // we'd need to disable the check.
359 constexpr bool kCheckTransaction = true;
360 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700361 case kBoolean:
362 if (UNLIKELY(field_value.is_volatile)) {
363 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
364 static_cast<bool>(field_value.value));
365 } else {
366 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
367 static_cast<bool>(field_value.value));
368 }
369 break;
370 case kByte:
371 if (UNLIKELY(field_value.is_volatile)) {
372 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
373 static_cast<int8_t>(field_value.value));
374 } else {
375 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
376 static_cast<int8_t>(field_value.value));
377 }
378 break;
379 case kChar:
380 if (UNLIKELY(field_value.is_volatile)) {
381 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
382 static_cast<uint16_t>(field_value.value));
383 } else {
384 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
385 static_cast<uint16_t>(field_value.value));
386 }
387 break;
388 case kShort:
389 if (UNLIKELY(field_value.is_volatile)) {
390 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
391 static_cast<int16_t>(field_value.value));
392 } else {
393 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
394 static_cast<int16_t>(field_value.value));
395 }
396 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100397 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700398 if (UNLIKELY(field_value.is_volatile)) {
399 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
400 static_cast<uint32_t>(field_value.value));
401 } else {
402 obj->SetField32<false, kCheckTransaction>(field_offset,
403 static_cast<uint32_t>(field_value.value));
404 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100405 break;
406 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700407 if (UNLIKELY(field_value.is_volatile)) {
408 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
409 } else {
410 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
411 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100412 break;
413 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700414 if (UNLIKELY(field_value.is_volatile)) {
415 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
416 reinterpret_cast<mirror::Object*>(field_value.value));
417 } else {
418 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
419 reinterpret_cast<mirror::Object*>(field_value.value));
420 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100421 break;
422 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700423 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100424 break;
425 }
426}
427
428void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
429 for (auto it : field_values_) {
430 FieldValue& field_value = it.second;
431 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800432 mirror::Object* obj =
433 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100434 if (obj != nullptr) {
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800435 callback(&obj, arg, RootInfo(kRootUnknown));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100436 field_value.value = reinterpret_cast<uintptr_t>(obj);
437 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100438 }
439 }
440}
441
442void Transaction::InternStringLog::Undo(InternTable* intern_table) {
443 DCHECK(intern_table != nullptr);
444 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700445 case InternStringLog::kInsert: {
446 switch (string_kind_) {
447 case InternStringLog::kStrongString:
448 intern_table->RemoveStrongFromTransaction(str_);
449 break;
450 case InternStringLog::kWeakString:
451 intern_table->RemoveWeakFromTransaction(str_);
452 break;
453 default:
454 LOG(FATAL) << "Unknown interned string kind";
455 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100456 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700457 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100458 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700459 case InternStringLog::kRemove: {
460 switch (string_kind_) {
461 case InternStringLog::kStrongString:
462 intern_table->InsertStrongFromTransaction(str_);
463 break;
464 case InternStringLog::kWeakString:
465 intern_table->InsertWeakFromTransaction(str_);
466 break;
467 default:
468 LOG(FATAL) << "Unknown interned string kind";
469 break;
470 }
471 break;
472 }
473 default:
474 LOG(FATAL) << "Unknown interned string op";
475 break;
476 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100477}
478
479void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
Mathieu Chartiere34fa1d2015-01-14 14:55:47 -0800480 callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100481}
482
483void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
484 auto it = array_values_.find(index);
485 if (it == array_values_.end()) {
486 array_values_.insert(std::make_pair(index, value));
487 }
488}
489
490void Transaction::ArrayLog::Undo(mirror::Array* array) {
491 DCHECK(array != nullptr);
492 DCHECK(array->IsArrayInstance());
493 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
494 for (auto it : array_values_) {
495 UndoArrayWrite(array, type, it.first, it.second);
496 }
497}
498
499void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
500 size_t index, uint64_t value) {
501 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
502 // we'd need to disable the check.
503 switch (array_type) {
504 case Primitive::kPrimBoolean:
505 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
506 break;
507 case Primitive::kPrimByte:
508 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
509 break;
510 case Primitive::kPrimChar:
511 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
512 break;
513 case Primitive::kPrimShort:
514 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
515 break;
516 case Primitive::kPrimInt:
517 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
518 break;
519 case Primitive::kPrimFloat:
520 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
521 break;
522 case Primitive::kPrimLong:
523 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
524 break;
525 case Primitive::kPrimDouble:
526 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
527 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100528 case Primitive::kPrimNot:
529 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100530 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100531 default:
532 LOG(FATAL) << "Unsupported type " << array_type;
533 }
534}
535
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100536} // namespace art