blob: c5da5d2e7e6486dc794126a391f87cf14b6e5c38 [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 }
Mathieu Chartierbb816d62016-09-07 10:17:46 -070052 size_t intern_string_count = intern_string_logs_.size();
53 size_t resolve_string_count = resolve_string_logs_.size();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010054 LOG(INFO) << "Transaction::~Transaction"
55 << ": objects_count=" << objects_count
56 << ", field_values_count=" << field_values_count
57 << ", array_count=" << array_count
58 << ", array_values_count=" << array_values_count
Mathieu Chartierbb816d62016-09-07 10:17:46 -070059 << ", intern_string_count=" << intern_string_count
60 << ", resolve_string_count=" << resolve_string_count;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010061 }
62}
63
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010064void Transaction::Abort(const std::string& abort_message) {
65 MutexLock mu(Thread::Current(), log_lock_);
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020066 // We may abort more than once if the exception thrown at the time of the
67 // previous abort has been caught during execution of a class initializer.
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010068 // We just keep the message of the first abort because it will cause the
69 // transaction to be rolled back anyway.
70 if (!aborted_) {
71 aborted_ = true;
72 abort_message_ = abort_message;
73 }
74}
75
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020076void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
77 const bool rethrow = (abort_message == nullptr);
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010078 if (kIsDebugBuild && rethrow) {
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020079 CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
80 << " while transaction is not aborted";
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010081 }
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020082 if (rethrow) {
83 // Rethrow an exception with the earlier abort message stored in the transaction.
84 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
85 GetAbortMessage().c_str());
86 } else {
87 // Throw an exception with the given abort message.
88 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
89 abort_message->c_str());
90 }
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010091}
92
93bool Transaction::IsAborted() {
94 MutexLock mu(Thread::Current(), log_lock_);
95 return aborted_;
96}
97
98const std::string& Transaction::GetAbortMessage() {
99 MutexLock mu(Thread::Current(), log_lock_);
100 return abort_message_;
101}
102
Fred Shih37f05ef2014-07-16 18:38:08 -0700103void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
104 uint8_t value, bool is_volatile) {
105 DCHECK(obj != nullptr);
106 MutexLock mu(Thread::Current(), log_lock_);
107 ObjectLog& object_log = object_logs_[obj];
108 object_log.LogBooleanValue(field_offset, value, is_volatile);
109}
110
111void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
112 int8_t value, bool is_volatile) {
113 DCHECK(obj != nullptr);
114 MutexLock mu(Thread::Current(), log_lock_);
115 ObjectLog& object_log = object_logs_[obj];
116 object_log.LogByteValue(field_offset, value, is_volatile);
117}
118
119void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
120 uint16_t value, bool is_volatile) {
121 DCHECK(obj != nullptr);
122 MutexLock mu(Thread::Current(), log_lock_);
123 ObjectLog& object_log = object_logs_[obj];
124 object_log.LogCharValue(field_offset, value, is_volatile);
125}
126
127
128void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
129 int16_t value, bool is_volatile) {
130 DCHECK(obj != nullptr);
131 MutexLock mu(Thread::Current(), log_lock_);
132 ObjectLog& object_log = object_logs_[obj];
133 object_log.LogShortValue(field_offset, value, is_volatile);
134}
135
136
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100137void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
138 bool is_volatile) {
139 DCHECK(obj != nullptr);
140 MutexLock mu(Thread::Current(), log_lock_);
141 ObjectLog& object_log = object_logs_[obj];
142 object_log.Log32BitsValue(field_offset, value, is_volatile);
143}
144
145void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
146 bool is_volatile) {
147 DCHECK(obj != nullptr);
148 MutexLock mu(Thread::Current(), log_lock_);
149 ObjectLog& object_log = object_logs_[obj];
150 object_log.Log64BitsValue(field_offset, value, is_volatile);
151}
152
153void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
154 mirror::Object* value, bool is_volatile) {
155 DCHECK(obj != nullptr);
156 MutexLock mu(Thread::Current(), log_lock_);
157 ObjectLog& object_log = object_logs_[obj];
158 object_log.LogReferenceValue(field_offset, value, is_volatile);
159}
160
161void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
162 DCHECK(array != nullptr);
163 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100164 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100165 MutexLock mu(Thread::Current(), log_lock_);
166 ArrayLog& array_log = array_logs_[array];
167 array_log.LogValue(index, value);
168}
169
Mathieu Chartier9e868092016-10-31 14:58:04 -0700170void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx) {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700171 DCHECK(dex_cache != nullptr);
172 DCHECK_LT(string_idx, dex_cache->GetDexFile()->NumStringIds());
173 MutexLock mu(Thread::Current(), log_lock_);
174 resolve_string_logs_.push_back(ResolveStringLog(dex_cache, string_idx));
175}
176
Mathieu Chartier9e868092016-10-31 14:58:04 -0700177void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700178 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100179 LogInternedString(log);
180}
181
Mathieu Chartier9e868092016-10-31 14:58:04 -0700182void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700183 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100184 LogInternedString(log);
185}
186
Mathieu Chartier9e868092016-10-31 14:58:04 -0700187void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700188 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100189 LogInternedString(log);
190}
191
Mathieu Chartier9e868092016-10-31 14:58:04 -0700192void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700193 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100194 LogInternedString(log);
195}
196
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700197void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100198 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
199 MutexLock mu(Thread::Current(), log_lock_);
200 intern_string_logs_.push_front(log);
201}
202
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100203void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100204 CHECK(!Runtime::Current()->IsActiveTransaction());
205 Thread* self = Thread::Current();
206 self->AssertNoPendingException();
207 MutexLock mu1(self, *Locks::intern_table_lock_);
208 MutexLock mu2(self, log_lock_);
209 UndoObjectModifications();
210 UndoArrayModifications();
211 UndoInternStringTableModifications();
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700212 UndoResolveStringModifications();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100213}
214
215void Transaction::UndoObjectModifications() {
216 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
217 // remove them from the heap.
218 for (auto it : object_logs_) {
219 it.second.Undo(it.first);
220 }
221 object_logs_.clear();
222}
223
224void Transaction::UndoArrayModifications() {
225 // TODO we may not need to restore array allocated during this transaction. Or we could directly
226 // remove them from the heap.
227 for (auto it : array_logs_) {
228 it.second.Undo(it.first);
229 }
230 array_logs_.clear();
231}
232
233void Transaction::UndoInternStringTableModifications() {
234 InternTable* const intern_table = Runtime::Current()->GetInternTable();
235 // We want to undo each operation from the most recent to the oldest. List has been filled so the
236 // most recent operation is at list begin so just have to iterate over it.
237 for (InternStringLog& string_log : intern_string_logs_) {
238 string_log.Undo(intern_table);
239 }
240 intern_string_logs_.clear();
241}
242
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700243void Transaction::UndoResolveStringModifications() {
244 for (ResolveStringLog& string_log : resolve_string_logs_) {
245 string_log.Undo();
246 }
247 resolve_string_logs_.clear();
248}
249
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700250void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100251 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700252 VisitObjectLogs(visitor);
253 VisitArrayLogs(visitor);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700254 VisitInternStringLogs(visitor);
255 VisitResolveStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100256}
257
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700258void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100259 // List of moving roots.
260 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
261 std::list<ObjectPair> moving_roots;
262
263 // Visit roots.
264 for (auto it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700265 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100266 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800267 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700268 visitor->VisitRoot(&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 object logs with moving roots.
275 for (const ObjectPair& pair : moving_roots) {
276 mirror::Object* old_root = pair.first;
277 mirror::Object* new_root = pair.second;
278 auto old_root_it = object_logs_.find(old_root);
279 CHECK(old_root_it != object_logs_.end());
280 CHECK(object_logs_.find(new_root) == object_logs_.end());
281 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
282 object_logs_.erase(old_root_it);
283 }
284}
285
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700286void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100287 // List of moving roots.
288 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
289 std::list<ArrayPair> moving_roots;
290
291 for (auto it : array_logs_) {
292 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100293 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800294 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700295 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100296 if (new_root != old_root) {
297 moving_roots.push_back(std::make_pair(old_root, new_root));
298 }
299 }
300
301 // Update array logs with moving roots.
302 for (const ArrayPair& pair : moving_roots) {
303 mirror::Array* old_root = pair.first;
304 mirror::Array* new_root = pair.second;
305 auto old_root_it = array_logs_.find(old_root);
306 CHECK(old_root_it != array_logs_.end());
307 CHECK(array_logs_.find(new_root) == array_logs_.end());
308 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
309 array_logs_.erase(old_root_it);
310 }
311}
312
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700313void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100314 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700315 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100316 }
317}
318
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700319void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
320 for (ResolveStringLog& log : resolve_string_logs_) {
321 log.VisitRoots(visitor);
322 }
323}
324
Fred Shih37f05ef2014-07-16 18:38:08 -0700325void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
326 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
327}
328
329void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
330 LogValue(ObjectLog::kByte, offset, value, is_volatile);
331}
332
333void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
334 LogValue(ObjectLog::kChar, offset, value, is_volatile);
335}
336
337void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
338 LogValue(ObjectLog::kShort, offset, value, is_volatile);
339}
340
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100341void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700342 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100343}
344
345void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700346 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
347}
348
349void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
350 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
351}
352
353void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
354 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100355 auto it = field_values_.find(offset.Uint32Value());
356 if (it == field_values_.end()) {
357 ObjectLog::FieldValue field_value;
358 field_value.value = value;
359 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700360 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100361 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
362 }
363}
364
365void Transaction::ObjectLog::Undo(mirror::Object* obj) {
366 for (auto& it : field_values_) {
367 // Garbage collector needs to access object's class and array's length. So we don't rollback
368 // these values.
369 MemberOffset field_offset(it.first);
370 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
371 // Skip Object::class field.
372 continue;
373 }
374 if (obj->IsArrayInstance() &&
375 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
376 // Skip Array::length field.
377 continue;
378 }
379 FieldValue& field_value = it.second;
380 UndoFieldWrite(obj, field_offset, field_value);
381 }
382}
383
384void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
385 const FieldValue& field_value) {
386 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
387 // we'd need to disable the check.
388 constexpr bool kCheckTransaction = true;
389 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700390 case kBoolean:
391 if (UNLIKELY(field_value.is_volatile)) {
392 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
393 static_cast<bool>(field_value.value));
394 } else {
395 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
396 static_cast<bool>(field_value.value));
397 }
398 break;
399 case kByte:
400 if (UNLIKELY(field_value.is_volatile)) {
401 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
402 static_cast<int8_t>(field_value.value));
403 } else {
404 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
405 static_cast<int8_t>(field_value.value));
406 }
407 break;
408 case kChar:
409 if (UNLIKELY(field_value.is_volatile)) {
410 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
411 static_cast<uint16_t>(field_value.value));
412 } else {
413 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
414 static_cast<uint16_t>(field_value.value));
415 }
416 break;
417 case kShort:
418 if (UNLIKELY(field_value.is_volatile)) {
419 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
420 static_cast<int16_t>(field_value.value));
421 } else {
422 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
423 static_cast<int16_t>(field_value.value));
424 }
425 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100426 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700427 if (UNLIKELY(field_value.is_volatile)) {
428 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
429 static_cast<uint32_t>(field_value.value));
430 } else {
431 obj->SetField32<false, kCheckTransaction>(field_offset,
432 static_cast<uint32_t>(field_value.value));
433 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100434 break;
435 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700436 if (UNLIKELY(field_value.is_volatile)) {
437 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
438 } else {
439 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
440 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100441 break;
442 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700443 if (UNLIKELY(field_value.is_volatile)) {
444 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
445 reinterpret_cast<mirror::Object*>(field_value.value));
446 } else {
447 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
448 reinterpret_cast<mirror::Object*>(field_value.value));
449 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100450 break;
451 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700452 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100453 break;
454 }
455}
456
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700457void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100458 for (auto it : field_values_) {
459 FieldValue& field_value = it.second;
460 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700461 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
462 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100463 }
464 }
465}
466
467void Transaction::InternStringLog::Undo(InternTable* intern_table) {
468 DCHECK(intern_table != nullptr);
469 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700470 case InternStringLog::kInsert: {
471 switch (string_kind_) {
472 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700473 intern_table->RemoveStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700474 break;
475 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700476 intern_table->RemoveWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700477 break;
478 default:
479 LOG(FATAL) << "Unknown interned string kind";
480 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100481 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700482 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100483 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700484 case InternStringLog::kRemove: {
485 switch (string_kind_) {
486 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700487 intern_table->InsertStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700488 break;
489 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700490 intern_table->InsertWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700491 break;
492 default:
493 LOG(FATAL) << "Unknown interned string kind";
494 break;
495 }
496 break;
497 }
498 default:
499 LOG(FATAL) << "Unknown interned string op";
500 break;
501 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100502}
503
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700504void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier9e868092016-10-31 14:58:04 -0700505 str_.VisitRoot(visitor, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100506}
507
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700508void Transaction::ResolveStringLog::Undo() {
509 dex_cache_.Read()->ClearString(string_idx_);
510}
511
Mathieu Chartier9e868092016-10-31 14:58:04 -0700512Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
513 uint32_t string_idx)
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700514 : dex_cache_(dex_cache),
515 string_idx_(string_idx) {
516 DCHECK(dex_cache != nullptr);
517 DCHECK_LT(string_idx_, dex_cache->GetDexFile()->NumStringIds());
518}
519
520void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
521 dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
522}
523
Mathieu Chartier9e868092016-10-31 14:58:04 -0700524Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
525 StringKind kind,
526 StringOp op)
527 : str_(s),
528 string_kind_(kind),
529 string_op_(op) {
530 DCHECK(s != nullptr);
531}
532
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100533void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
534 auto it = array_values_.find(index);
535 if (it == array_values_.end()) {
536 array_values_.insert(std::make_pair(index, value));
537 }
538}
539
540void Transaction::ArrayLog::Undo(mirror::Array* array) {
541 DCHECK(array != nullptr);
542 DCHECK(array->IsArrayInstance());
543 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
544 for (auto it : array_values_) {
545 UndoArrayWrite(array, type, it.first, it.second);
546 }
547}
548
549void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
550 size_t index, uint64_t value) {
551 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
552 // we'd need to disable the check.
553 switch (array_type) {
554 case Primitive::kPrimBoolean:
555 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
556 break;
557 case Primitive::kPrimByte:
558 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
559 break;
560 case Primitive::kPrimChar:
561 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
562 break;
563 case Primitive::kPrimShort:
564 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
565 break;
566 case Primitive::kPrimInt:
567 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
568 break;
569 case Primitive::kPrimFloat:
570 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
571 break;
572 case Primitive::kPrimLong:
573 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
574 break;
575 case Primitive::kPrimDouble:
576 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
577 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100578 case Primitive::kPrimNot:
579 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100580 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100581 default:
582 LOG(FATAL) << "Unsupported type " << array_type;
583 }
584}
585
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100586} // namespace art