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 33 Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) { 34 CHECK(Runtime::Current()->IsCompiler()); 35 } 36 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 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 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 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 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 93 void Transaction::RecordStrongStringInsertion(mirror::String* s) { 94 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert); 95 LogInternedString(log); 96 } 97 98 void Transaction::RecordWeakStringInsertion(mirror::String* s) { 99 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert); 100 LogInternedString(log); 101 } 102 103 void Transaction::RecordStrongStringRemoval(mirror::String* s) { 104 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove); 105 LogInternedString(log); 106 } 107 108 void Transaction::RecordWeakStringRemoval(mirror::String* s) { 109 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove); 110 LogInternedString(log); 111 } 112 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 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 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 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 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 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 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 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 220 void Transaction::VisitStringLogs(RootCallback* callback, void* arg) { 221 for (InternStringLog& log : intern_string_logs_) { 222 log.VisitRoots(callback, arg); 223 } 224 } 225 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 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 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 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 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 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 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 366 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) { 367 callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString)); 368 } 369 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 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 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