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