blob: cc02a8de74fdac5b684a19501d2a3e8a2fc164fd [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());
Sebastien Hertzee1d79a2014-02-21 15:46:30 +010087 DCHECK(!array->IsObjectArray());
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010088 MutexLock mu(Thread::Current(), log_lock_);
89 ArrayLog& array_log = array_logs_[array];
90 array_log.LogValue(index, value);
91}
92
93void Transaction::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010094 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kInsert);
95 LogInternedString(log);
96}
97
98void Transaction::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010099 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kInsert);
100 LogInternedString(log);
101}
102
103void Transaction::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) {
104 InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kRemove);
105 LogInternedString(log);
106}
107
108void Transaction::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) {
109 InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kRemove);
110 LogInternedString(log);
111}
112
113void Transaction::LogInternedString(InternStringLog& log) {
114 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
115 MutexLock mu(Thread::Current(), log_lock_);
116 intern_string_logs_.push_front(log);
117}
118
119void Transaction::Abort() {
120 CHECK(!Runtime::Current()->IsActiveTransaction());
121 Thread* self = Thread::Current();
122 self->AssertNoPendingException();
123 MutexLock mu1(self, *Locks::intern_table_lock_);
124 MutexLock mu2(self, log_lock_);
125 UndoObjectModifications();
126 UndoArrayModifications();
127 UndoInternStringTableModifications();
128}
129
130void Transaction::UndoObjectModifications() {
131 // TODO we may not need to restore objects allocated during this transaction. Or we could directly
132 // remove them from the heap.
133 for (auto it : object_logs_) {
134 it.second.Undo(it.first);
135 }
136 object_logs_.clear();
137}
138
139void Transaction::UndoArrayModifications() {
140 // TODO we may not need to restore array allocated during this transaction. Or we could directly
141 // remove them from the heap.
142 for (auto it : array_logs_) {
143 it.second.Undo(it.first);
144 }
145 array_logs_.clear();
146}
147
148void Transaction::UndoInternStringTableModifications() {
149 InternTable* const intern_table = Runtime::Current()->GetInternTable();
150 // We want to undo each operation from the most recent to the oldest. List has been filled so the
151 // most recent operation is at list begin so just have to iterate over it.
152 for (InternStringLog& string_log : intern_string_logs_) {
153 string_log.Undo(intern_table);
154 }
155 intern_string_logs_.clear();
156}
157
158void Transaction::VisitRoots(RootCallback* callback, void* arg) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100159 MutexLock mu(Thread::Current(), log_lock_);
160 VisitObjectLogs(callback, arg);
161 VisitArrayLogs(callback, arg);
162 VisitStringLogs(callback, arg);
163}
164
165void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
166 // List of moving roots.
167 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
168 std::list<ObjectPair> moving_roots;
169
170 // Visit roots.
171 for (auto it : object_logs_) {
172 it.second.VisitRoots(callback, arg);
173 mirror::Object* old_root = it.first;
Mathieu Chartier815873e2014-02-13 18:02:13 -0800174 mirror::Object* new_root = old_root;
175 callback(&new_root, arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100176 if (new_root != old_root) {
177 moving_roots.push_back(std::make_pair(old_root, new_root));
178 }
179 }
180
181 // Update object logs with moving roots.
182 for (const ObjectPair& pair : moving_roots) {
183 mirror::Object* old_root = pair.first;
184 mirror::Object* new_root = pair.second;
185 auto old_root_it = object_logs_.find(old_root);
186 CHECK(old_root_it != object_logs_.end());
187 CHECK(object_logs_.find(new_root) == object_logs_.end());
188 object_logs_.insert(std::make_pair(new_root, old_root_it->second));
189 object_logs_.erase(old_root_it);
190 }
191}
192
193void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
194 // List of moving roots.
195 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
196 std::list<ArrayPair> moving_roots;
197
198 for (auto it : array_logs_) {
199 mirror::Array* old_root = it.first;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100200 CHECK(!old_root->IsObjectArray());
Mathieu Chartier815873e2014-02-13 18:02:13 -0800201 mirror::Array* new_root = old_root;
202 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, 0, kRootUnknown);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100203 if (new_root != old_root) {
204 moving_roots.push_back(std::make_pair(old_root, new_root));
205 }
206 }
207
208 // Update array logs with moving roots.
209 for (const ArrayPair& pair : moving_roots) {
210 mirror::Array* old_root = pair.first;
211 mirror::Array* new_root = pair.second;
212 auto old_root_it = array_logs_.find(old_root);
213 CHECK(old_root_it != array_logs_.end());
214 CHECK(array_logs_.find(new_root) == array_logs_.end());
215 array_logs_.insert(std::make_pair(new_root, old_root_it->second));
216 array_logs_.erase(old_root_it);
217 }
218}
219
220void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
221 for (InternStringLog& log : intern_string_logs_) {
222 log.VisitRoots(callback, arg);
223 }
224}
225
226void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
227 auto it = field_values_.find(offset.Uint32Value());
228 if (it == field_values_.end()) {
229 ObjectLog::FieldValue field_value;
230 field_value.value = value;
231 field_value.is_volatile = is_volatile;
232 field_value.kind = ObjectLog::k32Bits;
233 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
234 }
235}
236
237void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
238 auto it = field_values_.find(offset.Uint32Value());
239 if (it == field_values_.end()) {
240 ObjectLog::FieldValue field_value;
241 field_value.value = value;
242 field_value.is_volatile = is_volatile;
243 field_value.kind = ObjectLog::k64Bits;
244 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
245 }
246}
247
248void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
249 auto it = field_values_.find(offset.Uint32Value());
250 if (it == field_values_.end()) {
251 ObjectLog::FieldValue field_value;
252 field_value.value = reinterpret_cast<uintptr_t>(obj);
253 field_value.is_volatile = is_volatile;
254 field_value.kind = ObjectLog::kReference;
255 field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
256 }
257}
258
259void Transaction::ObjectLog::Undo(mirror::Object* obj) {
260 for (auto& it : field_values_) {
261 // Garbage collector needs to access object's class and array's length. So we don't rollback
262 // these values.
263 MemberOffset field_offset(it.first);
264 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
265 // Skip Object::class field.
266 continue;
267 }
268 if (obj->IsArrayInstance() &&
269 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
270 // Skip Array::length field.
271 continue;
272 }
273 FieldValue& field_value = it.second;
274 UndoFieldWrite(obj, field_offset, field_value);
275 }
276}
277
278void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
279 const FieldValue& field_value) {
280 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
281 // we'd need to disable the check.
282 constexpr bool kCheckTransaction = true;
283 switch (field_value.kind) {
284 case k32Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700285 if (UNLIKELY(field_value.is_volatile)) {
286 obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
287 static_cast<uint32_t>(field_value.value));
288 } else {
289 obj->SetField32<false, kCheckTransaction>(field_offset,
290 static_cast<uint32_t>(field_value.value));
291 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100292 break;
293 case k64Bits:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700294 if (UNLIKELY(field_value.is_volatile)) {
295 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
296 } else {
297 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
298 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100299 break;
300 case kReference:
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700301 if (UNLIKELY(field_value.is_volatile)) {
302 obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
303 reinterpret_cast<mirror::Object*>(field_value.value));
304 } else {
305 obj->SetFieldObject<false, kCheckTransaction>(field_offset,
306 reinterpret_cast<mirror::Object*>(field_value.value));
307 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100308 break;
309 default:
310 LOG(FATAL) << "Unknown value kind " << field_value.kind;
311 break;
312 }
313}
314
315void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
316 for (auto it : field_values_) {
317 FieldValue& field_value = it.second;
318 if (field_value.kind == ObjectLog::kReference) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800319 mirror::Object* obj =
320 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
Sebastien Hertza559ccb2014-02-21 15:36:13 +0100321 if (obj != nullptr) {
322 callback(&obj, arg, 0, kRootUnknown);
323 field_value.value = reinterpret_cast<uintptr_t>(obj);
324 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100325 }
326 }
327}
328
329void Transaction::InternStringLog::Undo(InternTable* intern_table) {
330 DCHECK(intern_table != nullptr);
331 switch (string_op_) {
332 case InternStringLog::kInsert: {
333 switch (string_kind_) {
334 case InternStringLog::kStrongString:
335 intern_table->RemoveStrongFromTransaction(str_, hash_code_);
336 break;
337 case InternStringLog::kWeakString:
338 intern_table->RemoveWeakFromTransaction(str_, hash_code_);
339 break;
340 default:
341 LOG(FATAL) << "Unknown interned string kind";
342 break;
343 }
344 break;
345 }
346 case InternStringLog::kRemove: {
347 switch (string_kind_) {
348 case InternStringLog::kStrongString:
349 intern_table->InsertStrongFromTransaction(str_, hash_code_);
350 break;
351 case InternStringLog::kWeakString:
352 intern_table->InsertWeakFromTransaction(str_, hash_code_);
353 break;
354 default:
355 LOG(FATAL) << "Unknown interned string kind";
356 break;
357 }
358 break;
359 }
360 default:
361 LOG(FATAL) << "Unknown interned string op";
362 break;
363 }
364}
365
366void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800367 callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100368}
369
370void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
371 auto it = array_values_.find(index);
372 if (it == array_values_.end()) {
373 array_values_.insert(std::make_pair(index, value));
374 }
375}
376
377void Transaction::ArrayLog::Undo(mirror::Array* array) {
378 DCHECK(array != nullptr);
379 DCHECK(array->IsArrayInstance());
380 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
381 for (auto it : array_values_) {
382 UndoArrayWrite(array, type, it.first, it.second);
383 }
384}
385
386void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
387 size_t index, uint64_t value) {
388 // TODO We may want to abort a transaction while still being in transaction mode. In this case,
389 // we'd need to disable the check.
390 switch (array_type) {
391 case Primitive::kPrimBoolean:
392 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
393 break;
394 case Primitive::kPrimByte:
395 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
396 break;
397 case Primitive::kPrimChar:
398 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
399 break;
400 case Primitive::kPrimShort:
401 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
402 break;
403 case Primitive::kPrimInt:
404 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
405 break;
406 case Primitive::kPrimFloat:
407 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
408 break;
409 case Primitive::kPrimLong:
410 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
411 break;
412 case Primitive::kPrimDouble:
413 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
414 break;
Sebastien Hertzee1d79a2014-02-21 15:46:30 +0100415 case Primitive::kPrimNot:
416 LOG(FATAL) << "ObjectArray should be treated as Object";
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100417 break;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100418 default:
419 LOG(FATAL) << "Unsupported type " << array_type;
420 }
421}
422
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100423} // namespace art