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