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
28namespace art {
29
30// TODO: remove (only used for debugging purpose).
31static constexpr bool kEnableTransactionStats = false;
32
33Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
34  CHECK(Runtime::Current()->IsCompiler());
35}
36
37Transaction::~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
60void 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
68void 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
76void 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
84void 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
93void Transaction::RecordStrongStringInsertion(mirror::String* s) {
94  InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
95  LogInternedString(log);
96}
97
98void Transaction::RecordWeakStringInsertion(mirror::String* s) {
99  InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
100  LogInternedString(log);
101}
102
103void Transaction::RecordStrongStringRemoval(mirror::String* s) {
104  InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
105  LogInternedString(log);
106}
107
108void Transaction::RecordWeakStringRemoval(mirror::String* s) {
109  InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
110  LogInternedString(log);
111}
112
113void 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
119void 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
130void 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
139void 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
148void 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
158void 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
165void 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
193void 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
220void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
221  for (InternStringLog& log : intern_string_logs_) {
222    log.VisitRoots(callback, arg);
223  }
224}
225
226void 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
237void 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
248void 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
259void 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
278void 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
315void 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
329void 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
366void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
367  callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
368}
369
370void 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
377void 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
386void 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