Home | History | Annotate | Download | only in runtime
      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