* Copyright (c) 2021-2024 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 ECMASCRIPT_IC_IC_HANDLER_H
#define ECMASCRIPT_IC_IC_HANDLER_H
#include "ecmascript/ecma_macros.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/mem/tagged_object.h"
#include "ecmascript/object_operator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_primitive_ref.h"
namespace panda::ecmascript {
class HandlerBase {
public:
static constexpr uint32_t KIND_BIT_LENGTH = 4;
static constexpr uint32_t STORE_KIND_BIT_LENGTH = 2;
static constexpr uint32_t MAX_BIT_SIZE = 48;
enum HandlerKind {
NONE = 0,
FIELD,
ELEMENT,
DICTIONARY,
STRING,
STRING_LENGTH,
TYPED_ARRAY,
NUMBER,
BOOLEAN,
NON_EXIST,
TOTAL_KINDS,
};
static_assert(static_cast<size_t>(HandlerKind::TOTAL_KINDS) <= (1 << KIND_BIT_LENGTH));
enum StoreHandlerKind {
S_NONE = HandlerKind::NONE,
S_FIELD,
S_ELEMENT,
S_TOTAL_KINDS,
};
static_assert(static_cast<size_t>(StoreHandlerKind::S_TOTAL_KINDS) <= (1 << STORE_KIND_BIT_LENGTH));
using KindBit = BitField<HandlerKind, 0, KIND_BIT_LENGTH>;
using InlinedPropsBit = KindBit::NextFlag;
using AccessorBit = InlinedPropsBit::NextFlag;
using IsJSArrayBit = AccessorBit::NextFlag;
using OffsetBit = IsJSArrayBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>;
using RepresentationBit = OffsetBit::NextField<Representation, PropertyAttributes::REPRESENTATION_NUM>;
using AttrIndexBit =
RepresentationBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>;
using IsOnHeapBit = AttrIndexBit::NextFlag;
using NeedSkipInPGODumpBit = IsOnHeapBit::NextFlag;
static_assert(NeedSkipInPGODumpBit::END_BIT <= MAX_BIT_SIZE, "load handler overflow");
using SWholeKindBit = KindBit;
using SKindBit = BitField<StoreHandlerKind, 0, STORE_KIND_BIT_LENGTH>;
static_assert(SKindBit::START_BIT == KindBit::START_BIT);
using SSharedBit = SKindBit::NextFlag;
static_assert((SKindBit::SIZE + SSharedBit::SIZE) <= KindBit::SIZE);
using SOutOfBoundsBit = IsOnHeapBit::NextFlag;
using SFieldTypeBit = SOutOfBoundsBit::NextField<SharedFieldType, PropertyAttributes::FIELD_TYPE_NUM>;
static_assert(SFieldTypeBit::END_BIT <= MAX_BIT_SIZE, "store handler overflow");
using Type = uint64_t;
static_assert(sizeof(Type) <= JSTaggedValue::TaggedTypeSize());
HandlerBase() = default;
virtual ~HandlerBase() = default;
static inline bool IsAccessor(Type handler)
{
return AccessorBit::Get(handler);
}
static inline SharedFieldType GetFieldType(Type handler)
{
return static_cast<SharedFieldType>(SFieldTypeBit::Get(handler));
}
static inline bool IsNonExist(Type handler)
{
return GetKind(handler) == HandlerKind::NON_EXIST;
}
static inline bool IsField(Type handler)
{
return GetKind(handler) == HandlerKind::FIELD;
}
static inline bool IsNonSharedStoreField(Type handler)
{
return static_cast<StoreHandlerKind>(GetKind(handler)) == StoreHandlerKind::S_FIELD;
}
static inline bool IsStoreShared(Type handler)
{
return SSharedBit::Get(handler);
}
static inline void ClearSharedStoreKind(Type &handler)
{
SSharedBit::Set<Type>(false, &handler);
}
static inline bool IsStoreOutOfBounds(Type handler)
{
return SOutOfBoundsBit::Get(handler);
}
static inline void ClearStoreOutOfBounds(Type &handler)
{
SOutOfBoundsBit::Set<Type>(false, &handler);
}
static inline bool IsString(Type handler)
{
return GetKind(handler) == HandlerKind::STRING;
}
static inline bool IsNumber(Type handler)
{
return GetKind(handler) == HandlerKind::NUMBER;
}
static inline bool IsBoolean(Type handler)
{
return GetKind(handler) == HandlerKind::BOOLEAN;
}
static inline bool IsSupportedPrimitiveTypeICHandler(Type handler)
{
return IsString(handler) || IsNumber(handler) || IsBoolean(handler);
}
static inline bool IsStringLength(Type handler)
{
return GetKind(handler) == HandlerKind::STRING_LENGTH;
}
static inline PrimitiveType TryGetPrimitiveType(Type handler)
{
switch (GetKind(handler)) {
case HandlerKind::NUMBER:
return PrimitiveType::PRIMITIVE_NUMBER;
case HandlerKind::BOOLEAN:
return PrimitiveType::PRIMITIVE_BOOLEAN;
default:
return PrimitiveType::PRIMITIVE_TYPE_INVALID;
}
}
static inline bool IsElement(Type handler)
{
return IsNormalElement(handler) || IsStringElement(handler) || IsTypedArrayElement(handler);
}
static inline bool IsNormalElement(Type handler)
{
return GetKind(handler) == HandlerKind::ELEMENT;
}
static inline bool IsStringElement(Type handler)
{
return GetKind(handler) == HandlerKind::STRING;
}
static inline bool IsTypedArrayElement(Type handler)
{
return GetKind(handler) == HandlerKind::TYPED_ARRAY;
}
static inline bool IsDictionary(Type handler)
{
return GetKind(handler) == HandlerKind::DICTIONARY;
}
static inline bool IsInlinedProps(Type handler)
{
return InlinedPropsBit::Get(handler);
}
static inline HandlerKind GetKind(Type handler)
{
return KindBit::Get(handler);
}
static inline bool IsJSArray(Type handler)
{
return IsJSArrayBit::Get(handler);
}
static inline bool NeedSkipInPGODump(Type handler)
{
return NeedSkipInPGODumpBit::Get(handler);
}
static inline int GetOffset(Type handler)
{
return OffsetBit::Get(handler);
}
static inline bool IsOnHeap(Type handler)
{
return IsOnHeapBit::Get(handler);
}
static void PrintLoadHandler(uint64_t handler, std::ostream& os);
static void PrintStoreHandler(uint64_t handler, std::ostream& os);
};
class LoadHandler final : public HandlerBase {
public:
static JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op);
static JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op);
static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread)
{
uint64_t handler = 0;
KindBit::Set<uint64_t>(HandlerKind::STRING, &handler);
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
}
static inline JSHandle<JSTaggedValue> LoadTypedArrayElement(const JSThread *thread,
JSHandle<JSTypedArray> typedArray)
{
uint64_t handler = 0;
KindBit::Set<uint64_t>(HandlerKind::TYPED_ARRAY, &handler);
IsOnHeapBit::Set<uint64_t>(JSHandle<TaggedObject>(typedArray)->GetClass()->IsOnHeapFromBitField(), &handler);
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
}
};
class StoreHandler final : public HandlerBase {
public:
static JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op);
static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread,
JSHandle<JSTaggedValue> receiver, uint64_t handler)
{
SKindBit::Set<uint64_t>(StoreHandlerKind::S_ELEMENT, &handler);
if (receiver->IsJSArray()) {
IsJSArrayBit::Set<uint64_t>(true, &handler);
}
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
}
static inline void SFieldTypeBitSet(const JSThread *thread, const ObjectOperator &op,
JSHandle<JSObject> &receiver, uint64_t *handler)
{
SSharedBit::Set<uint64_t>(op.GetReceiver()->IsJSShared(), handler);
TaggedArray *array = TaggedArray::Cast(receiver->GetProperties(thread).GetTaggedObject());
if (!array->IsDictionaryMode()) {
SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetSharedFieldType(), handler);
} else {
SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetDictSharedFieldType(), handler);
}
}
};
class TransitionHandler : public TaggedObject {
public:
static TransitionHandler *Cast(TaggedObject *object)
{
ASSERT(JSTaggedValue(object).IsTransitionHandler());
return static_cast<TransitionHandler *>(object);
}
static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE)
DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
DECL_DUMP()
};
class PrototypeHandler : public TaggedObject {
public:
static PrototypeHandler *Cast(TaggedObject *object)
{
ASSERT(JSTaggedValue(object).IsPrototypeHandler());
return static_cast<PrototypeHandler *>(object);
}
static JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
ACCESSORS(Holder, HOLDER_OFFSET, ACCESSOR_JSFUNCTION_OFFSET)
ACCESSORS(AccessorJSFunction, ACCESSOR_JSFUNCTION_OFFSET, ACCESSOR_METHOD_ID_OFFSET)
ACCESSORS_PRIMITIVE_FIELD(AccessorMethodId, uint32_t, ACCESSOR_METHOD_ID_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, ACCESSOR_METHOD_ID_OFFSET)
DECL_DUMP()
};
class TransWithProtoHandler : public TaggedObject {
public:
static TransWithProtoHandler *Cast(TaggedObject *object)
{
ASSERT(JSTaggedValue(object).IsTransWithProtoHandler());
return static_cast<TransWithProtoHandler *>(object);
}
static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, PROTO_CELL_OFFSET)
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, SIZE)
DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
DECL_DUMP()
};
class StoreAOTHandler : public TaggedObject {
public:
static StoreAOTHandler *Cast(TaggedObject *object)
{
ASSERT(JSTaggedValue(object).IsStoreAOTHandler());
return static_cast<StoreAOTHandler *>(object);
}
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
ACCESSORS(Holder, HOLDER_OFFSET, SIZE)
DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
DECL_DUMP()
};
}
#endif