/* * Copyright (C) 2018 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. */ // The interpreter function takes considerable time to compile and link. // We compile the explicit definitions separately to speed up the build. #include "interpreter/interpreter_switch_impl-inl.h" #include "aot_class_linker.h" #include "transaction.h" namespace art HIDDEN { namespace interpreter { class ActiveTransactionChecker { public: static inline bool WriteConstraint(Thread* self, ObjPtr obj) REQUIRES_SHARED(Locks::mutator_lock_) { return GetClassLinker()->TransactionWriteConstraint(self, obj); } static inline bool WriteValueConstraint(Thread* self, ObjPtr value) REQUIRES_SHARED(Locks::mutator_lock_) { return GetClassLinker()->TransactionWriteValueConstraint(self, value); } static inline bool ReadConstraint(Thread* self, ObjPtr obj) REQUIRES_SHARED(Locks::mutator_lock_) { return GetClassLinker()->TransactionReadConstraint(self, obj); } static inline bool AllocationConstraint(Thread* self, ObjPtr klass) REQUIRES_SHARED(Locks::mutator_lock_) { return GetClassLinker()->TransactionAllocationConstraint(self, klass); } static inline bool IsTransactionAborted() { return GetClassLinker()->IsTransactionAborted(); } static void RecordArrayElementsInTransaction(ObjPtr array, int32_t count) REQUIRES_SHARED(Locks::mutator_lock_); static void RecordNewObject(ObjPtr new_object) REQUIRES_SHARED(Locks::mutator_lock_) { GetClassLinker()->GetTransaction()->RecordNewObject(new_object); } static void RecordNewArray(ObjPtr new_object) REQUIRES_SHARED(Locks::mutator_lock_) { GetClassLinker()->GetTransaction()->RecordNewArray(new_object); } private: static AotClassLinker* GetClassLinker() { return down_cast(Runtime::Current()->GetClassLinker()); } }; // TODO: Use ObjPtr here. template static void RecordArrayElementsInTransactionImpl(Transaction* transaction, ObjPtr> array, int32_t count) REQUIRES_SHARED(Locks::mutator_lock_) { for (int32_t i = 0; i < count; ++i) { transaction->RecordWriteArray(array.Ptr(), i, array->GetWithoutChecks(i)); } } void ActiveTransactionChecker::RecordArrayElementsInTransaction(ObjPtr array, int32_t count) { DCHECK(Runtime::Current()->IsActiveTransaction()); if (array == nullptr) { return; // The interpreter shall throw NPE. } DCHECK(array->IsArrayInstance()); DCHECK_LE(count, array->AsArray()->GetLength()); Transaction* transaction = GetClassLinker()->GetTransaction(); if (!transaction->ArrayNeedsTransactionRecords(array->AsArray())) { return; } // No read barrier is needed for reading a chain of constant references // for reading a constant primitive value, see `ReadBarrierOption`. Primitive::Type primitive_component_type = array->GetClass() ->GetComponentType()->GetPrimitiveType(); switch (primitive_component_type) { case Primitive::kPrimBoolean: RecordArrayElementsInTransactionImpl(transaction, array->AsBooleanArray(), count); break; case Primitive::kPrimByte: RecordArrayElementsInTransactionImpl(transaction, array->AsByteArray(), count); break; case Primitive::kPrimChar: RecordArrayElementsInTransactionImpl(transaction, array->AsCharArray(), count); break; case Primitive::kPrimShort: RecordArrayElementsInTransactionImpl(transaction, array->AsShortArray(), count); break; case Primitive::kPrimInt: RecordArrayElementsInTransactionImpl(transaction, array->AsIntArray(), count); break; case Primitive::kPrimFloat: RecordArrayElementsInTransactionImpl(transaction, array->AsFloatArray(), count); break; case Primitive::kPrimLong: RecordArrayElementsInTransactionImpl(transaction, array->AsLongArray(), count); break; case Primitive::kPrimDouble: RecordArrayElementsInTransactionImpl(transaction, array->AsDoubleArray(), count); break; default: LOG(FATAL) << "Unsupported primitive type " << primitive_component_type << " in fill-array-data"; UNREACHABLE(); } } class InactiveInstrumentationHandler { public: ALWAYS_INLINE WARN_UNUSED static bool HasFieldReadListeners(const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!instrumentation->HasFieldReadListeners()); return false; } ALWAYS_INLINE WARN_UNUSED static bool HasFieldWriteListeners(const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!instrumentation->HasFieldWriteListeners()); return false; } ALWAYS_INLINE WARN_UNUSED static bool HasBranchListeners(const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!instrumentation->HasBranchListeners()); return false; } ALWAYS_INLINE WARN_UNUSED static bool NeedsDexPcEvents(ShadowFrame& shadow_frame) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!shadow_frame.GetNotifyDexPcMoveEvents()); DCHECK(!Runtime::Current()->GetInstrumentation()->HasDexPcListeners()); return false; } ALWAYS_INLINE WARN_UNUSED static bool NeedsMethodExitEvent(const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!interpreter::NeedsMethodExitEvent(instrumentation)); return false; } ALWAYS_INLINE WARN_UNUSED static bool GetForcePopFrame(ShadowFrame& shadow_frame) { DCHECK(!shadow_frame.GetForcePopFrame()); DCHECK(!Runtime::Current()->AreNonStandardExitsEnabled()); return false; } NO_RETURN static void Branch([[maybe_unused]] Thread* self, [[maybe_unused]] ArtMethod* method, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] int32_t dex_pc_offset, [[maybe_unused]] const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } static bool ExceptionHandledEvent( [[maybe_unused]] Thread* self, [[maybe_unused]] bool is_move_exception, [[maybe_unused]] const instrumentation::Instrumentation* instrumentation) REQUIRES_SHARED(Locks::mutator_lock_) { LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } static bool DoDexPcMoveEvent( [[maybe_unused]] Thread* self, [[maybe_unused]] const CodeItemDataAccessor& accessor, [[maybe_unused]] const ShadowFrame& shadow_frame, [[maybe_unused]] uint32_t dex_pc, [[maybe_unused]] const instrumentation::Instrumentation* instrumentation, [[maybe_unused]] JValue* save_ref) REQUIRES_SHARED(Locks::mutator_lock_) { LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } template static bool SendMethodExitEvents( [[maybe_unused]] Thread* self, [[maybe_unused]] const instrumentation::Instrumentation* instrumentation, [[maybe_unused]] ShadowFrame& frame, [[maybe_unused]] ArtMethod* method, [[maybe_unused]] T& result) REQUIRES_SHARED(Locks::mutator_lock_) { LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } }; // Explicit definition of ExecuteSwitchImplCpp. template void ExecuteSwitchImplCpp(SwitchImplContext* ctx); } // namespace interpreter } // namespace art