blob: 00fd15eccefe2c3c352e06d291aa41419a440db2 [file] [log] [blame]
/*
* 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<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_) {
return GetClassLinker()->TransactionWriteConstraint(self, obj);
}
static inline bool WriteValueConstraint(Thread* self, ObjPtr<mirror::Object> value)
REQUIRES_SHARED(Locks::mutator_lock_) {
return GetClassLinker()->TransactionWriteValueConstraint(self, value);
}
static inline bool ReadConstraint(Thread* self, ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_) {
return GetClassLinker()->TransactionReadConstraint(self, obj);
}
static inline bool AllocationConstraint(Thread* self, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
return GetClassLinker()->TransactionAllocationConstraint(self, klass);
}
static inline bool IsTransactionAborted() {
return GetClassLinker()->IsTransactionAborted();
}
static void RecordArrayElementsInTransaction(ObjPtr<mirror::Object> array, int32_t count)
REQUIRES_SHARED(Locks::mutator_lock_);
static void RecordNewObject(ObjPtr<mirror::Object> new_object)
REQUIRES_SHARED(Locks::mutator_lock_) {
GetClassLinker()->GetTransaction()->RecordNewObject(new_object);
}
static void RecordNewArray(ObjPtr<mirror::Array> new_object)
REQUIRES_SHARED(Locks::mutator_lock_) {
GetClassLinker()->GetTransaction()->RecordNewArray(new_object);
}
private:
static AotClassLinker* GetClassLinker() {
return down_cast<AotClassLinker*>(Runtime::Current()->GetClassLinker());
}
};
// TODO: Use ObjPtr here.
template<typename T>
static void RecordArrayElementsInTransactionImpl(Transaction* transaction,
ObjPtr<mirror::PrimitiveArray<T>> 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<mirror::Object> 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<kDefaultVerifyFlags, kWithoutReadBarrier>()
->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>()->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 <typename T>
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<true>(SwitchImplContext* ctx);
} // namespace interpreter
} // namespace art