mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-20 03:54:08 -04:00
@@ -390,6 +390,7 @@ ecma_source = [
|
||||
"ecmascript/vmstat/runtime_stat.cpp",
|
||||
"ecmascript/weak_vector.cpp",
|
||||
"ecmascript/compiler/llvm/llvm_stackmap_parser.cpp",
|
||||
"ecmascript/class_info_extractor.cpp",
|
||||
]
|
||||
|
||||
ecma_source += [
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
|
||||
const JSHandle<TaggedArray> &literal)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
uint32_t literalBufferLength = literal->GetLength();
|
||||
// non static properties number is hidden in the last index of Literal buffer
|
||||
uint32_t nonStaticNum = literal->Get(thread, literalBufferLength - 1).GetInt();
|
||||
|
||||
// Reserve sufficient length to prevent frequent creation.
|
||||
JSHandle<TaggedArray> nonStaticKeys = factory->NewTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
|
||||
JSHandle<TaggedArray> nonStaticProperties = factory->NewTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
|
||||
|
||||
nonStaticKeys->Set(thread, CONSTRUCTOR_INDEX, globalConst->GetConstructorString());
|
||||
|
||||
JSHandle<TaggedArray> nonStaticElements = factory->EmptyArray();
|
||||
|
||||
if (nonStaticNum) {
|
||||
ExtractContentsDetail nonStaticDetail {0, nonStaticNum * 2, NON_STATIC_RESERVED_LENGTH, nullptr};
|
||||
|
||||
if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, nonStaticDetail, nonStaticKeys,
|
||||
nonStaticProperties, nonStaticElements))) {
|
||||
extractor->SetNonStaticWithElements();
|
||||
extractor->SetNonStaticElements(thread, nonStaticElements);
|
||||
}
|
||||
}
|
||||
|
||||
extractor->SetNonStaticKeys(thread, nonStaticKeys);
|
||||
extractor->SetNonStaticProperties(thread, nonStaticProperties);
|
||||
|
||||
JSHandle<JSHClass> prototypeHClass = CreatePrototypeHClass(thread, nonStaticKeys, nonStaticProperties);
|
||||
extractor->SetPrototypeHClass(thread, prototypeHClass);
|
||||
|
||||
uint32_t staticNum = (literalBufferLength - 1) / 2 - nonStaticNum;
|
||||
|
||||
// Reserve sufficient length to prevent frequent creation.
|
||||
JSHandle<TaggedArray> staticKeys = factory->NewTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
|
||||
JSHandle<TaggedArray> staticProperties = factory->NewTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
|
||||
|
||||
staticKeys->Set(thread, LENGTH_INDEX, globalConst->GetLengthString());
|
||||
staticKeys->Set(thread, NAME_INDEX, globalConst->GetNameString());
|
||||
staticKeys->Set(thread, PROTOTYPE_INDEX, globalConst->GetPrototypeString());
|
||||
|
||||
JSHandle<TaggedArray> staticElements = factory->EmptyArray();
|
||||
|
||||
if (staticNum) {
|
||||
ExtractContentsDetail staticDetail {
|
||||
nonStaticNum * 2,
|
||||
literalBufferLength - 1,
|
||||
STATIC_RESERVED_LENGTH,
|
||||
extractor->GetConstructorMethod()
|
||||
};
|
||||
|
||||
if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, staticDetail, staticKeys,
|
||||
staticProperties, staticElements))) {
|
||||
extractor->SetStaticWithElements();
|
||||
extractor->SetStaticElements(thread, staticElements);
|
||||
}
|
||||
} else {
|
||||
// without static properties, set class name
|
||||
CString clsName = extractor->GetConstructorMethod()->ParseFunctionName();
|
||||
JSHandle<EcmaString> clsNameHandle = factory->NewFromString(clsName.c_str());
|
||||
staticProperties->Set(thread, NAME_INDEX, clsNameHandle);
|
||||
}
|
||||
|
||||
// set prototype internal accessor
|
||||
JSHandle<JSTaggedValue> prototypeAccessor = globalConst->GetHandledFunctionPrototypeAccessor();
|
||||
staticProperties->Set(thread, PROTOTYPE_INDEX, prototypeAccessor);
|
||||
|
||||
extractor->SetStaticKeys(thread, staticKeys);
|
||||
extractor->SetStaticProperties(thread, staticProperties);
|
||||
|
||||
JSHandle<JSHClass> ctorHClass = CreateConstructorHClass(thread, staticKeys, staticProperties);
|
||||
extractor->SetConstructorHClass(thread, ctorHClass);
|
||||
}
|
||||
|
||||
bool ClassInfoExtractor::ExtractAndReturnWhetherWithElements(JSThread *thread, const JSHandle<TaggedArray> &literal,
|
||||
const ExtractContentsDetail &detail,
|
||||
JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties,
|
||||
JSHandle<TaggedArray> &elements)
|
||||
{
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
|
||||
ASSERT(keys->GetLength() == properties->GetLength() && elements->GetLength() == 0);
|
||||
|
||||
uint32_t pos = detail.fillStartLoc;
|
||||
bool withElemenstFlag = false;
|
||||
bool isStaticFlag = detail.ctorMethod ? true : false;
|
||||
bool keysHasNameFlag = false;
|
||||
|
||||
JSHandle<JSTaggedValue> nameString = globalConst->GetHandledNameString();
|
||||
JSMutableHandle<JSTaggedValue> firstValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> secondValue(thread, JSTaggedValue::Undefined());
|
||||
for (uint32_t index = detail.extractBegin; index < detail.extractEnd; index += 2) { // 2: key-value pair
|
||||
firstValue.Update(literal->Get(index));
|
||||
secondValue.Update(literal->Get(index + 1));
|
||||
ASSERT_PRINT(JSTaggedValue::IsPropertyKey(firstValue), "Key is not a property key");
|
||||
|
||||
if (LIKELY(firstValue->IsString())) {
|
||||
if (isStaticFlag && !keysHasNameFlag && JSTaggedValue::SameValue(firstValue, nameString)) {
|
||||
properties->Set(thread, NAME_INDEX, secondValue);
|
||||
keysHasNameFlag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// front-end can do better: write index in class literal directly.
|
||||
uint32_t elementIndex = 0;
|
||||
if (JSTaggedValue::StringToElementIndex(firstValue.GetTaggedValue(), &elementIndex)) {
|
||||
ASSERT(elementIndex < JSObject::MAX_ELEMENT_INDEX);
|
||||
uint32_t elementsLength = elements->GetLength();
|
||||
elements = TaggedArray::SetCapacity(thread, elements, elementsLength + 2); // 2: key-value pair
|
||||
elements->Set(thread, elementsLength, firstValue);
|
||||
elements->Set(thread, elementsLength + 1, secondValue);
|
||||
withElemenstFlag = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
keys->Set(thread, pos, firstValue);
|
||||
properties->Set(thread, pos, secondValue);
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (isStaticFlag) {
|
||||
if (LIKELY(!keysHasNameFlag)) {
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
CString clsName = detail.ctorMethod->ParseFunctionName();
|
||||
JSHandle<EcmaString> clsNameHandle = factory->NewFromString(clsName.c_str());
|
||||
properties->Set(thread, NAME_INDEX, clsNameHandle);
|
||||
} else {
|
||||
// class has static name property, reserved length bigger 1 than actual, need trim
|
||||
uint32_t trimOneLength = keys->GetLength() - 1;
|
||||
keys->Trim(thread, trimOneLength);
|
||||
properties->Trim(thread, trimOneLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(withElemenstFlag)) {
|
||||
ASSERT(pos + elements->GetLength() / 2 == properties->GetLength()); // 2: half
|
||||
keys->Trim(thread, pos);
|
||||
properties->Trim(thread, pos);
|
||||
}
|
||||
|
||||
return withElemenstFlag;
|
||||
}
|
||||
|
||||
JSHandle<JSHClass> ClassInfoExtractor::CreatePrototypeHClass(JSThread *thread, JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
uint32_t length = keys->GetLength();
|
||||
JSHandle<JSHClass> hclass;
|
||||
if (LIKELY(length <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
|
||||
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
|
||||
JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length);
|
||||
for (uint32_t index = 0; index < length; ++index) {
|
||||
key.Update(keys->Get(index));
|
||||
ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
|
||||
PropertyAttributes attributes = PropertyAttributes::Default(true, false, true); // non-enumerable
|
||||
|
||||
if (UNLIKELY(properties->Get(index).IsAccessor())) {
|
||||
attributes.SetIsAccessor(true);
|
||||
}
|
||||
|
||||
attributes.SetIsInlinedProps(true);
|
||||
attributes.SetRepresentation(Representation::MIXED);
|
||||
attributes.SetOffset(index);
|
||||
layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
|
||||
}
|
||||
|
||||
hclass = factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, length);
|
||||
// Not need set proto here
|
||||
hclass->SetLayout(thread, layout);
|
||||
hclass->SetNumberOfProps(length);
|
||||
} else {
|
||||
// dictionary mode
|
||||
hclass = factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, 0); // without in-obj
|
||||
hclass->SetIsDictionaryMode(true);
|
||||
hclass->SetNumberOfProps(0);
|
||||
}
|
||||
|
||||
hclass->SetClassPrototype(true);
|
||||
hclass->SetIsPrototype(true);
|
||||
return hclass;
|
||||
}
|
||||
|
||||
JSHandle<JSHClass> ClassInfoExtractor::CreateConstructorHClass(JSThread *thread, JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
uint32_t length = keys->GetLength();
|
||||
JSHandle<JSHClass> hclass;
|
||||
if (LIKELY(length <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
|
||||
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
|
||||
JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length);
|
||||
for (uint32_t index = 0; index < length; ++index) {
|
||||
key.Update(keys->Get(index));
|
||||
ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
|
||||
PropertyAttributes attributes;
|
||||
switch (index) {
|
||||
case LENGTH_INDEX:
|
||||
attributes = PropertyAttributes::Default(false, false, true);
|
||||
break;
|
||||
case NAME_INDEX:
|
||||
if (LIKELY(properties->Get(NAME_INDEX).IsString())) {
|
||||
attributes = PropertyAttributes::Default(false, false, true);
|
||||
} else {
|
||||
ASSERT(properties->Get(NAME_INDEX).IsJSFunction());
|
||||
attributes = PropertyAttributes::Default(true, false, true);
|
||||
}
|
||||
break;
|
||||
case PROTOTYPE_INDEX:
|
||||
attributes = PropertyAttributes::DefaultAccessor(false, false, false);
|
||||
break;
|
||||
default:
|
||||
attributes = PropertyAttributes::Default(true, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (UNLIKELY(properties->Get(index).IsAccessor())) {
|
||||
attributes.SetIsAccessor(true);
|
||||
}
|
||||
|
||||
attributes.SetIsInlinedProps(true);
|
||||
attributes.SetRepresentation(Representation::MIXED);
|
||||
attributes.SetOffset(index);
|
||||
layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
|
||||
}
|
||||
|
||||
hclass = factory->NewEcmaDynClass(JSFunction::SIZE, JSType::JS_FUNCTION, length);
|
||||
// Not need set proto here
|
||||
hclass->SetLayout(thread, layout);
|
||||
hclass->SetNumberOfProps(length);
|
||||
} else {
|
||||
// dictionary mode
|
||||
hclass = factory->NewEcmaDynClass(JSFunction::SIZE, JSType::JS_FUNCTION, 0); // without in-obj
|
||||
hclass->SetIsDictionaryMode(true);
|
||||
hclass->SetNumberOfProps(0);
|
||||
}
|
||||
|
||||
hclass->SetClassConstructor(true);
|
||||
hclass->SetConstructor(true);
|
||||
|
||||
return hclass;
|
||||
}
|
||||
|
||||
JSHandle<JSFunction> ClassHelper::DefineClassTemplate(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
|
||||
const JSHandle<ConstantPool> &constantpool)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
JSHandle<JSHClass> prototypeHClass(thread, extractor->GetPrototypeHClass());
|
||||
JSHandle<JSObject> prototype = factory->NewJSObject(prototypeHClass);
|
||||
|
||||
JSHandle<JSHClass> constructorHClass(thread, extractor->GetConstructorHClass());
|
||||
JSHandle<JSFunction> constructor = factory->NewJSFunctionByDynClass(extractor->GetConstructorMethod(),
|
||||
constructorHClass,
|
||||
FunctionKind::CLASS_CONSTRUCTOR);
|
||||
|
||||
// non-static
|
||||
JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
|
||||
nonStaticProperties->Set(thread, 0, constructor);
|
||||
|
||||
uint32_t nonStaticLength = nonStaticProperties->GetLength();
|
||||
JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
|
||||
|
||||
if (LIKELY(!prototypeHClass->IsDictionaryMode())) {
|
||||
for (uint32_t index = 0; index < nonStaticLength; ++index) {
|
||||
propValue.Update(nonStaticProperties->Get(index));
|
||||
if (propValue->IsJSFunction()) {
|
||||
JSHandle<JSFunction> propFunc = JSHandle<JSFunction>::Cast(propValue);
|
||||
propFunc->SetHomeObject(thread, prototype);
|
||||
propFunc->SetConstantPool(thread, constantpool);
|
||||
}
|
||||
prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
|
||||
}
|
||||
} else {
|
||||
JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
|
||||
JSHandle<NameDictionary> dict = BuildDictionaryPropeties(thread, prototype, nonStaticKeys, nonStaticProperties,
|
||||
ClassPropertyType::NON_STATIC, constantpool);
|
||||
prototype->SetProperties(thread, dict);
|
||||
}
|
||||
|
||||
// non-static elements
|
||||
if (UNLIKELY(extractor->IsNonStaticWithElements())) {
|
||||
JSHandle<TaggedArray> nonStaticElements(thread, extractor->GetNonStaticElements());
|
||||
ClassHelper::HandleElementsProperties(thread, prototype, nonStaticElements, constantpool);
|
||||
}
|
||||
|
||||
// static
|
||||
JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
|
||||
uint32_t staticLength = staticProperties->GetLength();
|
||||
|
||||
if (LIKELY(!constructorHClass->IsDictionaryMode())) {
|
||||
for (uint32_t index = 0; index < staticLength; ++index) {
|
||||
propValue.Update(staticProperties->Get(index));
|
||||
if (propValue->IsJSFunction()) {
|
||||
JSHandle<JSFunction> propFunc = JSHandle<JSFunction>::Cast(propValue);
|
||||
propFunc->SetHomeObject(thread, constructor);
|
||||
propFunc->SetConstantPool(thread, constantpool);
|
||||
}
|
||||
JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
|
||||
}
|
||||
} else {
|
||||
JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
|
||||
JSHandle<NameDictionary> dict = BuildDictionaryPropeties(thread, JSHandle<JSObject>(constructor), staticKeys,
|
||||
staticProperties, ClassPropertyType::STATIC,
|
||||
constantpool);
|
||||
constructor->SetProperties(thread, dict);
|
||||
}
|
||||
|
||||
// static elements
|
||||
if (UNLIKELY(extractor->IsStaticWithElements())) {
|
||||
JSHandle<TaggedArray> staticElements(thread, extractor->GetStaticElements());
|
||||
ClassHelper::HandleElementsProperties(thread, JSHandle<JSObject>(constructor), staticElements, constantpool);
|
||||
}
|
||||
|
||||
constructor->SetProtoOrDynClass(thread, prototype);
|
||||
|
||||
return constructor;
|
||||
}
|
||||
|
||||
JSHandle<NameDictionary> ClassHelper::BuildDictionaryPropeties(JSThread *thread, const JSHandle<JSObject> &object,
|
||||
JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties,
|
||||
ClassPropertyType type,
|
||||
const JSHandle<ConstantPool> &constantpool)
|
||||
{
|
||||
uint32_t length = keys->GetLength();
|
||||
ASSERT(length > PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES);
|
||||
ASSERT(keys->GetLength() == properties->GetLength());
|
||||
|
||||
JSMutableHandle<NameDictionary> dict(
|
||||
thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(length)));
|
||||
JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
|
||||
for (uint32_t index = 0; index < length; index++) {
|
||||
PropertyAttributes attributes;
|
||||
if (type == ClassPropertyType::STATIC) {
|
||||
switch (index) {
|
||||
case ClassInfoExtractor::LENGTH_INDEX:
|
||||
attributes = PropertyAttributes::Default(false, false, true);
|
||||
break;
|
||||
case ClassInfoExtractor::NAME_INDEX:
|
||||
if (LIKELY(properties->Get(ClassInfoExtractor::NAME_INDEX).IsString())) {
|
||||
attributes = PropertyAttributes::Default(false, false, true);
|
||||
} else {
|
||||
ASSERT(properties->Get(ClassInfoExtractor::NAME_INDEX).IsJSFunction());
|
||||
attributes = PropertyAttributes::Default(true, false, true);
|
||||
}
|
||||
break;
|
||||
case ClassInfoExtractor::PROTOTYPE_INDEX:
|
||||
attributes = PropertyAttributes::DefaultAccessor(false, false, false);
|
||||
break;
|
||||
default:
|
||||
attributes = PropertyAttributes::Default(true, false, true);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
attributes = PropertyAttributes::Default(true, false, true); // non-enumerable
|
||||
}
|
||||
propKey.Update(keys->Get(index));
|
||||
propValue.Update(properties->Get(index));
|
||||
if (propValue->IsJSFunction()) {
|
||||
JSHandle<JSFunction> propFunc = JSHandle<JSFunction>::Cast(propValue);
|
||||
propFunc->SetHomeObject(thread, object);
|
||||
propFunc->SetConstantPool(thread, constantpool);
|
||||
}
|
||||
JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attributes);
|
||||
dict.Update(newDict);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
void ClassHelper::HandleElementsProperties(JSThread *thread, const JSHandle<JSObject> &object,
|
||||
JSHandle<TaggedArray> &elements, const JSHandle<ConstantPool> &constantpool)
|
||||
{
|
||||
JSMutableHandle<JSTaggedValue> elementsKey(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> elementsValue(thread, JSTaggedValue::Undefined());
|
||||
for (uint32_t index = 0; index < elements->GetLength(); index += 2) { // 2: key-value pair
|
||||
elementsKey.Update(elements->Get(index));
|
||||
elementsValue.Update(elements->Get(index + 1));
|
||||
// class property attribute is not default, will transition to dictionary directly.
|
||||
JSObject::DefinePropertyByLiteral(thread, object, elementsKey, elementsValue, true);
|
||||
|
||||
if (elementsValue->IsJSFunction()) {
|
||||
JSHandle<JSFunction> elementsFunc = JSHandle<JSFunction>::Cast(elementsValue);
|
||||
elementsFunc->SetHomeObject(thread, object);
|
||||
elementsFunc->SetConstantPool(thread, constantpool);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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_CLASS_INFO_EXTRACTOR_H
|
||||
#define ECMASCRIPT_CLASS_INFO_EXTRACTOR_H
|
||||
|
||||
#include "js_tagged_value-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
// ClassInfoExtractor will analyze and extract the contents from class literal to keys, properties and elements(both
|
||||
// non-static and static), later generate the complete hclass (both prototype and constructor) based on keys.
|
||||
// Attention: keys accessor stores the property key and properties accessor stores the property value, but elements
|
||||
// accessor stores the key-value pair abuttally.
|
||||
class ClassInfoExtractor : public TaggedObject {
|
||||
public:
|
||||
static constexpr uint8_t NON_STATIC_RESERVED_LENGTH = 1;
|
||||
static constexpr uint8_t STATIC_RESERVED_LENGTH = 3;
|
||||
|
||||
static constexpr uint8_t CONSTRUCTOR_INDEX = 0;
|
||||
static constexpr uint8_t LENGTH_INDEX = 0;
|
||||
static constexpr uint8_t NAME_INDEX = 1;
|
||||
static constexpr uint8_t PROTOTYPE_INDEX = 2;
|
||||
|
||||
struct ExtractContentsDetail {
|
||||
uint32_t extractBegin;
|
||||
uint32_t extractEnd;
|
||||
uint8_t fillStartLoc;
|
||||
JSMethod *ctorMethod;
|
||||
};
|
||||
|
||||
CAST_CHECK(ClassInfoExtractor, IsClassInfoExtractor);
|
||||
|
||||
using NonStaticWithElementsBit = BitField<bool, 0, 1>;
|
||||
using StaticWithElementsBit = NonStaticWithElementsBit::NextFlag;
|
||||
|
||||
static void BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
|
||||
const JSHandle<TaggedArray> &literal);
|
||||
|
||||
inline void InitializeBitField()
|
||||
{
|
||||
SetBitField(0UL);
|
||||
}
|
||||
|
||||
inline void SetNonStaticWithElements()
|
||||
{
|
||||
uint8_t bits = GetBitField();
|
||||
uint8_t newVal = NonStaticWithElementsBit::Update(bits, true);
|
||||
SetBitField(newVal);
|
||||
}
|
||||
|
||||
inline void SetStaticWithElements()
|
||||
{
|
||||
uint8_t bits = GetBitField();
|
||||
uint8_t newVal = StaticWithElementsBit::Update(bits, true);
|
||||
SetBitField(newVal);
|
||||
}
|
||||
|
||||
inline bool IsNonStaticWithElements() const
|
||||
{
|
||||
return NonStaticWithElementsBit::Decode(GetBitField());
|
||||
}
|
||||
|
||||
inline bool IsStaticWithElements() const
|
||||
{
|
||||
return StaticWithElementsBit::Decode(GetBitField());
|
||||
}
|
||||
|
||||
static constexpr size_t BIT_FIELD_OFFSET = TaggedObjectSize();
|
||||
SET_GET_PRIMITIVE_FIELD(BitField, uint8_t, BIT_FIELD_OFFSET, CONSTRUCTOR_METHOD_OFFSET)
|
||||
SET_GET_NATIVE_FIELD(ConstructorMethod, JSMethod, CONSTRUCTOR_METHOD_OFFSET, PROTOTYPE_HCLASS_OFFSET)
|
||||
ACCESSORS(PrototypeHClass, PROTOTYPE_HCLASS_OFFSET, NON_STATIC_KEYS_OFFSET)
|
||||
ACCESSORS(NonStaticKeys, NON_STATIC_KEYS_OFFSET, NON_STATIC_PROPERTIES_OFFSET)
|
||||
ACCESSORS(NonStaticProperties, NON_STATIC_PROPERTIES_OFFSET, NON_STATIC_ELEMENTS_OFFSET)
|
||||
ACCESSORS(NonStaticElements, NON_STATIC_ELEMENTS_OFFSET, CONSTRUCTOR_HCLASS_OFFSET)
|
||||
ACCESSORS(ConstructorHClass, CONSTRUCTOR_HCLASS_OFFSET, STATIC_KEYS_OFFSET)
|
||||
ACCESSORS(StaticKeys, STATIC_KEYS_OFFSET, STATIC_PROPERTIES_OFFSET)
|
||||
ACCESSORS(StaticProperties, STATIC_PROPERTIES_OFFSET, STATIC_ELEMENTS_OFFSET)
|
||||
ACCESSORS(StaticElements, STATIC_ELEMENTS_OFFSET, SIZE)
|
||||
|
||||
DECL_VISIT_OBJECT(PROTOTYPE_HCLASS_OFFSET, SIZE)
|
||||
DECL_DUMP()
|
||||
|
||||
private:
|
||||
static bool ExtractAndReturnWhetherWithElements(JSThread *thread, const JSHandle<TaggedArray> &literal,
|
||||
const ExtractContentsDetail &detail,
|
||||
JSHandle<TaggedArray> &keys, JSHandle<TaggedArray> &properties,
|
||||
JSHandle<TaggedArray> &elements);
|
||||
|
||||
static JSHandle<JSHClass> CreatePrototypeHClass(JSThread *thread, JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties);
|
||||
|
||||
static JSHandle<JSHClass> CreateConstructorHClass(JSThread *thread, JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties);
|
||||
};
|
||||
|
||||
enum class ClassPropertyType : uint8_t { NON_STATIC = 0, STATIC };
|
||||
|
||||
class ClassHelper {
|
||||
public:
|
||||
static JSHandle<JSFunction> DefineClassTemplate(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
|
||||
const JSHandle<ConstantPool> &constantpool);
|
||||
|
||||
private:
|
||||
static JSHandle<NameDictionary> BuildDictionaryPropeties(JSThread *thread, const JSHandle<JSObject> &object,
|
||||
JSHandle<TaggedArray> &keys,
|
||||
JSHandle<TaggedArray> &properties, ClassPropertyType type,
|
||||
const JSHandle<ConstantPool> &constantpool);
|
||||
|
||||
static void HandleElementsProperties(JSThread *thread, const JSHandle<JSObject> &object,
|
||||
JSHandle<TaggedArray> &elements, const JSHandle<ConstantPool> &constantpool);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_CLASS_INFO_EXTRACTOR_H
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object-inl.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/interpreter/interpreter.h"
|
||||
@@ -138,7 +139,6 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf)
|
||||
JSHandle<JSHClass> normalDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutProto());
|
||||
JSHandle<JSHClass> asyncDynclass = JSHandle<JSHClass>::Cast(env->GetAsyncFunctionClass());
|
||||
JSHandle<JSHClass> generatorDynclass = JSHandle<JSHClass>::Cast(env->GetGeneratorFunctionClass());
|
||||
JSHandle<JSHClass> classDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutName());
|
||||
|
||||
for (const auto &it : constpoolMap_) {
|
||||
ConstPoolValue value(it.second);
|
||||
@@ -202,10 +202,8 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf)
|
||||
panda_file::File::EntityId id(it.first);
|
||||
auto method = const_cast<JSMethod *>(FindMethods(it.first));
|
||||
ASSERT(method != nullptr);
|
||||
JSHandle<JSFunction> jsFunc =
|
||||
factory_->NewJSFunctionByDynClass(method, classDynclass, FunctionKind::CLASS_CONSTRUCTOR);
|
||||
constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
|
||||
jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
|
||||
JSHandle<ClassInfoExtractor> classInfoExtractor = factory_->NewClassInfoExtractor(method);
|
||||
constpool->Set(thread_, value.GetConstpoolIndex(), classInfoExtractor.GetTaggedValue());
|
||||
} else if (value.GetConstpoolType() == ConstPoolType::METHOD) {
|
||||
ASSERT(mainMethodIndex_ != it.first);
|
||||
panda_file::File::EntityId id(it.first);
|
||||
@@ -264,6 +262,7 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf)
|
||||
constpool->Set(thread_, constpoolIndex_, program.GetTaggedValue());
|
||||
}
|
||||
|
||||
DefineClassInConstPool(constpool);
|
||||
return *program;
|
||||
}
|
||||
|
||||
@@ -578,4 +577,29 @@ JSHandle<JSFunction> PandaFileTranslator::DefineMethodInLiteral(JSThread *thread
|
||||
jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));
|
||||
return jsFunc;
|
||||
}
|
||||
|
||||
void PandaFileTranslator::DefineClassInConstPool(const JSHandle<ConstantPool> &constpool) const
|
||||
{
|
||||
array_size_t length = constpool->GetLength();
|
||||
array_size_t index = 0;
|
||||
while (index < length - 1) {
|
||||
JSTaggedValue value = constpool->Get(index);
|
||||
if (!value.IsClassInfoExtractor()) {
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Here, using a law: when inserting ctor in index of constantpool, the index + 1 location will be inserted by
|
||||
// corresponding class literal. Because translator fixes ECMA_DEFINECLASSWITHBUFFER two consecutive times.
|
||||
JSTaggedValue nextValue = constpool->Get(index + 1);
|
||||
ASSERT(nextValue.IsTaggedArray());
|
||||
|
||||
JSHandle<ClassInfoExtractor> extractor(thread_, value);
|
||||
JSHandle<TaggedArray> literal(thread_, nextValue);
|
||||
ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(thread_, extractor, literal);
|
||||
JSHandle<JSFunction> cls = ClassHelper::DefineClassTemplate(thread_, extractor, constpool);
|
||||
constpool->Set(thread_, index, cls);
|
||||
index += 2; // 2: pair of extractor and literal
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
@@ -31,20 +31,6 @@ class PandaFileTranslator {
|
||||
public:
|
||||
enum FixInstructionIndex : uint8_t { FIX_ONE = 1, FIX_TWO = 2, FIX_FOUR = 4 };
|
||||
|
||||
enum SecondInstructionOfMidr : uint8_t {
|
||||
DEFINE_FUNC_DYN = 0,
|
||||
DEFINE_NC_FUNC_DYN,
|
||||
DEFINE_GENERATOR_FUNC_DYN,
|
||||
DEFINE_ASYNC_FUNC_DYN,
|
||||
DEFINE_METHOD
|
||||
};
|
||||
|
||||
enum SecondInstructionOfImm : uint8_t {
|
||||
CREATE_OBJECT_WITH_BUFFER = 2,
|
||||
CREATE_ARRAY_WITH_BUFFER,
|
||||
CREATE_OBJECT_HAVING_METHOD
|
||||
};
|
||||
|
||||
explicit PandaFileTranslator(EcmaVM *vm);
|
||||
~PandaFileTranslator() = default;
|
||||
NO_COPY_SEMANTIC(PandaFileTranslator);
|
||||
@@ -111,6 +97,7 @@ private:
|
||||
void FixInstructionId32(const BytecodeInstruction &inst, uint32_t index, uint32_t fixOrder = 0) const;
|
||||
void FixOpcode(uint8_t *pc) const;
|
||||
void UpdateICOffset(JSMethod *method, uint8_t *pc) const;
|
||||
void DefineClassInConstPool(const JSHandle<ConstantPool> &constpool) const;
|
||||
|
||||
void SetMethods(Span<JSMethod> methods, const uint32_t numMethods)
|
||||
{
|
||||
|
||||
@@ -940,16 +940,15 @@ GateRef Stub::NotBuiltinsConstructor(GateRef object)
|
||||
|
||||
GateRef Stub::IsClassConstructor(GateRef object)
|
||||
{
|
||||
GateRef functionInfoFlagOffset = GetArchRelateConstant(JSFunction::FUNCTION_INFO_FLAG_OFFSET);
|
||||
GateRef functionInfoTaggedValue = Load(MachineType::UINT64, object, functionInfoFlagOffset);
|
||||
GateRef functionInfoInt32 = TaggedCastToInt32(functionInfoTaggedValue);
|
||||
GateRef functionInfoFlag = ZExtInt32ToInt64(functionInfoInt32);
|
||||
GateRef hClass = LoadHClass(object);
|
||||
GateRef bitfieldOffset = GetArchRelateConstant(JSHClass::BIT_FIELD_OFFSET);
|
||||
|
||||
GateRef bitfield = Load(MachineType::UINT32, hClass, bitfieldOffset);
|
||||
// decode
|
||||
return Word64NotEqual(
|
||||
Word64And(
|
||||
Word64LSR(functionInfoFlag, GetWord64Constant(JSFunction::ClassConstructorBit::START_BIT)),
|
||||
GetWord64Constant((1LLU << JSFunction::ClassConstructorBit::SIZE) - 1)),
|
||||
GetWord64Constant(0));
|
||||
return Word32NotEqual(
|
||||
Word32And(Word32LSR(bitfield, GetInt32Constant(JSHClass::ClassConstructorBit::START_BIT)),
|
||||
GetInt32Constant((1LU << JSHClass::ClassConstructorBit::SIZE) - 1)),
|
||||
GetInt32Constant(0));
|
||||
}
|
||||
|
||||
GateRef Stub::IsExtensible(GateRef object)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "ecmascript/accessor_data.h"
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object-inl.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
@@ -251,6 +252,8 @@ CString JSHClass::DumpJSType(JSType type)
|
||||
return "MachineCode";
|
||||
case JSType::ECMA_MODULE:
|
||||
return "EcmaModule";
|
||||
case JSType::CLASS_INFO_EXTRACTOR:
|
||||
return "ClassInfoExtractor";
|
||||
default: {
|
||||
CString ret = "unknown type ";
|
||||
return ret + static_cast<char>(type);
|
||||
@@ -591,6 +594,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os)
|
||||
case JSType::ECMA_MODULE:
|
||||
EcmaModule::Cast(obj)->Dump(thread, os);
|
||||
break;
|
||||
case JSType::CLASS_INFO_EXTRACTOR:
|
||||
ClassInfoExtractor::Cast(obj)->Dump(thread, os);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@@ -1890,6 +1896,34 @@ void EcmaModule::Dump(JSThread *thread, std::ostream &os) const
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void ClassInfoExtractor::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - PrototypeHClass: ";
|
||||
GetPrototypeHClass().D();
|
||||
os << "\n";
|
||||
os << " - NonStaticKeys: ";
|
||||
GetNonStaticKeys().D();
|
||||
os << "\n";
|
||||
os << " - NonStaticProperties: ";
|
||||
GetNonStaticProperties().D();
|
||||
os << "\n";
|
||||
os << " - NonStaticElements: ";
|
||||
GetNonStaticElements().D();
|
||||
os << "\n";
|
||||
os << " - ConstructorHClass: ";
|
||||
GetConstructorHClass().D();
|
||||
os << "\n";
|
||||
os << " - StaticKeys: ";
|
||||
GetStaticKeys().D();
|
||||
os << "\n";
|
||||
os << " - StaticProperties: ";
|
||||
GetStaticProperties().D();
|
||||
os << "\n";
|
||||
os << " - StaticElements: ";
|
||||
GetStaticElements().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
// ########################################################################################
|
||||
// Dump for Snapshot
|
||||
// ########################################################################################
|
||||
@@ -2140,6 +2174,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj,
|
||||
case JSType::PROTOTYPE_HANDLER:
|
||||
PrototypeHandler::Cast(obj)->DumpForSnapshot(thread, vec);
|
||||
return;
|
||||
case JSType::CLASS_INFO_EXTRACTOR:
|
||||
ClassInfoExtractor::Cast(obj)->DumpForSnapshot(thread, vec);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@@ -2958,4 +2995,16 @@ void EcmaModule::DumpForSnapshot(JSThread *thread, std::vector<std::pair<CString
|
||||
{
|
||||
vec.push_back(std::make_pair(CString("NameDictionary"), GetNameDictionary()));
|
||||
}
|
||||
|
||||
void ClassInfoExtractor::DumpForSnapshot(JSThread *thread, std::vector<std::pair<CString, JSTaggedValue>> &vec) const
|
||||
{
|
||||
vec.push_back(std::make_pair(CString("PrototypeHClass"), GetPrototypeHClass()));
|
||||
vec.push_back(std::make_pair(CString("NonStaticKeys"), GetNonStaticKeys()));
|
||||
vec.push_back(std::make_pair(CString("NonStaticProperties"), GetNonStaticProperties()));
|
||||
vec.push_back(std::make_pair(CString("NonStaticElements"), GetNonStaticElements()));
|
||||
vec.push_back(std::make_pair(CString("ConstructorHClass"), GetConstructorHClass()));
|
||||
vec.push_back(std::make_pair(CString("StaticKeys"), GetStaticKeys()));
|
||||
vec.push_back(std::make_pair(CString("StaticProperties"), GetStaticProperties()));
|
||||
vec.push_back(std::make_pair(CString("StaticElements"), GetStaticElements()));
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ecmascript/accessor_data.h"
|
||||
#include "ecmascript/builtins.h"
|
||||
#include "ecmascript/builtins/builtins_global.h"
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
@@ -150,6 +151,9 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl
|
||||
factory->NewEcmaDynClass(dynClassClass, JSRealm::SIZE, JSType::JS_REALM).GetTaggedValue());
|
||||
SetConstant(ConstantIndex::MACHINE_CODE_CLASS_INDEX,
|
||||
factory->NewEcmaDynClass(dynClassClass, 0, JSType::MACHINE_CODE_OBJECT).GetTaggedValue());
|
||||
SetConstant(ConstantIndex::CLASS_INFO_EXTRACTOR_HCLASS_INDEX,
|
||||
factory->NewEcmaDynClass(dynClassClass, ClassInfoExtractor::SIZE, JSType::CLASS_INFO_EXTRACTOR)
|
||||
.GetTaggedValue());
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-size)
|
||||
|
||||
@@ -66,7 +66,8 @@ class JSThread;
|
||||
V(JSTaggedValue, JSProxyConstructClass, JS_PROXY_CONSTRUCT_CLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, JSRealmClass, JS_REALM_CLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, JSRegExpClass, JS_REGEXP_CLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, MachineCodeClass, MACHINE_CODE_CLASS_INDEX, ecma_roots_class)
|
||||
V(JSTaggedValue, MachineCodeClass, MACHINE_CODE_CLASS_INDEX, ecma_roots_class) \
|
||||
V(JSTaggedValue, ClassInfoExtractorHClass, CLASS_INFO_EXTRACTOR_HCLASS_INDEX, ecma_roots_class)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define GLOBAL_ENV_CONSTANT_SPECIAL(V) \
|
||||
|
||||
@@ -3289,25 +3289,31 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
uint16_t v1 = READ_INST_8_8();
|
||||
LOG_INST() << "intrinsics::defineclasswithbuffer"
|
||||
<< " method id:" << methodId << " literal id:" << imm << " lexenv: v" << v0 << " parent: v" << v1;
|
||||
JSFunction *cls = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject());
|
||||
ASSERT(cls != nullptr);
|
||||
if (cls->IsResolved()) {
|
||||
auto res = SlowRuntimeStub::NewClassFunc(thread, cls);
|
||||
INTERPRETER_RETURN_IF_ABRUPT(res);
|
||||
cls = JSFunction::Cast(res.GetTaggedObject());
|
||||
cls->SetConstantPool(thread, JSTaggedValue(constpool));
|
||||
} else {
|
||||
cls->SetResolved(thread);
|
||||
}
|
||||
|
||||
cls->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));
|
||||
JSTaggedValue lexenv = GET_VREG_VALUE(v0);
|
||||
cls->SetLexicalEnv(thread, lexenv);
|
||||
JSFunction *classTemplate = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject());
|
||||
ASSERT(classTemplate != nullptr);
|
||||
|
||||
TaggedArray *literalBuffer = TaggedArray::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject());
|
||||
JSTaggedValue lexenv = GET_VREG_VALUE(v0);
|
||||
JSTaggedValue proto = GET_VREG_VALUE(v1);
|
||||
JSTaggedValue res = SlowRuntimeStub::DefineClass(thread, cls, literalBuffer, proto, lexenv, constpool);
|
||||
|
||||
JSTaggedValue res;
|
||||
if (LIKELY(!classTemplate->IsResolved())) {
|
||||
res = SlowRuntimeStub::ResolveClass(thread, JSTaggedValue(classTemplate), literalBuffer,
|
||||
proto, lexenv, constpool);
|
||||
} else {
|
||||
res = SlowRuntimeStub::CloneClassFromTemplate(thread, JSTaggedValue(classTemplate),
|
||||
proto, lexenv, constpool);
|
||||
}
|
||||
|
||||
INTERPRETER_RETURN_IF_ABRUPT(res);
|
||||
ASSERT(res.IsClassConstructor());
|
||||
JSFunction *cls = JSFunction::Cast(res.GetTaggedObject());
|
||||
|
||||
lexenv = GET_VREG_VALUE(v0); // slow runtime may gc
|
||||
cls->SetLexicalEnv(thread, lexenv);
|
||||
|
||||
SlowRuntimeStub::SetClassConstructorLength(thread, res, JSTaggedValue(length));
|
||||
|
||||
SET_ACC(res);
|
||||
DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_IMM16_V8_V8);
|
||||
}
|
||||
|
||||
@@ -1608,146 +1608,6 @@ JSTaggedValue SlowRuntimeStub::DefinefuncDyn(JSThread *thread, JSFunction *func)
|
||||
return jsFunc.GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::NewClassFunc(JSThread *thread, JSFunction *func)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NewClassFunc);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
auto method = func->GetCallTarget();
|
||||
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSHClass> dynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutName());
|
||||
JSHandle<JSFunction> jsFunc = factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::CLASS_CONSTRUCTOR);
|
||||
ASSERT_NO_ABRUPT_COMPLETION(thread);
|
||||
return jsFunc.GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::DefineClass(JSThread *thread, JSFunction *func, TaggedArray *literal,
|
||||
JSTaggedValue proto, JSTaggedValue lexenv, ConstantPool *constpool)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, DefineClass);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> cls(thread, func);
|
||||
ASSERT(cls->IsJSFunction());
|
||||
JSHandle<TaggedArray> literalBuffer(thread, literal);
|
||||
JSMutableHandle<JSTaggedValue> parent(thread, proto);
|
||||
JSHandle<JSTaggedValue> lexicalEnv(thread, lexenv);
|
||||
JSHandle<ConstantPool> constantpool(thread, constpool);
|
||||
|
||||
cls->GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
JSFunction::Cast(cls->GetTaggedObject())->SetClassConstructor(thread, true);
|
||||
|
||||
/*
|
||||
* set class __proto__
|
||||
*
|
||||
* class A / class A extends null class A extends B
|
||||
* a a
|
||||
* | |
|
||||
* | __proto__ | __proto__
|
||||
* | |
|
||||
* A ----> A.prototype A ----> A.prototype
|
||||
* | | | |
|
||||
* | __proto__ | __proto__ | __proto__ | __proto__
|
||||
* | | | |
|
||||
* Function.prototype Object.prototype / null B ----> B.prototype
|
||||
*/
|
||||
JSMutableHandle<JSTaggedValue> parentPrototype(thread, JSTaggedValue::Undefined());
|
||||
// hole means parent is not present
|
||||
if (parent->IsHole()) {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::CLASS_CONSTRUCTOR);
|
||||
parentPrototype.Update(env->GetObjectFunctionPrototype().GetTaggedValue());
|
||||
parent.Update(env->GetFunctionPrototype().GetTaggedValue());
|
||||
} else if (parent->IsNull()) {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::DERIVED_CONSTRUCTOR);
|
||||
parentPrototype.Update(JSTaggedValue::Null());
|
||||
parent.Update(env->GetFunctionPrototype().GetTaggedValue());
|
||||
} else if (!parent->IsConstructor()) {
|
||||
return ThrowTypeError(thread, "parent class is not constructor");
|
||||
} else {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::DERIVED_CONSTRUCTOR);
|
||||
parentPrototype.Update(JSTaggedValue::GetProperty(thread, parent, globalConst->GetHandledPrototypeString())
|
||||
.GetValue()
|
||||
.GetTaggedValue());
|
||||
if (!parentPrototype->IsECMAObject() && !parentPrototype->IsNull()) {
|
||||
return ThrowTypeError(thread, "parent class have no valid prototype");
|
||||
}
|
||||
}
|
||||
|
||||
// null cannot cast JSObject
|
||||
JSHandle<JSObject> clsPrototype = JSObject::ObjectCreate(thread, JSHandle<JSObject>(parentPrototype));
|
||||
|
||||
bool success = true;
|
||||
success = success && JSFunction::MakeClassConstructor(thread, cls, clsPrototype);
|
||||
clsPrototype.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassPrototype(true);
|
||||
|
||||
success = success && JSObject::SetPrototype(thread, JSHandle<JSObject>::Cast(cls), parent);
|
||||
|
||||
uint32_t bufferLength = literalBuffer->GetLength();
|
||||
// static location is hidden in the last index of Literal buffer
|
||||
uint32_t staticLoc = literalBuffer->Get(thread, bufferLength - 1).GetInt();
|
||||
|
||||
// set property on class.prototype and class
|
||||
JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
|
||||
for (uint32_t i = 0; i < staticLoc * 2; i += 2) { // 2: Each literal buffer contains a pair of key-value.
|
||||
// set non-static property on cls.prototype
|
||||
propKey.Update(literalBuffer->Get(thread, i));
|
||||
propValue.Update(literalBuffer->Get(thread, i + 1));
|
||||
if (propValue->IsJSFunction()) {
|
||||
propValue.Update(
|
||||
factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue), FunctionKind::NORMAL_FUNCTION)
|
||||
.GetTaggedValue());
|
||||
JSHandle<JSFunction> propFunc = JSHandle<JSFunction>::Cast(propValue);
|
||||
propFunc->SetHomeObject(thread, clsPrototype);
|
||||
propFunc->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
|
||||
propFunc->SetConstantPool(thread, constantpool.GetTaggedValue());
|
||||
}
|
||||
PropertyDescriptor desc(thread, propValue, true, false, true); // non-enumerable
|
||||
success = success && JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>::Cast(clsPrototype),
|
||||
propKey, desc);
|
||||
}
|
||||
for (uint32_t i = staticLoc * 2; i < bufferLength - 1; i += 2) { // 2: ditto
|
||||
// set static property on cls
|
||||
propKey.Update(literalBuffer->Get(thread, i));
|
||||
propValue.Update(literalBuffer->Get(thread, i + 1));
|
||||
if (propValue->IsJSFunction()) {
|
||||
propValue.Update(
|
||||
factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue), FunctionKind::NORMAL_FUNCTION)
|
||||
.GetTaggedValue());
|
||||
JSHandle<JSFunction> propFunc = JSHandle<JSFunction>::Cast(propValue);
|
||||
propFunc->SetHomeObject(thread, cls);
|
||||
propFunc->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
|
||||
propFunc->SetConstantPool(thread, constantpool.GetTaggedValue());
|
||||
}
|
||||
PropertyDescriptor desc(thread, propValue, true, false, true); // non-enumerable
|
||||
success = success && JSTaggedValue::DefinePropertyOrThrow(thread, cls, propKey, desc);
|
||||
}
|
||||
|
||||
// ECMA2015 14.5.15: if class don't have a method which is name(), set the class a string name.
|
||||
if (!JSTaggedValue::HasOwnProperty(thread, cls, globalConst->GetHandledNameString())) {
|
||||
JSMethod *clsTarget = JSHandle<JSFunction>::Cast(cls)->GetCallTarget();
|
||||
ASSERT(clsTarget != nullptr);
|
||||
CString clsName = clsTarget->ParseFunctionName();
|
||||
if (!clsName.empty()) {
|
||||
success =
|
||||
success && JSFunction::SetFunctionName(thread, JSHandle<JSFunctionBase>(cls),
|
||||
JSHandle<JSTaggedValue>(factory->NewFromString(clsName.c_str())),
|
||||
globalConst->GetHandledUndefined());
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
return JSTaggedValue::Exception();
|
||||
}
|
||||
|
||||
ASSERT_NO_ABRUPT_COMPLETION(thread);
|
||||
return cls.GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::SuperCall(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget,
|
||||
uint16_t firstVRegIdx, uint16_t length)
|
||||
{
|
||||
@@ -1922,4 +1782,144 @@ JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, JSFunction *f
|
||||
}
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal,
|
||||
JSTaggedValue base, JSTaggedValue lexenv, ConstantPool *constpool)
|
||||
{
|
||||
ASSERT(ctor.IsClassConstructor());
|
||||
JSHandle<JSFunction> cls(thread, ctor);
|
||||
JSHandle<TaggedArray> literalBuffer(thread, literal);
|
||||
JSHandle<JSTaggedValue> lexicalEnv(thread, lexenv);
|
||||
JSHandle<ConstantPool> constpoolHandle(thread, constpool);
|
||||
|
||||
SetClassInheritanceRelationship(thread, ctor, base);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
uint32_t literalBufferLength = literalBuffer->GetLength();
|
||||
|
||||
// only traverse the value of key-value pair
|
||||
for (uint32_t index = 1; index < literalBufferLength - 1; index += 2) { // 2: key-value pair
|
||||
JSTaggedValue value = literalBuffer->Get(index);
|
||||
if (LIKELY(value.IsJSFunction())) {
|
||||
JSFunction::Cast(value.GetTaggedObject())->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
|
||||
JSFunction::Cast(value.GetTaggedObject())->SetConstantPool(thread, constpoolHandle.GetTaggedValue());
|
||||
}
|
||||
}
|
||||
|
||||
cls->SetResolved(thread);
|
||||
return cls.GetTaggedValue();
|
||||
}
|
||||
|
||||
// clone class may need re-set inheritance relationship due to extends may be a variable.
|
||||
JSTaggedValue SlowRuntimeStub::CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base,
|
||||
JSTaggedValue lexenv, ConstantPool *constpool)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
|
||||
ASSERT(ctor.IsClassConstructor());
|
||||
JSHandle<JSTaggedValue> lexenvHandle(thread, lexenv);
|
||||
JSHandle<JSTaggedValue> constpoolHandle(thread, JSTaggedValue(constpool));
|
||||
JSHandle<JSTaggedValue> baseHandle(thread, base);
|
||||
|
||||
JSHandle<JSFunction> cls(thread, ctor);
|
||||
|
||||
JSHandle<JSObject> clsPrototype(thread, cls->GetFunctionPrototype());
|
||||
|
||||
bool canShareHClass = false;
|
||||
if (cls->GetClass()->GetProto() == baseHandle.GetTaggedValue()) {
|
||||
canShareHClass = true;
|
||||
}
|
||||
|
||||
JSHandle<JSFunction> cloneClass = factory->CloneClassCtor(cls, lexenvHandle, canShareHClass);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSObject> cloneClassPrototype = factory->CloneObjectLiteral(JSHandle<JSObject>(clsPrototype), lexenvHandle,
|
||||
constpoolHandle, canShareHClass);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
// After clone both, reset "constructor" and "prototype" properties.
|
||||
cloneClass->SetFunctionPrototype(thread, cloneClassPrototype.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
PropertyDescriptor ctorDesc(thread, JSHandle<JSTaggedValue>(cloneClass), true, false, true);
|
||||
JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(cloneClassPrototype),
|
||||
globalConst->GetHandledConstructorString(), ctorDesc);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
cloneClass->SetHomeObject(thread, cloneClassPrototype);
|
||||
|
||||
if (!canShareHClass) {
|
||||
SetClassInheritanceRelationship(thread, cloneClass.GetTaggedValue(), baseHandle.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
|
||||
return cloneClass.GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::SetClassInheritanceRelationship(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
|
||||
JSHandle<JSTaggedValue> cls(thread, ctor);
|
||||
ASSERT(cls->IsJSFunction());
|
||||
JSMutableHandle<JSTaggedValue> parent(thread, base);
|
||||
|
||||
/*
|
||||
* class A / class A extends null class A extends B
|
||||
* a a
|
||||
* | |
|
||||
* | __proto__ | __proto__
|
||||
* | |
|
||||
* A ----> A.prototype A ----> A.prototype
|
||||
* | | | |
|
||||
* | __proto__ | __proto__ | __proto__ | __proto__
|
||||
* | | | |
|
||||
* Function.prototype Object.prototype / null B ----> B.prototype
|
||||
*/
|
||||
|
||||
JSHandle<JSTaggedValue> parentPrototype;
|
||||
// hole means parent is not present
|
||||
if (parent->IsHole()) {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::CLASS_CONSTRUCTOR);
|
||||
parentPrototype = env->GetObjectFunctionPrototype();
|
||||
parent.Update(env->GetFunctionPrototype().GetTaggedValue());
|
||||
} else if (parent->IsNull()) {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::DERIVED_CONSTRUCTOR);
|
||||
parentPrototype = JSHandle<JSTaggedValue>(thread, JSTaggedValue::Null());
|
||||
parent.Update(env->GetFunctionPrototype().GetTaggedValue());
|
||||
} else if (!parent->IsConstructor()) {
|
||||
return ThrowTypeError(thread, "parent class is not constructor");
|
||||
} else {
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionKind(thread, FunctionKind::DERIVED_CONSTRUCTOR);
|
||||
parentPrototype = JSTaggedValue::GetProperty(thread, parent,
|
||||
globalConst->GetHandledPrototypeString()).GetValue();
|
||||
if (!parentPrototype->IsECMAObject() && !parentPrototype->IsNull()) {
|
||||
return ThrowTypeError(thread, "parent class have no valid prototype");
|
||||
}
|
||||
}
|
||||
|
||||
cls->GetTaggedObject()->GetClass()->SetPrototype(thread, parent);
|
||||
|
||||
JSHandle<JSObject> clsPrototype(thread, JSHandle<JSFunction>(cls)->GetFunctionPrototype());
|
||||
clsPrototype->GetClass()->SetPrototype(thread, parentPrototype);
|
||||
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
|
||||
JSTaggedValue SlowRuntimeStub::SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length)
|
||||
{
|
||||
ASSERT(ctor.IsClassConstructor());
|
||||
|
||||
JSFunction* cls = JSFunction::Cast(ctor.GetTaggedObject());
|
||||
if (LIKELY(!cls->GetClass()->IsDictionaryMode())) {
|
||||
cls->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, length);
|
||||
} else {
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
cls->UpdatePropertyInDictionary(thread, globalConst->GetLengthString(), length);
|
||||
}
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -135,10 +135,7 @@ public:
|
||||
static JSTaggedValue DefineAsyncFunc(JSThread *thread, JSFunction *func);
|
||||
static JSTaggedValue DefineNCFuncDyn(JSThread *thread, JSFunction *func);
|
||||
static JSTaggedValue DefinefuncDyn(JSThread *thread, JSFunction *func);
|
||||
static JSTaggedValue NewClassFunc(JSThread *thread, JSFunction *func);
|
||||
|
||||
static JSTaggedValue DefineClass(JSThread *thread, JSFunction *func, TaggedArray *literal, JSTaggedValue proto,
|
||||
JSTaggedValue lexenv, ConstantPool *constpool);
|
||||
static JSTaggedValue SuperCall(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, uint16_t firstVRegIdx,
|
||||
uint16_t length);
|
||||
static JSTaggedValue SuperCallSpread(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget,
|
||||
@@ -149,12 +146,19 @@ public:
|
||||
JSTaggedValue thisFunc);
|
||||
static JSTaggedValue NotifyInlineCache(JSThread *thread, JSFunction *func, JSMethod *method);
|
||||
static JSTaggedValue ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc);
|
||||
|
||||
static JSTaggedValue ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, JSTaggedValue base,
|
||||
JSTaggedValue lexenv, ConstantPool *constpool);
|
||||
static JSTaggedValue CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base,
|
||||
JSTaggedValue lexenv, ConstantPool *constpool);
|
||||
static JSTaggedValue SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length);
|
||||
/* -------------- Common API End, Don't change those interface!!! ----------------- */
|
||||
|
||||
private:
|
||||
static JSTaggedValue ThrowTypeError(JSThread *thread, const char *message);
|
||||
static JSTaggedValue ThrowSyntaxError(JSThread *thread, const char *message);
|
||||
static JSTaggedValue GetCallSpreadArgs(JSThread *thread, JSTaggedValue array);
|
||||
static JSTaggedValue SetClassInheritanceRelationship(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "js_function.h"
|
||||
|
||||
#include "ecmascript/base/error_type.h"
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/ecma_runtime_call_info.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
@@ -51,7 +52,6 @@ void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunctio
|
||||
func->SetFunctionExtraInfo(thread, JSTaggedValue::Undefined());
|
||||
func->SetFunctionInfoFlag(thread, JSTaggedValue(flag));
|
||||
|
||||
ASSERT(!func->IsPropertiesDict());
|
||||
auto globalConst = thread->GlobalConstants();
|
||||
if (HasPrototype(kind)) {
|
||||
JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
|
||||
@@ -59,9 +59,7 @@ void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunctio
|
||||
func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
|
||||
accessor = globalConst->GetHandledFunctionNameAccessor();
|
||||
func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
|
||||
} else if (JSFunction::IsClassConstructor(kind)) {
|
||||
func->SetPropertyInlinedProps(thread, CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
|
||||
} else {
|
||||
} else if (!JSFunction::IsClassConstructor(kind)) { // class ctor do nothing
|
||||
PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
|
||||
[[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(func),
|
||||
globalConst->GetHandledPrototypeString(), desc);
|
||||
@@ -247,21 +245,6 @@ bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &f
|
||||
return status;
|
||||
}
|
||||
|
||||
// set property constructor and prototype for class
|
||||
bool JSFunction::MakeClassConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &cls,
|
||||
const JSHandle<JSObject> &clsPrototype)
|
||||
{
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
bool status = true;
|
||||
PropertyDescriptor ctorDesc(thread, cls, true, false, true);
|
||||
status = status && JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>::Cast(clsPrototype),
|
||||
globalConst->GetHandledConstructorString(), ctorDesc);
|
||||
|
||||
JSHandle<JSFunction>::Cast(cls)->SetFunctionPrototype(thread, clsPrototype.GetTaggedValue());
|
||||
JSHandle<JSFunction>::Cast(cls)->SetHomeObject(thread, clsPrototype.GetTaggedValue());
|
||||
return status;
|
||||
}
|
||||
|
||||
JSTaggedValue JSFunction::Call(JSThread *thread, const JSHandle<JSTaggedValue> &func,
|
||||
const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[])
|
||||
{
|
||||
@@ -378,12 +361,6 @@ JSTaggedValue JSFunction::ConstructInternal(JSThread *thread, const JSHandle<JSF
|
||||
return obj.GetTaggedValue();
|
||||
}
|
||||
|
||||
void JSFunction::MakeMethod(const JSThread *thread, const JSHandle<JSFunction> &func,
|
||||
const JSHandle<JSObject> &homeObject)
|
||||
{
|
||||
func->SetHomeObject(thread, homeObject);
|
||||
}
|
||||
|
||||
JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
|
||||
{
|
||||
JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
|
||||
@@ -602,6 +579,7 @@ JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHa
|
||||
JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
|
||||
// guarante derived has function prototype
|
||||
JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrDynClass());
|
||||
ASSERT(!prototype->IsHole());
|
||||
newJSHClass->SetPrototype(thread, prototype);
|
||||
derived->SetProtoOrDynClass(thread, newJSHClass);
|
||||
return newJSHClass;
|
||||
|
||||
+13
-19
@@ -94,10 +94,6 @@ public:
|
||||
static bool AddRestrictedFunctionProperties(const JSHandle<JSFunction> &func, const JSHandle<JSTaggedValue> &realm);
|
||||
static bool MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
|
||||
const JSHandle<JSTaggedValue> &proto, bool writable = true);
|
||||
static bool MakeClassConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &cls,
|
||||
const JSHandle<JSObject> &clsPrototype);
|
||||
static void MakeMethod(const JSThread *thread, const JSHandle<JSFunction> &func,
|
||||
const JSHandle<JSObject> &homeObject);
|
||||
static bool SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length,
|
||||
bool cfg = true);
|
||||
static JSHandle<JSObject> NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory,
|
||||
@@ -171,7 +167,7 @@ public:
|
||||
inline bool IsDerivedConstructor() const
|
||||
{
|
||||
FunctionKind kind = GetFunctionKind();
|
||||
return kind == FunctionKind::DERIVED_CONSTRUCTOR || kind == FunctionKind::DEFAULT_DERIVED_CONSTRUCTOR;
|
||||
return kind == FunctionKind::DERIVED_CONSTRUCTOR;
|
||||
}
|
||||
|
||||
inline void SetFunctionKind(const JSThread *thread, FunctionKind kind)
|
||||
@@ -186,12 +182,6 @@ public:
|
||||
SetFunctionInfoFlag(thread, JSTaggedValue(StrictBit::Update(oldValue, flag)));
|
||||
}
|
||||
|
||||
inline void SetClassConstructor(const JSThread *thread, bool flag)
|
||||
{
|
||||
JSTaggedType oldValue = GetFunctionInfoFlag().GetRawData();
|
||||
SetFunctionInfoFlag(thread, JSTaggedValue(ClassConstructorBit::Update(oldValue, flag)));
|
||||
}
|
||||
|
||||
inline void SetResolved(const JSThread *thread)
|
||||
{
|
||||
TaggedType oldValue = GetFunctionInfoFlag().GetRawData();
|
||||
@@ -219,11 +209,6 @@ public:
|
||||
return StrictBit::Decode(GetFunctionInfoFlag().GetInt());
|
||||
}
|
||||
|
||||
inline bool IsClassConstructor() const
|
||||
{
|
||||
return ClassConstructorBit::Decode(GetFunctionInfoFlag().GetInt());
|
||||
}
|
||||
|
||||
inline FunctionMode GetFunctionMode() const
|
||||
{
|
||||
return ThisModeBit::Decode(GetFunctionInfoFlag().GetInt());
|
||||
@@ -236,7 +221,7 @@ public:
|
||||
|
||||
inline static bool IsClassConstructor(FunctionKind kind)
|
||||
{
|
||||
return (kind >= CLASS_CONSTRUCTOR) && (kind <= DERIVED_CONSTRUCTOR);
|
||||
return (kind == CLASS_CONSTRUCTOR) || (kind == DERIVED_CONSTRUCTOR);
|
||||
}
|
||||
|
||||
inline static bool IsConstructorKind(FunctionKind kind)
|
||||
@@ -259,6 +244,16 @@ public:
|
||||
return kind >= NORMAL_FUNCTION && kind <= ASYNC_FUNCTION;
|
||||
}
|
||||
|
||||
inline bool IsClassConstructor() const
|
||||
{
|
||||
return GetClass()->IsClassConstructor();
|
||||
}
|
||||
|
||||
inline void SetClassConstructor(bool flag)
|
||||
{
|
||||
GetClass()->SetClassConstructor(flag);
|
||||
}
|
||||
|
||||
/* -------------- Common API End, Don't change those interface!!! ----------------- */
|
||||
static void InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func,
|
||||
FunctionKind kind = FunctionKind::NORMAL_FUNCTION, bool strict = true);
|
||||
@@ -278,9 +273,8 @@ public:
|
||||
static constexpr uint32_t FUNCTION_KIND_BIT_NUM = 5;
|
||||
using FunctionKindBit = BitField<FunctionKind, 0, FUNCTION_KIND_BIT_NUM>;
|
||||
using StrictBit = FunctionKindBit::NextFlag;
|
||||
using ClassConstructorBit = StrictBit::NextFlag;
|
||||
|
||||
using ResolvedBit = ClassConstructorBit::NextFlag;
|
||||
using ResolvedBit = StrictBit::NextFlag;
|
||||
using ThisModeBit = ResolvedBit::NextField<FunctionMode, 2>; // 2: means this flag occupies two digits.
|
||||
|
||||
DECL_DUMP()
|
||||
|
||||
@@ -38,11 +38,8 @@ enum FunctionKind : uint8_t {
|
||||
// END base constructors
|
||||
// BEGIN class constructors
|
||||
CLASS_CONSTRUCTOR,
|
||||
// BEGIN derived constructors
|
||||
DEFAULT_DERIVED_CONSTRUCTOR,
|
||||
// END default constructors
|
||||
DERIVED_CONSTRUCTOR,
|
||||
// END derived constructors
|
||||
// END class constructors
|
||||
GENERATOR_FUNCTION,
|
||||
// END generators
|
||||
|
||||
@@ -287,6 +287,7 @@ void JSHClass::SetPrototype(const JSThread *thread, JSTaggedValue proto)
|
||||
}
|
||||
SetProto(thread, proto);
|
||||
}
|
||||
|
||||
void JSHClass::SetPrototype(const JSThread *thread, const JSHandle<JSTaggedValue> &proto)
|
||||
{
|
||||
SetPrototype(thread, proto.GetTaggedValue());
|
||||
|
||||
@@ -159,7 +159,8 @@ class ProtoChangeDetails;
|
||||
COMPLETION_RECORD, /* JS_RECORD_END /////////////////////////////////////////////////////////////////////// */ \
|
||||
MACHINE_CODE_OBJECT, \
|
||||
ECMA_MODULE, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_TYPE_LAST = ECMA_MODULE, /* ////////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
CLASS_INFO_EXTRACTOR, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_TYPE_LAST = CLASS_INFO_EXTRACTOR, /* ///////////////////////////////////////////////////////////-PADDING */ \
|
||||
\
|
||||
JS_FUNCTION_BEGIN = JS_FUNCTION, /* ///////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_FUNCTION_END = JS_ASYNC_AWAIT_STATUS_FUNCTION, /* //////////////////////////////////////////////-PADDING */ \
|
||||
@@ -686,6 +687,11 @@ public:
|
||||
return GetObjectType() == JSType::ECMA_MODULE;
|
||||
}
|
||||
|
||||
inline bool IsClassInfoExtractor() const
|
||||
{
|
||||
return GetObjectType() == JSType::CLASS_INFO_EXTRACTOR;
|
||||
}
|
||||
|
||||
inline bool IsLexicalFunction() const
|
||||
{
|
||||
return GetObjectType() == JSType::LEXICAL_FUNCTION;
|
||||
|
||||
@@ -1757,11 +1757,14 @@ JSHandle<JSForInIterator> JSObject::EnumerateObjectProperties(JSThread *thread,
|
||||
}
|
||||
|
||||
void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
|
||||
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
|
||||
bool useForClass)
|
||||
{
|
||||
ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
|
||||
ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
|
||||
auto attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes());
|
||||
PropertyAttributes attr = useForClass ? PropertyAttributes::Default(true, false, true)
|
||||
: PropertyAttributes::Default();
|
||||
|
||||
if (value->IsAccessorData()) {
|
||||
attr.SetIsAccessor(true);
|
||||
}
|
||||
|
||||
@@ -552,7 +552,8 @@ public:
|
||||
bool IsTypedArray() const;
|
||||
|
||||
static void DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
|
||||
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,
|
||||
|
||||
@@ -840,6 +840,11 @@ inline bool JSTaggedValue::IsMachineCodeObject() const
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsMachineCodeObject();
|
||||
}
|
||||
|
||||
inline bool JSTaggedValue::IsClassInfoExtractor() const
|
||||
{
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsClassInfoExtractor();
|
||||
}
|
||||
|
||||
inline double JSTaggedValue::ExtractNumber() const
|
||||
{
|
||||
ASSERT(IsNumber());
|
||||
|
||||
@@ -319,6 +319,7 @@ public:
|
||||
bool IsProtoChangeMarker() const;
|
||||
bool IsProtoChangeDetails() const;
|
||||
bool IsMachineCodeObject() const;
|
||||
bool IsClassInfoExtractor() const;
|
||||
static bool IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y);
|
||||
|
||||
static ComparisonResult Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define ECMASCRIPT_MEM_HEAP_ROOTS_INL_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
@@ -296,6 +297,9 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec
|
||||
case JSType::MACHINE_CODE_OBJECT:
|
||||
MachineCode::Cast(object)->VisitRangeSlot(visitor);
|
||||
break;
|
||||
case JSType::CLASS_INFO_EXTRACTOR:
|
||||
ClassInfoExtractor::Cast(object)->VisitRangeSlot(visitor);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -856,6 +856,12 @@ Local<FunctionRef> FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallbackWit
|
||||
vm->GetMethodForNativeFunction(reinterpret_cast<void *>(Callback::RegisterCallbackWithNewTarget));
|
||||
JSHandle<JSFunction> current =
|
||||
factory->NewJSFunctionByDynClass(method, dynclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR);
|
||||
|
||||
auto globalConst = thread->GlobalConstants();
|
||||
JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
|
||||
current->SetPropertyInlinedProps(thread, JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX,
|
||||
accessor.GetTaggedValue());
|
||||
|
||||
JSHandle<JSNativePointer> funcCallback = factory->NewJSNativePointer(reinterpret_cast<void *>(nativeFunc));
|
||||
JSHandle<JSNativePointer> dataCaddress(thread, JSTaggedValue::Undefined());
|
||||
if (deleter == nullptr) {
|
||||
@@ -867,14 +873,13 @@ Local<FunctionRef> FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallbackWit
|
||||
JSHandle<JSFunctionExtraInfo> extraInfo(factory->NewFunctionExtraInfo(funcCallback, dataCaddress));
|
||||
current->SetFunctionExtraInfo(thread, extraInfo.GetTaggedValue());
|
||||
|
||||
JSHandle<JSObject> clsPrototype =
|
||||
JSObject::ObjectCreate(thread, JSHandle<JSObject>(env->GetObjectFunctionPrototype()));
|
||||
JSHandle<JSObject> clsPrototype = JSFunction::NewJSFunctionPrototype(thread, factory, current);
|
||||
clsPrototype.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassPrototype(true);
|
||||
JSHandle<JSTaggedValue>::Cast(current)->GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
current->SetClassConstructor(thread, true);
|
||||
current->SetClassConstructor(true);
|
||||
JSHandle<JSTaggedValue> parent = env->GetFunctionPrototype();
|
||||
JSObject::SetPrototype(thread, JSHandle<JSObject>::Cast(current), parent);
|
||||
JSFunction::MakeClassConstructor(thread, JSHandle<JSTaggedValue>::Cast(current), clsPrototype);
|
||||
current->SetHomeObject(thread, clsPrototype);
|
||||
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
|
||||
}
|
||||
|
||||
|
||||
@@ -693,4 +693,17 @@ HWTEST_F_L0(JSNApiTests, InheritPrototype)
|
||||
JSHandle<JSFunction> son1Handle = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(son1));
|
||||
ASSERT_TRUE(son1Handle->HasFunctionPrototype());
|
||||
}
|
||||
|
||||
HWTEST_F_L0(JSNApiTests, ClassFunction)
|
||||
{
|
||||
LocalScope scope(vm_);
|
||||
Local<FunctionRef> cls = FunctionRef::NewClassFunction(vm_, nullptr, nullptr, nullptr);
|
||||
|
||||
JSHandle<JSTaggedValue> clsObj = JSNApiHelper::ToJSHandle(Local<JSValueRef>(cls));
|
||||
ASSERT_TRUE(clsObj->IsClassConstructor());
|
||||
|
||||
JSTaggedValue accessor = JSHandle<JSFunction>(clsObj)->GetPropertyInlinedProps(
|
||||
JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX);
|
||||
ASSERT_TRUE(accessor.IsInternalAccessor());
|
||||
}
|
||||
} // namespace panda::test
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ecmascript/builtins.h"
|
||||
#include "ecmascript/builtins/builtins_errors.h"
|
||||
#include "ecmascript/builtins/builtins_global.h"
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
@@ -152,6 +153,7 @@ void ObjectFactory::ObtainRootClass([[maybe_unused]] const JSHandle<GlobalEnv> &
|
||||
functionExtraInfo_ = JSHClass::Cast(globalConst->GetFunctionExtraInfoClass().GetTaggedObject());
|
||||
jsRealmClass_ = JSHClass::Cast(globalConst->GetJSRealmClass().GetTaggedObject());
|
||||
machineCodeClass_ = JSHClass::Cast(globalConst->GetMachineCodeClass().GetTaggedObject());
|
||||
classInfoExtractorHClass_ = JSHClass::Cast(globalConst->GetClassInfoExtractorHClass().GetTaggedObject());
|
||||
}
|
||||
|
||||
void ObjectFactory::InitObjectFields(const TaggedObject *object)
|
||||
@@ -395,11 +397,15 @@ JSHandle<TaggedArray> ObjectFactory::CloneProperties(const JSHandle<TaggedArray>
|
||||
}
|
||||
|
||||
JSHandle<JSObject> ObjectFactory::CloneObjectLiteral(JSHandle<JSObject> object, const JSHandle<JSTaggedValue> &env,
|
||||
const JSHandle<JSTaggedValue> &constpool)
|
||||
const JSHandle<JSTaggedValue> &constpool, bool canShareHClass)
|
||||
{
|
||||
NewObjectHook();
|
||||
auto klass = JSHandle<JSHClass>(thread_, object->GetClass());
|
||||
|
||||
if (!canShareHClass) {
|
||||
klass = JSHClass::Clone(thread_, klass);
|
||||
}
|
||||
|
||||
JSHandle<JSObject> cloneObject = NewJSObject(klass);
|
||||
|
||||
JSHandle<TaggedArray> elements(thread_, object->GetElements());
|
||||
@@ -444,6 +450,49 @@ JSHandle<JSFunction> ObjectFactory::CloneJSFuction(JSHandle<JSFunction> obj, Fun
|
||||
return cloneFunc;
|
||||
}
|
||||
|
||||
JSHandle<JSFunction> ObjectFactory::CloneClassCtor(JSHandle<JSFunction> ctor, const JSHandle<JSTaggedValue> &lexenv,
|
||||
bool canShareHClass)
|
||||
{
|
||||
NewObjectHook();
|
||||
JSHandle<JSTaggedValue> constpool(thread_, ctor->GetConstantPool());
|
||||
JSHandle<JSHClass> hclass(thread_, ctor->GetClass());
|
||||
|
||||
if (!canShareHClass) {
|
||||
hclass = JSHClass::Clone(thread_, hclass);
|
||||
}
|
||||
|
||||
FunctionKind kind = ctor->GetFunctionKind();
|
||||
ASSERT_PRINT(kind == FunctionKind::CLASS_CONSTRUCTOR || kind == FunctionKind::DERIVED_CONSTRUCTOR,
|
||||
"cloned function is not class");
|
||||
JSHandle<JSFunction> cloneCtor = NewJSFunctionByDynClass(ctor->GetCallTarget(), hclass, kind);
|
||||
|
||||
for (uint32_t i = 0; i < hclass->GetInlinedProperties(); i++) {
|
||||
JSTaggedValue value = ctor->GetPropertyInlinedProps(i);
|
||||
if (!value.IsJSFunction()) {
|
||||
cloneCtor->SetPropertyInlinedProps(thread_, i, value);
|
||||
} else {
|
||||
JSHandle<JSFunction> valueHandle(thread_, value);
|
||||
JSHandle<JSFunction> newFunc = CloneJSFuction(valueHandle, valueHandle->GetFunctionKind());
|
||||
newFunc->SetLexicalEnv(thread_, lexenv);
|
||||
newFunc->SetHomeObject(thread_, cloneCtor);
|
||||
newFunc->SetConstantPool(thread_, constpool);
|
||||
cloneCtor->SetPropertyInlinedProps(thread_, i, newFunc.GetTaggedValue());
|
||||
}
|
||||
}
|
||||
|
||||
JSHandle<TaggedArray> elements(thread_, ctor->GetElements());
|
||||
auto newElements = CloneProperties(elements, lexenv, JSHandle<JSObject>(cloneCtor), constpool);
|
||||
cloneCtor->SetElements(thread_, newElements.GetTaggedValue());
|
||||
|
||||
JSHandle<TaggedArray> properties(thread_, ctor->GetProperties());
|
||||
auto newProperties = CloneProperties(properties, lexenv, JSHandle<JSObject>(cloneCtor), constpool);
|
||||
cloneCtor->SetProperties(thread_, newProperties.GetTaggedValue());
|
||||
|
||||
cloneCtor->SetConstantPool(thread_, constpool);
|
||||
|
||||
return cloneCtor;
|
||||
}
|
||||
|
||||
JSHandle<JSObject> ObjectFactory::NewNonMovableJSObject(const JSHandle<JSHClass> &jshclass)
|
||||
{
|
||||
JSHandle<JSObject> obj(thread_,
|
||||
@@ -1989,6 +2038,25 @@ JSHandle<MachineCode> ObjectFactory::NewMachineCodeObject(size_t length, const u
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
JSHandle<ClassInfoExtractor> ObjectFactory::NewClassInfoExtractor(JSMethod *ctorMethod)
|
||||
{
|
||||
NewObjectHook();
|
||||
TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject(classInfoExtractorHClass_);
|
||||
JSHandle<ClassInfoExtractor> obj(thread_, header);
|
||||
obj->InitializeBitField();
|
||||
obj->SetConstructorMethod(ctorMethod);
|
||||
JSHandle<TaggedArray> emptyArray = EmptyArray();
|
||||
obj->SetPrototypeHClass(thread_, JSTaggedValue::Undefined());
|
||||
obj->SetNonStaticKeys(thread_, emptyArray, SKIP_BARRIER);
|
||||
obj->SetNonStaticProperties(thread_, emptyArray, SKIP_BARRIER);
|
||||
obj->SetNonStaticElements(thread_, emptyArray, SKIP_BARRIER);
|
||||
obj->SetConstructorHClass(thread_, JSTaggedValue::Undefined());
|
||||
obj->SetStaticKeys(thread_, emptyArray, SKIP_BARRIER);
|
||||
obj->SetStaticProperties(thread_, emptyArray, SKIP_BARRIER);
|
||||
obj->SetStaticElements(thread_, emptyArray, SKIP_BARRIER);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ----------------------------------- new string ----------------------------------------
|
||||
JSHandle<EcmaString> ObjectFactory::NewFromString(const CString &data)
|
||||
{
|
||||
|
||||
@@ -95,6 +95,7 @@ class ProtoChangeMarker;
|
||||
class ProtoChangeDetails;
|
||||
class ProfileTypeInfo;
|
||||
class MachineCode;
|
||||
class ClassInfoExtractor;
|
||||
|
||||
enum class PrimitiveType : uint8_t;
|
||||
enum class IterationKind;
|
||||
@@ -282,10 +283,12 @@ public:
|
||||
JSHandle<JSPromiseAllResolveElementFunction> NewJSPromiseAllResolveElementFunction(const void *nativeFunc);
|
||||
|
||||
JSHandle<JSObject> CloneObjectLiteral(JSHandle<JSObject> object, const JSHandle<JSTaggedValue> &env,
|
||||
const JSHandle<JSTaggedValue> &constpool);
|
||||
const JSHandle<JSTaggedValue> &constpool, bool canShareHClass = true);
|
||||
JSHandle<JSObject> CloneObjectLiteral(JSHandle<JSObject> object);
|
||||
JSHandle<JSArray> CloneArrayLiteral(JSHandle<JSArray> object);
|
||||
JSHandle<JSFunction> CloneJSFuction(JSHandle<JSFunction> obj, FunctionKind kind);
|
||||
JSHandle<JSFunction> CloneClassCtor(JSHandle<JSFunction> ctor, const JSHandle<JSTaggedValue> &lexenv,
|
||||
bool canShareHClass);
|
||||
|
||||
void NewJSArrayBufferData(const JSHandle<JSArrayBuffer> &array, int32_t length);
|
||||
|
||||
@@ -328,6 +331,7 @@ public:
|
||||
|
||||
uintptr_t NewSpaceBySnapShotAllocator(size_t size);
|
||||
JSHandle<MachineCode> NewMachineCodeObject(size_t length, const uint8_t *data);
|
||||
JSHandle<ClassInfoExtractor> NewClassInfoExtractor(JSMethod *ctorMethod);
|
||||
|
||||
~ObjectFactory() = default;
|
||||
|
||||
@@ -407,6 +411,7 @@ private:
|
||||
JSHClass *programClass_ {nullptr};
|
||||
JSHClass *machineCodeClass_ {nullptr};
|
||||
JSHClass *ecmaModuleClass_ {nullptr};
|
||||
JSHClass *classInfoExtractorHClass_ {nullptr};
|
||||
|
||||
EcmaVM *vm_ {nullptr};
|
||||
Heap *heap_ {nullptr};
|
||||
@@ -462,6 +467,7 @@ private:
|
||||
friend class PandaFileTranslator;
|
||||
friend class LiteralDataExtractor;
|
||||
friend class RuntimeTrampolines;
|
||||
friend class ClassInfoExtractor;
|
||||
};
|
||||
|
||||
class ClassLinkerFactory {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/accessor_data.h"
|
||||
#include "ecmascript/class_info_extractor.h"
|
||||
#include "ecmascript/class_linker/program_object-inl.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
@@ -614,6 +615,12 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
|
||||
DUMP_FOR_HANDLE(ecmaModule)
|
||||
break;
|
||||
}
|
||||
case JSType::CLASS_INFO_EXTRACTOR: {
|
||||
CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ClassInfoExtractor::SIZE, 10)
|
||||
JSHandle<ClassInfoExtractor> classInfoExtractor = factory->NewClassInfoExtractor(nullptr);
|
||||
DUMP_FOR_HANDLE(classInfoExtractor)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ECMA_MEM(ERROR) << "JSType " << static_cast<int>(type) << " cannot be dumped.";
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -47,7 +47,7 @@ def judge_output(args):
|
||||
subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
env={'LD_LIBRARY_PATH': str(input_args.env_path)})
|
||||
try:
|
||||
out, err = subp.communicate(timeout=120) # units: s
|
||||
out, err = subp.communicate(timeout=300) # units: s
|
||||
except TimeoutExpired:
|
||||
subp.kill()
|
||||
out, err = subp.communicate()
|
||||
|
||||
Reference in New Issue
Block a user