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/object-inl.h"
     24 #include "mirror/object_array-inl.h"
     25 
     26 #include <list>
     27 
     28 namespace art {
     29 
     30 // TODO: remove (only used for debugging purpose).
     31 static constexpr bool kEnableTransactionStats = false;
     32 
     33 Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
     34   CHECK(Runtime::Current()->IsCompiler());
     35 }
     36 
     37 Transaction::~Transaction() {
     38   if (kEnableTransactionStats) {
     39     MutexLock mu(Thread::Current(), log_lock_);
     40     size_t objects_count = object_logs_.size();
     41     size_t field_values_count = 0;
     42     for (auto it : object_logs_) {
     43       field_values_count += it.second.Size();
     44     }
     45     size_t array_count = array_logs_.size();
     46     size_t array_values_count = 0;
     47     for (auto it : array_logs_) {
     48       array_values_count += it.second.Size();
     49     }
     50     size_t string_count = intern_string_logs_.size();
     51     LOG(INFO) << "Transaction::~Transaction"
     52               << ": objects_count=" << objects_count
     53               << ", field_values_count=" << field_values_count
     54               << ", array_count=" << array_count
     55               << ", array_values_count=" << array_values_count
     56               << ", string_count=" << string_count;
     57   }
     58 }
     59 
     60 void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
     61                                      bool is_volatile) {
     62   DCHECK(obj != nullptr);
     63   MutexLock mu(Thread::Current(), log_lock_);
     64   ObjectLog& object_log = object_logs_[obj];
     65   object_log.Log32BitsValue(field_offset, value, is_volatile);
     66 }
     67 
     68 void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
     69                                      bool is_volatile) {
     70   DCHECK(obj != nullptr);
     71   MutexLock mu(Thread::Current(), log_lock_);
     72   ObjectLog& object_log = object_logs_[obj];
     73   object_log.Log64BitsValue(field_offset, value, is_volatile);
     74 }
     75 
     76 void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
     77                                             mirror::Object* value, bool is_volatile) {
     78   DCHECK(obj != nullptr);
     79   MutexLock mu(Thread::Current(), log_lock_);
     80   ObjectLog& object_log = object_logs_[obj];
     81   object_log.LogReferenceValue(field_offset, value, is_volatile);
     82 }
     83 
     84 void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
     85   DCHECK(array != nullptr);
     86   DCHECK(array->IsArrayInstance());
     87   DCHECK(!array->IsObjectArray());
     88   MutexLock mu(Thread::Current(), log_lock_);
     89   ArrayLog& array_log = array_logs_[array];
     90   array_log.LogValue(index, value);
     91 }
     92 
     93 void Transaction::RecordStrongStringInsertion(mirror::String* s) {
     94   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
     95   LogInternedString(log);
     96 }
     97 
     98 void Transaction::RecordWeakStringInsertion(mirror::String* s) {
     99   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
    100   LogInternedString(log);
    101 }
    102 
    103 void Transaction::RecordStrongStringRemoval(mirror::String* s) {
    104   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
    105   LogInternedString(log);
    106 }
    107 
    108 void Transaction::RecordWeakStringRemoval(mirror::String* s) {
    109   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
    110   LogInternedString(log);
    111 }
    112 
    113 void Transaction::LogInternedString(InternStringLog& log) {
    114   Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
    115   MutexLock mu(Thread::Current(), log_lock_);
    116   intern_string_logs_.push_front(log);
    117 }
    118 
    119 void Transaction::Abort() {
    120   CHECK(!Runtime::Current()->IsActiveTransaction());
    121   Thread* self = Thread::Current();
    122   self->AssertNoPendingException();
    123   MutexLock mu1(self, *Locks::intern_table_lock_);
    124   MutexLock mu2(self, log_lock_);
    125   UndoObjectModifications();
    126   UndoArrayModifications();
    127   UndoInternStringTableModifications();
    128 }
    129 
    130 void Transaction::UndoObjectModifications() {
    131   // TODO we may not need to restore objects allocated during this transaction. Or we could directly
    132   // remove them from the heap.
    133   for (auto it : object_logs_) {
    134     it.second.Undo(it.first);
    135   }
    136   object_logs_.clear();
    137 }
    138 
    139 void Transaction::UndoArrayModifications() {
    140   // TODO we may not need to restore array allocated during this transaction. Or we could directly
    141   // remove them from the heap.
    142   for (auto it : array_logs_) {
    143     it.second.Undo(it.first);
    144   }
    145   array_logs_.clear();
    146 }
    147 
    148 void Transaction::UndoInternStringTableModifications() {
    149   InternTable* const intern_table = Runtime::Current()->GetInternTable();
    150   // We want to undo each operation from the most recent to the oldest. List has been filled so the
    151   // most recent operation is at list begin so just have to iterate over it.
    152   for (InternStringLog& string_log : intern_string_logs_) {
    153     string_log.Undo(intern_table);
    154   }
    155   intern_string_logs_.clear();
    156 }
    157 
    158 void Transaction::VisitRoots(RootCallback* callback, void* arg) {
    159   MutexLock mu(Thread::Current(), log_lock_);
    160   VisitObjectLogs(callback, arg);
    161   VisitArrayLogs(callback, arg);
    162   VisitStringLogs(callback, arg);
    163 }
    164 
    165 void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
    166   // List of moving roots.
    167   typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
    168   std::list<ObjectPair> moving_roots;
    169 
    170   // Visit roots.
    171   for (auto it : object_logs_) {
    172     it.second.VisitRoots(callback, arg);
    173     mirror::Object* old_root = it.first;
    174     mirror::Object* new_root = old_root;
    175     callback(&new_root, arg, RootInfo(kRootUnknown));
    176     if (new_root != old_root) {
    177       moving_roots.push_back(std::make_pair(old_root, new_root));
    178     }
    179   }
    180 
    181   // Update object logs with moving roots.
    182   for (const ObjectPair& pair : moving_roots) {
    183     mirror::Object* old_root = pair.first;
    184     mirror::Object* new_root = pair.second;
    185     auto old_root_it = object_logs_.find(old_root);
    186     CHECK(old_root_it != object_logs_.end());
    187     CHECK(object_logs_.find(new_root) == object_logs_.end());
    188     object_logs_.insert(std::make_pair(new_root, old_root_it->second));
    189     object_logs_.erase(old_root_it);
    190   }
    191 }
    192 
    193 void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
    194   // List of moving roots.
    195   typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
    196   std::list<ArrayPair> moving_roots;
    197 
    198   for (auto it : array_logs_) {
    199     mirror::Array* old_root = it.first;
    200     CHECK(!old_root->IsObjectArray());
    201     mirror::Array* new_root = old_root;
    202     callback(reinterpret_cast<mirror::Object**>(&new_root), arg, RootInfo(kRootUnknown));
    203     if (new_root != old_root) {
    204       moving_roots.push_back(std::make_pair(old_root, new_root));
    205     }
    206   }
    207 
    208   // Update array logs with moving roots.
    209   for (const ArrayPair& pair : moving_roots) {
    210     mirror::Array* old_root = pair.first;
    211     mirror::Array* new_root = pair.second;
    212     auto old_root_it = array_logs_.find(old_root);
    213     CHECK(old_root_it != array_logs_.end());
    214     CHECK(array_logs_.find(new_root) == array_logs_.end());
    215     array_logs_.insert(std::make_pair(new_root, old_root_it->second));
    216     array_logs_.erase(old_root_it);
    217   }
    218 }
    219 
    220 void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
    221   for (InternStringLog& log : intern_string_logs_) {
    222     log.VisitRoots(callback, arg);
    223   }
    224 }
    225 
    226 void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
    227   auto it = field_values_.find(offset.Uint32Value());
    228   if (it == field_values_.end()) {
    229     ObjectLog::FieldValue field_value;
    230     field_value.value = value;
    231     field_value.is_volatile = is_volatile;
    232     field_value.kind = ObjectLog::k32Bits;
    233     field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
    234   }
    235 }
    236 
    237 void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
    238   auto it = field_values_.find(offset.Uint32Value());
    239   if (it == field_values_.end()) {
    240     ObjectLog::FieldValue field_value;
    241     field_value.value = value;
    242     field_value.is_volatile = is_volatile;
    243     field_value.kind = ObjectLog::k64Bits;
    244     field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
    245   }
    246 }
    247 
    248 void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
    249   auto it = field_values_.find(offset.Uint32Value());
    250   if (it == field_values_.end()) {
    251     ObjectLog::FieldValue field_value;
    252     field_value.value = reinterpret_cast<uintptr_t>(obj);
    253     field_value.is_volatile = is_volatile;
    254     field_value.kind = ObjectLog::kReference;
    255     field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
    256   }
    257 }
    258 
    259 void Transaction::ObjectLog::Undo(mirror::Object* obj) {
    260   for (auto& it : field_values_) {
    261     // Garbage collector needs to access object's class and array's length. So we don't rollback
    262     // these values.
    263     MemberOffset field_offset(it.first);
    264     if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
    265       // Skip Object::class field.
    266       continue;
    267     }
    268     if (obj->IsArrayInstance() &&
    269         field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
    270       // Skip Array::length field.
    271       continue;
    272     }
    273     FieldValue& field_value = it.second;
    274     UndoFieldWrite(obj, field_offset, field_value);
    275   }
    276 }
    277 
    278 void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
    279                                             const FieldValue& field_value) {
    280   // TODO We may want to abort a transaction while still being in transaction mode. In this case,
    281   // we'd need to disable the check.
    282   constexpr bool kCheckTransaction = true;
    283   switch (field_value.kind) {
    284     case k32Bits:
    285       if (UNLIKELY(field_value.is_volatile)) {
    286         obj->SetField32Volatile<false, kCheckTransaction>(field_offset,
    287                                                           static_cast<uint32_t>(field_value.value));
    288       } else {
    289         obj->SetField32<false, kCheckTransaction>(field_offset,
    290                                                   static_cast<uint32_t>(field_value.value));
    291       }
    292       break;
    293     case k64Bits:
    294       if (UNLIKELY(field_value.is_volatile)) {
    295         obj->SetField64Volatile<false, kCheckTransaction>(field_offset, field_value.value);
    296       } else {
    297         obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value);
    298       }
    299       break;
    300     case kReference:
    301       if (UNLIKELY(field_value.is_volatile)) {
    302         obj->SetFieldObjectVolatile<false, kCheckTransaction>(field_offset,
    303                                                               reinterpret_cast<mirror::Object*>(field_value.value));
    304       } else {
    305         obj->SetFieldObject<false, kCheckTransaction>(field_offset,
    306                                                       reinterpret_cast<mirror::Object*>(field_value.value));
    307       }
    308       break;
    309     default:
    310       LOG(FATAL) << "Unknown value kind " << field_value.kind;
    311       break;
    312   }
    313 }
    314 
    315 void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
    316   for (auto it : field_values_) {
    317     FieldValue& field_value = it.second;
    318     if (field_value.kind == ObjectLog::kReference) {
    319       mirror::Object* obj =
    320           reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
    321       if (obj != nullptr) {
    322         callback(&obj, arg, RootInfo(kRootUnknown));
    323         field_value.value = reinterpret_cast<uintptr_t>(obj);
    324       }
    325     }
    326   }
    327 }
    328 
    329 void Transaction::InternStringLog::Undo(InternTable* intern_table) {
    330   DCHECK(intern_table != nullptr);
    331   switch (string_op_) {
    332       case InternStringLog::kInsert: {
    333         switch (string_kind_) {
    334           case InternStringLog::kStrongString:
    335             intern_table->RemoveStrongFromTransaction(str_);
    336             break;
    337           case InternStringLog::kWeakString:
    338             intern_table->RemoveWeakFromTransaction(str_);
    339             break;
    340           default:
    341             LOG(FATAL) << "Unknown interned string kind";
    342             break;
    343         }
    344         break;
    345       }
    346       case InternStringLog::kRemove: {
    347         switch (string_kind_) {
    348           case InternStringLog::kStrongString:
    349             intern_table->InsertStrongFromTransaction(str_);
    350             break;
    351           case InternStringLog::kWeakString:
    352             intern_table->InsertWeakFromTransaction(str_);
    353             break;
    354           default:
    355             LOG(FATAL) << "Unknown interned string kind";
    356             break;
    357         }
    358         break;
    359       }
    360       default:
    361         LOG(FATAL) << "Unknown interned string op";
    362         break;
    363     }
    364 }
    365 
    366 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
    367   callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
    368 }
    369 
    370 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
    371   auto it = array_values_.find(index);
    372   if (it == array_values_.end()) {
    373     array_values_.insert(std::make_pair(index, value));
    374   }
    375 }
    376 
    377 void Transaction::ArrayLog::Undo(mirror::Array* array) {
    378   DCHECK(array != nullptr);
    379   DCHECK(array->IsArrayInstance());
    380   Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
    381   for (auto it : array_values_) {
    382     UndoArrayWrite(array, type, it.first, it.second);
    383   }
    384 }
    385 
    386 void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
    387                                            size_t index, uint64_t value) {
    388   // TODO We may want to abort a transaction while still being in transaction mode. In this case,
    389   // we'd need to disable the check.
    390   switch (array_type) {
    391     case Primitive::kPrimBoolean:
    392       array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
    393       break;
    394     case Primitive::kPrimByte:
    395       array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
    396       break;
    397     case Primitive::kPrimChar:
    398       array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
    399       break;
    400     case Primitive::kPrimShort:
    401       array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
    402       break;
    403     case Primitive::kPrimInt:
    404       array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
    405       break;
    406     case Primitive::kPrimFloat:
    407       array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
    408       break;
    409     case Primitive::kPrimLong:
    410       array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
    411       break;
    412     case Primitive::kPrimDouble:
    413       array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
    414       break;
    415     case Primitive::kPrimNot:
    416       LOG(FATAL) << "ObjectArray should be treated as Object";
    417       break;
    418     default:
    419       LOG(FATAL) << "Unsupported type " << array_type;
    420   }
    421 }
    422 
    423 }  // namespace art
    424