blob: b4e35cd7d27c3d7c5fb241f38c5ee4ebe2c286c8 [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
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010019#include "base/logging.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070020#include "base/stl_util.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010021#include "gc/accounting/card_table-inl.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070022#include "gc_root-inl.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010023#include "intern_table.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070024#include "mirror/class-inl.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070025#include "mirror/dex_cache-inl.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010026#include "mirror/object-inl.h"
27#include "mirror/object_array-inl.h"
28
29#include <list>
30
31namespace art {
32
33// TODO: remove (only used for debugging purpose).
34static constexpr bool kEnableTransactionStats = false;
35
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010036Transaction::Transaction()
Chang Xing5a906fc2017-07-26 15:01:16 -070037 : log_lock_("transaction log lock", kTransactionLogLock),
38 aborted_(false),
39 strict_(false) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080040 CHECK(Runtime::Current()->IsAotCompiler());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010041}
42
Chang Xing5a906fc2017-07-26 15:01:16 -070043Transaction::Transaction(bool strict, mirror::Class* root) : Transaction() {
44 strict_ = strict;
Chang Xingcade5c32017-07-20 17:56:26 -070045 root_ = root;
46}
47
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010048Transaction::~Transaction() {
49 if (kEnableTransactionStats) {
50 MutexLock mu(Thread::Current(), log_lock_);
51 size_t objects_count = object_logs_.size();
52 size_t field_values_count = 0;
Mathieu Chartier38e954c2017-02-03 16:06:35 -080053 for (const auto& it : object_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010054 field_values_count += it.second.Size();
55 }
56 size_t array_count = array_logs_.size();
57 size_t array_values_count = 0;
Mathieu Chartier38e954c2017-02-03 16:06:35 -080058 for (const auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010059 array_values_count += it.second.Size();
60 }
Mathieu Chartierbb816d62016-09-07 10:17:46 -070061 size_t intern_string_count = intern_string_logs_.size();
62 size_t resolve_string_count = resolve_string_logs_.size();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010063 LOG(INFO) << "Transaction::~Transaction"
64 << ": objects_count=" << objects_count
65 << ", field_values_count=" << field_values_count
66 << ", array_count=" << array_count
67 << ", array_values_count=" << array_values_count
Mathieu Chartierbb816d62016-09-07 10:17:46 -070068 << ", intern_string_count=" << intern_string_count
69 << ", resolve_string_count=" << resolve_string_count;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010070 }
71}
72
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010073void Transaction::Abort(const std::string& abort_message) {
74 MutexLock mu(Thread::Current(), log_lock_);
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020075 // We may abort more than once if the exception thrown at the time of the
76 // previous abort has been caught during execution of a class initializer.
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010077 // We just keep the message of the first abort because it will cause the
78 // transaction to be rolled back anyway.
79 if (!aborted_) {
80 aborted_ = true;
81 abort_message_ = abort_message;
82 }
83}
84
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020085void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
86 const bool rethrow = (abort_message == nullptr);
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010087 if (kIsDebugBuild && rethrow) {
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020088 CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
89 << " while transaction is not aborted";
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010090 }
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020091 if (rethrow) {
92 // Rethrow an exception with the earlier abort message stored in the transaction.
93 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
94 GetAbortMessage().c_str());
95 } else {
96 // Throw an exception with the given abort message.
97 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
98 abort_message->c_str());
99 }
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100100}
101
102bool Transaction::IsAborted() {
103 MutexLock mu(Thread::Current(), log_lock_);
104 return aborted_;
105}
106
Chang Xing5a906fc2017-07-26 15:01:16 -0700107bool Transaction::IsStrict() {
108 MutexLock mu(Thread::Current(), log_lock_);
109 return strict_;
110}
111
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100112const std::string& Transaction::GetAbortMessage() {
113 MutexLock mu(Thread::Current(), log_lock_);
114 return abort_message_;
115}
116
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800117void Transaction::RecordWriteFieldBoolean(mirror::Object* obj,
118 MemberOffset field_offset,
119 uint8_t value,
120 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700121 DCHECK(obj != nullptr);
122 MutexLock mu(Thread::Current(), log_lock_);
123 ObjectLog& object_log = object_logs_[obj];
124 object_log.LogBooleanValue(field_offset, value, is_volatile);
125}
126
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800127void Transaction::RecordWriteFieldByte(mirror::Object* obj,
128 MemberOffset field_offset,
129 int8_t value,
130 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700131 DCHECK(obj != nullptr);
132 MutexLock mu(Thread::Current(), log_lock_);
133 ObjectLog& object_log = object_logs_[obj];
134 object_log.LogByteValue(field_offset, value, is_volatile);
135}
136
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800137void Transaction::RecordWriteFieldChar(mirror::Object* obj,
138 MemberOffset field_offset,
139 uint16_t value,
140 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700141 DCHECK(obj != nullptr);
142 MutexLock mu(Thread::Current(), log_lock_);
143 ObjectLog& object_log = object_logs_[obj];
144 object_log.LogCharValue(field_offset, value, is_volatile);
145}
146
147
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800148void Transaction::RecordWriteFieldShort(mirror::Object* obj,
149 MemberOffset field_offset,
150 int16_t value,
151 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700152 DCHECK(obj != nullptr);
153 MutexLock mu(Thread::Current(), log_lock_);
154 ObjectLog& object_log = object_logs_[obj];
155 object_log.LogShortValue(field_offset, value, is_volatile);
156}
157
158
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800159void Transaction::RecordWriteField32(mirror::Object* obj,
160 MemberOffset field_offset,
161 uint32_t value,
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100162 bool is_volatile) {
163 DCHECK(obj != nullptr);
164 MutexLock mu(Thread::Current(), log_lock_);
165 ObjectLog& object_log = object_logs_[obj];
166 object_log.Log32BitsValue(field_offset, value, is_volatile);
167}
168
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800169void Transaction::RecordWriteField64(mirror::Object* obj,
170 MemberOffset field_offset,
171 uint64_t value,
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100172 bool is_volatile) {
173 DCHECK(obj != nullptr);
174 MutexLock mu(Thread::Current(), log_lock_);
175 ObjectLog& object_log = object_logs_[obj];
176 object_log.Log64BitsValue(field_offset, value, is_volatile);
177}
178
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800179void Transaction::RecordWriteFieldReference(mirror::Object* obj,
180 MemberOffset field_offset,
181 mirror::Object* value,
182 bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100183 DCHECK(obj != nullptr);
184 MutexLock mu(Thread::Current(), log_lock_);
185 ObjectLog& object_log = object_logs_[obj];
186 object_log.LogReferenceValue(field_offset, value, is_volatile);
187}
188
189void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
190 DCHECK(array != nullptr);
191 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100192 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100193 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800194 auto it = array_logs_.find(array);
195 if (it == array_logs_.end()) {
196 ArrayLog log;
197 it = array_logs_.emplace(array, std::move(log)).first;
198 }
199 it->second.LogValue(index, value);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100200}
201
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800202void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,
203 dex::StringIndex string_idx) {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700204 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800205 DCHECK_LT(string_idx.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700206 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800207 resolve_string_logs_.emplace_back(dex_cache, string_idx);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700208}
209
Mathieu Chartier9e868092016-10-31 14:58:04 -0700210void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700211 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800212 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100213}
214
Mathieu Chartier9e868092016-10-31 14:58:04 -0700215void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700216 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800217 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100218}
219
Mathieu Chartier9e868092016-10-31 14:58:04 -0700220void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700221 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800222 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100223}
224
Mathieu Chartier9e868092016-10-31 14:58:04 -0700225void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700226 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800227 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100228}
229
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800230void Transaction::LogInternedString(InternStringLog&& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100231 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
232 MutexLock mu(Thread::Current(), log_lock_);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800233 intern_string_logs_.push_front(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100234}
235
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100236void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100237 CHECK(!Runtime::Current()->IsActiveTransaction());
238 Thread* self = Thread::Current();
239 self->AssertNoPendingException();
240 MutexLock mu1(self, *Locks::intern_table_lock_);
241 MutexLock mu2(self, log_lock_);
242 UndoObjectModifications();
243 UndoArrayModifications();
244 UndoInternStringTableModifications();
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700245 UndoResolveStringModifications();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100246}
247
248void Transaction::UndoObjectModifications() {
249 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
250 // remove them from the heap.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800251 for (const auto& it : object_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100252 it.second.Undo(it.first);
253 }
254 object_logs_.clear();
255}
256
257void Transaction::UndoArrayModifications() {
258 // TODO we may not need to restore array allocated during this transaction. Or we could directly
259 // remove them from the heap.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800260 for (const auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100261 it.second.Undo(it.first);
262 }
263 array_logs_.clear();
264}
265
266void Transaction::UndoInternStringTableModifications() {
267 InternTable* const intern_table = Runtime::Current()->GetInternTable();
268 // We want to undo each operation from the most recent to the oldest. List has been filled so the
269 // most recent operation is at list begin so just have to iterate over it.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800270 for (const InternStringLog& string_log : intern_string_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100271 string_log.Undo(intern_table);
272 }
273 intern_string_logs_.clear();
274}
275
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700276void Transaction::UndoResolveStringModifications() {
277 for (ResolveStringLog& string_log : resolve_string_logs_) {
278 string_log.Undo();
279 }
280 resolve_string_logs_.clear();
281}
282
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700283void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100284 MutexLock mu(Thread::Current(), log_lock_);
Chang Xingcade5c32017-07-20 17:56:26 -0700285 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&root_), RootInfo(kRootUnknown));
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700286 VisitObjectLogs(visitor);
287 VisitArrayLogs(visitor);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700288 VisitInternStringLogs(visitor);
289 VisitResolveStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100290}
291
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700292void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100293 // List of moving roots.
294 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
295 std::list<ObjectPair> moving_roots;
296
297 // Visit roots.
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800298 for (auto& it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700299 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100300 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800301 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700302 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100303 if (new_root != old_root) {
304 moving_roots.push_back(std::make_pair(old_root, new_root));
305 }
306 }
307
308 // Update object logs with moving roots.
309 for (const ObjectPair& pair : moving_roots) {
310 mirror::Object* old_root = pair.first;
311 mirror::Object* new_root = pair.second;
312 auto old_root_it = object_logs_.find(old_root);
313 CHECK(old_root_it != object_logs_.end());
314 CHECK(object_logs_.find(new_root) == object_logs_.end());
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800315 object_logs_.emplace(new_root, std::move(old_root_it->second));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100316 object_logs_.erase(old_root_it);
317 }
318}
319
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700320void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100321 // List of moving roots.
322 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
323 std::list<ArrayPair> moving_roots;
324
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800325 for (auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100326 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100327 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800328 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700329 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100330 if (new_root != old_root) {
331 moving_roots.push_back(std::make_pair(old_root, new_root));
332 }
333 }
334
335 // Update array logs with moving roots.
336 for (const ArrayPair& pair : moving_roots) {
337 mirror::Array* old_root = pair.first;
338 mirror::Array* new_root = pair.second;
339 auto old_root_it = array_logs_.find(old_root);
340 CHECK(old_root_it != array_logs_.end());
341 CHECK(array_logs_.find(new_root) == array_logs_.end());
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800342 array_logs_.emplace(new_root, std::move(old_root_it->second));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100343 array_logs_.erase(old_root_it);
344 }
345}
346
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700347void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100348 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700349 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100350 }
351}
352
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700353void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
354 for (ResolveStringLog& log : resolve_string_logs_) {
355 log.VisitRoots(visitor);
356 }
357}
358
Fred Shih37f05ef2014-07-16 18:38:08 -0700359void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
360 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
361}
362
363void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
364 LogValue(ObjectLog::kByte, offset, value, is_volatile);
365}
366
367void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
368 LogValue(ObjectLog::kChar, offset, value, is_volatile);
369}
370
371void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
372 LogValue(ObjectLog::kShort, offset, value, is_volatile);
373}
374
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100375void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700376 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100377}
378
379void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700380 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
381}
382
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800383void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset,
384 mirror::Object* obj,
385 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700386 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
387}
388
389void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800390 MemberOffset offset,
391 uint64_t value,
392 bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100393 auto it = field_values_.find(offset.Uint32Value());
394 if (it == field_values_.end()) {
395 ObjectLog::FieldValue field_value;
396 field_value.value = value;
397 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700398 field_value.kind = kind;
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800399 field_values_.emplace(offset.Uint32Value(), std::move(field_value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100400 }
401}
402
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800403void Transaction::ObjectLog::Undo(mirror::Object* obj) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100404 for (auto& it : field_values_) {
405 // Garbage collector needs to access object's class and array's length. So we don't rollback
406 // these values.
407 MemberOffset field_offset(it.first);
408 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
409 // Skip Object::class field.
410 continue;
411 }
412 if (obj->IsArrayInstance() &&
413 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
414 // Skip Array::length field.
415 continue;
416 }
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800417 const FieldValue& field_value = it.second;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100418 UndoFieldWrite(obj, field_offset, field_value);
419 }
420}
421
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800422void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj,
423 MemberOffset field_offset,
424 const FieldValue& field_value) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100425 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
426 // we'd need to disable the check.
427 constexpr bool kCheckTransaction = true;
428 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700429 case kBoolean:
430 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800431 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(
432 field_offset,
433 static_cast<bool>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700434 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800435 obj->SetFieldBoolean<false, kCheckTransaction>(
436 field_offset,
437 static_cast<bool>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700438 }
439 break;
440 case kByte:
441 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800442 obj->SetFieldByteVolatile<false, kCheckTransaction>(
443 field_offset,
444 static_cast<int8_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700445 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800446 obj->SetFieldByte<false, kCheckTransaction>(
447 field_offset,
448 static_cast<int8_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700449 }
450 break;
451 case kChar:
452 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800453 obj->SetFieldCharVolatile<false, kCheckTransaction>(
454 field_offset,
455 static_cast<uint16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700456 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800457 obj->SetFieldChar<false, kCheckTransaction>(
458 field_offset,
459 static_cast<uint16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700460 }
461 break;
462 case kShort:
463 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800464 obj->SetFieldShortVolatile<false, kCheckTransaction>(
465 field_offset,
466 static_cast<int16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700467 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800468 obj->SetFieldShort<false, kCheckTransaction>(
469 field_offset,
470 static_cast<int16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700471 }
472 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100473 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700474 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800475 obj->SetField32Volatile<false, kCheckTransaction>(
476 field_offset,
477 static_cast<uint32_t>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700478 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800479 obj->SetField32<false, kCheckTransaction>(
480 field_offset,
481 static_cast<uint32_t>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700482 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100483 break;
484 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700485 if (UNLIKELY(field_value.is_volatile)) {
486 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
487 } else {
488 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
489 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100490 break;
491 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700492 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800493 obj->SetFieldObjectVolatile<false, kCheckTransaction>(
494 field_offset,
495 reinterpret_cast<mirror::Object*>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700496 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800497 obj->SetFieldObject<false, kCheckTransaction>(
498 field_offset,
499 reinterpret_cast<mirror::Object*>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700500 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100501 break;
502 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700503 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100504 break;
505 }
506}
507
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700508void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800509 for (auto& it : field_values_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100510 FieldValue& field_value = it.second;
511 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700512 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
513 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100514 }
515 }
516}
517
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800518void Transaction::InternStringLog::Undo(InternTable* intern_table) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100519 DCHECK(intern_table != nullptr);
520 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700521 case InternStringLog::kInsert: {
522 switch (string_kind_) {
523 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700524 intern_table->RemoveStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700525 break;
526 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700527 intern_table->RemoveWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700528 break;
529 default:
530 LOG(FATAL) << "Unknown interned string kind";
531 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100532 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700533 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100534 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700535 case InternStringLog::kRemove: {
536 switch (string_kind_) {
537 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700538 intern_table->InsertStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700539 break;
540 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700541 intern_table->InsertWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700542 break;
543 default:
544 LOG(FATAL) << "Unknown interned string kind";
545 break;
546 }
547 break;
548 }
549 default:
550 LOG(FATAL) << "Unknown interned string op";
551 break;
552 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100553}
554
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700555void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier9e868092016-10-31 14:58:04 -0700556 str_.VisitRoot(visitor, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100557}
558
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800559void Transaction::ResolveStringLog::Undo() const {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700560 dex_cache_.Read()->ClearString(string_idx_);
561}
562
Mathieu Chartier9e868092016-10-31 14:58:04 -0700563Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800564 dex::StringIndex string_idx)
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700565 : dex_cache_(dex_cache),
566 string_idx_(string_idx) {
567 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800568 DCHECK_LT(string_idx_.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700569}
570
571void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
572 dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
573}
574
Mathieu Chartier9e868092016-10-31 14:58:04 -0700575Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
576 StringKind kind,
577 StringOp op)
578 : str_(s),
579 string_kind_(kind),
580 string_op_(op) {
581 DCHECK(s != nullptr);
582}
583
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100584void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
585 auto it = array_values_.find(index);
586 if (it == array_values_.end()) {
587 array_values_.insert(std::make_pair(index, value));
588 }
589}
590
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800591void Transaction::ArrayLog::Undo(mirror::Array* array) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100592 DCHECK(array != nullptr);
593 DCHECK(array->IsArrayInstance());
594 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
595 for (auto it : array_values_) {
596 UndoArrayWrite(array, type, it.first, it.second);
597 }
598}
599
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800600void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array,
601 Primitive::Type array_type,
602 size_t index,
603 uint64_t value) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100604 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
605 // we'd need to disable the check.
606 switch (array_type) {
607 case Primitive::kPrimBoolean:
608 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
609 break;
610 case Primitive::kPrimByte:
611 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
612 break;
613 case Primitive::kPrimChar:
614 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
615 break;
616 case Primitive::kPrimShort:
617 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
618 break;
619 case Primitive::kPrimInt:
620 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
621 break;
622 case Primitive::kPrimFloat:
623 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
624 break;
625 case Primitive::kPrimLong:
626 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
627 break;
628 case Primitive::kPrimDouble:
629 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
630 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100631 case Primitive::kPrimNot:
632 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100633 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100634 default:
635 LOG(FATAL) << "Unsupported type " << array_type;
636 }
637}
638
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100639} // namespace art