Files
ark_runtime_core/runtime/include/class.h
T
Ilya Trubachev 1aa56bf224 copyright update
Signed-off-by: Ilya Trubachev <trubachev.ilya@huawei.com>
2022-03-25 13:17:51 +03:00

902 lines
22 KiB
C++

/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* 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 PANDA_RUNTIME_INCLUDE_CLASS_H_
#define PANDA_RUNTIME_INCLUDE_CLASS_H_
#include <securec.h>
#include <atomic>
#include <cstdint>
#include <iostream>
#include <memory>
#include "libpandafile/file.h"
#include "libpandafile/file_items.h"
#include "runtime/include/field.h"
#include "runtime/include/itable.h"
#include "runtime/include/method.h"
#include "runtime/include/object_header.h"
#include "libpandabase/macros.h"
namespace panda {
class ClassLinkerContext;
class Field;
class ManagedThread;
class BaseClass {
public:
static constexpr uint32_t DYNAMIC_CLASS = 1U;
public:
explicit BaseClass(panda_file::SourceLang lang) : lang_(lang) {}
~BaseClass() = default;
DEFAULT_COPY_SEMANTIC(BaseClass);
DEFAULT_MOVE_SEMANTIC(BaseClass);
uint32_t GetFlags() const
{
return flags_;
}
void SetFlags(uint32_t flags)
{
flags_ = flags;
}
bool IsDynamicClass() const
{
return (flags_ & DYNAMIC_CLASS) != 0;
}
uint32_t GetObjectSize() const
{
return object_size_;
}
void SetObjectSize(uint32_t size)
{
object_size_ = size;
}
void SetManagedObject(ObjectHeader *obj)
{
managed_object_ = obj;
}
ObjectHeader *GetManagedObject() const
{
return managed_object_;
}
panda_file::SourceLang GetSourceLang() const
{
return lang_;
}
void SetSourceLang(panda_file::SourceLang lang)
{
lang_ = lang;
}
static constexpr size_t OffsetOfManageObject()
{
return offsetof(BaseClass, managed_object_);
}
private:
uint32_t flags_ {0};
// Size of the object of this class. In case of static classes it is 0
// for abstract classes, interfaces and classes whose objects
// have variable size (for example strings).
uint32_t object_size_ {0};
ObjectHeader *managed_object_ {nullptr};
panda_file::SourceLang lang_;
};
class Class : public BaseClass {
public:
using UniqId = uint64_t;
static constexpr uint32_t STRING_CLASS = 1U << 1U;
static constexpr size_t IMTABLE_SIZE = 32;
enum {
DUMPCLASSFULLDETAILS = 1,
DUMPCLASSCLASSLODER = 2,
DUMPCLASSINITIALIZED = 4,
};
enum class State : uint8_t { INITIAL = 0, LOADED, VERIFIED, INITIALIZING, ERRONEOUS, INITIALIZED };
Class(const uint8_t *descriptor, panda_file::SourceLang lang, uint32_t vtable_size, uint32_t imt_size,
uint32_t size);
Class *GetBase() const
{
return base_;
}
void SetBase(Class *base)
{
base_ = base;
}
panda_file::File::EntityId GetFileId() const
{
return file_id_;
}
void SetFileId(panda_file::File::EntityId file_id)
{
file_id_ = file_id;
}
const panda_file::File *GetPandaFile() const
{
return panda_file_;
}
void SetPandaFile(const panda_file::File *pf)
{
panda_file_ = pf;
}
const uint8_t *GetDescriptor() const
{
return descriptor_;
}
void SetMethods(Span<Method> methods, uint32_t num_vmethods, uint32_t num_smethods)
{
methods_ = methods.data();
num_methods_ = num_vmethods + num_smethods;
num_vmethods_ = num_vmethods;
num_copied_methods_ = methods.size() - num_methods_;
}
Span<Method> GetMethods() const
{
return {methods_, num_methods_};
}
Span<Method> GetStaticMethods() const
{
return GetMethods().SubSpan(num_vmethods_);
}
Span<Method> GetVirtualMethods() const
{
return {methods_, num_vmethods_};
}
Span<Method> GetCopiedMethods() const
{
Span<Method> res {methods_, num_methods_ + num_copied_methods_};
return res.SubSpan(num_methods_);
}
Span<Field> GetFields() const
{
return {fields_, num_fields_};
}
Span<Field> GetStaticFields() const
{
return {fields_, num_sfields_};
}
Span<Field> GetInstanceFields() const
{
return GetFields().SubSpan(num_sfields_);
}
void SetFields(Span<Field> fields, uint32_t num_sfields)
{
fields_ = fields.data();
num_fields_ = fields.size();
num_sfields_ = num_sfields;
}
Span<Method *> GetVTable()
{
return GetClassSpan().SubSpan<Method *>(GetVTableOffset(), vtable_size_);
}
Span<Method *const> GetVTable() const
{
return GetClassSpan().SubSpan<Method *const>(GetVTableOffset(), vtable_size_);
}
Span<Class *> GetInterfaces() const
{
return {ifaces_, num_ifaces_};
}
void SetInterfaces(Span<Class *> ifaces)
{
ifaces_ = ifaces.data();
num_ifaces_ = ifaces.size();
}
Span<Method *> GetIMT()
{
return GetClassSpan().SubSpan<Method *>(GetIMTOffset(), imt_size_);
}
Span<Method *const> GetIMT() const
{
return GetClassSpan().SubSpan<Method *const>(GetIMTOffset(), imt_size_);
}
uint32_t GetIMTableIndex(uint32_t method_offset) const
{
ASSERT(imt_size_ != 0);
return method_offset % imt_size_;
}
uint32_t GetAccessFlags() const
{
return access_flags_;
}
void SetAccessFlags(uint32_t access_flags)
{
access_flags_ = access_flags;
}
bool IsPublic() const
{
return (access_flags_ & ACC_PUBLIC) != 0;
}
bool IsFinal() const
{
return (access_flags_ & ACC_FINAL) != 0;
}
bool IsAnnotation() const
{
return (access_flags_ & ACC_ANNOTATION) != 0;
}
bool IsEnum() const
{
return (access_flags_ & ACC_ENUM) != 0;
}
uint32_t GetVTableSize() const
{
return vtable_size_;
}
uint32_t GetIMTSize() const
{
return imt_size_;
}
uint32_t GetClassSize() const
{
return class_size_;
}
uint32_t GetObjectSize() const
{
ASSERT(!IsVariableSize());
return BaseClass::GetObjectSize();
}
void SetObjectSize(uint32_t size)
{
ASSERT(!IsVariableSize());
BaseClass::SetObjectSize(size);
}
static uint32_t GetTypeSize(panda_file::Type type);
uint32_t GetComponentSize() const;
Class *GetComponentType() const
{
return component_type_;
}
void SetComponentType(Class *type)
{
component_type_ = type;
}
bool IsArrayClass() const
{
return component_type_ != nullptr;
}
bool IsObjectArrayClass() const
{
return IsArrayClass() && !component_type_->IsPrimitive();
}
bool IsStringClass() const
{
return (GetFlags() & STRING_CLASS) != 0;
}
bool IsVariableSize() const
{
return IsArrayClass() || IsStringClass();
}
size_t GetStaticFieldsOffset() const
{
return ClassHelper::ComputeClassSize(vtable_size_, imt_size_, 0, 0, 0, 0, 0, 0);
}
panda_file::Type GetType() const
{
return type_;
}
void SetType(panda_file::Type type)
{
type_ = type;
}
bool IsPrimitive() const
{
return type_.IsPrimitive();
}
bool IsAbstract() const
{
return (access_flags_ & ACC_ABSTRACT) != 0;
}
bool IsInterface() const
{
return (access_flags_ & ACC_INTERFACE) != 0;
}
bool IsInstantiable() const
{
return (!IsPrimitive() && !IsAbstract() && !IsInterface()) || IsArrayClass();
}
bool IsObjectClass() const
{
return !IsPrimitive() && GetBase() == nullptr;
}
/**
* Check if the object is Class instance
* @return true if the object is Class instance
*/
bool IsClassClass() const
{
return GetManagedObject()->ClassAddr<Class>() == this;
}
bool IsSubClassOf(const Class *klass) const;
/**
* Check whether an instance of this class can be assigned from an instance of class "klass".
* Object of type O is instance of type T if O is the same as T or is subtype of T. For arrays T should be a root
* type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements.
*/
bool IsAssignableFrom(const Class *klass) const;
bool IsProxy() const
{
return (GetAccessFlags() & ACC_PROXY) != 0;
}
bool Implements(const Class *klass) const;
void SetITable(ITable itable)
{
itable_ = itable;
}
ITable GetITable() const
{
return itable_;
}
State GetState() const
{
return state_;
}
void SetState(State state);
bool IsVerified() const
{
return state_ >= State::VERIFIED;
}
bool IsInitializing() const
{
return state_ == State::INITIALIZING;
}
bool IsInitialized() const
{
return state_ == State::INITIALIZED;
}
bool IsLoaded() const
{
return state_ >= State::LOADED;
}
bool IsErroneous() const
{
return state_ == State::ERRONEOUS;
}
static constexpr uint32_t GetStateOffset()
{
return MEMBER_OFFSET(Class, state_);
}
static constexpr uint32_t GetComponentTypeOffset()
{
return MEMBER_OFFSET(Class, component_type_);
}
static constexpr uint32_t GetTypeOffset()
{
return MEMBER_OFFSET(Class, type_);
}
static constexpr uint32_t GetBaseOffset()
{
return MEMBER_OFFSET(Class, base_);
}
uint8_t GetInitializedValue()
{
return static_cast<uint8_t>(State::INITIALIZED);
}
bool IsVerifiedSuccess() const
{
return (IsVerified() && (!IsErroneous()));
}
void SetInitTid(uint32_t id)
{
init_tid_ = id;
}
uint32_t GetInitTid() const
{
return init_tid_;
}
static size_t GetVTableOffset()
{
return ClassHelper::ComputeClassSize(0, 0, 0, 0, 0, 0, 0, 0);
}
uint32_t GetNumVirtualMethods() const
{
return num_vmethods_;
}
void SetNumVirtualMethods(uint32_t n)
{
num_vmethods_ = n;
}
uint32_t GetNumCopiedMethods() const
{
return num_copied_methods_;
}
void SetNumCopiedMethods(uint32_t n)
{
num_copied_methods_ = n;
}
uint32_t GetNumStaticFields() const
{
return num_sfields_;
}
void SetNumStaticFields(uint32_t n)
{
num_sfields_ = n;
}
void SetHasDefaultMethods()
{
access_flags_ |= ACC_HAS_DEFAULT_METHODS;
}
bool HasDefaultMethods() const
{
return (access_flags_ & ACC_HAS_DEFAULT_METHODS) != 0;
}
size_t GetIMTOffset()
{
return GetVTableOffset() + vtable_size_ * sizeof(uintptr_t);
}
size_t GetIMTOffset() const
{
return GetVTableOffset() + vtable_size_ * sizeof(uintptr_t);
}
std::string GetName() const;
ClassLinkerContext *GetLoadContext() const
{
ASSERT(load_context_ != nullptr);
return load_context_;
}
void SetLoadContext(ClassLinkerContext *context)
{
ASSERT(context != nullptr);
load_context_ = context;
}
template <class Pred>
Field *FindInstanceField(Pred pred) const;
template <class Pred>
Field *FindStaticField(Pred pred) const;
template <class Pred>
Field *FindField(Pred pred) const;
template <class Pred>
Field *FindDeclaredField(Pred pred) const;
Field *GetInstanceFieldByName(const uint8_t *mutf8_name) const;
Field *GetStaticFieldByName(const uint8_t *mutf8_name) const;
Field *GetDeclaredFieldByName(const uint8_t *mutf8_name) const;
template <class Pred>
Method *FindVirtualClassMethod(Pred pred) const;
template <class Pred>
Method *FindInterfaceMethod(Pred pred) const;
template <class Pred>
Method *FindVirtualInterfaceMethod(Pred pred) const;
template <class Pred>
Method *FindStaticInterfaceMethod(Pred pred) const;
template <class Pred>
Method *FindStaticClassMethod(Pred pred) const;
template <class Pred>
Method *FindClassMethod(Pred pred) const;
Method *GetDirectMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const;
Method *GetClassMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const;
Method *GetInterfaceMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const;
Method *GetDirectMethod(const uint8_t *mutf8_name) const;
Method *GetClassMethod(const uint8_t *mutf8_name) const;
Method *ResolveVirtualMethod(const Method *method) const;
template <class T, bool is_volatile = false>
T GetFieldPrimitive(size_t offset) const;
template <class T, bool is_volatile = false>
void SetFieldPrimitive(size_t offset, T value);
template <bool is_volatile = false, bool need_read_barrier = true>
ObjectHeader *GetFieldObject(size_t offset) const;
template <bool is_volatile = false, bool need_write_barrier = true>
void SetFieldObject(size_t offset, ObjectHeader *value);
template <class T>
T GetFieldPrimitive(const Field &field) const;
template <class T>
void SetFieldPrimitive(const Field &field, T value);
template <bool need_read_barrier = true>
ObjectHeader *GetFieldObject(const Field &field) const;
template <bool need_write_barrier = true>
void SetFieldObject(const Field &field, ObjectHeader *value);
// Pass thread parameter to speed up interpreter
template <bool need_read_barrier = true>
ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const;
template <bool need_write_barrier = true>
void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value);
template <class T>
T GetFieldPrimitive(size_t offset, std::memory_order memory_order) const;
template <class T>
void SetFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
template <bool need_read_barrier = true>
ObjectHeader *GetFieldObject(size_t offset, std::memory_order memory_order) const;
template <bool need_write_barrier = true>
void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
template <typename T>
bool CompareAndSetFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
bool strong);
template <bool need_write_barrier = true>
bool CompareAndSetFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
std::memory_order memory_order, bool strong);
template <typename T>
T CompareAndExchangeFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
bool strong);
template <bool need_write_barrier = true>
ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
std::memory_order memory_order, bool strong);
template <typename T>
T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
template <bool need_write_barrier = true>
ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
template <typename T>
T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
template <typename T>
T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
template <typename T>
T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
template <typename T>
T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
void DumpClass(std::ostream &os, size_t flags);
static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId file_id);
// for synthetic classes, like arrays
static UniqId CalcUniqId(const uint8_t *descriptor);
UniqId GetUniqId() const
{
auto id = uniq_id_.load();
if (id == 0) {
id = CalcUniqId();
uniq_id_.store(id);
}
return id;
}
void SetRefFieldsNum(uint32_t num, bool is_static)
{
if (is_static) {
num_refsfields_ = num;
} else {
num_reffields_ = num;
}
}
void SetRefFieldsOffset(uint32_t offset, bool is_static)
{
if (is_static) {
offset_refsfields_ = offset;
} else {
offset_reffields_ = offset;
}
}
void SetVolatileRefFieldsNum(uint32_t num, bool is_static)
{
if (is_static) {
volatile_refsfields_num_ = num;
} else {
volatile_reffields_num_ = num;
}
}
template <bool is_static>
uint32_t GetRefFieldsNum() const
{
return is_static ? num_refsfields_ : num_reffields_;
}
template <bool is_static>
uint32_t GetRefFieldsOffset() const
{
return is_static ? offset_refsfields_ : offset_reffields_;
}
template <bool is_static>
uint32_t GetVolatileRefFieldsNum() const
{
return is_static ? volatile_refsfields_num_ : volatile_reffields_num_;
}
panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const
{
return class_idx_[idx];
}
panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const
{
return method_idx_[idx];
}
panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const
{
return field_idx_[idx];
}
Span<const panda_file::File::EntityId> GetClassIndex() const
{
return class_idx_;
}
void SetClassIndex(Span<const panda_file::File::EntityId> index)
{
class_idx_ = index;
}
Span<const panda_file::File::EntityId> GetMethodIndex() const
{
return method_idx_;
}
void SetMethodIndex(Span<const panda_file::File::EntityId> index)
{
method_idx_ = index;
}
Span<const panda_file::File::EntityId> GetFieldIndex() const
{
return field_idx_;
}
void SetFieldIndex(Span<const panda_file::File::EntityId> index)
{
field_idx_ = index;
}
static Class *FromClassObject(const ObjectHeader *obj);
static size_t GetClassObjectSizeFromClass(Class *cls);
~Class() = default;
NO_COPY_SEMANTIC(Class);
NO_MOVE_SEMANTIC(Class);
private:
enum class FindFilter { STATIC, INSTANCE, ALL, COPIED };
template <FindFilter filter>
Span<Field> GetFields() const;
template <FindFilter filter, class Pred>
Field *FindDeclaredField(Pred pred) const;
template <FindFilter filter, class Pred>
Field *FindField(Pred pred) const;
template <FindFilter filter>
Span<Method> GetMethods() const;
template <FindFilter filter, class Pred>
Method *FindDirectMethod(Pred pred) const;
template <FindFilter filter, class Pred>
Method *FindClassMethod(Pred pred) const;
template <FindFilter filter, class Pred>
Method *FindInterfaceMethod(Pred pred) const;
Span<std::byte> GetClassSpan()
{
return Span(reinterpret_cast<std::byte *>(this), class_size_);
}
Span<const std::byte> GetClassSpan() const
{
return Span(reinterpret_cast<const std::byte *>(this), class_size_);
}
Class *base_ {nullptr};
const panda_file::File *panda_file_ {nullptr};
// Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information.
const uint8_t *descriptor_;
Method *methods_ {nullptr};
Field *fields_ {nullptr};
Class **ifaces_ {nullptr};
panda_file::File::EntityId file_id_ {};
uint32_t vtable_size_;
uint32_t imt_size_;
uint32_t class_size_;
uint32_t access_flags_ {0};
uint32_t num_methods_ {0};
uint32_t num_vmethods_ {0};
uint32_t num_copied_methods_ {0};
uint32_t num_fields_ {0};
uint32_t num_sfields_ {0};
uint32_t num_ifaces_ {0};
uint32_t init_tid_ {0};
ITable itable_;
// For array types this field contains array's element size, for non-array type it should be zero.
Class *component_type_ {nullptr};
ClassLinkerContext *load_context_ {nullptr};
panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE};
std::atomic<State> state_ {State::INITIAL};
UniqId CalcUniqId() const;
mutable std::atomic<UniqId> uniq_id_ {0};
uint32_t num_reffields_ {0}; // instance reference fields num
uint32_t num_refsfields_ {0}; // static reference fields num
uint32_t offset_reffields_ {0}; // first instance reference fields offset in object layout
uint32_t offset_refsfields_ {0}; // first static reference fields offset in object layout
uint32_t volatile_reffields_num_ {0};
uint32_t volatile_refsfields_num_ {0};
Span<const panda_file::File::EntityId> class_idx_ {nullptr, nullptr};
Span<const panda_file::File::EntityId> method_idx_ {nullptr, nullptr};
Span<const panda_file::File::EntityId> field_idx_ {nullptr, nullptr};
};
std::ostream &operator<<(std::ostream &os, const Class::State &state);
#ifdef PANDA_TARGET_64
constexpr uint32_t CLASS_MANAGE_OBJECT_OFFSET = 8U;
static_assert(CLASS_MANAGE_OBJECT_OFFSET == Class::OffsetOfManageObject());
constexpr uint32_t CLASS_STATE_OFFSET = 153U;
static_assert(CLASS_STATE_OFFSET == panda::Class::GetStateOffset());
constexpr uint32_t CLASS_COMPONENT_TYPE_OFFSET = 136U;
static_assert(CLASS_COMPONENT_TYPE_OFFSET == panda::Class::GetComponentTypeOffset());
constexpr uint32_t CLASS_TYPE_OFFSET = 152U;
static_assert(CLASS_TYPE_OFFSET == panda::Class::GetTypeOffset());
constexpr uint32_t CLASS_BASE_OFFSET = 24U;
static_assert(CLASS_BASE_OFFSET == panda::Class::GetBaseOffset());
#endif
} // namespace panda
#endif // PANDA_RUNTIME_INCLUDE_CLASS_H_