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