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 
Transaction()33 Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
34   CHECK(Runtime::Current()->IsCompiler());
35 }
36 
~Transaction()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 
RecordWriteField32(mirror::Object * obj,MemberOffset field_offset,uint32_t value,bool is_volatile)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 
RecordWriteField64(mirror::Object * obj,MemberOffset field_offset,uint64_t value,bool is_volatile)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 
RecordWriteFieldReference(mirror::Object * obj,MemberOffset field_offset,mirror::Object * value,bool is_volatile)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 
RecordWriteArray(mirror::Array * array,size_t index,uint64_t value)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 
RecordStrongStringInsertion(mirror::String * s)93 void Transaction::RecordStrongStringInsertion(mirror::String* s) {
94   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
95   LogInternedString(log);
96 }
97 
RecordWeakStringInsertion(mirror::String * s)98 void Transaction::RecordWeakStringInsertion(mirror::String* s) {
99   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
100   LogInternedString(log);
101 }
102 
RecordStrongStringRemoval(mirror::String * s)103 void Transaction::RecordStrongStringRemoval(mirror::String* s) {
104   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
105   LogInternedString(log);
106 }
107 
RecordWeakStringRemoval(mirror::String * s)108 void Transaction::RecordWeakStringRemoval(mirror::String* s) {
109   InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
110   LogInternedString(log);
111 }
112 
LogInternedString(InternStringLog & log)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 
Abort()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 
UndoObjectModifications()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 
UndoArrayModifications()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 
UndoInternStringTableModifications()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 
VisitRoots(RootCallback * callback,void * arg)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 
VisitObjectLogs(RootCallback * callback,void * arg)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 
VisitArrayLogs(RootCallback * callback,void * arg)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 
VisitStringLogs(RootCallback * callback,void * arg)220 void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
221   for (InternStringLog& log : intern_string_logs_) {
222     log.VisitRoots(callback, arg);
223   }
224 }
225 
Log32BitsValue(MemberOffset offset,uint32_t value,bool is_volatile)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 
Log64BitsValue(MemberOffset offset,uint64_t value,bool is_volatile)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 
LogReferenceValue(MemberOffset offset,mirror::Object * obj,bool is_volatile)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 
Undo(mirror::Object * obj)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 
UndoFieldWrite(mirror::Object * obj,MemberOffset field_offset,const FieldValue & field_value)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 
VisitRoots(RootCallback * callback,void * arg)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 
Undo(InternTable * intern_table)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 
VisitRoots(RootCallback * callback,void * arg)366 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
367   callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
368 }
369 
LogValue(size_t index,uint64_t value)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 
Undo(mirror::Array * array)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 
UndoArrayWrite(mirror::Array * array,Primitive::Type array_type,size_t index,uint64_t value)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