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/class-inl.h" 24 #include "mirror/object-inl.h" 25 #include "mirror/object_array-inl.h" 26 27 #include <list> 28 29 namespace art { 30 31 // TODO: remove (only used for debugging purpose). 32 static constexpr bool kEnableTransactionStats = false; 33 34 Transaction::Transaction() 35 : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) { 36 CHECK(Runtime::Current()->IsAotCompiler()); 37 } 38 39 Transaction::~Transaction() { 40 if (kEnableTransactionStats) { 41 MutexLock mu(Thread::Current(), log_lock_); 42 size_t objects_count = object_logs_.size(); 43 size_t field_values_count = 0; 44 for (const auto& it : object_logs_) { 45 field_values_count += it.second.Size(); 46 } 47 size_t array_count = array_logs_.size(); 48 size_t array_values_count = 0; 49 for (const auto& it : array_logs_) { 50 array_values_count += it.second.Size(); 51 } 52 size_t intern_string_count = intern_string_logs_.size(); 53 size_t resolve_string_count = resolve_string_logs_.size(); 54 LOG(INFO) << "Transaction::~Transaction" 55 << ": objects_count=" << objects_count 56 << ", field_values_count=" << field_values_count 57 << ", array_count=" << array_count 58 << ", array_values_count=" << array_values_count 59 << ", intern_string_count=" << intern_string_count 60 << ", resolve_string_count=" << resolve_string_count; 61 } 62 } 63 64 void Transaction::Abort(const std::string& abort_message) { 65 MutexLock mu(Thread::Current(), log_lock_); 66 // We may abort more than once if the exception thrown at the time of the 67 // previous abort has been caught during execution of a class initializer. 68 // We just keep the message of the first abort because it will cause the 69 // transaction to be rolled back anyway. 70 if (!aborted_) { 71 aborted_ = true; 72 abort_message_ = abort_message; 73 } 74 } 75 76 void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) { 77 const bool rethrow = (abort_message == nullptr); 78 if (kIsDebugBuild && rethrow) { 79 CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor 80 << " while transaction is not aborted"; 81 } 82 if (rethrow) { 83 // Rethrow an exception with the earlier abort message stored in the transaction. 84 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature, 85 GetAbortMessage().c_str()); 86 } else { 87 // Throw an exception with the given abort message. 88 self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature, 89 abort_message->c_str()); 90 } 91 } 92 93 bool Transaction::IsAborted() { 94 MutexLock mu(Thread::Current(), log_lock_); 95 return aborted_; 96 } 97 98 const std::string& Transaction::GetAbortMessage() { 99 MutexLock mu(Thread::Current(), log_lock_); 100 return abort_message_; 101 } 102 103 void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, 104 MemberOffset field_offset, 105 uint8_t value, 106 bool is_volatile) { 107 DCHECK(obj != nullptr); 108 MutexLock mu(Thread::Current(), log_lock_); 109 ObjectLog& object_log = object_logs_[obj]; 110 object_log.LogBooleanValue(field_offset, value, is_volatile); 111 } 112 113 void Transaction::RecordWriteFieldByte(mirror::Object* obj, 114 MemberOffset field_offset, 115 int8_t value, 116 bool is_volatile) { 117 DCHECK(obj != nullptr); 118 MutexLock mu(Thread::Current(), log_lock_); 119 ObjectLog& object_log = object_logs_[obj]; 120 object_log.LogByteValue(field_offset, value, is_volatile); 121 } 122 123 void Transaction::RecordWriteFieldChar(mirror::Object* obj, 124 MemberOffset field_offset, 125 uint16_t value, 126 bool is_volatile) { 127 DCHECK(obj != nullptr); 128 MutexLock mu(Thread::Current(), log_lock_); 129 ObjectLog& object_log = object_logs_[obj]; 130 object_log.LogCharValue(field_offset, value, is_volatile); 131 } 132 133 134 void Transaction::RecordWriteFieldShort(mirror::Object* obj, 135 MemberOffset field_offset, 136 int16_t value, 137 bool is_volatile) { 138 DCHECK(obj != nullptr); 139 MutexLock mu(Thread::Current(), log_lock_); 140 ObjectLog& object_log = object_logs_[obj]; 141 object_log.LogShortValue(field_offset, value, is_volatile); 142 } 143 144 145 void Transaction::RecordWriteField32(mirror::Object* obj, 146 MemberOffset field_offset, 147 uint32_t value, 148 bool is_volatile) { 149 DCHECK(obj != nullptr); 150 MutexLock mu(Thread::Current(), log_lock_); 151 ObjectLog& object_log = object_logs_[obj]; 152 object_log.Log32BitsValue(field_offset, value, is_volatile); 153 } 154 155 void Transaction::RecordWriteField64(mirror::Object* obj, 156 MemberOffset field_offset, 157 uint64_t value, 158 bool is_volatile) { 159 DCHECK(obj != nullptr); 160 MutexLock mu(Thread::Current(), log_lock_); 161 ObjectLog& object_log = object_logs_[obj]; 162 object_log.Log64BitsValue(field_offset, value, is_volatile); 163 } 164 165 void Transaction::RecordWriteFieldReference(mirror::Object* obj, 166 MemberOffset field_offset, 167 mirror::Object* value, 168 bool is_volatile) { 169 DCHECK(obj != nullptr); 170 MutexLock mu(Thread::Current(), log_lock_); 171 ObjectLog& object_log = object_logs_[obj]; 172 object_log.LogReferenceValue(field_offset, value, is_volatile); 173 } 174 175 void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) { 176 DCHECK(array != nullptr); 177 DCHECK(array->IsArrayInstance()); 178 DCHECK(!array->IsObjectArray()); 179 MutexLock mu(Thread::Current(), log_lock_); 180 auto it = array_logs_.find(array); 181 if (it == array_logs_.end()) { 182 ArrayLog log; 183 it = array_logs_.emplace(array, std::move(log)).first; 184 } 185 it->second.LogValue(index, value); 186 } 187 188 void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, 189 dex::StringIndex string_idx) { 190 DCHECK(dex_cache != nullptr); 191 DCHECK_LT(string_idx.index_, dex_cache->GetDexFile()->NumStringIds()); 192 MutexLock mu(Thread::Current(), log_lock_); 193 resolve_string_logs_.emplace_back(dex_cache, string_idx); 194 } 195 196 void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) { 197 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert); 198 LogInternedString(std::move(log)); 199 } 200 201 void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) { 202 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert); 203 LogInternedString(std::move(log)); 204 } 205 206 void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) { 207 InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove); 208 LogInternedString(std::move(log)); 209 } 210 211 void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) { 212 InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove); 213 LogInternedString(std::move(log)); 214 } 215 216 void Transaction::LogInternedString(InternStringLog&& log) { 217 Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current()); 218 MutexLock mu(Thread::Current(), log_lock_); 219 intern_string_logs_.push_front(std::move(log)); 220 } 221 222 void Transaction::Rollback() { 223 CHECK(!Runtime::Current()->IsActiveTransaction()); 224 Thread* self = Thread::Current(); 225 self->AssertNoPendingException(); 226 MutexLock mu1(self, *Locks::intern_table_lock_); 227 MutexLock mu2(self, log_lock_); 228 UndoObjectModifications(); 229 UndoArrayModifications(); 230 UndoInternStringTableModifications(); 231 UndoResolveStringModifications(); 232 } 233 234 void Transaction::UndoObjectModifications() { 235 // TODO we may not need to restore objects allocated during this transaction. Or we could directly 236 // remove them from the heap. 237 for (const auto& it : object_logs_) { 238 it.second.Undo(it.first); 239 } 240 object_logs_.clear(); 241 } 242 243 void Transaction::UndoArrayModifications() { 244 // TODO we may not need to restore array allocated during this transaction. Or we could directly 245 // remove them from the heap. 246 for (const auto& it : array_logs_) { 247 it.second.Undo(it.first); 248 } 249 array_logs_.clear(); 250 } 251 252 void Transaction::UndoInternStringTableModifications() { 253 InternTable* const intern_table = Runtime::Current()->GetInternTable(); 254 // We want to undo each operation from the most recent to the oldest. List has been filled so the 255 // most recent operation is at list begin so just have to iterate over it. 256 for (const InternStringLog& string_log : intern_string_logs_) { 257 string_log.Undo(intern_table); 258 } 259 intern_string_logs_.clear(); 260 } 261 262 void Transaction::UndoResolveStringModifications() { 263 for (ResolveStringLog& string_log : resolve_string_logs_) { 264 string_log.Undo(); 265 } 266 resolve_string_logs_.clear(); 267 } 268 269 void Transaction::VisitRoots(RootVisitor* visitor) { 270 MutexLock mu(Thread::Current(), log_lock_); 271 VisitObjectLogs(visitor); 272 VisitArrayLogs(visitor); 273 VisitInternStringLogs(visitor); 274 VisitResolveStringLogs(visitor); 275 } 276 277 void Transaction::VisitObjectLogs(RootVisitor* visitor) { 278 // List of moving roots. 279 typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair; 280 std::list<ObjectPair> moving_roots; 281 282 // Visit roots. 283 for (auto& it : object_logs_) { 284 it.second.VisitRoots(visitor); 285 mirror::Object* old_root = it.first; 286 mirror::Object* new_root = old_root; 287 visitor->VisitRoot(&new_root, RootInfo(kRootUnknown)); 288 if (new_root != old_root) { 289 moving_roots.push_back(std::make_pair(old_root, new_root)); 290 } 291 } 292 293 // Update object logs with moving roots. 294 for (const ObjectPair& pair : moving_roots) { 295 mirror::Object* old_root = pair.first; 296 mirror::Object* new_root = pair.second; 297 auto old_root_it = object_logs_.find(old_root); 298 CHECK(old_root_it != object_logs_.end()); 299 CHECK(object_logs_.find(new_root) == object_logs_.end()); 300 object_logs_.emplace(new_root, std::move(old_root_it->second)); 301 object_logs_.erase(old_root_it); 302 } 303 } 304 305 void Transaction::VisitArrayLogs(RootVisitor* visitor) { 306 // List of moving roots. 307 typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair; 308 std::list<ArrayPair> moving_roots; 309 310 for (auto& it : array_logs_) { 311 mirror::Array* old_root = it.first; 312 CHECK(!old_root->IsObjectArray()); 313 mirror::Array* new_root = old_root; 314 visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&new_root), RootInfo(kRootUnknown)); 315 if (new_root != old_root) { 316 moving_roots.push_back(std::make_pair(old_root, new_root)); 317 } 318 } 319 320 // Update array logs with moving roots. 321 for (const ArrayPair& pair : moving_roots) { 322 mirror::Array* old_root = pair.first; 323 mirror::Array* new_root = pair.second; 324 auto old_root_it = array_logs_.find(old_root); 325 CHECK(old_root_it != array_logs_.end()); 326 CHECK(array_logs_.find(new_root) == array_logs_.end()); 327 array_logs_.emplace(new_root, std::move(old_root_it->second)); 328 array_logs_.erase(old_root_it); 329 } 330 } 331 332 void Transaction::VisitInternStringLogs(RootVisitor* visitor) { 333 for (InternStringLog& log : intern_string_logs_) { 334 log.VisitRoots(visitor); 335 } 336 } 337 338 void Transaction::VisitResolveStringLogs(RootVisitor* visitor) { 339 for (ResolveStringLog& log : resolve_string_logs_) { 340 log.VisitRoots(visitor); 341 } 342 } 343 344 void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) { 345 LogValue(ObjectLog::kBoolean, offset, value, is_volatile); 346 } 347 348 void Transaction::ObjectLog::LogByteValue(MemberOffset offset, int8_t value, bool is_volatile) { 349 LogValue(ObjectLog::kByte, offset, value, is_volatile); 350 } 351 352 void Transaction::ObjectLog::LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile) { 353 LogValue(ObjectLog::kChar, offset, value, is_volatile); 354 } 355 356 void Transaction::ObjectLog::LogShortValue(MemberOffset offset, int16_t value, bool is_volatile) { 357 LogValue(ObjectLog::kShort, offset, value, is_volatile); 358 } 359 360 void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) { 361 LogValue(ObjectLog::k32Bits, offset, value, is_volatile); 362 } 363 364 void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) { 365 LogValue(ObjectLog::k64Bits, offset, value, is_volatile); 366 } 367 368 void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, 369 mirror::Object* obj, 370 bool is_volatile) { 371 LogValue(ObjectLog::kReference, offset, reinterpret_cast<uintptr_t>(obj), is_volatile); 372 } 373 374 void Transaction::ObjectLog::LogValue(ObjectLog::FieldValueKind kind, 375 MemberOffset offset, 376 uint64_t value, 377 bool is_volatile) { 378 auto it = field_values_.find(offset.Uint32Value()); 379 if (it == field_values_.end()) { 380 ObjectLog::FieldValue field_value; 381 field_value.value = value; 382 field_value.is_volatile = is_volatile; 383 field_value.kind = kind; 384 field_values_.emplace(offset.Uint32Value(), std::move(field_value)); 385 } 386 } 387 388 void Transaction::ObjectLog::Undo(mirror::Object* obj) const { 389 for (auto& it : field_values_) { 390 // Garbage collector needs to access object's class and array's length. So we don't rollback 391 // these values. 392 MemberOffset field_offset(it.first); 393 if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) { 394 // Skip Object::class field. 395 continue; 396 } 397 if (obj->IsArrayInstance() && 398 field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) { 399 // Skip Array::length field. 400 continue; 401 } 402 const FieldValue& field_value = it.second; 403 UndoFieldWrite(obj, field_offset, field_value); 404 } 405 } 406 407 void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, 408 MemberOffset field_offset, 409 const FieldValue& field_value) const { 410 // TODO We may want to abort a transaction while still being in transaction mode. In this case, 411 // we'd need to disable the check. 412 constexpr bool kCheckTransaction = true; 413 switch (field_value.kind) { 414 case kBoolean: 415 if (UNLIKELY(field_value.is_volatile)) { 416 obj->SetFieldBooleanVolatile<false, kCheckTransaction>( 417 field_offset, 418 static_cast<bool>(field_value.value)); 419 } else { 420 obj->SetFieldBoolean<false, kCheckTransaction>( 421 field_offset, 422 static_cast<bool>(field_value.value)); 423 } 424 break; 425 case kByte: 426 if (UNLIKELY(field_value.is_volatile)) { 427 obj->SetFieldByteVolatile<false, kCheckTransaction>( 428 field_offset, 429 static_cast<int8_t>(field_value.value)); 430 } else { 431 obj->SetFieldByte<false, kCheckTransaction>( 432 field_offset, 433 static_cast<int8_t>(field_value.value)); 434 } 435 break; 436 case kChar: 437 if (UNLIKELY(field_value.is_volatile)) { 438 obj->SetFieldCharVolatile<false, kCheckTransaction>( 439 field_offset, 440 static_cast<uint16_t>(field_value.value)); 441 } else { 442 obj->SetFieldChar<false, kCheckTransaction>( 443 field_offset, 444 static_cast<uint16_t>(field_value.value)); 445 } 446 break; 447 case kShort: 448 if (UNLIKELY(field_value.is_volatile)) { 449 obj->SetFieldShortVolatile<false, kCheckTransaction>( 450 field_offset, 451 static_cast<int16_t>(field_value.value)); 452 } else { 453 obj->SetFieldShort<false, kCheckTransaction>( 454 field_offset, 455 static_cast<int16_t>(field_value.value)); 456 } 457 break; 458 case k32Bits: 459 if (UNLIKELY(field_value.is_volatile)) { 460 obj->SetField32Volatile<false, kCheckTransaction>( 461 field_offset, 462 static_cast<uint32_t>(field_value.value)); 463 } else { 464 obj->SetField32<false, kCheckTransaction>( 465 field_offset, 466 static_cast<uint32_t>(field_value.value)); 467 } 468 break; 469 case k64Bits: 470 if (UNLIKELY(field_value.is_volatile)) { 471 obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value); 472 } else { 473 obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value); 474 } 475 break; 476 case kReference: 477 if (UNLIKELY(field_value.is_volatile)) { 478 obj->SetFieldObjectVolatile<false, kCheckTransaction>( 479 field_offset, 480 reinterpret_cast<mirror::Object*>(field_value.value)); 481 } else { 482 obj->SetFieldObject<false, kCheckTransaction>( 483 field_offset, 484 reinterpret_cast<mirror::Object*>(field_value.value)); 485 } 486 break; 487 default: 488 LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind); 489 break; 490 } 491 } 492 493 void Transaction::ObjectLog::VisitRoots(RootVisitor* visitor) { 494 for (auto& it : field_values_) { 495 FieldValue& field_value = it.second; 496 if (field_value.kind == ObjectLog::kReference) { 497 visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&field_value.value), 498 RootInfo(kRootUnknown)); 499 } 500 } 501 } 502 503 void Transaction::InternStringLog::Undo(InternTable* intern_table) const { 504 DCHECK(intern_table != nullptr); 505 switch (string_op_) { 506 case InternStringLog::kInsert: { 507 switch (string_kind_) { 508 case InternStringLog::kStrongString: 509 intern_table->RemoveStrongFromTransaction(str_.Read()); 510 break; 511 case InternStringLog::kWeakString: 512 intern_table->RemoveWeakFromTransaction(str_.Read()); 513 break; 514 default: 515 LOG(FATAL) << "Unknown interned string kind"; 516 break; 517 } 518 break; 519 } 520 case InternStringLog::kRemove: { 521 switch (string_kind_) { 522 case InternStringLog::kStrongString: 523 intern_table->InsertStrongFromTransaction(str_.Read()); 524 break; 525 case InternStringLog::kWeakString: 526 intern_table->InsertWeakFromTransaction(str_.Read()); 527 break; 528 default: 529 LOG(FATAL) << "Unknown interned string kind"; 530 break; 531 } 532 break; 533 } 534 default: 535 LOG(FATAL) << "Unknown interned string op"; 536 break; 537 } 538 } 539 540 void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) { 541 str_.VisitRoot(visitor, RootInfo(kRootInternedString)); 542 } 543 544 void Transaction::ResolveStringLog::Undo() const { 545 dex_cache_.Read()->ClearString(string_idx_); 546 } 547 548 Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache, 549 dex::StringIndex string_idx) 550 : dex_cache_(dex_cache), 551 string_idx_(string_idx) { 552 DCHECK(dex_cache != nullptr); 553 DCHECK_LT(string_idx_.index_, dex_cache->GetDexFile()->NumStringIds()); 554 } 555 556 void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) { 557 dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal)); 558 } 559 560 Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s, 561 StringKind kind, 562 StringOp op) 563 : str_(s), 564 string_kind_(kind), 565 string_op_(op) { 566 DCHECK(s != nullptr); 567 } 568 569 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) { 570 auto it = array_values_.find(index); 571 if (it == array_values_.end()) { 572 array_values_.insert(std::make_pair(index, value)); 573 } 574 } 575 576 void Transaction::ArrayLog::Undo(mirror::Array* array) const { 577 DCHECK(array != nullptr); 578 DCHECK(array->IsArrayInstance()); 579 Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType(); 580 for (auto it : array_values_) { 581 UndoArrayWrite(array, type, it.first, it.second); 582 } 583 } 584 585 void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, 586 Primitive::Type array_type, 587 size_t index, 588 uint64_t value) const { 589 // TODO We may want to abort a transaction while still being in transaction mode. In this case, 590 // we'd need to disable the check. 591 switch (array_type) { 592 case Primitive::kPrimBoolean: 593 array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value)); 594 break; 595 case Primitive::kPrimByte: 596 array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value)); 597 break; 598 case Primitive::kPrimChar: 599 array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value)); 600 break; 601 case Primitive::kPrimShort: 602 array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value)); 603 break; 604 case Primitive::kPrimInt: 605 array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value)); 606 break; 607 case Primitive::kPrimFloat: 608 array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value)); 609 break; 610 case Primitive::kPrimLong: 611 array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value)); 612 break; 613 case Primitive::kPrimDouble: 614 array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value)); 615 break; 616 case Primitive::kPrimNot: 617 LOG(FATAL) << "ObjectArray should be treated as Object"; 618 break; 619 default: 620 LOG(FATAL) << "Unsupported type " << array_type; 621 } 622 } 623 624 } // namespace art 625