blob: 0293d231f4891337d73049f736b7ad1c03dfa7c7 [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
Andreas Gampe57943812017-12-06 21:39:13 -080019#include <android-base/logging.h>
20
Vladimir Marko7ed2d382019-11-25 10:41:53 +000021#include "aot_class_linker.h"
Andreas Gampe88dbad32018-06-26 19:54:12 -070022#include "base/mutex-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070023#include "base/stl_util.h"
Vladimir Marko0685b982021-03-25 11:59:22 +000024#include "dex/descriptors_names.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010025#include "gc/accounting/card_table-inl.h"
Vladimir Marko672c0802019-07-26 13:03:13 +010026#include "gc/heap.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070027#include "gc_root-inl.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010028#include "intern_table.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070029#include "mirror/class-inl.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070030#include "mirror/dex_cache-inl.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010031#include "mirror/object-inl.h"
32#include "mirror/object_array-inl.h"
Vladimir Marko672c0802019-07-26 13:03:13 +010033#include "obj_ptr-inl.h"
34#include "runtime.h"
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010035
36#include <list>
37
38namespace art {
39
40// TODO: remove (only used for debugging purpose).
41static constexpr bool kEnableTransactionStats = false;
42
Vladimir Marko672c0802019-07-26 13:03:13 +010043Transaction::Transaction(bool strict, mirror::Class* root)
44 : log_lock_("transaction log lock", kTransactionLogLock),
45 aborted_(false),
46 rolling_back_(false),
Vladimir Marko4d7b6892020-01-16 17:06:35 +000047 heap_(Runtime::Current()->GetHeap()),
48 strict_(strict),
Vladimir Markob68bb7a2020-03-17 10:55:25 +000049 root_(root),
50 assert_no_new_records_reason_(nullptr) {
Vladimir Marko672c0802019-07-26 13:03:13 +010051 DCHECK(Runtime::Current()->IsAotCompiler());
Chang Xingcade5c32017-07-20 17:56:26 -070052}
53
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010054Transaction::~Transaction() {
55 if (kEnableTransactionStats) {
56 MutexLock mu(Thread::Current(), log_lock_);
57 size_t objects_count = object_logs_.size();
58 size_t field_values_count = 0;
Mathieu Chartier38e954c2017-02-03 16:06:35 -080059 for (const auto& it : object_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010060 field_values_count += it.second.Size();
61 }
62 size_t array_count = array_logs_.size();
63 size_t array_values_count = 0;
Mathieu Chartier38e954c2017-02-03 16:06:35 -080064 for (const auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010065 array_values_count += it.second.Size();
66 }
Mathieu Chartierbb816d62016-09-07 10:17:46 -070067 size_t intern_string_count = intern_string_logs_.size();
68 size_t resolve_string_count = resolve_string_logs_.size();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010069 LOG(INFO) << "Transaction::~Transaction"
70 << ": objects_count=" << objects_count
71 << ", field_values_count=" << field_values_count
72 << ", array_count=" << array_count
73 << ", array_values_count=" << array_values_count
Mathieu Chartierbb816d62016-09-07 10:17:46 -070074 << ", intern_string_count=" << intern_string_count
75 << ", resolve_string_count=" << resolve_string_count;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010076 }
77}
78
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010079void Transaction::Abort(const std::string& abort_message) {
80 MutexLock mu(Thread::Current(), log_lock_);
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020081 // We may abort more than once if the exception thrown at the time of the
82 // previous abort has been caught during execution of a class initializer.
Sebastien Hertz1c80bec2015-02-03 11:58:06 +010083 // We just keep the message of the first abort because it will cause the
84 // transaction to be rolled back anyway.
85 if (!aborted_) {
86 aborted_ = true;
87 abort_message_ = abort_message;
88 }
89}
90
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020091void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
92 const bool rethrow = (abort_message == nullptr);
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010093 if (kIsDebugBuild && rethrow) {
Vladimir Marko0685b982021-03-25 11:59:22 +000094 CHECK(IsAborted()) << "Rethrow " << DescriptorToDot(Transaction::kAbortExceptionDescriptor)
Sebastien Hertz2fd7e692015-04-02 11:11:19 +020095 << " while transaction is not aborted";
Sebastien Hertzbd9cf9f2015-03-03 12:16:13 +010096 }
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +020097 if (rethrow) {
98 // Rethrow an exception with the earlier abort message stored in the transaction.
Vladimir Marko0685b982021-03-25 11:59:22 +000099 self->ThrowNewWrappedException(Transaction::kAbortExceptionDescriptor,
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +0200100 GetAbortMessage().c_str());
101 } else {
102 // Throw an exception with the given abort message.
Vladimir Marko0685b982021-03-25 11:59:22 +0000103 self->ThrowNewWrappedException(Transaction::kAbortExceptionDescriptor,
Sebastien Hertzb81e1cd2015-04-28 12:31:41 +0200104 abort_message->c_str());
105 }
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100106}
107
108bool Transaction::IsAborted() {
109 MutexLock mu(Thread::Current(), log_lock_);
110 return aborted_;
111}
112
Chang Xing605fe242017-07-20 15:57:21 -0700113bool Transaction::IsRollingBack() {
114 return rolling_back_;
115}
116
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100117const std::string& Transaction::GetAbortMessage() {
118 MutexLock mu(Thread::Current(), log_lock_);
119 return abort_message_;
120}
121
Vladimir Marko4d7b6892020-01-16 17:06:35 +0000122bool Transaction::WriteConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
123 DCHECK(obj != nullptr);
Vladimir Marko672c0802019-07-26 13:03:13 +0100124 MutexLock mu(self, log_lock_);
Vladimir Marko4d7b6892020-01-16 17:06:35 +0000125
126 // Prevent changes in boot image spaces for app or boot image extension.
127 // For boot image there are no boot image spaces and this condition evaluates to false.
128 if (heap_->ObjectIsInBootImageSpace(obj)) {
129 return true;
Chang Xingbd208d82017-07-12 14:53:17 -0700130 }
Vladimir Marko4d7b6892020-01-16 17:06:35 +0000131
132 // For apps, also prevent writing to other classes.
133 return IsStrict() &&
134 obj->IsClass() && // no constraint updating instances or arrays
135 obj != root_; // modifying other classes' static field, fail
Chang Xingbd208d82017-07-12 14:53:17 -0700136}
137
Vladimir Marko149cdda2019-11-12 15:02:51 +0000138bool Transaction::WriteValueConstraint(Thread* self, ObjPtr<mirror::Object> value) {
139 if (value == nullptr) {
140 return false; // We can always store null values.
141 }
142 gc::Heap* heap = Runtime::Current()->GetHeap();
143 MutexLock mu(self, log_lock_);
144 if (IsStrict()) {
145 // TODO: Should we restrict writes the same way as for boot image extension?
146 return false;
147 } else if (heap->GetBootImageSpaces().empty()) {
148 return false; // No constraints for boot image.
149 } else {
150 // Boot image extension.
Vladimir Marko149cdda2019-11-12 15:02:51 +0000151 ObjPtr<mirror::Class> klass = value->IsClass() ? value->AsClass() : value->GetClass();
Vladimir Marko7ed2d382019-11-25 10:41:53 +0000152 return !AotClassLinker::CanReferenceInBootImageExtension(klass, heap);
Vladimir Marko149cdda2019-11-12 15:02:51 +0000153 }
154}
155
Vladimir Marko4d7b6892020-01-16 17:06:35 +0000156bool Transaction::ReadConstraint(Thread* self, ObjPtr<mirror::Object> obj) {
157 // Read constraints are checked only for static field reads as there are
158 // no constraints on reading instance fields and array elements.
Chang Xingbd208d82017-07-12 14:53:17 -0700159 DCHECK(obj->IsClass());
Vladimir Marko672c0802019-07-26 13:03:13 +0100160 MutexLock mu(self, log_lock_);
161 if (IsStrict()) {
162 return obj != root_; // fail if not self-updating
163 } else {
164 // For boot image and boot image extension, allow reading any field.
Chang Xingbd208d82017-07-12 14:53:17 -0700165 return false;
166 }
Chang Xingbd208d82017-07-12 14:53:17 -0700167}
168
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800169void Transaction::RecordWriteFieldBoolean(mirror::Object* obj,
170 MemberOffset field_offset,
171 uint8_t value,
172 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700173 DCHECK(obj != nullptr);
174 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000175 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Fred Shih37f05ef2014-07-16 18:38:08 -0700176 ObjectLog& object_log = object_logs_[obj];
177 object_log.LogBooleanValue(field_offset, value, is_volatile);
178}
179
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800180void Transaction::RecordWriteFieldByte(mirror::Object* obj,
181 MemberOffset field_offset,
182 int8_t value,
183 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700184 DCHECK(obj != nullptr);
185 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000186 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Fred Shih37f05ef2014-07-16 18:38:08 -0700187 ObjectLog& object_log = object_logs_[obj];
188 object_log.LogByteValue(field_offset, value, is_volatile);
189}
190
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800191void Transaction::RecordWriteFieldChar(mirror::Object* obj,
192 MemberOffset field_offset,
193 uint16_t value,
194 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700195 DCHECK(obj != nullptr);
196 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000197 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Fred Shih37f05ef2014-07-16 18:38:08 -0700198 ObjectLog& object_log = object_logs_[obj];
199 object_log.LogCharValue(field_offset, value, is_volatile);
200}
201
202
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800203void Transaction::RecordWriteFieldShort(mirror::Object* obj,
204 MemberOffset field_offset,
205 int16_t value,
206 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700207 DCHECK(obj != nullptr);
208 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000209 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Fred Shih37f05ef2014-07-16 18:38:08 -0700210 ObjectLog& object_log = object_logs_[obj];
211 object_log.LogShortValue(field_offset, value, is_volatile);
212}
213
214
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800215void Transaction::RecordWriteField32(mirror::Object* obj,
216 MemberOffset field_offset,
217 uint32_t value,
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100218 bool is_volatile) {
219 DCHECK(obj != nullptr);
220 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000221 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100222 ObjectLog& object_log = object_logs_[obj];
223 object_log.Log32BitsValue(field_offset, value, is_volatile);
224}
225
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800226void Transaction::RecordWriteField64(mirror::Object* obj,
227 MemberOffset field_offset,
228 uint64_t value,
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100229 bool is_volatile) {
230 DCHECK(obj != nullptr);
231 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000232 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100233 ObjectLog& object_log = object_logs_[obj];
234 object_log.Log64BitsValue(field_offset, value, is_volatile);
235}
236
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800237void Transaction::RecordWriteFieldReference(mirror::Object* obj,
238 MemberOffset field_offset,
239 mirror::Object* value,
240 bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100241 DCHECK(obj != nullptr);
242 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000243 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100244 ObjectLog& object_log = object_logs_[obj];
245 object_log.LogReferenceValue(field_offset, value, is_volatile);
246}
247
248void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
249 DCHECK(array != nullptr);
250 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100251 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100252 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000253 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800254 auto it = array_logs_.find(array);
255 if (it == array_logs_.end()) {
256 ArrayLog log;
257 it = array_logs_.emplace(array, std::move(log)).first;
258 }
259 it->second.LogValue(index, value);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100260}
261
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800262void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache,
263 dex::StringIndex string_idx) {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700264 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800265 DCHECK_LT(string_idx.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700266 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000267 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800268 resolve_string_logs_.emplace_back(dex_cache, string_idx);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700269}
270
Mathieu Chartier9e868092016-10-31 14:58:04 -0700271void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700272 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800273 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100274}
275
Mathieu Chartier9e868092016-10-31 14:58:04 -0700276void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700277 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800278 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100279}
280
Mathieu Chartier9e868092016-10-31 14:58:04 -0700281void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700282 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800283 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100284}
285
Mathieu Chartier9e868092016-10-31 14:58:04 -0700286void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
Mathieu Chartiercdfd39f2014-08-29 18:16:58 -0700287 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800288 LogInternedString(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100289}
290
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800291void Transaction::LogInternedString(InternStringLog&& log) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100292 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
293 MutexLock mu(Thread::Current(), log_lock_);
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000294 DCHECK(assert_no_new_records_reason_ == nullptr) << assert_no_new_records_reason_;
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800295 intern_string_logs_.push_front(std::move(log));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100296}
297
Sebastien Hertz1c80bec2015-02-03 11:58:06 +0100298void Transaction::Rollback() {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100299 Thread* self = Thread::Current();
300 self->AssertNoPendingException();
301 MutexLock mu1(self, *Locks::intern_table_lock_);
302 MutexLock mu2(self, log_lock_);
Chang Xing605fe242017-07-20 15:57:21 -0700303 rolling_back_ = true;
304 CHECK(!Runtime::Current()->IsActiveTransaction());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100305 UndoObjectModifications();
306 UndoArrayModifications();
307 UndoInternStringTableModifications();
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700308 UndoResolveStringModifications();
Chang Xing605fe242017-07-20 15:57:21 -0700309 rolling_back_ = false;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100310}
311
312void Transaction::UndoObjectModifications() {
313 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
314 // remove them from the heap.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800315 for (const auto& it : object_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100316 it.second.Undo(it.first);
317 }
318 object_logs_.clear();
319}
320
321void Transaction::UndoArrayModifications() {
322 // TODO we may not need to restore array allocated during this transaction. Or we could directly
323 // remove them from the heap.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800324 for (const auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100325 it.second.Undo(it.first);
326 }
327 array_logs_.clear();
328}
329
330void Transaction::UndoInternStringTableModifications() {
331 InternTable* const intern_table = Runtime::Current()->GetInternTable();
332 // We want to undo each operation from the most recent to the oldest. List has been filled so the
333 // most recent operation is at list begin so just have to iterate over it.
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800334 for (const InternStringLog& string_log : intern_string_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100335 string_log.Undo(intern_table);
336 }
337 intern_string_logs_.clear();
338}
339
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700340void Transaction::UndoResolveStringModifications() {
341 for (ResolveStringLog& string_log : resolve_string_logs_) {
342 string_log.Undo();
343 }
344 resolve_string_logs_.clear();
345}
346
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700347void Transaction::VisitRoots(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100348 MutexLock mu(Thread::Current(), log_lock_);
Chang Xingcade5c32017-07-20 17:56:26 -0700349 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&root_), RootInfo(kRootUnknown));
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700350 VisitObjectLogs(visitor);
351 VisitArrayLogs(visitor);
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700352 VisitInternStringLogs(visitor);
353 VisitResolveStringLogs(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100354}
355
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700356void Transaction::VisitObjectLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100357 // List of moving roots.
Andreas Gampec55bb392018-09-21 00:02:02 +0000358 using ObjectPair = std::pair<mirror::Object*, mirror::Object*>;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100359 std::list<ObjectPair> moving_roots;
360
361 // Visit roots.
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800362 for (auto& it : object_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700363 it.second.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100364 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800365 mirror::Object* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700366 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100367 if (new_root != old_root) {
368 moving_roots.push_back(std::make_pair(old_root, new_root));
369 }
370 }
371
372 // Update object logs with moving roots.
373 for (const ObjectPair& pair : moving_roots) {
374 mirror::Object* old_root = pair.first;
375 mirror::Object* new_root = pair.second;
376 auto old_root_it = object_logs_.find(old_root);
377 CHECK(old_root_it != object_logs_.end());
378 CHECK(object_logs_.find(new_root) == object_logs_.end());
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800379 object_logs_.emplace(new_root, std::move(old_root_it->second));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100380 object_logs_.erase(old_root_it);
381 }
382}
383
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700384void Transaction::VisitArrayLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100385 // List of moving roots.
Andreas Gampec55bb392018-09-21 00:02:02 +0000386 using ArrayPair = std::pair<mirror::Array*, mirror::Array*>;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100387 std::list<ArrayPair> moving_roots;
388
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800389 for (auto& it : array_logs_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100390 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100391 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800392 mirror::Array* new_root = old_root;
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700393 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100394 if (new_root != old_root) {
395 moving_roots.push_back(std::make_pair(old_root, new_root));
396 }
397 }
398
399 // Update array logs with moving roots.
400 for (const ArrayPair& pair : moving_roots) {
401 mirror::Array* old_root = pair.first;
402 mirror::Array* new_root = pair.second;
403 auto old_root_it = array_logs_.find(old_root);
404 CHECK(old_root_it != array_logs_.end());
405 CHECK(array_logs_.find(new_root) == array_logs_.end());
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800406 array_logs_.emplace(new_root, std::move(old_root_it->second));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100407 array_logs_.erase(old_root_it);
408 }
409}
410
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700411void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100412 for (InternStringLog& log : intern_string_logs_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700413 log.VisitRoots(visitor);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100414 }
415}
416
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700417void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
418 for (ResolveStringLog& log : resolve_string_logs_) {
419 log.VisitRoots(visitor);
420 }
421}
422
Fred Shih37f05ef2014-07-16 18:38:08 -0700423void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
424 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
425}
426
427void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
428 LogValue(ObjectLog::kByte, offset, value, is_volatile);
429}
430
431void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
432 LogValue(ObjectLog::kChar, offset, value, is_volatile);
433}
434
435void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
436 LogValue(ObjectLog::kShort, offset, value, is_volatile);
437}
438
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100439void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700440 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100441}
442
443void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700444 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
445}
446
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800447void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset,
448 mirror::Object* obj,
449 bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700450 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
451}
452
453void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800454 MemberOffset offset,
455 uint64_t value,
456 bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100457 auto it = field_values_.find(offset.Uint32Value());
458 if (it == field_values_.end()) {
459 ObjectLog::FieldValue field_value;
460 field_value.value = value;
461 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700462 field_value.kind = kind;
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800463 field_values_.emplace(offset.Uint32Value(), std::move(field_value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100464 }
465}
466
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800467void Transaction::ObjectLog::Undo(mirror::Object* obj) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100468 for (auto& it : field_values_) {
469 // Garbage collector needs to access object's class and array's length. So we don't rollback
470 // these values.
471 MemberOffset field_offset(it.first);
472 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
473 // Skip Object::class field.
474 continue;
475 }
476 if (obj->IsArrayInstance() &&
477 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
478 // Skip Array::length field.
479 continue;
480 }
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800481 const FieldValue& field_value = it.second;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100482 UndoFieldWrite(obj, field_offset, field_value);
483 }
484}
485
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800486void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj,
487 MemberOffset field_offset,
488 const FieldValue& field_value) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100489 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
490 // we'd need to disable the check.
Chang Xing605fe242017-07-20 15:57:21 -0700491 constexpr bool kCheckTransaction = false;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100492 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700493 case kBoolean:
494 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800495 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(
496 field_offset,
Andreas Gampe7c5acbb2018-09-20 13:54:52 -0700497 field_value.value);
Fred Shih37f05ef2014-07-16 18:38:08 -0700498 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800499 obj->SetFieldBoolean<false, kCheckTransaction>(
500 field_offset,
Andreas Gampe7c5acbb2018-09-20 13:54:52 -0700501 field_value.value);
Fred Shih37f05ef2014-07-16 18:38:08 -0700502 }
503 break;
504 case kByte:
505 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800506 obj->SetFieldByteVolatile<false, kCheckTransaction>(
507 field_offset,
508 static_cast<int8_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700509 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800510 obj->SetFieldByte<false, kCheckTransaction>(
511 field_offset,
512 static_cast<int8_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700513 }
514 break;
515 case kChar:
516 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800517 obj->SetFieldCharVolatile<false, kCheckTransaction>(
518 field_offset,
519 static_cast<uint16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700520 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800521 obj->SetFieldChar<false, kCheckTransaction>(
522 field_offset,
523 static_cast<uint16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700524 }
525 break;
526 case kShort:
527 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800528 obj->SetFieldShortVolatile<false, kCheckTransaction>(
529 field_offset,
530 static_cast<int16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700531 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800532 obj->SetFieldShort<false, kCheckTransaction>(
533 field_offset,
534 static_cast<int16_t>(field_value.value));
Fred Shih37f05ef2014-07-16 18:38:08 -0700535 }
536 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100537 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700538 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800539 obj->SetField32Volatile<false, kCheckTransaction>(
540 field_offset,
541 static_cast<uint32_t>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700542 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800543 obj->SetField32<false, kCheckTransaction>(
544 field_offset,
545 static_cast<uint32_t>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700546 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100547 break;
548 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700549 if (UNLIKELY(field_value.is_volatile)) {
550 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
551 } else {
552 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
553 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100554 break;
555 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700556 if (UNLIKELY(field_value.is_volatile)) {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800557 obj->SetFieldObjectVolatile<false, kCheckTransaction>(
558 field_offset,
559 reinterpret_cast<mirror::Object*>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700560 } else {
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800561 obj->SetFieldObject<false, kCheckTransaction>(
562 field_offset,
563 reinterpret_cast<mirror::Object*>(field_value.value));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700564 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100565 break;
566 default:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700567 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
Elliott Hughesc1896c92018-11-29 11:33:18 -0800568 UNREACHABLE();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100569 }
570}
571
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700572void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier5f257b12017-02-03 14:47:36 -0800573 for (auto& it : field_values_) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100574 FieldValue& field_value = it.second;
575 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700576 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value),
577 RootInfo(kRootUnknown));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100578 }
579 }
580}
581
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800582void Transaction::InternStringLog::Undo(InternTable* intern_table) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100583 DCHECK(intern_table != nullptr);
584 switch (string_op_) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700585 case InternStringLog::kInsert: {
586 switch (string_kind_) {
587 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700588 intern_table->RemoveStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700589 break;
590 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700591 intern_table->RemoveWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700592 break;
593 default:
594 LOG(FATAL) << "Unknown interned string kind";
Elliott Hughesc1896c92018-11-29 11:33:18 -0800595 UNREACHABLE();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100596 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700597 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100598 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700599 case InternStringLog::kRemove: {
600 switch (string_kind_) {
601 case InternStringLog::kStrongString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700602 intern_table->InsertStrongFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700603 break;
604 case InternStringLog::kWeakString:
Mathieu Chartier9e868092016-10-31 14:58:04 -0700605 intern_table->InsertWeakFromTransaction(str_.Read());
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700606 break;
607 default:
608 LOG(FATAL) << "Unknown interned string kind";
Elliott Hughesc1896c92018-11-29 11:33:18 -0800609 UNREACHABLE();
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700610 }
611 break;
612 }
613 default:
614 LOG(FATAL) << "Unknown interned string op";
Elliott Hughesc1896c92018-11-29 11:33:18 -0800615 UNREACHABLE();
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700616 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100617}
618
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700619void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
Mathieu Chartier9e868092016-10-31 14:58:04 -0700620 str_.VisitRoot(visitor, RootInfo(kRootInternedString));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100621}
622
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800623void Transaction::ResolveStringLog::Undo() const {
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700624 dex_cache_.Read()->ClearString(string_idx_);
625}
626
Mathieu Chartier9e868092016-10-31 14:58:04 -0700627Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800628 dex::StringIndex string_idx)
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700629 : dex_cache_(dex_cache),
630 string_idx_(string_idx) {
631 DCHECK(dex_cache != nullptr);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800632 DCHECK_LT(string_idx_.index_, dex_cache->GetDexFile()->NumStringIds());
Mathieu Chartierbb816d62016-09-07 10:17:46 -0700633}
634
635void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
636 dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
637}
638
Mathieu Chartier9e868092016-10-31 14:58:04 -0700639Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
640 StringKind kind,
641 StringOp op)
642 : str_(s),
643 string_kind_(kind),
644 string_op_(op) {
645 DCHECK(s != nullptr);
646}
647
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100648void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
649 auto it = array_values_.find(index);
650 if (it == array_values_.end()) {
651 array_values_.insert(std::make_pair(index, value));
652 }
653}
654
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800655void Transaction::ArrayLog::Undo(mirror::Array* array) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100656 DCHECK(array != nullptr);
657 DCHECK(array->IsArrayInstance());
658 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
659 for (auto it : array_values_) {
660 UndoArrayWrite(array, type, it.first, it.second);
661 }
662}
663
Mathieu Chartier38e954c2017-02-03 16:06:35 -0800664void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array,
665 Primitive::Type array_type,
666 size_t index,
667 uint64_t value) const {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100668 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
669 // we'd need to disable the check.
Chang Xing605fe242017-07-20 15:57:21 -0700670 constexpr bool kCheckTransaction = false;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100671 switch (array_type) {
672 case Primitive::kPrimBoolean:
Chang Xing605fe242017-07-20 15:57:21 -0700673 array->AsBooleanArray()->SetWithoutChecks<false, kCheckTransaction>(
674 index, static_cast<uint8_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100675 break;
676 case Primitive::kPrimByte:
Chang Xing605fe242017-07-20 15:57:21 -0700677 array->AsByteArray()->SetWithoutChecks<false, kCheckTransaction>(
678 index, static_cast<int8_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100679 break;
680 case Primitive::kPrimChar:
Chang Xing605fe242017-07-20 15:57:21 -0700681 array->AsCharArray()->SetWithoutChecks<false, kCheckTransaction>(
682 index, static_cast<uint16_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100683 break;
684 case Primitive::kPrimShort:
Chang Xing605fe242017-07-20 15:57:21 -0700685 array->AsShortArray()->SetWithoutChecks<false, kCheckTransaction>(
686 index, static_cast<int16_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100687 break;
688 case Primitive::kPrimInt:
Chang Xing605fe242017-07-20 15:57:21 -0700689 array->AsIntArray()->SetWithoutChecks<false, kCheckTransaction>(
690 index, static_cast<int32_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100691 break;
692 case Primitive::kPrimFloat:
Chang Xing605fe242017-07-20 15:57:21 -0700693 array->AsFloatArray()->SetWithoutChecks<false, kCheckTransaction>(
694 index, static_cast<float>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100695 break;
696 case Primitive::kPrimLong:
Chang Xing605fe242017-07-20 15:57:21 -0700697 array->AsLongArray()->SetWithoutChecks<false, kCheckTransaction>(
698 index, static_cast<int64_t>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100699 break;
700 case Primitive::kPrimDouble:
Chang Xing605fe242017-07-20 15:57:21 -0700701 array->AsDoubleArray()->SetWithoutChecks<false, kCheckTransaction>(
702 index, static_cast<double>(value));
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100703 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100704 case Primitive::kPrimNot:
705 LOG(FATAL) << "ObjectArray should be treated as Object";
Elliott Hughesc1896c92018-11-29 11:33:18 -0800706 UNREACHABLE();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100707 default:
708 LOG(FATAL) << "Unsupported type " << array_type;
Elliott Hughesc1896c92018-11-29 11:33:18 -0800709 UNREACHABLE();
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100710 }
711}
712
Vladimir Markob68bb7a2020-03-17 10:55:25 +0000713Transaction* ScopedAssertNoNewTransactionRecords::InstallAssertion(const char* reason) {
714 Transaction* transaction = nullptr;
715 if (kIsDebugBuild && Runtime::Current()->IsActiveTransaction()) {
716 transaction = Runtime::Current()->GetTransaction().get();
717 if (transaction != nullptr) {
718 MutexLock mu(Thread::Current(), transaction->log_lock_);
719 CHECK(transaction->assert_no_new_records_reason_ == nullptr)
720 << "old: " << transaction->assert_no_new_records_reason_ << " new: " << reason;
721 transaction->assert_no_new_records_reason_ = reason;
722 }
723 }
724 return transaction;
725}
726
727void ScopedAssertNoNewTransactionRecords::RemoveAssertion(Transaction* transaction) {
728 if (kIsDebugBuild) {
729 CHECK(Runtime::Current()->GetTransaction().get() == transaction);
730 MutexLock mu(Thread::Current(), transaction->log_lock_);
731 CHECK(transaction->assert_no_new_records_reason_ != nullptr);
732 transaction->assert_no_new_records_reason_ = nullptr;
733 }
734}
735
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100736} // namespace art