2022-08-16 13:05:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 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.
|
|
|
|
*/
|
|
|
|
|
2023-03-01 09:00:42 +00:00
|
|
|
#ifndef ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
|
|
|
|
#define ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
#include "ecmascript/base/aligned_struct.h"
|
2023-02-06 07:31:06 +00:00
|
|
|
#include "ecmascript/compiler/gate_meta_data.h"
|
2022-08-26 12:40:41 +00:00
|
|
|
#include "ecmascript/js_function_kind.h"
|
2022-08-16 13:05:02 +00:00
|
|
|
#include "ecmascript/js_tagged_value.h"
|
|
|
|
#include "ecmascript/mem/c_string.h"
|
|
|
|
#include "libpandafile/file.h"
|
|
|
|
|
|
|
|
static constexpr uint32_t CALL_TYPE_MASK = 0xF; // 0xF: the last 4 bits are used as callType
|
|
|
|
|
|
|
|
namespace panda::ecmascript {
|
|
|
|
class JSPandaFile;
|
|
|
|
using EntityId = panda_file::File::EntityId;
|
2023-01-09 07:19:40 +00:00
|
|
|
using StringData = panda_file::File::StringData;
|
2022-08-16 13:05:02 +00:00
|
|
|
struct PUBLIC_API MethodLiteral : public base::AlignedStruct<sizeof(uint64_t),
|
|
|
|
base::AlignedUint64,
|
|
|
|
base::AlignedPointer,
|
2022-08-26 12:40:41 +00:00
|
|
|
base::AlignedUint64,
|
2022-08-16 13:05:02 +00:00
|
|
|
base::AlignedUint64> {
|
2022-09-17 08:06:32 +00:00
|
|
|
public:
|
2022-08-30 13:43:46 +00:00
|
|
|
static constexpr uint8_t INVALID_IC_SLOT = 0xFFU;
|
|
|
|
static constexpr uint16_t MAX_SLOT_SIZE = 0xFFFFU;
|
2022-08-16 13:05:02 +00:00
|
|
|
|
2022-12-19 12:24:12 +00:00
|
|
|
explicit MethodLiteral(EntityId methodId);
|
2022-08-16 13:05:02 +00:00
|
|
|
MethodLiteral() = delete;
|
|
|
|
~MethodLiteral() = default;
|
2022-12-28 03:22:56 +00:00
|
|
|
|
|
|
|
NO_COPY_SEMANTIC(MethodLiteral);
|
|
|
|
NO_MOVE_SEMANTIC(MethodLiteral);
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455
|
|
|
|
using HaveThisBit = BitField<bool, 0, 1>; // offset 0
|
|
|
|
using HaveNewTargetBit = HaveThisBit::NextFlag; // offset 1
|
|
|
|
using HaveExtraBit = HaveNewTargetBit::NextFlag; // offset 2
|
|
|
|
using HaveFuncBit = HaveExtraBit::NextFlag; // offset 3
|
|
|
|
using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 4-31
|
|
|
|
using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 32-59
|
|
|
|
using IsNativeBit = NumArgsBits::NextFlag; // offset 60
|
|
|
|
using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61
|
|
|
|
using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62
|
2023-05-18 11:13:51 +00:00
|
|
|
using IsFastCallBit = IsFastBuiltinBit::NextFlag; // offset 63
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
uint64_t GetCallField() const
|
|
|
|
{
|
|
|
|
return callField_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetNativeBit(bool isNative)
|
|
|
|
{
|
|
|
|
callField_ = IsNativeBit::Update(callField_, isNative);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetAotCodeBit(bool isCompiled)
|
|
|
|
{
|
|
|
|
callField_ = IsAotCodeBit::Update(callField_, isCompiled);
|
|
|
|
}
|
|
|
|
|
2022-12-19 12:24:12 +00:00
|
|
|
void Initialize(const JSPandaFile *jsPandaFile);
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
bool HaveThisWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return HaveThisWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HaveNewTargetWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return HaveNewTargetWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HaveExtraWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return HaveExtraWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HaveFuncWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return HaveFuncWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsNativeWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return IsNativeWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsAotWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return IsAotWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetNumArgsWithCallField() const
|
|
|
|
{
|
2022-09-08 15:22:35 +00:00
|
|
|
return GetNumArgsWithCallField(callField_);
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetNumArgs() const
|
|
|
|
{
|
|
|
|
return GetNumArgsWithCallField() + HaveFuncWithCallField() +
|
|
|
|
HaveNewTargetWithCallField() + HaveThisWithCallField();
|
|
|
|
}
|
|
|
|
|
2022-10-03 02:45:22 +00:00
|
|
|
uint32_t GetNumberVRegs() const
|
|
|
|
{
|
|
|
|
return GetNumVregsWithCallField() + GetNumArgs();
|
|
|
|
}
|
|
|
|
|
2022-08-16 13:05:02 +00:00
|
|
|
static uint64_t SetNativeBit(uint64_t callField, bool isNative)
|
|
|
|
{
|
|
|
|
return IsNativeBit::Update(callField, isNative);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled)
|
|
|
|
{
|
|
|
|
return IsAotCodeBit::Update(callField, isCompiled);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool HaveThisWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return HaveThisBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool HaveNewTargetWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return HaveNewTargetBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool HaveExtraWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return HaveExtraBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool HaveFuncWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return HaveFuncBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsNativeWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return IsNativeBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsAotWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return IsAotCodeBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool OnlyHaveThisWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return (callField & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return (callField & CALL_TYPE_MASK) == 0b11; // the first two bit of callFiled is `This` and `NewTarget`
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t GetNumVregsWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return NumVregsBits::Decode(callField);
|
|
|
|
}
|
|
|
|
|
2022-10-03 02:45:22 +00:00
|
|
|
uint32_t GetNumVregsWithCallField() const
|
|
|
|
{
|
|
|
|
return NumVregsBits::Decode(callField_);
|
|
|
|
}
|
|
|
|
|
2022-08-16 13:05:02 +00:00
|
|
|
static uint32_t GetNumArgsWithCallField(uint64_t callField)
|
|
|
|
{
|
|
|
|
return NumArgsBits::Decode(callField);
|
|
|
|
}
|
|
|
|
|
2023-05-18 11:13:51 +00:00
|
|
|
static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall)
|
2022-09-08 15:22:35 +00:00
|
|
|
{
|
2023-05-18 11:13:51 +00:00
|
|
|
return IsFastCallBit::Update(callField, isFastCall);
|
2022-09-08 15:22:35 +00:00
|
|
|
}
|
|
|
|
|
2023-05-18 11:13:51 +00:00
|
|
|
void SetIsFastCall(bool isFastCall)
|
2022-09-08 15:22:35 +00:00
|
|
|
{
|
2023-05-18 11:13:51 +00:00
|
|
|
callField_ = IsFastCallBit::Update(callField_, isFastCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsFastCall(uint64_t callField)
|
|
|
|
{
|
|
|
|
return IsFastCallBit::Decode(callField);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsFastCall() const
|
|
|
|
{
|
|
|
|
return IsFastCallBit::Decode(callField_);
|
2022-09-08 15:22:35 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 13:05:02 +00:00
|
|
|
static constexpr size_t METHOD_ARGS_NUM_BITS = 16;
|
|
|
|
static constexpr size_t METHOD_ARGS_METHODID_BITS = 32;
|
2022-08-26 12:40:41 +00:00
|
|
|
static constexpr size_t METHOD_SLOT_SIZE_BITS = 16;
|
2022-08-16 13:05:02 +00:00
|
|
|
using HotnessCounterBits = BitField<int16_t, 0, METHOD_ARGS_NUM_BITS>; // offset 0-15
|
|
|
|
using MethodIdBits = HotnessCounterBits::NextField<uint32_t, METHOD_ARGS_METHODID_BITS>; // offset 16-47
|
2022-08-30 13:43:46 +00:00
|
|
|
using SlotSizeBits = MethodIdBits::NextField<uint16_t, METHOD_SLOT_SIZE_BITS>; // offset 48-63
|
2022-08-26 12:40:41 +00:00
|
|
|
|
|
|
|
static constexpr size_t BUILTINID_NUM_BITS = 8;
|
|
|
|
static constexpr size_t FUNCTION_KIND_NUM_BITS = 4;
|
|
|
|
using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7
|
|
|
|
using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11
|
2023-07-13 13:13:13 +00:00
|
|
|
using IsNoGCBit = FunctionKindBits::NextFlag; // offset 12
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter)
|
|
|
|
{
|
|
|
|
literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter);
|
|
|
|
}
|
|
|
|
|
|
|
|
EntityId GetMethodId() const
|
|
|
|
{
|
|
|
|
return EntityId(MethodIdBits::Decode(literalInfo_));
|
|
|
|
}
|
|
|
|
|
2022-09-23 07:52:16 +00:00
|
|
|
uint32_t GetSlotSize() const
|
2022-08-16 13:05:02 +00:00
|
|
|
{
|
2022-09-23 07:52:16 +00:00
|
|
|
auto size = SlotSizeBits::Decode(literalInfo_);
|
|
|
|
return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + 2 : size; // 2: last maybe two slot
|
2022-08-16 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-30 13:43:46 +00:00
|
|
|
uint8_t UpdateSlotSizeWith8Bit(uint16_t size)
|
2022-08-16 13:05:02 +00:00
|
|
|
{
|
2022-09-23 07:52:16 +00:00
|
|
|
uint16_t start = SlotSizeBits::Decode(literalInfo_);
|
2022-08-30 13:43:46 +00:00
|
|
|
uint32_t end = start + size;
|
|
|
|
// ic overflow
|
|
|
|
if (end >= INVALID_IC_SLOT) {
|
2022-09-23 07:52:16 +00:00
|
|
|
if (start < INVALID_IC_SLOT + 1) {
|
2022-08-30 13:43:46 +00:00
|
|
|
literalInfo_ = SlotSizeBits::Update(literalInfo_, INVALID_IC_SLOT + 1);
|
|
|
|
}
|
|
|
|
return INVALID_IC_SLOT;
|
|
|
|
}
|
|
|
|
literalInfo_ = SlotSizeBits::Update(literalInfo_, static_cast<uint8_t>(end));
|
2022-08-16 13:05:02 +00:00
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
2022-08-26 12:40:41 +00:00
|
|
|
void SetFunctionKind(FunctionKind kind)
|
|
|
|
{
|
|
|
|
extraLiteralInfo_ = FunctionKindBits::Update(extraLiteralInfo_, kind);
|
|
|
|
}
|
|
|
|
|
2023-07-13 13:13:13 +00:00
|
|
|
void SetNoGCBit(bool isNoGC)
|
|
|
|
{
|
|
|
|
extraLiteralInfo_ = IsNoGCBit::Update(extraLiteralInfo_, isNoGC);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsNoGC() const
|
|
|
|
{
|
|
|
|
return IsNoGCBit::Decode(extraLiteralInfo_);
|
|
|
|
}
|
|
|
|
|
2022-08-26 12:40:41 +00:00
|
|
|
FunctionKind GetFunctionKind() const
|
|
|
|
{
|
|
|
|
return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_));
|
|
|
|
}
|
|
|
|
|
2023-05-16 09:10:44 +00:00
|
|
|
inline bool IsClassConstructor() const
|
|
|
|
{
|
|
|
|
return GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR;
|
|
|
|
}
|
|
|
|
|
2022-08-16 13:05:02 +00:00
|
|
|
static inline int16_t GetHotnessCounter(uint64_t literalInfo)
|
|
|
|
{
|
|
|
|
return HotnessCounterBits::Decode(literalInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter)
|
|
|
|
{
|
|
|
|
return HotnessCounterBits::Update(literalInfo, counter);
|
|
|
|
}
|
|
|
|
|
2022-09-08 15:22:35 +00:00
|
|
|
static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
|
|
|
|
{
|
|
|
|
return FunctionKindBits::Update(extraLiteralInfo, kind);
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:13:23 +00:00
|
|
|
static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo)
|
|
|
|
{
|
|
|
|
return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
|
|
|
|
}
|
|
|
|
|
2022-08-16 13:05:02 +00:00
|
|
|
static EntityId GetMethodId(uint64_t literalInfo)
|
|
|
|
{
|
|
|
|
return EntityId(MethodIdBits::Decode(literalInfo));
|
|
|
|
}
|
|
|
|
|
2022-09-23 07:52:16 +00:00
|
|
|
static uint16_t GetSlotSize(uint64_t literalInfo)
|
2022-08-16 13:05:02 +00:00
|
|
|
{
|
|
|
|
return SlotSizeBits::Decode(literalInfo);
|
|
|
|
}
|
|
|
|
|
2022-12-26 10:40:19 +00:00
|
|
|
static const char PUBLIC_API *GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId);
|
2022-08-16 13:05:02 +00:00
|
|
|
static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId);
|
|
|
|
static uint32_t GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId);
|
2022-12-16 02:54:52 +00:00
|
|
|
static CString GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId);
|
2023-07-12 12:58:11 +00:00
|
|
|
static const char PUBLIC_API *GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId);
|
2022-08-16 13:05:02 +00:00
|
|
|
|
|
|
|
const uint8_t *GetBytecodeArray() const
|
|
|
|
{
|
|
|
|
return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_);
|
|
|
|
}
|
|
|
|
|
|
|
|
const void* GetNativePointer() const
|
|
|
|
{
|
|
|
|
return nativePointerOrBytecodeArray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t GetLiteralInfo() const
|
|
|
|
{
|
|
|
|
return literalInfo_;
|
|
|
|
}
|
|
|
|
|
2022-08-26 12:40:41 +00:00
|
|
|
uint64_t GetExtraLiteralInfo() const
|
|
|
|
{
|
|
|
|
return extraLiteralInfo_;
|
|
|
|
}
|
|
|
|
|
2022-09-17 08:06:32 +00:00
|
|
|
private:
|
|
|
|
enum class Index : size_t {
|
|
|
|
CALL_FIELD_INDEX = 0,
|
|
|
|
NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX,
|
|
|
|
LITERAL_INFO_INDEX,
|
|
|
|
EXTRA_LITERAL_INFO_INDEX,
|
|
|
|
NUM_OF_MEMBERS
|
|
|
|
};
|
|
|
|
static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes);
|
|
|
|
|
2022-12-19 12:24:12 +00:00
|
|
|
void SetMethodId(EntityId methodId)
|
|
|
|
{
|
|
|
|
literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetSlotSize(uint32_t size)
|
|
|
|
{
|
|
|
|
size = size > MAX_SLOT_SIZE ? MAX_SLOT_SIZE : size;
|
|
|
|
literalInfo_ = SlotSizeBits::Update(literalInfo_, size);
|
|
|
|
}
|
|
|
|
|
2022-08-26 12:40:41 +00:00
|
|
|
alignas(EAS) uint64_t callField_ {0ULL};
|
2022-08-16 13:05:02 +00:00
|
|
|
// Native method decides this filed is NativePointer or BytecodeArray pointer.
|
|
|
|
alignas(EAS) const void *nativePointerOrBytecodeArray_ {nullptr};
|
|
|
|
// hotnessCounter, methodId and slotSize are encoded in literalInfo_.
|
2022-08-26 12:40:41 +00:00
|
|
|
alignas(EAS) uint64_t literalInfo_ {0ULL};
|
|
|
|
// BuiltinId, FunctionKind are encoded in extraLiteralInfo_.
|
|
|
|
alignas(EAS) uint64_t extraLiteralInfo_ {0ULL};
|
2022-08-16 13:05:02 +00:00
|
|
|
};
|
|
|
|
STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64);
|
|
|
|
} // namespace panda::ecmascript
|
|
|
|
|
2023-03-01 09:00:42 +00:00
|
|
|
#endif // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
|