blob: fcda6c9a6ecffe28580ad7d9f08972ea8c85e47d [file] [log] [blame]
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "transaction.h"
18
19#include "base/stl_util.h"
20#include "base/logging.h"
21#include "gc/accounting/card_table-inl.h"
22#include "intern_table.h"
23#include "mirror/object-inl.h"
24#include "mirror/object_array-inl.h"
25
26#include <list>
27
28namespace art {
29
30// TODO: remove (only used for debugging purpose).
31static constexpr bool kEnableTransactionStats = false;
32
33Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
34 CHECK(Runtime::Current()->IsCompiler());
35}
36
37Transaction::~Transaction() {
38 if (kEnableTransactionStats) {
39 MutexLock mu(Thread::Current(), log_lock_);
40 size_t objects_count = object_logs_.size();
41 size_t field_values_count = 0;
42 for (auto it : object_logs_) {
43 field_values_count += it.second.Size();
44 }
45 size_t array_count = array_logs_.size();
46 size_t array_values_count = 0;
47 for (auto it : array_logs_) {
48 array_values_count += it.second.Size();
49 }
50 size_t string_count = intern_string_logs_.size();
51 LOG(INFO) << "Transaction::~Transaction"
52 << ": objects_count=" << objects_count
53 << ", field_values_count=" << field_values_count
54 << ", array_count=" << array_count
55 << ", array_values_count=" << array_values_count
56 << ", string_count=" << string_count;
57 }
58}
59
60void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
61 bool is_volatile) {
62 DCHECK(obj != nullptr);
63 MutexLock mu(Thread::Current(), log_lock_);
64 ObjectLog& object_log = object_logs_[obj];
65 object_log.Log32BitsValue(field_offset, value, is_volatile);
66}
67
68void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
69 bool is_volatile) {
70 DCHECK(obj != nullptr);
71 MutexLock mu(Thread::Current(), log_lock_);
72 ObjectLog& object_log = object_logs_[obj];
73 object_log.Log64BitsValue(field_offset, value, is_volatile);
74}
75
76void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
77 mirror::Object* value, bool is_volatile) {
78 DCHECK(obj != nullptr);
79 MutexLock mu(Thread::Current(), log_lock_);
80 ObjectLog& object_log = object_logs_[obj];
81 object_log.LogReferenceValue(field_offset, value, is_volatile);
82}
83
84void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
85 DCHECK(array != nullptr);
86 DCHECK(array->IsArrayInstance());
87 MutexLock mu(Thread::Current(), log_lock_);
88 ArrayLog& array_log = array_logs_[array];
89 array_log.LogValue(index, value);
90}
91
92void Transaction::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) {
93 DCHECK(s != nullptr);
94 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kInsert);
95 LogInternedString(log);
96}
97
98void Transaction::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) {
99 DCHECK(s != nullptr);
100 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kInsert);
101 LogInternedString(log);
102}
103
104void Transaction::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) {
105 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kRemove);
106 LogInternedString(log);
107}
108
109void Transaction::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) {
110 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kRemove);
111 LogInternedString(log);
112}
113
114void Transaction::LogInternedString(InternStringLog& log) {
115 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
116 MutexLock mu(Thread::Current(), log_lock_);
117 intern_string_logs_.push_front(log);
118}
119
120void Transaction::Abort() {
121 CHECK(!Runtime::Current()->IsActiveTransaction());
122 Thread* self = Thread::Current();
123 self->AssertNoPendingException();
124 MutexLock mu1(self, *Locks::intern_table_lock_);
125 MutexLock mu2(self, log_lock_);
126 UndoObjectModifications();
127 UndoArrayModifications();
128 UndoInternStringTableModifications();
129}
130
131void Transaction::UndoObjectModifications() {
132 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
133 // remove them from the heap.
134 for (auto it : object_logs_) {
135 it.second.Undo(it.first);
136 }
137 object_logs_.clear();
138}
139
140void Transaction::UndoArrayModifications() {
141 // TODO we may not need to restore array allocated during this transaction. Or we could directly
142 // remove them from the heap.
143 for (auto it : array_logs_) {
144 it.second.Undo(it.first);
145 }
146 array_logs_.clear();
147}
148
149void Transaction::UndoInternStringTableModifications() {
150 InternTable* const intern_table = Runtime::Current()->GetInternTable();
151 // We want to undo each operation from the most recent to the oldest. List has been filled so the
152 // most recent operation is at list begin so just have to iterate over it.
153 for (InternStringLog& string_log : intern_string_logs_) {
154 string_log.Undo(intern_table);
155 }
156 intern_string_logs_.clear();
157}
158
159void Transaction::VisitRoots(RootCallback* callback, void* arg) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100160 MutexLock mu(Thread::Current(), log_lock_);
161 VisitObjectLogs(callback, arg);
162 VisitArrayLogs(callback, arg);
163 VisitStringLogs(callback, arg);
164}
165
166void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
167 // List of moving roots.
168 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
169 std::list<ObjectPair> moving_roots;
170
171 // Visit roots.
172 for (auto it : object_logs_) {
173 it.second.VisitRoots(callback, arg);
174 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800175 mirror::Object* new_root = old_root;
176 callback(&new_root, arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100177 if (new_root != old_root) {
178 moving_roots.push_back(std::make_pair(old_root, new_root));
179 }
180 }
181
182 // Update object logs with moving roots.
183 for (const ObjectPair& pair : moving_roots) {
184 mirror::Object* old_root = pair.first;
185 mirror::Object* new_root = pair.second;
186 auto old_root_it = object_logs_.find(old_root);
187 CHECK(old_root_it != object_logs_.end());
188 CHECK(object_logs_.find(new_root) == object_logs_.end());
189 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
190 object_logs_.erase(old_root_it);
191 }
192}
193
194void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
195 // List of moving roots.
196 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
197 std::list<ArrayPair> moving_roots;
198
199 for (auto it : array_logs_) {
200 mirror::Array* old_root = it.first;
201 if (old_root->IsObjectArray()) {
202 it.second.VisitRoots(callback, arg);
203 }
Mathieu Chartier815873e2014-02-13 18:02:13 -0800204 mirror::Array* new_root = old_root;
205 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100206 if (new_root != old_root) {
207 moving_roots.push_back(std::make_pair(old_root, new_root));
208 }
209 }
210
211 // Update array logs with moving roots.
212 for (const ArrayPair& pair : moving_roots) {
213 mirror::Array* old_root = pair.first;
214 mirror::Array* new_root = pair.second;
215 auto old_root_it = array_logs_.find(old_root);
216 CHECK(old_root_it != array_logs_.end());
217 CHECK(array_logs_.find(new_root) == array_logs_.end());
218 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
219 array_logs_.erase(old_root_it);
220 }
221}
222
223void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
224 for (InternStringLog& log : intern_string_logs_) {
225 log.VisitRoots(callback, arg);
226 }
227}
228
229void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
230 auto it = field_values_.find(offset.Uint32Value());
231 if (it == field_values_.end()) {
232 ObjectLog::FieldValue field_value;
233 field_value.value = value;
234 field_value.is_volatile = is_volatile;
235 field_value.kind = ObjectLog::k32Bits;
236 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
237 }
238}
239
240void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
241 auto it = field_values_.find(offset.Uint32Value());
242 if (it == field_values_.end()) {
243 ObjectLog::FieldValue field_value;
244 field_value.value = value;
245 field_value.is_volatile = is_volatile;
246 field_value.kind = ObjectLog::k64Bits;
247 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
248 }
249}
250
251void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
252 auto it = field_values_.find(offset.Uint32Value());
253 if (it == field_values_.end()) {
254 ObjectLog::FieldValue field_value;
255 field_value.value = reinterpret_cast<uintptr_t>(obj);
256 field_value.is_volatile = is_volatile;
257 field_value.kind = ObjectLog::kReference;
258 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
259 }
260}
261
262void Transaction::ObjectLog::Undo(mirror::Object* obj) {
263 for (auto& it : field_values_) {
264 // Garbage collector needs to access object's class and array's length. So we don't rollback
265 // these values.
266 MemberOffset field_offset(it.first);
267 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
268 // Skip Object::class field.
269 continue;
270 }
271 if (obj->IsArrayInstance() &&
272 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
273 // Skip Array::length field.
274 continue;
275 }
276 FieldValue& field_value = it.second;
277 UndoFieldWrite(obj, field_offset, field_value);
278 }
279}
280
281void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
282 const FieldValue& field_value) {
283 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
284 // we'd need to disable the check.
285 constexpr bool kCheckTransaction = true;
286 switch (field_value.kind) {
287 case k32Bits:
288 obj->SetField32<false, kCheckTransaction>(field_offset, static_cast<uint32_t>(field_value.value),
289 field_value.is_volatile);
290 break;
291 case k64Bits:
292 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value,
293 field_value.is_volatile);
294 break;
295 case kReference:
296 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
297 reinterpret_cast<mirror::Object*>(field_value.value),
298 field_value.is_volatile);
299 break;
300 default:
301 LOG(FATAL) << "Unknown value kind " << field_value.kind;
302 break;
303 }
304}
305
306void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
307 for (auto it : field_values_) {
308 FieldValue& field_value = it.second;
309 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800310 mirror::Object* obj =
311 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100312 if (obj != nullptr) {
313 callback(&obj, arg, 0, kRootUnknown);
314 field_value.value = reinterpret_cast<uintptr_t>(obj);
315 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100316 }
317 }
318}
319
320void Transaction::InternStringLog::Undo(InternTable* intern_table) {
321 DCHECK(intern_table != nullptr);
322 switch (string_op_) {
323 case InternStringLog::kInsert: {
324 switch (string_kind_) {
325 case InternStringLog::kStrongString:
326 intern_table->RemoveStrongFromTransaction(str_, hash_code_);
327 break;
328 case InternStringLog::kWeakString:
329 intern_table->RemoveWeakFromTransaction(str_, hash_code_);
330 break;
331 default:
332 LOG(FATAL) << "Unknown interned string kind";
333 break;
334 }
335 break;
336 }
337 case InternStringLog::kRemove: {
338 switch (string_kind_) {
339 case InternStringLog::kStrongString:
340 intern_table->InsertStrongFromTransaction(str_, hash_code_);
341 break;
342 case InternStringLog::kWeakString:
343 intern_table->InsertWeakFromTransaction(str_, hash_code_);
344 break;
345 default:
346 LOG(FATAL) << "Unknown interned string kind";
347 break;
348 }
349 break;
350 }
351 default:
352 LOG(FATAL) << "Unknown interned string op";
353 break;
354 }
355}
356
357void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800358 callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100359}
360
361void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
362 auto it = array_values_.find(index);
363 if (it == array_values_.end()) {
364 array_values_.insert(std::make_pair(index, value));
365 }
366}
367
368void Transaction::ArrayLog::Undo(mirror::Array* array) {
369 DCHECK(array != nullptr);
370 DCHECK(array->IsArrayInstance());
371 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
372 for (auto it : array_values_) {
373 UndoArrayWrite(array, type, it.first, it.second);
374 }
375}
376
377void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
378 size_t index, uint64_t value) {
379 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
380 // we'd need to disable the check.
381 switch (array_type) {
382 case Primitive::kPrimBoolean:
383 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
384 break;
385 case Primitive::kPrimByte:
386 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
387 break;
388 case Primitive::kPrimChar:
389 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
390 break;
391 case Primitive::kPrimShort:
392 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
393 break;
394 case Primitive::kPrimInt:
395 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
396 break;
397 case Primitive::kPrimFloat:
398 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
399 break;
400 case Primitive::kPrimLong:
401 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
402 break;
403 case Primitive::kPrimDouble:
404 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
405 break;
406 case Primitive::kPrimNot: {
407 mirror::ObjectArray<mirror::Object>* obj_array = array->AsObjectArray<mirror::Object>();
408 obj_array->SetWithoutChecks<false>(index, reinterpret_cast<mirror::Object*>(
409 static_cast<uintptr_t>(value)));
410 break;
411 }
412 default:
413 LOG(FATAL) << "Unsupported type " << array_type;
414 }
415}
416
417void Transaction::ArrayLog::VisitRoots(RootCallback* callback, void* arg) {
418 for (auto& it : array_values_) {
419 mirror::Object* obj = reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(it.second));
Mathieu Chartier815873e2014-02-13 18:02:13 -0800420 callback(&obj, arg, 0, kRootUnknown);
421 it.second = reinterpret_cast<uintptr_t>(obj);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100422 }
423}
424
425} // namespace art