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