blob: f94bb65881c4c54388bb2f8201343837ee76e8cf [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
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800170void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,
171 dex::StringIndex string_idx) {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700172 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800173 DCHECK_LT(string_idx.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700174 MutexLock mu(Thread::Current(), log_lock_);
175 resolve_string_logs_.push_back(ResolveStringLog(dex_cache, string_idx));
176}
177
Mathieu Chartier9e868092016-10-31 14:58:04 -0700178void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700179 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100180 LogInternedString(log);
181}
182
Mathieu Chartier9e868092016-10-31 14:58:04 -0700183void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700184 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100185 LogInternedString(log);
186}
187
Mathieu Chartier9e868092016-10-31 14:58:04 -0700188void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700189 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100190 LogInternedString(log);
191}
192
Mathieu Chartier9e868092016-10-31 14:58:04 -0700193void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700194 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100195 LogInternedString(log);
196}
197
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700198void Transaction::LogInternedString(const InternStringLog& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100199 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
200 MutexLock mu(Thread::Current(), log_lock_);
201 intern_string_logs_.push_front(log);
202}
203
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100204void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100205 CHECK(!Runtime::Current()->IsActiveTransaction());
206 Thread* self = Thread::Current();
207 self->AssertNoPendingException();
208 MutexLock mu1(self, *Locks::intern_table_lock_);
209 MutexLock mu2(self, log_lock_);
210 UndoObjectModifications();
211 UndoArrayModifications();
212 UndoInternStringTableModifications();
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700213 UndoResolveStringModifications();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100214}
215
216void Transaction::UndoObjectModifications() {
217 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
218 // remove them from the heap.
219 for (auto it : object_logs_) {
220 it.second.Undo(it.first);
221 }
222 object_logs_.clear();
223}
224
225void Transaction::UndoArrayModifications() {
226 // TODO we may not need to restore array allocated during this transaction. Or we could directly
227 // remove them from the heap.
228 for (auto it : array_logs_) {
229 it.second.Undo(it.first);
230 }
231 array_logs_.clear();
232}
233
234void Transaction::UndoInternStringTableModifications() {
235 InternTable* const intern_table = Runtime::Current()->GetInternTable();
236 // We want to undo each operation from the most recent to the oldest. List has been filled so the
237 // most recent operation is at list begin so just have to iterate over it.
238 for (InternStringLog& string_log : intern_string_logs_) {
239 string_log.Undo(intern_table);
240 }
241 intern_string_logs_.clear();
242}
243
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700244void Transaction::UndoResolveStringModifications() {
245 for (ResolveStringLog& string_log : resolve_string_logs_) {
246 string_log.Undo();
247 }
248 resolve_string_logs_.clear();
249}
250
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700251void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100252 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700253 VisitObjectLogs(visitor);
254 VisitArrayLogs(visitor);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700255 VisitInternStringLogs(visitor);
256 VisitResolveStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100257}
258
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700259void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100260 // List of moving roots.
261 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
262 std::list<ObjectPair> moving_roots;
263
264 // Visit roots.
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800265 for (auto& it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700266 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100267 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800268 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700269 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100270 if (new_root != old_root) {
271 moving_roots.push_back(std::make_pair(old_root, new_root));
272 }
273 }
274
275 // Update object logs with moving roots.
276 for (const ObjectPair& pair : moving_roots) {
277 mirror::Object* old_root = pair.first;
278 mirror::Object* new_root = pair.second;
279 auto old_root_it = object_logs_.find(old_root);
280 CHECK(old_root_it != object_logs_.end());
281 CHECK(object_logs_.find(new_root) == object_logs_.end());
282 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
283 object_logs_.erase(old_root_it);
284 }
285}
286
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700287void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100288 // List of moving roots.
289 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
290 std::list<ArrayPair> moving_roots;
291
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800292 for (auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100293 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100294 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800295 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700296 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100297 if (new_root != old_root) {
298 moving_roots.push_back(std::make_pair(old_root, new_root));
299 }
300 }
301
302 // Update array logs with moving roots.
303 for (const ArrayPair& pair : moving_roots) {
304 mirror::Array* old_root = pair.first;
305 mirror::Array* new_root = pair.second;
306 auto old_root_it = array_logs_.find(old_root);
307 CHECK(old_root_it != array_logs_.end());
308 CHECK(array_logs_.find(new_root) == array_logs_.end());
309 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
310 array_logs_.erase(old_root_it);
311 }
312}
313
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700314void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100315 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700316 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100317 }
318}
319
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700320void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
321 for (ResolveStringLog& log : resolve_string_logs_) {
322 log.VisitRoots(visitor);
323 }
324}
325
Fred Shih37f05ef2014-07-16 18:38:08 -0700326void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
327 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
328}
329
330void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
331 LogValue(ObjectLog::kByte, offset, value, is_volatile);
332}
333
334void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
335 LogValue(ObjectLog::kChar, offset, value, is_volatile);
336}
337
338void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
339 LogValue(ObjectLog::kShort, offset, value, is_volatile);
340}
341
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100342void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700343 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100344}
345
346void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700347 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
348}
349
350void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
351 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
352}
353
354void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
355 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100356 auto it = field_values_.find(offset.Uint32Value());
357 if (it == field_values_.end()) {
358 ObjectLog::FieldValue field_value;
359 field_value.value = value;
360 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700361 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100362 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
363 }
364}
365
366void Transaction::ObjectLog::Undo(mirror::Object* obj) {
367 for (auto& it : field_values_) {
368 // Garbage collector needs to access object's class and array's length. So we don't rollback
369 // these values.
370 MemberOffset field_offset(it.first);
371 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
372 // Skip Object::class field.
373 continue;
374 }
375 if (obj->IsArrayInstance() &&
376 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
377 // Skip Array::length field.
378 continue;
379 }
380 FieldValue& field_value = it.second;
381 UndoFieldWrite(obj, field_offset, field_value);
382 }
383}
384
385void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
386 const FieldValue& field_value) {
387 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
388 // we'd need to disable the check.
389 constexpr bool kCheckTransaction = true;
390 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700391 case kBoolean:
392 if (UNLIKELY(field_value.is_volatile)) {
393 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
394 static_cast<bool>(field_value.value));
395 } else {
396 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
397 static_cast<bool>(field_value.value));
398 }
399 break;
400 case kByte:
401 if (UNLIKELY(field_value.is_volatile)) {
402 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
403 static_cast<int8_t>(field_value.value));
404 } else {
405 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
406 static_cast<int8_t>(field_value.value));
407 }
408 break;
409 case kChar:
410 if (UNLIKELY(field_value.is_volatile)) {
411 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
412 static_cast<uint16_t>(field_value.value));
413 } else {
414 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
415 static_cast<uint16_t>(field_value.value));
416 }
417 break;
418 case kShort:
419 if (UNLIKELY(field_value.is_volatile)) {
420 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
421 static_cast<int16_t>(field_value.value));
422 } else {
423 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
424 static_cast<int16_t>(field_value.value));
425 }
426 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100427 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700428 if (UNLIKELY(field_value.is_volatile)) {
429 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
430 static_cast<uint32_t>(field_value.value));
431 } else {
432 obj->SetField32<false, kCheckTransaction>(field_offset,
433 static_cast<uint32_t>(field_value.value));
434 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100435 break;
436 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700437 if (UNLIKELY(field_value.is_volatile)) {
438 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
439 } else {
440 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
441 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100442 break;
443 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700444 if (UNLIKELY(field_value.is_volatile)) {
445 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
446 reinterpret_cast<mirror::Object*>(field_value.value));
447 } else {
448 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
449 reinterpret_cast<mirror::Object*>(field_value.value));
450 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100451 break;
452 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700453 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100454 break;
455 }
456}
457
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700458void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800459 for (auto& it : field_values_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100460 FieldValue& field_value = it.second;
461 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700462 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
463 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100464 }
465 }
466}
467
468void Transaction::InternStringLog::Undo(InternTable* intern_table) {
469 DCHECK(intern_table != nullptr);
470 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700471 case InternStringLog::kInsert: {
472 switch (string_kind_) {
473 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700474 intern_table->RemoveStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700475 break;
476 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700477 intern_table->RemoveWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700478 break;
479 default:
480 LOG(FATAL) << "Unknown interned string kind";
481 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100482 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700483 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100484 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700485 case InternStringLog::kRemove: {
486 switch (string_kind_) {
487 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700488 intern_table->InsertStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700489 break;
490 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700491 intern_table->InsertWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700492 break;
493 default:
494 LOG(FATAL) << "Unknown interned string kind";
495 break;
496 }
497 break;
498 }
499 default:
500 LOG(FATAL) << "Unknown interned string op";
501 break;
502 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100503}
504
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700505void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier9e868092016-10-31 14:58:04 -0700506 str_.VisitRoot(visitor, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100507}
508
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700509void Transaction::ResolveStringLog::Undo() {
510 dex_cache_.Read()->ClearString(string_idx_);
511}
512
Mathieu Chartier9e868092016-10-31 14:58:04 -0700513Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800514 dex::StringIndex string_idx)
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700515 : dex_cache_(dex_cache),
516 string_idx_(string_idx) {
517 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800518 DCHECK_LT(string_idx_.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700519}
520
521void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
522 dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
523}
524
Mathieu Chartier9e868092016-10-31 14:58:04 -0700525Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
526 StringKind kind,
527 StringOp op)
528 : str_(s),
529 string_kind_(kind),
530 string_op_(op) {
531 DCHECK(s != nullptr);
532}
533
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100534void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
535 auto it = array_values_.find(index);
536 if (it == array_values_.end()) {
537 array_values_.insert(std::make_pair(index, value));
538 }
539}
540
541void Transaction::ArrayLog::Undo(mirror::Array* array) {
542 DCHECK(array != nullptr);
543 DCHECK(array->IsArrayInstance());
544 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
545 for (auto it : array_values_) {
546 UndoArrayWrite(array, type, it.first, it.second);
547 }
548}
549
550void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
551 size_t index, uint64_t value) {
552 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
553 // we'd need to disable the check.
554 switch (array_type) {
555 case Primitive::kPrimBoolean:
556 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
557 break;
558 case Primitive::kPrimByte:
559 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
560 break;
561 case Primitive::kPrimChar:
562 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
563 break;
564 case Primitive::kPrimShort:
565 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
566 break;
567 case Primitive::kPrimInt:
568 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
569 break;
570 case Primitive::kPrimFloat:
571 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
572 break;
573 case Primitive::kPrimLong:
574 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
575 break;
576 case Primitive::kPrimDouble:
577 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
578 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100579 case Primitive::kPrimNot:
580 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100581 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100582 default:
583 LOG(FATAL) << "Unsupported type " << array_type;
584 }
585}
586
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100587} // namespace art