* 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_JSOBJECT_H
#define ECMASCRIPT_JSOBJECT_H
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/enum_cache.h"
#include "ecmascript/filter_helper.h"
#include "ecmascript/ic/property_box.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_hclass.h"
#include "ecmascript/js_tagged_value_wrapper.h"
#include "ecmascript/mem/layout_visitor.h"
#include "ecmascript/mem/slots.h"
#include "ecmascript/mem/visitor.h"
#include "ecmascript/method.h"
#include "ecmascript/property_attributes.h"
#include "ecmascript/tagged_array.h"
namespace panda {
namespace ecmascript {
class ObjectOperator;
class JSFunction;
class AccessorData;
class JSArray;
class JSForInIterator;
class LexicalEnv;
class GlobalEnv;
class TaggedQueue;
class NumberDictionary;
class DependentInfos;
namespace builtins {
class BuiltinsArkTools;
}
using SCheckMode = JSShared::SCheckMode;
enum IntegrityLevel { SEALED, FROZEN };
enum PositionKind { UNKNOWN = 0, INDEXED_PROPERTY = 1, INLINE_NAMED_PROPERTY = 2, OUT_NAMED_PROPERTY = 3 };
enum PropertyKind { KEY = 0, VALUE, KEY_VALUE };
enum class TrackTypeUpdateMode { ENABLE, DISABLE };
class PropertyDescriptor final {
public:
PropertyDescriptor() = delete;
~PropertyDescriptor() = default;
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyDescriptor);
DEFAULT_COPY_SEMANTIC(PropertyDescriptor);
explicit PropertyDescriptor(const JSThread *thread) : thread_(thread) {}
PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v) : thread_(thread), value_(v) {}
PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v, bool w, bool e, bool c)
: thread_(thread),
writable_(w),
enumerable_(e),
configurable_(c),
hasWritable_(true),
hasEnumerable_(true),
hasConfigurable_(true),
value_(v)
{
}
PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c)
: PropertyDescriptor(thread, JSHandle<JSTaggedValue>(), w, e, c)
{
}
inline JSHandle<JSTaggedValue> GetValue() const
{
if (value_.IsEmpty()) {
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
}
return value_;
}
inline JSHandle<JSTaggedValue> GetKey() const
{
if (key_.IsEmpty()) {
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
}
return key_;
}
inline void SetValue(JSHandle<JSTaggedValue> value)
{
value_ = value;
}
inline void SetKey(JSHandle<JSTaggedValue> key)
{
key_ = key;
}
inline void SetSharedFieldType(SharedFieldType fieldType)
{
fieldType_ = fieldType;
}
inline SharedFieldType GetSharedFieldType() const
{
return fieldType_;
}
inline bool IsWritable() const
{
return writable_;
}
inline void SetWritable(bool flag)
{
writable_ = flag;
hasWritable_ = true;
}
inline bool IsEnumerable() const
{
return enumerable_;
}
inline void SetEnumerable(bool flag)
{
enumerable_ = flag;
hasEnumerable_ = true;
}
inline bool IsConfigurable() const
{
return configurable_;
}
inline void SetConfigurable(bool flag)
{
configurable_ = flag;
hasConfigurable_ = true;
}
inline bool HasValue() const
{
return !value_.IsEmpty();
}
inline bool HasWritable() const
{
return hasWritable_;
}
inline bool HasConfigurable() const
{
return hasConfigurable_;
}
inline bool HasEnumerable() const
{
return hasEnumerable_;
}
inline bool HasGetter() const
{
return !getter_.IsEmpty();
}
inline bool HasSetter() const
{
return !setter_.IsEmpty();
}
inline JSHandle<JSTaggedValue> GetGetter() const
{
if (getter_->IsNull()) {
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
}
return getter_;
}
inline JSHandle<JSTaggedValue> GetSetter() const
{
if (setter_->IsNull()) {
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
}
return setter_;
}
inline void SetGetter(JSHandle<JSTaggedValue> value)
{
getter_ = value;
}
inline void SetSetter(JSHandle<JSTaggedValue> value)
{
setter_ = value;
}
inline bool IsAccessorDescriptor() const
{
return !(getter_.IsEmpty() && setter_.IsEmpty());
}
inline bool IsDataDescriptor() const
{
return !(value_.IsEmpty() && !hasWritable_);
}
inline bool IsGenericDescriptor() const
{
return !IsAccessorDescriptor() && !IsDataDescriptor();
}
inline bool IsEmpty() const
{
return !hasWritable_ && !hasEnumerable_ && !hasConfigurable_ && !HasValue() && !HasGetter() && !HasSetter();
}
static void CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc);
private:
const JSThread *thread_{nullptr};
bool writable_ {false};
bool enumerable_ {false};
bool configurable_ {false};
bool hasWritable_ {false};
bool hasEnumerable_ {false};
bool hasConfigurable_ {false};
SharedFieldType fieldType_ {SharedFieldType::NONE};
JSHandle<JSTaggedValue> value_ {};
JSHandle<JSTaggedValue> getter_ {};
JSHandle<JSTaggedValue> setter_ {};
JSHandle<JSTaggedValue> key_ {};
};
enum class ElementTypes { ALLTYPES, STRING_AND_SYMBOL };
class PropertyMetaData {
public:
using IsFoundField = BitField<bool, 0, 1>;
using IsInlinedPropsField = IsFoundField::NextFlag;
using RepresentationField = IsInlinedPropsField::NextField<Representation, 3>;
using OffsetField = RepresentationField::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>;
explicit PropertyMetaData(uint32_t metaData) : metaData_(metaData) {}
~PropertyMetaData() = default;
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyMetaData);
DEFAULT_COPY_SEMANTIC(PropertyMetaData);
explicit PropertyMetaData(bool isFound)
{
SetFound(isFound);
}
inline bool IsFound() const
{
return IsFoundField::Get(metaData_);
}
inline void SetFound(bool flag)
{
IsFoundField::Set(flag, &metaData_);
}
inline bool GetIsInlinedProps() const
{
return IsInlinedPropsField::Get(metaData_);
}
inline void SetIsInlinedProps(bool flag)
{
IsInlinedPropsField::Set(flag, &metaData_);
}
inline Representation GetRepresentation() const
{
return RepresentationField::Get(metaData_);
}
inline void SetRepresentation(Representation representation)
{
RepresentationField::Set<uint32_t>(representation, &metaData_);
}
inline void SetOffset(uint32_t offset)
{
OffsetField::Set<uint32_t>(offset, &metaData_);
}
inline uint32_t GetOffset() const
{
return OffsetField::Get(metaData_);
}
private:
uint32_t metaData_{0};
};
class OperationResult {
public:
OperationResult(const JSThread *thread, JSTaggedValue value, PropertyMetaData metaData)
: metaData_(metaData)
{
thread_ = thread;
value_ = JSHandle<JSTaggedValue>(thread_, value);
}
~OperationResult() = default;
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(OperationResult);
DEFAULT_COPY_SEMANTIC(OperationResult);
JSHandle<JSTaggedValue> GetValue() const
{
if (value_->IsPropertyBox()) {
return JSHandle<JSTaggedValue>(thread_,
PropertyBox::Cast(value_.GetTaggedValue().GetTaggedObject())->GetValue(thread_));
}
return value_;
}
JSHandle<JSTaggedValue> GetRawValue() const
{
return value_;
}
const PropertyMetaData &GetPropertyMetaData() const
{
return metaData_;
}
private:
const JSThread *thread_ {nullptr};
JSHandle<JSTaggedValue> value_ {};
PropertyMetaData metaData_ {0U};
};
class ECMAObject : public TaggedObject {
public:
static constexpr int HASH_INDEX = 0;
static constexpr int FUNCTION_EXTRA_INDEX = 1;
static constexpr int RESOLVED_MAX_SIZE = 2;
CAST_CHECK(ECMAObject, IsECMAObject);
void SetCallable(bool flag);
bool IsCallable() const;
Method *GetCallTarget(const JSThread *thread) const;
void *GetNativePointer(const JSThread *thread) const;
static constexpr size_t HASH_OFFSET = TaggedObjectSize();
static constexpr size_t SIZE = HASH_OFFSET + sizeof(JSTaggedType);
static void SetHash(const JSThread *thread, int32_t hash, const JSHandle<ECMAObject> &obj);
int32_t GetHash(const JSThread *thread) const;
bool HasHash(const JSThread *thread) const;
void InitializeHash()
{
Barriers::SetPrimitive<JSTaggedType>(this, ECMAObject::HASH_OFFSET, JSTaggedValue(0).GetRawData());
}
JSTaggedValue GetNativePointerByIndexOnHashField(const JSThread *thread, int32_t index) const;
static void SetNativePointerFieldOnHashField(const JSThread *thread, const JSHandle<JSObject> &obj, int32_t index,
void *nativePointer, const NativePointerCallback &callBack, void *data,
size_t nativeBindingsize = 0,
Concurrent isConcurrent = Concurrent::NO);
int32_t GetNativePointerFieldCountOnHashField(const JSThread *thread) const;
static int32_t GetObjectHash(const JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static int32_t GetObjectHashCode(const JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static void SetNativePointerFieldCountOnHashField(const JSThread *thread, const JSHandle<JSObject> &obj,
int32_t count);
DECL_VISIT_OBJECT(HASH_OFFSET, SIZE);
template <VisitType visitType, class DerivedVisitor>
void VisitObjects(BaseObjectVisitor<DerivedVisitor> &visitor)
{
VisitRangeSlot<visitType>(visitor);
}
};
class JSObject : public ECMAObject {
public:
static constexpr int MIN_ELEMENTS_LENGTH = 3;
static constexpr int MIN_PROPERTIES_LENGTH = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS;
static constexpr int FAST_ELEMENTS_FACTOR = 3;
static constexpr int MIN_GAP = 256;
static constexpr int MAX_GAP = 1_KB;
static constexpr uint32_t LARGE_ARRAY_DELETE_EAGER_LENGTH = 20000;
static constexpr uint32_t MAX_ELEMENT_INDEX = std::numeric_limits<uint32_t>::max();
static constexpr int MIN_ELEMENTS_HINT_LENGTH = 1_KB;
static constexpr int MAX_ELEMENTS_HINT_LENGTH = 2_MB;
static constexpr int ELEMENTS_HINT_FACTOR = 8;
static constexpr int SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR = 2;
static constexpr size_t PAIR_SIZE = 2;
static constexpr size_t VALUE_OFFSET = 1;
CAST_CHECK(JSObject, IsECMAObject);
static JSHandle<JSTaggedValue> FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc);
static void ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc);
static bool ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
PropertyDescriptor &desc);
static JSHandle<JSTaggedValue> CallFunction(JSThread *thread, const JSHandle<JSTaggedValue> &func);
static JSHandle<JSTaggedValue> GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key);
static JSHandle<JSTaggedValue> FastGetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key);
static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
SCheckMode sCheckMode = SCheckMode::CHECK);
static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
const JSHandle<JSTaggedValue> &value,
SCheckMode sCheckMode = SCheckMode::CHECK);
static JSHandle<TaggedArray> PUBLIC_API EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj);
static JSHandle<TaggedArray> EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
PropertyKind kind);
static void EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &properties,
uint32_t &index, bool &fastMode, PropertyKind kind);
static JSHandle<GlobalEnv> GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object);
static bool SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level);
static bool FreezeSharedObject(JSThread *thread, const JSHandle<JSObject> &obj);
static bool TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level);
static JSHandle<JSTaggedValue> SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &defaultConstructor);
static JSHandle<JSTaggedValue> SlowSpeciesConstructor(JSThread *thread,
const JSHandle<JSTaggedValue> &objConstructor,
const JSHandle<JSTaggedValue> &defaultConstructor);
template<ElementTypes types = ElementTypes::ALLTYPES>
static JSHandle<JSTaggedValue> CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
static JSTaggedValue GetPrototype(const JSThread *thread, const JSHandle<JSObject> &obj);
static JSTaggedValue GetPrototype(const JSThread *thread, JSTaggedValue obj);
static bool SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &proto,
bool isChangeProto = false);
bool IsExtensible() const;
static bool PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj);
static bool GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
PropertyDescriptor &desc);
static bool GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
static bool OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
static bool DefineOwnProperty(JSThread *thread, ObjectOperator *op,
const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool OrdinaryDefineOwnProperty(JSThread *thread, ObjectOperator *op,
const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
SCheckMode sCheckMode = SCheckMode::CHECK);
static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
const PropertyDescriptor &desc,
SCheckMode sCheckMode = SCheckMode::CHECK);
static bool IsCompatiblePropertyDescriptor(JSThread *thread, bool extensible, const PropertyDescriptor &desc,
const PropertyDescriptor ¤t);
static bool ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
const PropertyDescriptor ¤t,
SCheckMode sCheckMode = SCheckMode::CHECK);
static OperationResult PUBLIC_API GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key);
static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver);
static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode = SCheckMode::CHECK,
SCheckMode concurChk = SCheckMode::CHECK);
static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index);
static OperationResult GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key);
static bool SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
JSHandle<JSTaggedValue> value, bool mayThrow = false);
static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
JSHandle<JSTaggedValue> value, bool mayThrow = false,
SCheckMode checkMode = SCheckMode::CHECK);
static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
JSHandle<JSTaggedValue> value, const JSHandle<JSTaggedValue> &receiver,
bool mayThrow = false);
static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
JSHandle<JSTaggedValue> value, bool mayThrow = false);
static bool GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key,
JSHandle<JSTaggedValue> value, bool mayThrow);
static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key);
static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index);
static bool DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
SCheckMode sCheckMode = SCheckMode::CHECK);
static JSHandle<TaggedArray> GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj);
static JSHandle<TaggedArray> GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter);
static void CollectEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj,
JSHandle<TaggedArray> keyArray, uint32_t *keys,
JSHandle<TaggedQueue> shadowQueue, int32_t lastLength = -1);
static void AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj,
JSHandle<TaggedArray> keyArray, uint32_t *keys,
JSHandle<TaggedQueue> shadowQueue);
static JSHandle<TaggedArray> GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj);
static JSHandle<JSObject> ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto);
static bool InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
const JSHandle<JSTaggedValue> &target);
static JSTaggedValue TryGetEnumCache(JSThread *thread, JSTaggedValue obj);
static JSHandle<JSForInIterator> EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
static JSHandle<JSForInIterator> LoadEnumerateProperties(JSThread *thread, const JSHandle<JSTaggedValue> &object);
static bool IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument);
static JSTaggedValue CallGetter(JSThread *thread, const AccessorData *accessor,
const JSHandle<JSTaggedValue> &receiver);
static bool PUBLIC_API CallSetter(JSThread *thread, const AccessorData &accessor,
const JSHandle<JSTaggedValue> &receiver,
const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
static void FillElementsWithHoles(const JSThread *thread, const JSHandle<JSObject> &obj,
uint32_t start, uint32_t end);
JSHClass *GetJSHClass() const
{
return GetClass();
}
uint32_t GetNonInlinedFastPropsCapacity() const;
bool IsJSGlobalObject() const;
bool IsConstructor() const;
bool IsECMAObject() const;
bool IsJSError() const;
bool IsArguments() const;
bool IsDate() const;
bool IsJSArray() const;
bool IsJSSArray() const;
bool IsJSShared() const;
bool IsJSMap() const;
bool IsJSSet() const;
bool IsJSRegExp() const;
bool IsJSFunction() const;
bool IsBoundFunction() const;
bool IsJSIntlBoundFunction() const;
bool IsProxyRevocFunction() const;
bool IsAccessorData() const;
bool IsJSGlobalEnv() const;
bool IsJSProxy() const;
bool IsGeneratorObject() const;
bool IsAsyncGeneratorObject() const;
bool IsForinIterator() const;
bool IsJSSetIterator() const;
bool IsJSRegExpIterator() const;
bool IsJSMapIterator() const;
bool IsJSArrayIterator() const;
bool IsJSAPIArrayListIterator() const;
bool IsJSAPIStackIterator() const;
bool IsJSAPIVectorIterator() const;
bool IsJSAPIBitVectorIterator() const;
bool IsJSAPILinkedListIterator() const;
bool IsJSAPIListIterator() const;
bool IsJSPrimitiveRef() const;
bool IsElementDict(const JSThread *thread) const;
bool IsPropertiesDict(const JSThread *thread) const;
bool IsTypedArray() const;
bool IsSharedTypedArray() const;
bool PUBLIC_API ElementsAndPropertiesIsEmpty(JSThread *thread) const;
static PUBLIC_API void DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key,
const JSHandle<JSTaggedValue> &value,
bool useForClass = false);
static void DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
const JSHandle<JSTaggedValue> &value);
static void DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
const JSHandle<JSTaggedValue> &value);
static PUBLIC_API JSHandle<JSObject> CreateObjectFromProperties(const JSThread *thread,
const JSHandle<TaggedArray> &properties,
JSTaggedValue ihc = JSTaggedValue::Undefined());
static JSHandle<JSObject> CreateObjectFromPropertiesByIHClass(const JSThread *thread,
const JSHandle<TaggedArray> &properties,
uint32_t propsLen,
const JSHandle<JSHClass> &ihc,
TrackTypeUpdateMode trackMode);
static bool CheckPropertiesForRep(const JSThread *thread,
const JSHandle<TaggedArray> &properties, uint32_t propsLen, const JSHandle<JSHClass> &ihc);
static void GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
const JSHandle<TaggedArray> &keyArray);
static void GetAllKeysForSerialization(const JSThread *thread, const JSHandle<JSObject> &obj,
std::vector<JSTaggedValue> &keyVector);
static void GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj,
uint32_t &keyArrayEffectivelength,
const JSHandle<TaggedArray> &keyArray,
uint32_t filter);
static void GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
const JSHandle<TaggedArray> &keyArray);
static void GetAllElementKeysByFilter(JSThread *thread,
const JSHandle<JSObject> &obj,
const JSHandle<TaggedArray> &keyArray,
uint32_t &keyArrayEffectiveLength,
uint32_t filter);
static void GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj,
std::vector<JSTaggedValue> &keyVector);
std::pair<uint32_t, uint32_t> GetNumberOfEnumKeys(const JSThread *thread) const;
uint32_t GetNumberOfKeys(const JSThread *thread);
uint32_t GetNumberOfElements(JSThread *thread);
static JSHandle<TaggedArray> GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
uint32_t numOfElements, uint32_t *keys);
static void CollectEnumElements(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
JSHandle<TaggedArray> elementArray, uint32_t *keys,
int32_t lastLength = -1);
static void GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
const JSHandle<TaggedArray> &keyArray);
static JSHandle<TaggedArray> GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj,
uint32_t numOfKeys, uint32_t *keys);
static uint32_t GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
const JSHandle<TaggedArray> &keyArray);
static void AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
const JSHandle<AccessorData> &value, PropertyAttributes attr);
static constexpr size_t PROPERTIES_OFFSET = ECMAObject::SIZE;
ACCESSORS(Properties, PROPERTIES_OFFSET, ELEMENTS_OFFSET);
ACCESSORS(Elements, ELEMENTS_OFFSET, SIZE);
DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, PROPERTIES_OFFSET, SIZE)
void Dump(const JSThread *thread, std::ostream &os, bool isPrivacy = false) const DUMP_API_ATTR;
void Dump(const JSThread *thread) const DUMP_API_ATTR
{
Dump(thread, std::cout);
}
void DumpForSnapshot(const JSThread *thread, std::vector<Reference> &vec) const;
static const CString ExtractConstructorAndRecordName(JSThread *thread, TaggedObject *obj, bool noAllocate = false,
bool *isCallGetter = nullptr);
static const CString ExtractFilePath(JSThread *thread, CString name, CString moduleName,
CString defaultName, CString fileName, int32_t line);
static JSHandle<NameDictionary> PUBLIC_API TransitionToDictionary(const JSThread *thread,
const JSHandle<JSObject> &receiver);
static inline std::pair<bool, JSTaggedValue> ConvertValueWithRep(PropertyAttributes attr, JSTaggedValue value);
inline void SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value);
template <size_t objectSize, uint32_t index, bool needBarrier = true>
inline void SetPropertyInlinedPropsWithSize(const JSThread* thread, JSTaggedValue value);
template <bool needBarrier = true>
inline void SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value);
template <bool needBarrier = true>
inline void SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index,
JSTaggedValue value);
inline JSTaggedValue GetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index,
PropertyAttributes attr) const;
inline JSTaggedValue GetPropertyInlinedPropsWithRep(const JSThread* thread, const JSHClass *hclass, uint32_t index,
PropertyAttributes attr) const;
template <size_t objectSize, uint32_t index>
inline JSTaggedValue GetPropertyInlinedPropsWithSize(const JSThread* thread) const;
inline JSTaggedValue GetPropertyInlinedProps(const JSThread* thread, uint32_t index) const;
inline JSTaggedValue GetPropertyInlinedProps(const JSThread* thread, const JSHClass *hclass, uint32_t index) const;
inline JSTaggedValue GetProperty(const JSThread* thread, const JSHClass *hclass, PropertyAttributes attr) const;
PropertyBox* GetGlobalPropertyBox(const JSThread *thread, const std::string& key);
template <bool needBarrier = true>
inline void SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr,
JSTaggedValue value);
static bool IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver);
bool UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value);
static bool ShouldTransToDict(uint32_t capacity, uint32_t index);
static bool ShouldTransToFastElements(JSThread *thread, TaggedArray *elements, uint32_t capacity, uint32_t index);
static bool AttributesUnchanged(const JSThread *thread, const JSHandle<JSObject> &obj);
static JSHandle<TaggedArray> GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
uint32_t capacity, bool highGrowth = false, bool isNew = false);
static bool IsDepulicateKeys(JSThread *thread, JSHandle<TaggedArray> keys, int32_t lastLength,
JSHandle<TaggedQueue> shadowQueue, JSHandle<JSTaggedValue> key);
static JSHandle<EnumCache> GetOrCreateEnumCache(JSThread *thread, JSHandle<JSHClass> jsHClass);
static JSHandle<JSTaggedValue> GetOrCreateDependentInfos(JSThread *thread, JSHandle<JSHClass> jsHClass);
static JSHandle<JSTaggedValue> GetOrCreateDetectorDependentInfos(JSThread *thread,
uint32_t detectorID,
GlobalEnv *globalEnv);
static inline void SetEnumCacheKind([[maybe_unused]] const JSThread *thread,
JSHandle<EnumCache> enumCache, const EnumCacheKind kind)
{
enumCache->SetEnumCacheKind(static_cast<uint32_t>(kind));
}
static inline EnumCacheKind GetEnumCacheKind(JSTaggedValue enumCache)
{
if (!enumCache.IsEnumCache()) {
return EnumCacheKind::NONE;
}
EnumCacheKind kind = static_cast<EnumCacheKind>(EnumCache::Cast(enumCache)->GetEnumCacheKind());
ASSERT(kind == EnumCacheKind::NONE ||
kind == EnumCacheKind::SIMPLE ||
kind == EnumCacheKind::PROTOCHAIN);
return kind;
}
static void ClearHasDeleteProperty(JSHandle<JSTaggedValue> object);
static JSHandle<JSTaggedValue> IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
JSTaggedValue method = JSTaggedValue::Undefined());
static void TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
static void OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj);
static void SetSProperties(JSThread *thread, JSHandle<JSObject> obj, const std::vector<PropertyDescriptor> &descs);
static void PUBLIC_API TryMigrateToGenericKindForJSObject(const JSThread *thread, const JSHandle<JSObject> &obj,
const ElementsKind oldKind);
static void ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj);
#if ENABLE_V70_OPTIMIZATION
static void NormalizeElements(const JSThread *thread, JSHandle<JSObject> obj);
static bool ShouldNormalizeElementsOnDeletion(JSThread *thread, JSHandle<JSObject> obj, uint32_t deletedIndex);
static void DeleteElementsAtEnd(const JSThread *thread, JSHandle<JSObject> obj, uint32_t entry);
#endif
static JSHandle<JSTaggedValue> FindFuncInObjectForHook(JSThread *thread, JSHandle<JSTaggedValue> object,
const std::string &className, const std::string &funcName);
JSTaggedValue GetNativePointerByIndex(const JSThread *thread, int32_t index) const;
void* GetNativePointerField(const JSThread *thread, int32_t index) const;
static void SetNativePointerField(const JSThread *thread, const JSHandle<JSObject> &obj, int32_t index,
void *nativePointer, const NativePointerCallback &callBack, void *data,
size_t nativeBindingsize = 0, Concurrent isConcurrent = Concurrent::NO);
int32_t GetNativePointerFieldCount(const JSThread *thread) const;
static void SetNativePointerFieldCount(const JSThread *thread, const JSHandle<JSObject> &obj,
int32_t count);
private:
friend class ObjectOperator;
friend class LoadICRuntime;
friend class StoreICRuntime;
friend class ObjectFastOperator;
friend class ICRuntimeStub;
friend class NapiLoadICRuntime;
friend class NapiStoreICRuntime;
friend class RuntimeStubs;
friend class JSSharedArray;
friend class builtins::BuiltinsArkTools;
static bool HasMutantTaggedArrayElements(const JSThread *thread, const JSHandle<JSObject> &obj);
PropertyBox* GetGlobalPropertyBox(const JSThread *thread, JSTaggedValue key);
static bool CheckAndUpdateArrayLength(JSThread *thread, const JSHandle<JSObject> &receiver,
uint32_t index, ElementsKind &kind);
static bool PUBLIC_API AddElementInternal(
JSThread *thread, const JSHandle<JSObject> &receiver, uint32_t index, const JSHandle<JSTaggedValue> &value,
PropertyAttributes attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes()));
static JSTaggedValue GetProperty(JSThread *thread, ObjectOperator *op);
static bool SetProperty(ObjectOperator *op, JSHandle<JSTaggedValue> value, bool mayThrow);
static bool SetPropertyForData(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool *isAccessor);
static bool SetPropertyForAccessor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value);
static void DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &key, uint32_t index);
int FindProperty(const JSHandle<JSTaggedValue> &key);
static uint32_t ComputeElementCapacity(uint32_t oldCapacity, bool isNew = false);
static uint32_t ComputeElementCapacityHighGrowth(uint32_t oldCapacity);
static uint32_t ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint);
static uint32_t ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity,
uint32_t maxNonInlinedFastPropsCapacity);
static JSTaggedValue ShouldGetValueFromBox(ObjectOperator *op);
static std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> GetOwnEnumerableNamesInFastMode(
JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements);
static bool CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls);
static uint32_t SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index,
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
PropertyKind kind);
static bool IsSimpleEnumCacheValid(JSThread *thread, JSTaggedValue receiver);
static bool IsProtoChainCacheValid(JSThread *thread, JSTaggedValue receiver);
static void TrimInlinePropsSpace(const JSThread *thread, const JSHandle<JSObject> &object,
uint32_t numberInlinedProps);
static bool ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const PropertyDescriptor &desc,
const PropertyDescriptor ¤t, SCheckMode sCheckMode);
static bool SetPropertyForDataDescriptor(ObjectOperator *op, JSHandle<JSTaggedValue> value,
JSHandle<JSTaggedValue> &receiver, bool mayThrow, bool isInternalAccessor);
static bool SetPropertyForDataDescriptorProxy(JSThread *thread, ObjectOperator *op,
const JSHandle<JSTaggedValue> &value,
JSHandle<JSTaggedValue> &receiver,
bool mayThrow);
static bool ThrowTypeErrorInextensiableAddProperty(ObjectOperator *op);
};
class JSWrappedNapiObject : public JSObject {
public:
CAST_CHECK(JSWrappedNapiObject, IsJSWrappedNapiObject);
static constexpr size_t NATIVE_POINTERS_OFFSET = JSObject::SIZE;
ACCESSORS(NativePointers, NATIVE_POINTERS_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, NATIVE_POINTERS_OFFSET, LAST_OFFSET)
DECL_DUMP()
static inline void InitializeNativePointersField(const JSThread *thread, const JSHandle<JSObject> &obj)
{
JSHandle<JSWrappedNapiObject>::Cast(obj)->SetNativePointers<SKIP_BARRIER>(thread, JSTaggedValue::Undefined());
}
};
}
}
#endif