/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_TRANSACTION_H_ #define ART_RUNTIME_TRANSACTION_H_ #include "base/macros.h" #include "base/mutex.h" #include "base/value_object.h" #include "gc_root.h" #include "object_callbacks.h" #include "offsets.h" #include "primitive.h" #include "safe_map.h" #include #include namespace art { namespace mirror { class Array; class Object; class String; } class InternTable; class Transaction FINAL { public: static constexpr const char* kAbortExceptionDescriptor = "dalvik.system.TransactionAbortError"; static constexpr const char* kAbortExceptionSignature = "Ldalvik/system/TransactionAbortError;"; Transaction(); ~Transaction(); void Abort(const std::string& abort_message) REQUIRES(!log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void ThrowAbortError(Thread* self, const std::string* abort_message) REQUIRES(!log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); bool IsAborted() REQUIRES(!log_lock_); // Record object field changes. void RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset, uint8_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteFieldByte(mirror::Object* obj, MemberOffset field_offset, int8_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteFieldChar(mirror::Object* obj, MemberOffset field_offset, uint16_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteFieldShort(mirror::Object* obj, MemberOffset field_offset, int16_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value, bool is_volatile) REQUIRES(!log_lock_); void RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset, mirror::Object* value, bool is_volatile) REQUIRES(!log_lock_); // Record array change. void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) REQUIRES(!log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Record intern string table changes. void RecordStrongStringInsertion(mirror::String* s) REQUIRES(Locks::intern_table_lock_) REQUIRES(!log_lock_); void RecordWeakStringInsertion(mirror::String* s) REQUIRES(Locks::intern_table_lock_) REQUIRES(!log_lock_); void RecordStrongStringRemoval(mirror::String* s) REQUIRES(Locks::intern_table_lock_) REQUIRES(!log_lock_); void RecordWeakStringRemoval(mirror::String* s) REQUIRES(Locks::intern_table_lock_) REQUIRES(!log_lock_); // Abort transaction by undoing all recorded changes. void Rollback() SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!log_lock_); void VisitRoots(RootVisitor* visitor) REQUIRES(!log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); private: class ObjectLog : public ValueObject { public: void LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile); void LogByteValue(MemberOffset offset, int8_t value, bool is_volatile); void LogCharValue(MemberOffset offset, uint16_t value, bool is_volatile); void LogShortValue(MemberOffset offset, int16_t value, bool is_volatile); void Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile); void Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile); void LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile); void Undo(mirror::Object* obj) SHARED_REQUIRES(Locks::mutator_lock_); void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_); size_t Size() const { return field_values_.size(); } private: enum FieldValueKind { kBoolean, kByte, kChar, kShort, k32Bits, k64Bits, kReference }; struct FieldValue : public ValueObject { // TODO use JValue instead ? uint64_t value; FieldValueKind kind; bool is_volatile; }; void LogValue(FieldValueKind kind, MemberOffset offset, uint64_t value, bool is_volatile); void UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset, const FieldValue& field_value) SHARED_REQUIRES(Locks::mutator_lock_); // Maps field's offset to its value. std::map field_values_; }; class ArrayLog : public ValueObject { public: void LogValue(size_t index, uint64_t value); void Undo(mirror::Array* obj) SHARED_REQUIRES(Locks::mutator_lock_); size_t Size() const { return array_values_.size(); } private: void UndoArrayWrite(mirror::Array* array, Primitive::Type array_type, size_t index, uint64_t value) SHARED_REQUIRES(Locks::mutator_lock_); // Maps index to value. // TODO use JValue instead ? std::map array_values_; }; class InternStringLog : public ValueObject { public: enum StringKind { kStrongString, kWeakString }; enum StringOp { kInsert, kRemove }; InternStringLog(mirror::String* s, StringKind kind, StringOp op) : str_(s), string_kind_(kind), string_op_(op) { DCHECK(s != nullptr); } void Undo(InternTable* intern_table) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_); void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_); private: mirror::String* str_; const StringKind string_kind_; const StringOp string_op_; }; void LogInternedString(const InternStringLog& log) REQUIRES(Locks::intern_table_lock_) REQUIRES(!log_lock_); void UndoObjectModifications() REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void UndoArrayModifications() REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void UndoInternStringTableModifications() REQUIRES(Locks::intern_table_lock_) REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void VisitObjectLogs(RootVisitor* visitor) REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void VisitArrayLogs(RootVisitor* visitor) REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); void VisitStringLogs(RootVisitor* visitor) REQUIRES(log_lock_) SHARED_REQUIRES(Locks::mutator_lock_); const std::string& GetAbortMessage() REQUIRES(!log_lock_); Mutex log_lock_ ACQUIRED_AFTER(Locks::intern_table_lock_); std::map object_logs_ GUARDED_BY(log_lock_); std::map array_logs_ GUARDED_BY(log_lock_); std::list intern_string_logs_ GUARDED_BY(log_lock_); bool aborted_ GUARDED_BY(log_lock_); std::string abort_message_ GUARDED_BY(log_lock_); DISALLOW_COPY_AND_ASSIGN(Transaction); }; } // namespace art #endif // ART_RUNTIME_TRANSACTION_H_