mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 01:59:58 +00:00
ElementsKind Support JSArray as Proto
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAE3RU Signed-off-by: yaoyuan <yuanyao14@huawei.com> Change-Id: I4501de04972faa211d6f5822c951da8592b909d0
This commit is contained in:
parent
be50acd63d
commit
72a3e62801
@ -484,8 +484,8 @@ JSTaggedValue BuiltinsArkTools::GetElementsKind(EcmaRuntimeCallInfo *info)
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
|
||||
JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
|
||||
JSHandle<JSObject> receiver(thread, obj.GetTaggedValue());
|
||||
ElementsKind kind = receiver->GetClass()->GetElementsKind();
|
||||
JSHClass *hclass = obj->GetTaggedObject()->GetClass();
|
||||
ElementsKind kind = hclass->GetElementsKind();
|
||||
return JSTaggedValue(static_cast<uint32_t>(kind));
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ JSHandle<GlobalEnv> AOTCompilationEnv::GetGlobalEnv() const
|
||||
return vm_->GetGlobalEnv();
|
||||
}
|
||||
|
||||
const CMap<ElementsKind, ConstantIndex> &AOTCompilationEnv::GetArrayHClassIndexMap() const
|
||||
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &AOTCompilationEnv::GetArrayHClassIndexMap() const
|
||||
{
|
||||
return thread_->GetArrayHClassIndexMap();
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
JSRuntimeOptions &GetJSOptions() override;
|
||||
|
||||
// thread
|
||||
const CMap<ElementsKind, ConstantIndex> &GetArrayHClassIndexMap() const override;
|
||||
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &GetArrayHClassIndexMap() const override;
|
||||
const BuiltinHClassEntries &GetBuiltinHClassEntries() const override;
|
||||
JSHClass *GetBuiltinPrototypeHClass(BuiltinTypeId type) const override;
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
virtual std::shared_ptr<pgo::PGOProfiler> GetPGOProfiler() const;
|
||||
|
||||
// thread
|
||||
virtual const CMap<ElementsKind, ConstantIndex> &GetArrayHClassIndexMap() const = 0;
|
||||
virtual const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &GetArrayHClassIndexMap() const = 0;
|
||||
virtual const BuiltinHClassEntries &GetBuiltinHClassEntries() const = 0;
|
||||
virtual JSHClass *GetBuiltinPrototypeHClass(BuiltinTypeId type) const = 0;
|
||||
|
||||
|
@ -40,7 +40,7 @@ JSRuntimeOptions &JitCompilationEnv::GetJSOptions()
|
||||
return hostThread_->GetEcmaVM()->GetJSOptions();
|
||||
}
|
||||
|
||||
const CMap<ElementsKind, ConstantIndex> &JitCompilationEnv::GetArrayHClassIndexMap() const
|
||||
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &JitCompilationEnv::GetArrayHClassIndexMap() const
|
||||
{
|
||||
return hostThread_->GetArrayHClassIndexMap();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
JSRuntimeOptions &GetJSOptions() override;
|
||||
// thread
|
||||
const CMap<ElementsKind, ConstantIndex> &GetArrayHClassIndexMap() const override;
|
||||
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &GetArrayHClassIndexMap() const override;
|
||||
const BuiltinHClassEntries &GetBuiltinHClassEntries() const override;
|
||||
JSHClass *GetBuiltinPrototypeHClass(BuiltinTypeId type) const override;
|
||||
void SetTsManagerCompilationEnv();
|
||||
|
@ -206,7 +206,8 @@ GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef glue, GateRef gate, GateRef
|
||||
ElementsKind kind = acc_.GetArrayMetaDataAccessor(gate).GetElementsKind();
|
||||
GateRef hclass = Circuit::NullGate();
|
||||
if (!Elements::IsGeneric(kind)) {
|
||||
auto hclassIndex = compilationEnv_->GetArrayHClassIndexMap().at(kind);
|
||||
// At define point, we use initial array class without IsPrototype set.
|
||||
auto hclassIndex = compilationEnv_->GetArrayHClassIndexMap().at(kind).first;
|
||||
hclass = builder_.GetGlobalConstantValue(hclassIndex);
|
||||
} else {
|
||||
GateRef globalEnv = builder_.GetGlobalEnv();
|
||||
|
@ -109,7 +109,9 @@ bool ArrayParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLo
|
||||
ptManager_->RecordLocationToElementsKind(loc, kind);
|
||||
|
||||
auto traceId = rootType.GetId();
|
||||
auto hclassIdx = ptManager_->GetJSThread()->GetArrayHClassIndexMap().at(kind);
|
||||
// For PGO, we do not care whether an array isPrototype or not.
|
||||
// This type is used at define point, we can use initial array hclass without IsPrototype bit set.
|
||||
auto hclassIdx = ptManager_->GetJSThread()->GetArrayHClassIndexMap().at(kind).first;
|
||||
ptManager_->RecordConstantIndex(traceId, static_cast<uint32_t>(hclassIdx));
|
||||
return true;
|
||||
}
|
||||
|
@ -1567,7 +1567,7 @@ void SlowPathLowering::LowerFastStrictEqual(GateRef gate)
|
||||
void SlowPathLowering::LowerCreateEmptyArray(GateRef gate)
|
||||
{
|
||||
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateEmptyArray, { glue_ });
|
||||
GateRef newRes = LowerUpdateArrayHClass(gate, result);
|
||||
GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
|
||||
ReplaceHirWithValue(gate, newRes, true);
|
||||
}
|
||||
|
||||
@ -1583,15 +1583,15 @@ void SlowPathLowering::LowerCreateArrayWithBuffer(GateRef gate)
|
||||
GateRef index = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
|
||||
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateArrayWithBuffer, { glue_, index, jsFunc });
|
||||
// when elementsKind switch on, we should not update arrayHClass here.
|
||||
GateRef newRes = LowerUpdateArrayHClass(gate, result);
|
||||
GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
|
||||
ReplaceHirWithValue(gate, newRes, true);
|
||||
}
|
||||
|
||||
GateRef SlowPathLowering::LowerUpdateArrayHClass(GateRef gate, GateRef array)
|
||||
GateRef SlowPathLowering::LowerUpdateArrayHClassAtDefine(GateRef gate, GateRef array)
|
||||
{
|
||||
ElementsKind kind = acc_.TryGetElementsKind(gate);
|
||||
if (!Elements::IsGeneric(kind)) {
|
||||
size_t hclassIndex = static_cast<size_t>(compilationEnv_->GetArrayHClassIndexMap().at(kind));
|
||||
size_t hclassIndex = static_cast<size_t>(compilationEnv_->GetArrayHClassIndexMap().at(kind).first);
|
||||
GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_,
|
||||
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(false)));
|
||||
GateRef constantIndex = builder_.IntPtr(JSTaggedValue::TaggedTypeSize() * hclassIndex);
|
||||
|
@ -303,7 +303,7 @@ private:
|
||||
void LowerSetGeneratorState(GateRef gate);
|
||||
GateRef GetValueFromTaggedArray(GateRef arrayGate, GateRef indexOffset);
|
||||
GateRef GetTaggedArrayFromValueIn(Environment *env, GateRef gate, size_t length);
|
||||
GateRef LowerUpdateArrayHClass(GateRef gate, GateRef array);
|
||||
GateRef LowerUpdateArrayHClassAtDefine(GateRef gate, GateRef array);
|
||||
void AddProfiling(GateRef gate, bool skipGenerator = true);
|
||||
GateRef FastStrictEqual(GateRef left, GateRef right);
|
||||
void LowerWideLdPatchVar(GateRef gate);
|
||||
|
@ -599,9 +599,12 @@ void TypedHCRLowering::BuiltinInstanceHClassCheck(Environment *env, GateRef gate
|
||||
auto arrayHClassIndexMap = compilationEnv_->GetArrayHClassIndexMap();
|
||||
auto iter = arrayHClassIndexMap.find(kind);
|
||||
ASSERT(iter != arrayHClassIndexMap.end());
|
||||
GateRef initialIhcAddress = builder_.GetGlobalConstantValue(iter->second);
|
||||
GateRef initialIhcAddress = builder_.GetGlobalConstantValue(iter->second.first);
|
||||
GateRef initialIhcWithProtoAddress = builder_.GetGlobalConstantValue(iter->second.second);
|
||||
GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver);
|
||||
ihcMatches = builder_.Equal(receiverHClass, initialIhcAddress);
|
||||
GateRef tryIhcMatches = builder_.Equal(receiverHClass, initialIhcAddress);
|
||||
GateRef tryIhcWithProtoMatches = builder_.Equal(receiverHClass, initialIhcWithProtoAddress);
|
||||
ihcMatches = builder_.BoolOr(tryIhcMatches, tryIhcWithProtoMatches);
|
||||
} else {
|
||||
GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver);
|
||||
GateRef elementsKind = builder_.GetElementsKindByHClass(receiverHClass);
|
||||
|
@ -20,21 +20,14 @@
|
||||
#include "ecmascript/tagged_array-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
CMap<ElementsKind, ConstantIndex> Elements::InitializeHClassMap()
|
||||
CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> Elements::InitializeHClassMap()
|
||||
{
|
||||
CMap<ElementsKind, ConstantIndex> result;
|
||||
result.emplace(ElementsKind::NONE, ConstantIndex::ELEMENT_NONE_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE, ConstantIndex::ELEMENT_HOLE_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::INT, ConstantIndex::ELEMENT_INT_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::NUMBER, ConstantIndex::ELEMENT_NUMBER_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::STRING, ConstantIndex::ELEMENT_STRING_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::OBJECT, ConstantIndex::ELEMENT_OBJECT_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::TAGGED, ConstantIndex::ELEMENT_TAGGED_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE_INT, ConstantIndex::ELEMENT_HOLE_INT_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE_NUMBER, ConstantIndex::ELEMENT_HOLE_NUMBER_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE_STRING, ConstantIndex::ELEMENT_HOLE_STRING_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE_OBJECT, ConstantIndex::ELEMENT_HOLE_OBJECT_HCLASS_INDEX);
|
||||
result.emplace(ElementsKind::HOLE_TAGGED, ConstantIndex::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
|
||||
CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> result;
|
||||
#define INIT_ARRAY_HCLASS_INDEX_MAPS(name) \
|
||||
result.emplace(ElementsKind::name, std::make_pair(ConstantIndex::ELEMENT_##name##_HCLASS_INDEX, \
|
||||
ConstantIndex::ELEMENT_##name##_PROTO_HCLASS_INDEX));
|
||||
ELEMENTS_KIND_INIT_HCLASS_LIST(INIT_ARRAY_HCLASS_INDEX_MAPS)
|
||||
#undef INIT_ARRAY_HCLASS_INDEX_MAPS
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,21 @@
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
|
||||
#define ELEMENTS_KIND_INIT_HCLASS_LIST(V) \
|
||||
V(NONE) \
|
||||
V(HOLE) \
|
||||
V(INT) \
|
||||
V(NUMBER) \
|
||||
V(STRING) \
|
||||
V(OBJECT) \
|
||||
V(TAGGED) \
|
||||
V(HOLE_INT) \
|
||||
V(HOLE_NUMBER) \
|
||||
V(HOLE_STRING) \
|
||||
V(HOLE_OBJECT) \
|
||||
V(HOLE_TAGGED)
|
||||
|
||||
enum class ElementsKind : uint8_t {
|
||||
NONE = 0x00UL,
|
||||
HOLE = 0x01UL,
|
||||
@ -40,7 +55,7 @@ enum class ElementsKind : uint8_t {
|
||||
|
||||
class PUBLIC_API Elements {
|
||||
public:
|
||||
static CMap<ElementsKind, ConstantIndex> InitializeHClassMap();
|
||||
static CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> InitializeHClassMap();
|
||||
|
||||
static std::string GetString(ElementsKind kind);
|
||||
static bool IsInt(ElementsKind kind);
|
||||
|
@ -419,12 +419,14 @@ void GlobalEnvConstants::InitElementKindHClass(const JSThread *thread, JSHandle<
|
||||
{
|
||||
auto map = thread->GetArrayHClassIndexMap();
|
||||
for (auto iter : map) {
|
||||
JSHandle<JSHClass> hclass = originHClass;
|
||||
JSHandle<JSHClass> hclassWithProto = JSHClass::CloneWithElementsKind(thread, originHClass, iter.first, true);
|
||||
if (iter.first != ElementsKind::GENERIC) {
|
||||
hclass = JSHClass::Clone(thread, originHClass);
|
||||
hclass->SetElementsKind(iter.first);
|
||||
JSHandle<JSHClass> hclass = JSHClass::CloneWithElementsKind(thread, originHClass, iter.first, false);
|
||||
SetConstant(iter.second.first, hclass);
|
||||
} else {
|
||||
SetConstant(iter.second.first, originHClass);
|
||||
}
|
||||
SetConstant(iter.second, hclass);
|
||||
SetConstant(iter.second.second, hclassWithProto);
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -134,6 +134,18 @@ class ObjectFactory;
|
||||
V(JSTaggedValue, IteratorResultClass, ITERATOR_RESULT_CLASS, ecma_roots_class) \
|
||||
V(JSTaggedValue, ClassPrototypeClass, CLASS_PROTOTYPE_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ClassConstructorClass, CLASS_CONSTRUCTOR_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementNoneProtoClass, ELEMENT_NONE_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleProtoClass, ELEMENT_HOLE_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementIntProtoClass, ELEMENT_INT_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementNumberProtoClass, ELEMENT_NUMBER_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementStringProtoClass, ELEMENT_STRING_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementObjectProtoClass, ELEMENT_OBJECT_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementTaggedProtoClass, ELEMENT_TAGGED_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleIntProtoClass, ELEMENT_HOLE_INT_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleNumberProtoClass, ELEMENT_HOLE_NUMBER_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleStringProtoClass, ELEMENT_HOLE_STRING_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleObjectProtoClass, ELEMENT_HOLE_OBJECT_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleTaggedProtoClass, ELEMENT_HOLE_TAGGED_PROTO_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementNoneClass, ELEMENT_NONE_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementHoleClass, ELEMENT_HOLE_HCLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ElementIntClass, ELEMENT_INT_HCLASS_INDEX, ecma_roots_class) \
|
||||
|
@ -985,7 +985,8 @@ bool JITProfiler::AddBuiltinsInfoByNameInInstance(ApEntityId abcId, int32_t bcOf
|
||||
}
|
||||
JSHClass *exceptRecvHClass = nullptr;
|
||||
if (builtinsId == BuiltinTypeId::ARRAY) {
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind());
|
||||
bool receiverIsPrototype = receiver->IsPrototype();
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
|
||||
} else if (builtinsId == BuiltinTypeId::STRING) {
|
||||
exceptRecvHClass = receiver;
|
||||
} else {
|
||||
@ -1021,7 +1022,8 @@ bool JITProfiler::AddBuiltinsInfoByNameInProt(ApEntityId abcId, int32_t bcOffset
|
||||
auto thread = vm_->GetJSThread();
|
||||
JSHClass *exceptRecvHClass = nullptr;
|
||||
if (builtinsId == BuiltinTypeId::ARRAY) {
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind());
|
||||
bool receiverIsPrototype = receiver->IsPrototype();
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
|
||||
} else if (builtinsId == BuiltinTypeId::STRING) {
|
||||
exceptRecvHClass = receiver;
|
||||
} else {
|
||||
|
@ -30,6 +30,22 @@ inline JSHClass *JSHClass::Cast(const TaggedObject *object)
|
||||
return static_cast<JSHClass *>(const_cast<TaggedObject *>(object));
|
||||
}
|
||||
|
||||
bool JSHClass::ProtoIsFastJSArray(const JSThread *thread, const JSHandle<JSTaggedValue> proto,
|
||||
const JSHandle<JSHClass> hclass)
|
||||
{
|
||||
// Since we currently only support ElementsKind for JSArray initial hclass,
|
||||
// if an object's hclass has a non-generic ElementsKind, it must be one of the JSArray initial hclass.
|
||||
// if an object's hclass has a Generic ElementsKind, it might be the JSArray initial generic elementskind hclass,
|
||||
// which therefore needs further hclass comparison.
|
||||
if (proto->IsJSArray()) {
|
||||
JSTaggedValue genericArrayHClass = thread->GlobalConstants()->GetElementHoleTaggedClass();
|
||||
if (!Elements::IsGeneric(hclass->GetElementsKind()) || hclass.GetTaggedValue() == genericArrayHClass) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, const JSHandle<JSHClass> &child,
|
||||
const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes)
|
||||
{
|
||||
|
@ -267,6 +267,15 @@ JSHandle<JSHClass> JSHClass::Clone(const JSThread *thread, const JSHandle<JSHCla
|
||||
return newJsHClass;
|
||||
}
|
||||
|
||||
JSHandle<JSHClass> JSHClass::CloneWithElementsKind(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
|
||||
const ElementsKind kind, bool isPrototype)
|
||||
{
|
||||
JSHandle<JSHClass> newHClass = Clone(thread, jshclass);
|
||||
newHClass->SetIsPrototype(isPrototype);
|
||||
newHClass->SetElementsKind(kind);
|
||||
return newHClass;
|
||||
}
|
||||
|
||||
// use for transition to dictionary
|
||||
JSHandle<JSHClass> JSHClass::CloneWithoutInlinedProperties(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
|
||||
{
|
||||
@ -530,7 +539,16 @@ void JSHClass::OptimizePrototypeForIC(const JSThread *thread, const JSHandle<JST
|
||||
// o1 becomes a prototype object of object o2 and an on-proto IC loading x from o2 will rely on the
|
||||
// stability of the prototype-chain o2 -> o1. If directly marking the o1.hclass1 as a prototype hclass,
|
||||
// the previous IC of adding property x won't trigger IC-miss and fails to notify the IC on o2.
|
||||
JSHandle<JSHClass> newProtoClass = JSHClass::Clone(thread, hclass);
|
||||
|
||||
// At here, When a JSArray with initial hclass is set as a proto,
|
||||
// we substitute its hclass with preserved proto hclass.
|
||||
JSHandle<JSHClass> newProtoClass;
|
||||
if (ProtoIsFastJSArray(thread, proto, hclass)) {
|
||||
newProtoClass = JSHandle<JSHClass>(thread, thread->GetArrayInstanceHClass(hclass->GetElementsKind(),
|
||||
true));
|
||||
} else {
|
||||
newProtoClass = JSHClass::Clone(thread, hclass);
|
||||
}
|
||||
JSTaggedValue layout = newProtoClass->GetLayout();
|
||||
// If the type of object is JSObject, the layout info value is initialized to the default value,
|
||||
// if the value is not JSObject, the layout info value is initialized to null.
|
||||
@ -551,9 +569,6 @@ void JSHClass::OptimizePrototypeForIC(const JSThread *thread, const JSHandle<JST
|
||||
if (!isChangeProto) {
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->UpdateRootProfileTypeSafe(*hclass, *newProtoClass);
|
||||
}
|
||||
if (proto->IsJSObject()) {
|
||||
TryRestoreElementsKind(thread, newProtoClass, JSHandle<JSObject>::Cast(proto));
|
||||
}
|
||||
} else {
|
||||
// There is no sharing in AOT hclass. Therefore, it is not necessary or possible to clone here.
|
||||
hclass->SetIsPrototype(true);
|
||||
@ -659,17 +674,21 @@ void JSHClass::TransitionForRepChange(const JSThread *thread, const JSHandle<JSO
|
||||
// 4. Maybe Transition And Maintain subtypeing check
|
||||
}
|
||||
|
||||
JSHClass* JSHClass::GetInitialArrayHClassWithElementsKind(const JSThread *thread, const ElementsKind kind)
|
||||
bool JSHClass::IsInitialArrayHClassWithElementsKind(const JSThread *thread, const JSHClass *targetHClass,
|
||||
const ElementsKind targetKind)
|
||||
{
|
||||
const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
|
||||
auto newKindIter = arrayHClassIndexMap.find(kind);
|
||||
auto newKindIter = arrayHClassIndexMap.find(targetKind);
|
||||
if (newKindIter != arrayHClassIndexMap.end()) {
|
||||
auto index = static_cast<size_t>(newKindIter->second);
|
||||
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
|
||||
auto indexPair = newKindIter->second;
|
||||
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(static_cast<size_t>(indexPair.first));
|
||||
auto hclassWithProtoVal = thread->GlobalConstants()->
|
||||
GetGlobalConstantObject(static_cast<size_t>(indexPair.second));
|
||||
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
|
||||
return hclass;
|
||||
JSHClass *hclassWithProto = JSHClass::Cast(hclassWithProtoVal.GetTaggedObject());
|
||||
return (targetHClass == hclass || targetHClass == hclassWithProto);
|
||||
}
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JSHClass::TransitToElementsKindUncheck(const JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
@ -677,16 +696,21 @@ bool JSHClass::TransitToElementsKindUncheck(const JSThread *thread, const JSHand
|
||||
{
|
||||
ElementsKind current = obj->GetJSHClass()->GetElementsKind();
|
||||
// currently we only support initial array hclass
|
||||
if (obj->GetClass() == GetInitialArrayHClassWithElementsKind(thread, current)) {
|
||||
JSHClass *objHclass = obj->GetClass();
|
||||
if (IsInitialArrayHClassWithElementsKind(thread, objHclass, current)) {
|
||||
const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
|
||||
auto newKindIter = arrayHClassIndexMap.find(newKind);
|
||||
bool objHclassIsPrototype = objHclass->IsPrototype();
|
||||
if (newKindIter != arrayHClassIndexMap.end()) {
|
||||
auto index = static_cast<size_t>(newKindIter->second);
|
||||
auto indexPair = newKindIter->second;
|
||||
auto index = objHclassIsPrototype ? static_cast<size_t>(indexPair.second) :
|
||||
static_cast<size_t>(indexPair.first);
|
||||
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
|
||||
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
|
||||
obj->SynchronizedSetClass(thread, hclass);
|
||||
return true;
|
||||
}
|
||||
LOG_ECMA(FATAL) << "Unknown newKind: " << static_cast<int32_t>(newKind);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -703,16 +727,9 @@ void JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSAr
|
||||
if (newKind == current) {
|
||||
return;
|
||||
}
|
||||
// Currently, we only support fast array elementsKind
|
||||
ASSERT(array->GetClass() == GetInitialArrayHClassWithElementsKind(thread, current));
|
||||
const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
|
||||
auto newKindIter = arrayHClassIndexMap.find(newKind);
|
||||
if (newKindIter != arrayHClassIndexMap.end()) {
|
||||
auto index = static_cast<size_t>(newKindIter->second);
|
||||
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
|
||||
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
|
||||
array->SynchronizedSetClass(thread, hclass);
|
||||
}
|
||||
|
||||
ASSERT(IsInitialArrayHClassWithElementsKind(thread, array->GetJSHClass(), current));
|
||||
TransitToElementsKindUncheck(thread, JSHandle<JSObject>(array), newKind);
|
||||
}
|
||||
|
||||
bool JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSObject> &object,
|
||||
@ -732,27 +749,21 @@ bool JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSOb
|
||||
return false;
|
||||
}
|
||||
// Currently, we only support fast array elementsKind
|
||||
ASSERT(object->GetClass() == GetInitialArrayHClassWithElementsKind(thread, current));
|
||||
const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
|
||||
auto newKindIter = arrayHClassIndexMap.find(newKind);
|
||||
if (newKindIter != arrayHClassIndexMap.end()) {
|
||||
auto index = static_cast<size_t>(newKindIter->second);
|
||||
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
|
||||
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
|
||||
object->SynchronizedSetClass(thread, hclass);
|
||||
ASSERT(IsInitialArrayHClassWithElementsKind(thread, object->GetJSHClass(), current));
|
||||
if (!TransitToElementsKindUncheck(thread, object, newKind)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
|
||||
// Update TrackInfo
|
||||
if (!thread->IsPGOProfilerEnable()) {
|
||||
return true;
|
||||
}
|
||||
auto trackInfoVal = JSHandle<JSArray>(object)->GetTrackInfo();
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackElementsKind(trackInfoVal, newKind);
|
||||
if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
|
||||
// Update TrackInfo
|
||||
if (!thread->IsPGOProfilerEnable()) {
|
||||
return true;
|
||||
}
|
||||
auto trackInfoVal = JSHandle<JSArray>(object)->GetTrackInfo();
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackElementsKind(trackInfoVal, newKind);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TransitionResult JSHClass::ConvertOrTransitionWithRep(const JSThread *thread,
|
||||
|
@ -427,6 +427,8 @@ public:
|
||||
static JSHandle<JSHClass> Clone(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
|
||||
bool withoutInlinedProperties = false, uint32_t incInlinedProperties = 0);
|
||||
static JSHandle<JSHClass> CloneWithoutInlinedProperties(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
|
||||
static JSHandle<JSHClass> CloneWithElementsKind(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
|
||||
const ElementsKind kind, bool isPrototype);
|
||||
|
||||
static void TransitionElementsToDictionary(const JSThread *thread, const JSHandle<JSObject> &obj);
|
||||
static void OptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
@ -463,7 +465,8 @@ public:
|
||||
const JSHandle<JSTaggedValue> &key, PropertyAttributes attr);
|
||||
static void TransitionForElementsKindChange(const JSThread *thread, const JSHandle<JSObject> &receiver,
|
||||
const ElementsKind newKind);
|
||||
static JSHClass* GetInitialArrayHClassWithElementsKind(const JSThread *thread, const ElementsKind kind);
|
||||
static bool IsInitialArrayHClassWithElementsKind(const JSThread *thread, const JSHClass *targetHClass,
|
||||
const ElementsKind targetKind);
|
||||
static bool PUBLIC_API TransitToElementsKindUncheck(const JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
ElementsKind newKind);
|
||||
static void PUBLIC_API TransitToElementsKind(const JSThread *thread, const JSHandle<JSArray> &array,
|
||||
@ -2040,6 +2043,10 @@ public:
|
||||
static JSHandle<JSHClass> CreateSPrototypeHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs);
|
||||
|
||||
private:
|
||||
|
||||
static inline bool ProtoIsFastJSArray(const JSThread *thread, const JSHandle<JSTaggedValue> proto,
|
||||
const JSHandle<JSHClass> hclass);
|
||||
|
||||
static void CreateSInlinedLayout(JSThread *thread,
|
||||
const std::vector<PropertyDescriptor> &descs,
|
||||
const JSHandle<JSHClass> &hclass,
|
||||
|
@ -619,11 +619,11 @@ JSHClass *JSThread::GetBuiltinExtraHClass(BuiltinTypeId type) const
|
||||
return glueData_.builtinHClassEntries_.entries[index].extraHClass;
|
||||
}
|
||||
|
||||
JSHClass *JSThread::GetArrayInstanceHClass(ElementsKind kind) const
|
||||
JSHClass *JSThread::GetArrayInstanceHClass(ElementsKind kind, bool isPrototype) const
|
||||
{
|
||||
auto iter = GetArrayHClassIndexMap().find(kind);
|
||||
ASSERT(iter != GetArrayHClassIndexMap().end());
|
||||
auto index = static_cast<size_t>(iter->second);
|
||||
auto index = isPrototype ? static_cast<size_t>(iter->second.second) : static_cast<size_t>(iter->second.first);
|
||||
auto exceptArrayHClass = GlobalConstants()->GetGlobalConstantObject(index);
|
||||
auto exceptRecvHClass = JSHClass::Cast(exceptArrayHClass.GetTaggedObject());
|
||||
ASSERT(exceptRecvHClass->IsJSArray());
|
||||
|
@ -316,7 +316,7 @@ public:
|
||||
return &glueData_.builtinEntries_;
|
||||
}
|
||||
|
||||
const CMap<ElementsKind, ConstantIndex> &GetArrayHClassIndexMap() const
|
||||
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &GetArrayHClassIndexMap() const
|
||||
{
|
||||
return arrayHClassIndexMap_;
|
||||
}
|
||||
@ -346,7 +346,7 @@ public:
|
||||
|
||||
JSHClass *GetBuiltinInstanceHClass(BuiltinTypeId type) const;
|
||||
JSHClass *GetBuiltinExtraHClass(BuiltinTypeId type) const;
|
||||
JSHClass *GetArrayInstanceHClass(ElementsKind kind) const;
|
||||
JSHClass *GetArrayInstanceHClass(ElementsKind kind, bool isPrototype) const;
|
||||
|
||||
PUBLIC_API JSHClass *GetBuiltinPrototypeHClass(BuiltinTypeId type) const;
|
||||
PUBLIC_API JSHClass *GetBuiltinPrototypeOfPrototypeHClass(BuiltinTypeId type) const;
|
||||
@ -1522,7 +1522,7 @@ private:
|
||||
glueData_.currentContext_ = context;
|
||||
}
|
||||
|
||||
void SetArrayHClassIndexMap(const CMap<ElementsKind, ConstantIndex> &map)
|
||||
void SetArrayHClassIndexMap(const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &map)
|
||||
{
|
||||
arrayHClassIndexMap_ = map;
|
||||
}
|
||||
@ -1607,7 +1607,8 @@ private:
|
||||
bool isMainThread_ {false};
|
||||
bool fullMarkRequest_ {false};
|
||||
|
||||
CMap<ElementsKind, ConstantIndex> arrayHClassIndexMap_;
|
||||
// { ElementsKind, (hclass, hclassWithProto) }
|
||||
CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> arrayHClassIndexMap_;
|
||||
CMap<JSHClass *, GlobalIndex> ctorHclassEntries_;
|
||||
|
||||
CVector<EcmaContext *> contexts_;
|
||||
|
@ -271,7 +271,9 @@ void PGOProfiler::UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKi
|
||||
trackInfo->SetElementsKind(mixKind);
|
||||
auto thread = vm_->GetJSThread();
|
||||
auto globalConst = thread->GlobalConstants();
|
||||
auto constantId = thread->GetArrayHClassIndexMap().at(mixKind);
|
||||
// Since trackinfo is only used at define point,
|
||||
// we update cachedHClass with initial array hclass which does not have IsPrototype set.
|
||||
auto constantId = thread->GetArrayHClassIndexMap().at(mixKind).first;
|
||||
auto hclass = globalConst->GetGlobalConstantObject(static_cast<size_t>(constantId));
|
||||
trackInfo->SetCachedHClass(vm_->GetJSThread(), hclass);
|
||||
UpdateTrackInfo(JSTaggedValue(trackInfo));
|
||||
@ -1684,7 +1686,8 @@ bool PGOProfiler::AddBuiltinsInfoByNameInInstance(ApEntityId abcId, const CStrin
|
||||
}
|
||||
JSHClass *exceptRecvHClass = nullptr;
|
||||
if (builtinsId == BuiltinTypeId::ARRAY) {
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind());
|
||||
bool receiverIsPrototype = receiver->IsPrototype();
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
|
||||
} else if (builtinsId == BuiltinTypeId::STRING) {
|
||||
exceptRecvHClass = receiver;
|
||||
} else {
|
||||
@ -1720,7 +1723,8 @@ bool PGOProfiler::AddBuiltinsInfoByNameInProt(ApEntityId abcId, const CString &r
|
||||
auto thread = vm_->GetJSThread();
|
||||
JSHClass *exceptRecvHClass = nullptr;
|
||||
if (builtinsId == BuiltinTypeId::ARRAY) {
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind());
|
||||
bool receiverIsPrototype = receiver->IsPrototype();
|
||||
exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
|
||||
} else if (builtinsId == BuiltinTypeId::STRING) {
|
||||
exceptRecvHClass = receiver;
|
||||
} else {
|
||||
|
@ -637,22 +637,20 @@ DEF_RUNTIME_STUBS(UpdateHClassForElementsKind)
|
||||
JSTaggedType elementsKind = GetTArg(argv, argc, 1); // 1: means the first parameter
|
||||
ASSERT(receiver->IsJSArray());
|
||||
ElementsKind kind = Elements::FixElementsKind(static_cast<ElementsKind>(elementsKind));
|
||||
auto arrayIndexMap = thread->GetArrayHClassIndexMap();
|
||||
if (arrayIndexMap.find(kind) != arrayIndexMap.end()) {
|
||||
auto index = thread->GetArrayHClassIndexMap().at(kind);
|
||||
auto globalConst = thread->GlobalConstants();
|
||||
auto targetHClassValue = globalConst->GetGlobalConstantObject(static_cast<size_t>(index));
|
||||
auto hclass = JSHClass::Cast(targetHClassValue.GetTaggedObject());
|
||||
auto array = JSHandle<JSArray>(receiver);
|
||||
array->SynchronizedSetClass(thread, hclass);
|
||||
if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
|
||||
// Update TrackInfo
|
||||
if (!thread->IsPGOProfilerEnable()) {
|
||||
return JSTaggedValue::Hole().GetRawData();
|
||||
}
|
||||
auto trackInfoVal = array->GetTrackInfo();
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackElementsKind(trackInfoVal, kind);
|
||||
auto array = JSHandle<JSArray>(receiver);
|
||||
ASSERT(JSHClass::IsInitialArrayHClassWithElementsKind(thread, receiver->GetTaggedObject()->GetClass(),
|
||||
receiver->GetTaggedObject()->GetClass()->GetElementsKind()));
|
||||
if (!JSHClass::TransitToElementsKindUncheck(thread, JSHandle<JSObject>(array), kind)) {
|
||||
return JSTaggedValue::Hole().GetRawData();
|
||||
}
|
||||
|
||||
if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
|
||||
// Update TrackInfo
|
||||
if (!thread->IsPGOProfilerEnable()) {
|
||||
return JSTaggedValue::Hole().GetRawData();
|
||||
}
|
||||
auto trackInfoVal = JSHandle<JSArray>(receiver)->GetTrackInfo();
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackElementsKind(trackInfoVal, kind);
|
||||
}
|
||||
return JSTaggedValue::Hole().GetRawData();
|
||||
}
|
||||
|
@ -88,3 +88,31 @@ function testArrayUsedAsProto() {
|
||||
}
|
||||
|
||||
testArrayUsedAsProto();
|
||||
|
||||
function testProto1() {
|
||||
let a = [1, 2, 3];
|
||||
let obj = {};
|
||||
obj.__proto__ = a;
|
||||
print(a[0]);
|
||||
print(ArkTools.getElementsKind(a));
|
||||
}
|
||||
|
||||
print(ArkTools.isAOTCompiled(testProto1));
|
||||
testProto1();
|
||||
|
||||
|
||||
function testProto2() {
|
||||
let obj = {};
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let a = [1, 2, 3];
|
||||
if (i == 2) {
|
||||
obj.__proto__ = a;
|
||||
a[1] = 1.5
|
||||
}
|
||||
print(a[0] + 1);
|
||||
print(ArkTools.getElementsKind(a));
|
||||
}
|
||||
}
|
||||
|
||||
print(ArkTools.isAOTCompiled(testProto2));
|
||||
testProto2();
|
||||
|
@ -19,4 +19,17 @@ undefined
|
||||
2
|
||||
0
|
||||
success
|
||||
testArrayUsedAsProto success
|
||||
testArrayUsedAsProto success
|
||||
true
|
||||
1
|
||||
2
|
||||
true
|
||||
2
|
||||
6
|
||||
2
|
||||
6
|
||||
2
|
||||
6
|
||||
2
|
||||
6
|
||||
|
||||
|
@ -19,4 +19,17 @@ undefined
|
||||
2
|
||||
0
|
||||
success
|
||||
testArrayUsedAsProto success
|
||||
testArrayUsedAsProto success
|
||||
false
|
||||
1
|
||||
2
|
||||
false
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
6
|
||||
2
|
||||
6
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user