1 /*
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
28 namespace art {
29
30 // TODO: remove (only used for debugging purpose).
31 static constexpr bool kEnableTransactionStats = false;
32
Transaction()33 Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
34 CHECK(Runtime::Current()->IsCompiler());
35 }
36
~Transaction()37 Transaction::~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
RecordWriteField32(mirror::Object * obj,MemberOffset field_offset,uint32_t value,bool is_volatile)60 void 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
RecordWriteField64(mirror::Object * obj,MemberOffset field_offset,uint64_t value,bool is_volatile)68 void 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
RecordWriteFieldReference(mirror::Object * obj,MemberOffset field_offset,mirror::Object * value,bool is_volatile)76 void 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
RecordWriteArray(mirror::Array * array,size_t index,uint64_t value)84 void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
85 DCHECK(array != nullptr);
86 DCHECK(array->IsArrayInstance());
87 DCHECK(!array->IsObjectArray());
88 MutexLock mu(Thread::Current(), log_lock_);
89 ArrayLog& array_log = array_logs_[array];
90 array_log.LogValue(index, value);
91 }
92
RecordStrongStringInsertion(mirror::String * s)93 void Transaction::RecordStrongStringInsertion(mirror::String* s) {
94 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
95 LogInternedString(log);
96 }
97
RecordWeakStringInsertion(mirror::String * s)98 void Transaction::RecordWeakStringInsertion(mirror::String* s) {
99 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
100 LogInternedString(log);
101 }
102
RecordStrongStringRemoval(mirror::String * s)103 void Transaction::RecordStrongStringRemoval(mirror::String* s) {
104 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
105 LogInternedString(log);
106 }
107
RecordWeakStringRemoval(mirror::String * s)108 void Transaction::RecordWeakStringRemoval(mirror::String* s) {
109 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
110 LogInternedString(log);
111 }
112
LogInternedString(InternStringLog & log)113 void 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
Abort()119 void 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
UndoObjectModifications()130 void 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
UndoArrayModifications()139 void 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
UndoInternStringTableModifications()148 void 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
VisitRoots(RootCallback * callback,void * arg)158 void Transaction::VisitRoots(RootCallback* callback, void* arg) {
159 MutexLock mu(Thread::Current(), log_lock_);
160 VisitObjectLogs(callback, arg);
161 VisitArrayLogs(callback, arg);
162 VisitStringLogs(callback, arg);
163 }
164
VisitObjectLogs(RootCallback * callback,void * arg)165 void 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;
174 mirror::Object* new_root = old_root;
175 callback(&new_root, arg, RootInfo(kRootUnknown));
176 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
VisitArrayLogs(RootCallback * callback,void * arg)193 void 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;
200 CHECK(!old_root->IsObjectArray());
201 mirror::Array* new_root = old_root;
202 callback(reinterpret_cast<mirror::Object**>(&new_root), arg, RootInfo(kRootUnknown));
203 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
VisitStringLogs(RootCallback * callback,void * arg)220 void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
221 for (InternStringLog& log : intern_string_logs_) {
222 log.VisitRoots(callback, arg);
223 }
224 }
225
Log32BitsValue(MemberOffset offset,uint32_t value,bool is_volatile)226 void 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
Log64BitsValue(MemberOffset offset,uint64_t value,bool is_volatile)237 void 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
LogReferenceValue(MemberOffset offset,mirror::Object * obj,bool is_volatile)248 void 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
Undo(mirror::Object * obj)259 void 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
UndoFieldWrite(mirror::Object * obj,MemberOffset field_offset,const FieldValue & field_value)278 void 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:
285 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 }
292 break;
293 case k64Bits:
294 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 }
299 break;
300 case kReference:
301 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 }
308 break;
309 default:
310 LOG(FATAL) << "Unknown value kind " << field_value.kind;
311 break;
312 }
313 }
314
VisitRoots(RootCallback * callback,void * arg)315 void 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) {
319 mirror::Object* obj =
320 reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
321 if (obj != nullptr) {
322 callback(&obj, arg, RootInfo(kRootUnknown));
323 field_value.value = reinterpret_cast<uintptr_t>(obj);
324 }
325 }
326 }
327 }
328
Undo(InternTable * intern_table)329 void 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_);
336 break;
337 case InternStringLog::kWeakString:
338 intern_table->RemoveWeakFromTransaction(str_);
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_);
350 break;
351 case InternStringLog::kWeakString:
352 intern_table->InsertWeakFromTransaction(str_);
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
VisitRoots(RootCallback * callback,void * arg)366 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
367 callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
368 }
369
LogValue(size_t index,uint64_t value)370 void 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
Undo(mirror::Array * array)377 void 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
UndoArrayWrite(mirror::Array * array,Primitive::Type array_type,size_t index,uint64_t value)386 void 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;
415 case Primitive::kPrimNot:
416 LOG(FATAL) << "ObjectArray should be treated as Object";
417 break;
418 default:
419 LOG(FATAL) << "Unsupported type " << array_type;
420 }
421 }
422
423 } // namespace art
424