blob: 0cfdfc57fc9862cec80ecf7ef2f3f72578daf145 [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
Fred Shih37f05ef2014-07-16 18:38:08 -070060void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
61 uint8_t value, bool is_volatile) {
62 DCHECK(obj != nullptr);
63 MutexLock mu(Thread::Current(), log_lock_);
64 ObjectLog& object_log = object_logs_[obj];
65 object_log.LogBooleanValue(field_offset, value, is_volatile);
66}
67
68void Transaction::RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset,
69 int8_t value, bool is_volatile) {
70 DCHECK(obj != nullptr);
71 MutexLock mu(Thread::Current(), log_lock_);
72 ObjectLog& object_log = object_logs_[obj];
73 object_log.LogByteValue(field_offset, value, is_volatile);
74}
75
76void Transaction::RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset,
77 uint16_t 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.LogCharValue(field_offset, value, is_volatile);
82}
83
84
85void Transaction::RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset,
86 int16_t value, bool is_volatile) {
87 DCHECK(obj != nullptr);
88 MutexLock mu(Thread::Current(), log_lock_);
89 ObjectLog& object_log = object_logs_[obj];
90 object_log.LogShortValue(field_offset, value, is_volatile);
91}
92
93
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010094void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
95 bool is_volatile) {
96 DCHECK(obj != nullptr);
97 MutexLock mu(Thread::Current(), log_lock_);
98 ObjectLog& object_log = object_logs_[obj];
99 object_log.Log32BitsValue(field_offset, value, is_volatile);
100}
101
102void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
103 bool is_volatile) {
104 DCHECK(obj != nullptr);
105 MutexLock mu(Thread::Current(), log_lock_);
106 ObjectLog& object_log = object_logs_[obj];
107 object_log.Log64BitsValue(field_offset, value, is_volatile);
108}
109
110void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
111 mirror::Object* value, bool is_volatile) {
112 DCHECK(obj != nullptr);
113 MutexLock mu(Thread::Current(), log_lock_);
114 ObjectLog& object_log = object_logs_[obj];
115 object_log.LogReferenceValue(field_offset, value, is_volatile);
116}
117
118void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
119 DCHECK(array != nullptr);
120 DCHECK(array->IsArrayInstance());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100121 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100122 MutexLock mu(Thread::Current(), log_lock_);
123 ArrayLog& array_log = array_logs_[array];
124 array_log.LogValue(index, value);
125}
126
127void Transaction::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100128 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kInsert);
129 LogInternedString(log);
130}
131
132void Transaction::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100133 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kInsert);
134 LogInternedString(log);
135}
136
137void Transaction::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) {
138 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kRemove);
139 LogInternedString(log);
140}
141
142void Transaction::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) {
143 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kRemove);
144 LogInternedString(log);
145}
146
147void Transaction::LogInternedString(InternStringLog& log) {
148 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
149 MutexLock mu(Thread::Current(), log_lock_);
150 intern_string_logs_.push_front(log);
151}
152
153void Transaction::Abort() {
154 CHECK(!Runtime::Current()->IsActiveTransaction());
155 Thread* self = Thread::Current();
156 self->AssertNoPendingException();
157 MutexLock mu1(self, *Locks::intern_table_lock_);
158 MutexLock mu2(self, log_lock_);
159 UndoObjectModifications();
160 UndoArrayModifications();
161 UndoInternStringTableModifications();
162}
163
164void Transaction::UndoObjectModifications() {
165 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
166 // remove them from the heap.
167 for (auto it : object_logs_) {
168 it.second.Undo(it.first);
169 }
170 object_logs_.clear();
171}
172
173void Transaction::UndoArrayModifications() {
174 // TODO we may not need to restore array allocated during this transaction. Or we could directly
175 // remove them from the heap.
176 for (auto it : array_logs_) {
177 it.second.Undo(it.first);
178 }
179 array_logs_.clear();
180}
181
182void Transaction::UndoInternStringTableModifications() {
183 InternTable* const intern_table = Runtime::Current()->GetInternTable();
184 // We want to undo each operation from the most recent to the oldest. List has been filled so the
185 // most recent operation is at list begin so just have to iterate over it.
186 for (InternStringLog& string_log : intern_string_logs_) {
187 string_log.Undo(intern_table);
188 }
189 intern_string_logs_.clear();
190}
191
192void Transaction::VisitRoots(RootCallback* callback, void* arg) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100193 MutexLock mu(Thread::Current(), log_lock_);
194 VisitObjectLogs(callback, arg);
195 VisitArrayLogs(callback, arg);
196 VisitStringLogs(callback, arg);
197}
198
199void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
200 // List of moving roots.
201 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
202 std::list<ObjectPair> moving_roots;
203
204 // Visit roots.
205 for (auto it : object_logs_) {
206 it.second.VisitRoots(callback, arg);
207 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800208 mirror::Object* new_root = old_root;
209 callback(&new_root, arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100210 if (new_root != old_root) {
211 moving_roots.push_back(std::make_pair(old_root, new_root));
212 }
213 }
214
215 // Update object logs with moving roots.
216 for (const ObjectPair& pair : moving_roots) {
217 mirror::Object* old_root = pair.first;
218 mirror::Object* new_root = pair.second;
219 auto old_root_it = object_logs_.find(old_root);
220 CHECK(old_root_it != object_logs_.end());
221 CHECK(object_logs_.find(new_root) == object_logs_.end());
222 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
223 object_logs_.erase(old_root_it);
224 }
225}
226
227void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
228 // List of moving roots.
229 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
230 std::list<ArrayPair> moving_roots;
231
232 for (auto it : array_logs_) {
233 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100234 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800235 mirror::Array* new_root = old_root;
236 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100237 if (new_root != old_root) {
238 moving_roots.push_back(std::make_pair(old_root, new_root));
239 }
240 }
241
242 // Update array logs with moving roots.
243 for (const ArrayPair& pair : moving_roots) {
244 mirror::Array* old_root = pair.first;
245 mirror::Array* new_root = pair.second;
246 auto old_root_it = array_logs_.find(old_root);
247 CHECK(old_root_it != array_logs_.end());
248 CHECK(array_logs_.find(new_root) == array_logs_.end());
249 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
250 array_logs_.erase(old_root_it);
251 }
252}
253
254void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
255 for (InternStringLog& log : intern_string_logs_) {
256 log.VisitRoots(callback, arg);
257 }
258}
259
Fred Shih37f05ef2014-07-16 18:38:08 -0700260void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
261 LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
262}
263
264void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) {
265 LogValue(ObjectLog::kByte, offset, value, is_volatile);
266}
267
268void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) {
269 LogValue(ObjectLog::kChar, offset, value, is_volatile);
270}
271
272void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) {
273 LogValue(ObjectLog::kShort, offset, value, is_volatile);
274}
275
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100276void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700277 LogValue(ObjectLog::k32Bits, offset, value, is_volatile);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100278}
279
280void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700281 LogValue(ObjectLog::k64Bits, offset, value, is_volatile);
282}
283
284void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
285 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile);
286}
287
288void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind,
289 MemberOffset offset, uint64_t value, bool is_volatile) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100290 auto it = field_values_.find(offset.Uint32Value());
291 if (it == field_values_.end()) {
292 ObjectLog::FieldValue field_value;
293 field_value.value = value;
294 field_value.is_volatile = is_volatile;
Fred Shih37f05ef2014-07-16 18:38:08 -0700295 field_value.kind = kind;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100296 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
297 }
298}
299
300void Transaction::ObjectLog::Undo(mirror::Object* obj) {
301 for (auto& it : field_values_) {
302 // Garbage collector needs to access object's class and array's length. So we don't rollback
303 // these values.
304 MemberOffset field_offset(it.first);
305 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
306 // Skip Object::class field.
307 continue;
308 }
309 if (obj->IsArrayInstance() &&
310 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
311 // Skip Array::length field.
312 continue;
313 }
314 FieldValue& field_value = it.second;
315 UndoFieldWrite(obj, field_offset, field_value);
316 }
317}
318
319void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
320 const FieldValue& field_value) {
321 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
322 // we'd need to disable the check.
323 constexpr bool kCheckTransaction = true;
324 switch (field_value.kind) {
Fred Shih37f05ef2014-07-16 18:38:08 -0700325 case kBoolean:
326 if (UNLIKELY(field_value.is_volatile)) {
327 obj->SetFieldBooleanVolatile<false, kCheckTransaction>(field_offset,
328 static_cast<bool>(field_value.value));
329 } else {
330 obj->SetFieldBoolean<false, kCheckTransaction>(field_offset,
331 static_cast<bool>(field_value.value));
332 }
333 break;
334 case kByte:
335 if (UNLIKELY(field_value.is_volatile)) {
336 obj->SetFieldByteVolatile<false, kCheckTransaction>(field_offset,
337 static_cast<int8_t>(field_value.value));
338 } else {
339 obj->SetFieldByte<false, kCheckTransaction>(field_offset,
340 static_cast<int8_t>(field_value.value));
341 }
342 break;
343 case kChar:
344 if (UNLIKELY(field_value.is_volatile)) {
345 obj->SetFieldCharVolatile<false, kCheckTransaction>(field_offset,
346 static_cast<uint16_t>(field_value.value));
347 } else {
348 obj->SetFieldChar<false, kCheckTransaction>(field_offset,
349 static_cast<uint16_t>(field_value.value));
350 }
351 break;
352 case kShort:
353 if (UNLIKELY(field_value.is_volatile)) {
354 obj->SetFieldShortVolatile<false, kCheckTransaction>(field_offset,
355 static_cast<int16_t>(field_value.value));
356 } else {
357 obj->SetFieldShort<false, kCheckTransaction>(field_offset,
358 static_cast<int16_t>(field_value.value));
359 }
360 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100361 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700362 if (UNLIKELY(field_value.is_volatile)) {
363 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
364 static_cast<uint32_t>(field_value.value));
365 } else {
366 obj->SetField32<false, kCheckTransaction>(field_offset,
367 static_cast<uint32_t>(field_value.value));
368 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100369 break;
370 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700371 if (UNLIKELY(field_value.is_volatile)) {
372 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
373 } else {
374 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
375 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100376 break;
377 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700378 if (UNLIKELY(field_value.is_volatile)) {
379 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
380 reinterpret_cast<mirror::Object*>(field_value.value));
381 } else {
382 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
383 reinterpret_cast<mirror::Object*>(field_value.value));
384 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100385 break;
386 default:
387 LOG(FATAL) << "Unknown value kind " << field_value.kind;
388 break;
389 }
390}
391
392void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
393 for (auto it : field_values_) {
394 FieldValue& field_value = it.second;
395 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800396 mirror::Object* obj =
397 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100398 if (obj != nullptr) {
399 callback(&obj, arg, 0, kRootUnknown);
400 field_value.value = reinterpret_cast<uintptr_t>(obj);
401 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100402 }
403 }
404}
405
406void Transaction::InternStringLog::Undo(InternTable* intern_table) {
407 DCHECK(intern_table != nullptr);
408 switch (string_op_) {
409 case InternStringLog::kInsert: {
410 switch (string_kind_) {
411 case InternStringLog::kStrongString:
412 intern_table->RemoveStrongFromTransaction(str_, hash_code_);
413 break;
414 case InternStringLog::kWeakString:
415 intern_table->RemoveWeakFromTransaction(str_, hash_code_);
416 break;
417 default:
418 LOG(FATAL) << "Unknown interned string kind";
419 break;
420 }
421 break;
422 }
423 case InternStringLog::kRemove: {
424 switch (string_kind_) {
425 case InternStringLog::kStrongString:
426 intern_table->InsertStrongFromTransaction(str_, hash_code_);
427 break;
428 case InternStringLog::kWeakString:
429 intern_table->InsertWeakFromTransaction(str_, hash_code_);
430 break;
431 default:
432 LOG(FATAL) << "Unknown interned string kind";
433 break;
434 }
435 break;
436 }
437 default:
438 LOG(FATAL) << "Unknown interned string op";
439 break;
440 }
441}
442
443void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800444 callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100445}
446
447void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
448 auto it = array_values_.find(index);
449 if (it == array_values_.end()) {
450 array_values_.insert(std::make_pair(index, value));
451 }
452}
453
454void Transaction::ArrayLog::Undo(mirror::Array* array) {
455 DCHECK(array != nullptr);
456 DCHECK(array->IsArrayInstance());
457 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
458 for (auto it : array_values_) {
459 UndoArrayWrite(array, type, it.first, it.second);
460 }
461}
462
463void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
464 size_t index, uint64_t value) {
465 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
466 // we'd need to disable the check.
467 switch (array_type) {
468 case Primitive::kPrimBoolean:
469 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
470 break;
471 case Primitive::kPrimByte:
472 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
473 break;
474 case Primitive::kPrimChar:
475 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
476 break;
477 case Primitive::kPrimShort:
478 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
479 break;
480 case Primitive::kPrimInt:
481 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
482 break;
483 case Primitive::kPrimFloat:
484 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
485 break;
486 case Primitive::kPrimLong:
487 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
488 break;
489 case Primitive::kPrimDouble:
490 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
491 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100492 case Primitive::kPrimNot:
493 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100494 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100495 default:
496 LOG(FATAL) << "Unsupported type " << array_type;
497 }
498}
499
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100500} // namespace art