mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 16:13:49 +00:00
Merge branch 'master' of gitee.com:openharmony/arkcompiler_ets_runtime into master
Signed-off-by: 王笑佳 <wangxiaojia5@huawei.com>
This commit is contained in:
commit
fc1b6f3890
14
BUILD.gn
14
BUILD.gn
@ -752,6 +752,7 @@ ecma_source = [
|
||||
"ecmascript/pgo_profiler/pgo_utils.cpp",
|
||||
"ecmascript/pgo_profiler/ap_file/pgo_method_type_set.cpp",
|
||||
"ecmascript/pgo_profiler/types/pgo_profile_type.cpp",
|
||||
"ecmascript/property_accessor.cpp",
|
||||
"ecmascript/stackmap/ark_stackmap_builder.cpp",
|
||||
"ecmascript/stackmap/ark_stackmap_parser.cpp",
|
||||
"ecmascript/stackmap/llvm_stackmap_parser.cpp",
|
||||
@ -979,7 +980,7 @@ ohos_source_set("libark_jsruntime_set") {
|
||||
if (is_ohos && is_standard_system && product_name != "ohos-sdk") {
|
||||
if (!is_cross_platform_build) {
|
||||
defines += [ "ENABLE_QOS" ]
|
||||
external_deps += [ "frame_aware_sched:qos_manager" ]
|
||||
external_deps += [ "qos_manager:qos" ]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,7 +1070,7 @@ ohos_source_set("libark_jsruntime_test_set") {
|
||||
if (is_ohos && is_standard_system && product_name != "ohos-sdk") {
|
||||
if (!is_cross_platform_build) {
|
||||
defines += [ "ENABLE_QOS" ]
|
||||
external_deps += [ "frame_aware_sched:qos_manager" ]
|
||||
external_deps += [ "qos_manager:qos" ]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1219,3 +1220,12 @@ ohos_shared_library("libark_jsruntime_test") {
|
||||
}
|
||||
subsystem_name = "test"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("app_aot_white_list") {
|
||||
relative_install_dir = "ark"
|
||||
source = "$js_root/ecmascript/ohos/app_aot_white_list.conf"
|
||||
|
||||
# Set the subsystem name
|
||||
part_name = "ets_runtime"
|
||||
subsystem_name = "arkcompiler"
|
||||
}
|
||||
|
@ -23,9 +23,9 @@
|
||||
"deps": {
|
||||
"components": [
|
||||
"faultloggerd",
|
||||
"frame_aware_sched",
|
||||
"hitrace",
|
||||
"hilog",
|
||||
"qos_manager",
|
||||
"runtime_core",
|
||||
"c_utils",
|
||||
"code_signature"
|
||||
@ -38,6 +38,7 @@
|
||||
},
|
||||
"build": {
|
||||
"sub_component": [
|
||||
"//arkcompiler/ets_runtime:app_aot_white_list",
|
||||
"//arkcompiler/ets_runtime:ark_js_packages"
|
||||
],
|
||||
"inner_kits": [
|
||||
|
@ -32,8 +32,8 @@ class JSArray;
|
||||
namespace base {
|
||||
class BuiltinConstantEntry {
|
||||
public:
|
||||
constexpr BuiltinConstantEntry(std::string_view name, JSTaggedValue value) :
|
||||
name_(name), rawTaggedValue_(value.GetRawData()) {}
|
||||
constexpr BuiltinConstantEntry(std::string_view name, JSTaggedValue value)
|
||||
: name_(name), rawTaggedValue_(value.GetRawData()) {}
|
||||
|
||||
static constexpr BuiltinConstantEntry Create(std::string_view name, JSTaggedValue value)
|
||||
{
|
||||
@ -116,8 +116,8 @@ private:
|
||||
EcmaEntrypoint entrypoint_;
|
||||
uint64_t bitfield_;
|
||||
|
||||
constexpr BuiltinFunctionEntry(std::string_view name, EcmaEntrypoint entrypoint, uint64_t bitfield) :
|
||||
name_(name), entrypoint_(entrypoint), bitfield_(bitfield) {}
|
||||
constexpr BuiltinFunctionEntry(std::string_view name, EcmaEntrypoint entrypoint, uint64_t bitfield)
|
||||
: name_(name), entrypoint_(entrypoint), bitfield_(bitfield) {}
|
||||
};
|
||||
|
||||
class BuiltinsBase {
|
||||
|
@ -488,7 +488,7 @@ bool FastJsonStringifier::TryCacheSerializeKeys(const JSHandle<JSObject> &obj, b
|
||||
if (!propertiesArr->IsDictionaryMode()) {
|
||||
JSHandle<JSHClass> jsHclass(thread_, obj->GetJSHClass());
|
||||
JSTaggedValue enumCache = jsHclass->GetEnumCache();
|
||||
if (!enumCache.IsNull()) {
|
||||
if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) {
|
||||
JSHandle<TaggedArray> cache(thread_, enumCache);
|
||||
uint32_t length = cache->GetLength();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
@ -765,7 +765,7 @@ bool FastJsonStringifier::DefaultSerializeKeys(const JSHandle<JSObject> &obj, bo
|
||||
if (!propertiesArr->IsDictionaryMode()) {
|
||||
JSHandle<JSHClass> jsHclass(thread_, obj->GetJSHClass());
|
||||
JSTaggedValue enumCache = jsHclass->GetEnumCache();
|
||||
if (!enumCache.IsNull()) {
|
||||
if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) {
|
||||
JSHandle<TaggedArray> cache(thread_, enumCache);
|
||||
uint32_t length = cache->GetLength();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
|
@ -616,7 +616,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
bool hasChangedToDictionaryMode = false;
|
||||
JSHandle<JSHClass> jsHclass(thread_, obj->GetJSHClass());
|
||||
JSTaggedValue enumCache = jsHclass->GetEnumCache();
|
||||
if (!enumCache.IsNull()) {
|
||||
if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) {
|
||||
JSHandle<TaggedArray> cache(thread_, enumCache);
|
||||
uint32_t length = cache->GetLength();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
@ -673,6 +673,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
hasChangedToDictionaryMode = true;
|
||||
propertiesArr = JSHandle<TaggedArray>(thread_, obj->GetProperties());
|
||||
}
|
||||
jsHclass = JSHandle<JSHClass>(thread_, obj->GetJSHClass());
|
||||
}
|
||||
handleValue_.Update(value);
|
||||
hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent);
|
||||
@ -685,7 +686,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
continue;
|
||||
}
|
||||
PropertyAttributes attr = nameDic->GetAttributes(index);
|
||||
if (!attr.IsEnumerable()) {
|
||||
if (!attr.IsEnumerable() || index < 0) {
|
||||
continue;
|
||||
}
|
||||
JSTaggedValue value = nameDic->GetValue(index);
|
||||
@ -693,6 +694,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
if (UNLIKELY(value.IsAccessor())) {
|
||||
value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()),
|
||||
JSHandle<JSTaggedValue>(obj));
|
||||
jsHclass = JSHandle<JSHClass>(thread_, obj->GetJSHClass());
|
||||
}
|
||||
handleValue_.Update(value);
|
||||
hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent);
|
||||
|
@ -877,4 +877,15 @@ double RandomGenerator::ToDouble(uint64_t state)
|
||||
uint64_t random = (state >> base::RIGHT12) | EXPONENTBITS_RANGE_IN_ONE_AND_TWO;
|
||||
return base::bit_cast<double>(random) - 1;
|
||||
}
|
||||
|
||||
int32_t RandomGenerator::Next(int bits)
|
||||
{
|
||||
uint64_t val = XorShift64(&randomState_);
|
||||
return static_cast<int32_t>(val >> (INT64_BITS - bits));
|
||||
}
|
||||
|
||||
int32_t RandomGenerator::GenerateIdentityHash()
|
||||
{
|
||||
return RandomGenerator::Next(INT32_BITS) & INT32_MAX;
|
||||
}
|
||||
} // namespace panda::ecmascript::base
|
||||
|
@ -133,6 +133,8 @@ class RandomGenerator {
|
||||
public:
|
||||
static void InitRandom();
|
||||
static double NextDouble();
|
||||
static int32_t GenerateIdentityHash();
|
||||
static int32_t Next(int bits);
|
||||
|
||||
private:
|
||||
static uint64_t XorShift64(uint64_t *pVal);
|
||||
|
@ -292,30 +292,30 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread, bool
|
||||
LazyInitializeDataView(env);
|
||||
LazyInitializeSharedArrayBuffer(env);
|
||||
} else {
|
||||
InitializeDate(env, objFuncClass);
|
||||
InitializeSet(env, objFuncClass);
|
||||
InitializeMap(env, objFuncClass);
|
||||
InitializeDate(env, objFuncPrototypeVal);
|
||||
InitializeSet(env, objFuncPrototypeVal);
|
||||
InitializeMap(env, objFuncPrototypeVal);
|
||||
InitializeWeakMap(env, objFuncClass);
|
||||
InitializeWeakSet(env, objFuncClass);
|
||||
InitializeWeakRef(env, objFuncClass);
|
||||
InitializeFinalizationRegistry(env, objFuncClass);
|
||||
InitializeTypedArray(env, objFuncClass);
|
||||
InitializeTypedArray(env, objFuncPrototypeVal);
|
||||
InitializeArrayBuffer(env, objFuncClass);
|
||||
InitializeDataView(env, objFuncClass);
|
||||
InitializeDataView(env, objFuncPrototypeVal);
|
||||
InitializeSharedArrayBuffer(env, objFuncClass);
|
||||
}
|
||||
InitializeNumber(env, globalObject, primRefObjHClass);
|
||||
InitializeObject(env, objFuncPrototype, objectFunction);
|
||||
InitializeBoolean(env, primRefObjHClass);
|
||||
InitializeRegExp(env);
|
||||
InitializeString(env, primRefObjHClass);
|
||||
InitializeString(env, objFuncPrototypeVal);
|
||||
|
||||
JSHandle<JSHClass> argumentsClass = factory_->CreateJSArguments(env);
|
||||
env->SetArgumentsClass(thread_, argumentsClass);
|
||||
SetArgumentsSharedAccessor(env);
|
||||
|
||||
InitializeGlobalObject(env, globalObject);
|
||||
InitializeMath(env, objFuncPrototypeVal);
|
||||
InitializeGlobalObject(env, globalObject);
|
||||
InitializeAtomics(env, objFuncPrototypeVal);
|
||||
InitializeJson(env, objFuncPrototypeVal);
|
||||
InitializeIterator(env, objFuncClass);
|
||||
@ -837,11 +837,13 @@ void Builtins::InitializeBigInt(const JSHandle<GlobalEnv> &env, const JSHandle<J
|
||||
env->SetBigIntFunction(thread_, bigIntFunction);
|
||||
}
|
||||
|
||||
void Builtins::InitializeDate(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
void Builtins::InitializeDate(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
// Date.prototype
|
||||
JSHandle<JSObject> dateFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass);
|
||||
JSHandle<JSHClass> dateFuncPrototypeHClass = factory_->NewEcmaHClass(
|
||||
JSObject::SIZE, Date::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> dateFuncPrototype = factory_->NewJSObjectWithInit(dateFuncPrototypeHClass);
|
||||
JSHandle<JSTaggedValue> dateFuncPrototypeValue(dateFuncPrototype);
|
||||
|
||||
// Date.prototype_or_hclass
|
||||
@ -871,6 +873,10 @@ void Builtins::InitializeDate(const JSHandle<GlobalEnv> &env, const JSHandle<JSH
|
||||
SetConstant(dateFunction, "length", JSTaggedValue(Date::UTC_LENGTH));
|
||||
|
||||
env->SetDateFunction(thread_, dateFunction);
|
||||
env->SetDatePrototype(thread_, dateFuncPrototype);
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::DATE,
|
||||
dateFunction->GetJSHClass(),
|
||||
dateFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::LazyInitializeDate(const JSHandle<GlobalEnv> &env) const
|
||||
@ -1200,12 +1206,14 @@ void Builtins::InitializeCtor(const JSHandle<GlobalEnv> &env, const JSHandle<JSO
|
||||
}
|
||||
}
|
||||
|
||||
void Builtins::InitializeSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
void Builtins::InitializeSet(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
|
||||
// Set.prototype
|
||||
JSHandle<JSObject> setFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass);
|
||||
JSHandle<JSHClass> setFuncPrototypeHClass = factory_->NewEcmaHClass(
|
||||
JSObject::SIZE, BuiltinsSet::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> setFuncPrototype = factory_->NewJSObjectWithInit(setFuncPrototypeHClass);
|
||||
JSHandle<JSTaggedValue> setFuncPrototypeValue(setFuncPrototype);
|
||||
// Set.prototype_or_hclass
|
||||
JSHandle<JSHClass> setFuncInstanceHClass =
|
||||
@ -1252,6 +1260,10 @@ void Builtins::InitializeSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSHC
|
||||
JSObject::DefineOwnProperty(thread_, setFuncPrototype, iteratorSymbol, descriptor);
|
||||
|
||||
env->SetBuiltinsSetFunction(thread_, setFunction);
|
||||
env->SetSetPrototype(thread_, setFuncPrototype);
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::SET,
|
||||
setFunction->GetTaggedObject()->GetClass(),
|
||||
setFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::LazyInitializeSet(const JSHandle<GlobalEnv> &env)
|
||||
@ -1264,12 +1276,14 @@ void Builtins::LazyInitializeSet(const JSHandle<GlobalEnv> &env)
|
||||
env->SetBuiltinsSetFunction(thread_, accessor);
|
||||
}
|
||||
|
||||
void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
|
||||
// Map.prototype
|
||||
JSHandle<JSObject> mapFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass);
|
||||
JSHandle<JSHClass> mapFuncPrototypeHClass = factory_->NewEcmaHClass(
|
||||
JSObject::SIZE, BuiltinsMap::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> mapFuncPrototype = factory_->NewJSObjectWithInit(mapFuncPrototypeHClass);
|
||||
JSHandle<JSTaggedValue> mapFuncPrototypeValue(mapFuncPrototype);
|
||||
// Map.prototype_or_hclass
|
||||
JSHandle<JSHClass> mapFuncInstanceHClass =
|
||||
@ -1315,6 +1329,9 @@ void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHC
|
||||
|
||||
env->SetBuiltinsMapFunction(thread_, mapFunction);
|
||||
env->SetMapPrototype(thread_, mapFuncPrototype);
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::MAP,
|
||||
mapFunction->GetTaggedObject()->GetClass(),
|
||||
mapFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::LazyInitializeMap(const JSHandle<GlobalEnv> &env) const
|
||||
@ -1564,11 +1581,14 @@ void Builtins::InitializeJson(const JSHandle<GlobalEnv> &env, const JSHandle<JST
|
||||
env->SetJsonFunction(thread_, jsonObject);
|
||||
}
|
||||
|
||||
void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjHClass) const
|
||||
void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
// String.prototype
|
||||
JSHandle<JSTaggedValue> toObject(factory_->GetEmptyString());
|
||||
JSHandle<JSHClass> primRefObjHClass =
|
||||
factory_->NewEcmaHClass(JSPrimitiveRef::SIZE, BuiltinsSet::GetNumPrototypeInlinedProperties(),
|
||||
JSType::JS_PRIMITIVE_REF, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> stringFuncPrototype =
|
||||
JSHandle<JSObject>::Cast(factory_->NewJSPrimitiveRef(primRefObjHClass, toObject));
|
||||
JSHandle<JSTaggedValue> stringFuncPrototypeValue(stringFuncPrototype);
|
||||
@ -1603,6 +1623,9 @@ void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<J
|
||||
|
||||
env->SetStringFunction(thread_, stringFunction);
|
||||
env->SetStringPrototype(thread_, stringFuncPrototype);
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::STRING,
|
||||
stringFunction->GetJSHClass(),
|
||||
stringFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::InitializeStringIterator(const JSHandle<GlobalEnv> &env,
|
||||
@ -1876,6 +1899,10 @@ void Builtins::InitializeRegExp(const JSHandle<GlobalEnv> &env)
|
||||
env->SetRegExpFunction(thread_, regexpFunction);
|
||||
env->SetRegExpPrototype(thread_, regPrototype);
|
||||
env->SetRegExpExecFunction(thread_, execFunc);
|
||||
// Set RegExp.prototype hclass
|
||||
JSHandle<JSHClass> regPrototypeClass(thread_, regPrototype->GetJSHClass());
|
||||
env->SetRegExpPrototypeClass(thread_, regPrototypeClass.GetTaggedValue());
|
||||
|
||||
auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
|
||||
globalConst->SetConstant(ConstantIndex::JS_REGEXP_CLASS_INDEX, regexpFuncInstanceHClass.GetTaggedValue());
|
||||
}
|
||||
@ -1884,7 +1911,8 @@ void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JS
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
// Arraybase.prototype
|
||||
JSHandle<JSHClass> arrBaseFuncInstanceHClass = factory_->CreateJSArrayInstanceClass(objFuncPrototypeVal);
|
||||
JSHandle<JSHClass> arrBaseFuncInstanceHClass = factory_->CreateJSArrayInstanceClass(
|
||||
objFuncPrototypeVal, BuiltinsArray::GetNumPrototypeInlinedProperties());
|
||||
|
||||
// Array.prototype
|
||||
JSHandle<JSObject> arrFuncPrototype = factory_->NewJSObjectWithInit(arrBaseFuncInstanceHClass);
|
||||
@ -1957,18 +1985,25 @@ void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JS
|
||||
env->SetArrayProtoValuesFunction(thread_, desc.GetValue());
|
||||
env->SetArrayFunction(thread_, arrayFunction);
|
||||
env->SetArrayPrototype(thread_, arrFuncPrototype);
|
||||
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::ARRAY,
|
||||
arrayFunction->GetJSHClass(),
|
||||
arrFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::InitializeTypedArray(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
void Builtins::InitializeTypedArray(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
// TypedArray.prototype
|
||||
JSHandle<JSObject> typedArrFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass);
|
||||
JSHandle<JSHClass> typedArrFuncPrototypeHClass = factory_->NewEcmaHClass(
|
||||
JSObject::SIZE, BuiltinsTypedArray::GetNumPrototypeInlinedProperties(),
|
||||
JSType::JS_OBJECT, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> typedArrFuncPrototype = factory_->NewJSObjectWithInit(typedArrFuncPrototypeHClass);
|
||||
JSHandle<JSTaggedValue> typedArrFuncPrototypeValue(typedArrFuncPrototype);
|
||||
|
||||
// TypedArray.prototype_or_hclass
|
||||
JSHandle<JSHClass> typedArrFuncInstanceHClass = factory_->NewEcmaHClass(
|
||||
panda::ecmascript::JSTypedArray::SIZE, JSType::JS_TYPED_ARRAY, typedArrFuncPrototypeValue);
|
||||
JSTypedArray::SIZE, JSType::JS_TYPED_ARRAY, typedArrFuncPrototypeValue);
|
||||
|
||||
// TypedArray = new Function()
|
||||
JSHandle<JSObject> typedArrayFunction(NewBuiltinConstructor(
|
||||
@ -2028,6 +2063,9 @@ void Builtins::InitializeTypedArray(const JSHandle<GlobalEnv> &env, const JSHand
|
||||
|
||||
env->SetTypedArrayFunction(thread_, typedArrayFunction.GetTaggedValue());
|
||||
env->SetTypedArrayPrototype(thread_, typedArrFuncPrototype);
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPED_ARRAY,
|
||||
typedArrayFunction->GetJSHClass(),
|
||||
typedArrFuncPrototype->GetJSHClass());
|
||||
|
||||
JSHandle<JSHClass> specificTypedArrayFuncClass =
|
||||
factory_->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, env->GetTypedArrayFunction());
|
||||
@ -2077,6 +2115,10 @@ void Builtins::Initialize##Type(const JSHandle<GlobalEnv> &env, const JSHandle<J
|
||||
SetConstant(arrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \
|
||||
SetConstant(JSHandle<JSObject>(arrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \
|
||||
env->Set##Type##Function(thread_, arrayFunction); \
|
||||
/* Initializes HClass record of %TypedArray% */ \
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPE, \
|
||||
arrayFunction->GetJSHClass(), \
|
||||
arrFuncPrototype->GetJSHClass()); \
|
||||
}
|
||||
|
||||
BUILTIN_TYPED_ARRAY_TYPES(BUILTIN_TYPED_ARRAY_DEFINE_INITIALIZE)
|
||||
@ -2332,11 +2374,13 @@ void Builtins::InitializePromiseJob(const JSHandle<GlobalEnv> &env)
|
||||
env->SetDynamicImportJob(thread_, func);
|
||||
}
|
||||
|
||||
void Builtins::InitializeDataView(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
void Builtins::InitializeDataView(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
// ArrayBuffer.prototype
|
||||
JSHandle<JSObject> dataViewFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass);
|
||||
JSHandle<JSHClass> dataViewFuncPrototypeHClass = factory_->NewEcmaHClass(
|
||||
JSObject::SIZE, DataView::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal);
|
||||
JSHandle<JSObject> dataViewFuncPrototype = factory_->NewJSObjectWithInit(dataViewFuncPrototypeHClass);
|
||||
JSHandle<JSTaggedValue> dataViewFuncPrototypeValue(dataViewFuncPrototype);
|
||||
|
||||
// ArrayBuffer.prototype_or_hclass
|
||||
@ -2372,7 +2416,12 @@ void Builtins::InitializeDataView(const JSHandle<GlobalEnv> &env, const JSHandle
|
||||
|
||||
// 24.2.4.21 DataView.prototype[ @@toStringTag ]
|
||||
SetStringTagSymbol(env, dataViewFuncPrototype, "DataView");
|
||||
|
||||
env->SetDataViewFunction(thread_, dataViewFunction.GetTaggedValue());
|
||||
env->SetDataViewPrototype(thread_, dataViewFuncPrototype.GetTaggedValue());
|
||||
thread_->SetInitialBuiltinHClass(BuiltinTypeId::DATA_VIEW,
|
||||
dataViewFunction->GetJSHClass(),
|
||||
dataViewFuncPrototype->GetJSHClass());
|
||||
}
|
||||
|
||||
void Builtins::LazyInitializeDataView(const JSHandle<GlobalEnv> &env) const
|
||||
|
@ -89,7 +89,7 @@ private:
|
||||
|
||||
void InitializeBigIntWithRealm(const JSHandle<GlobalEnv> &realm) const;
|
||||
|
||||
void InitializeDate(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void InitializeDate(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
void LazyInitializeDate(const JSHandle<GlobalEnv> &env) const;
|
||||
|
||||
void InitializeBoolean(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjClass) const;
|
||||
@ -100,7 +100,7 @@ private:
|
||||
|
||||
void InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
|
||||
|
||||
void InitializeTypedArray(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void InitializeTypedArray(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
void LazyInitializeTypedArray(const JSHandle<GlobalEnv> &env) const;
|
||||
|
||||
void InitializeInt8Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
@ -174,10 +174,10 @@ private:
|
||||
void GeneralUpdateError(ErrorParameter *error, EcmaEntrypoint constructor, EcmaEntrypoint method,
|
||||
std::string_view name, JSType type) const;
|
||||
|
||||
void InitializeSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void InitializeSet(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
void LazyInitializeSet(const JSHandle<GlobalEnv> &env);
|
||||
|
||||
void InitializeMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void InitializeMap(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
void LazyInitializeMap(const JSHandle<GlobalEnv> &env) const;
|
||||
|
||||
void InitializeWeakMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
@ -199,7 +199,7 @@ private:
|
||||
|
||||
void InitializeJson(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
|
||||
|
||||
void InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjHClass) const;
|
||||
void InitializeString(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
|
||||
void InitializeIterator(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
|
||||
@ -224,7 +224,7 @@ private:
|
||||
void InitializeSharedArrayBuffer(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void LazyInitializeSharedArrayBuffer(const JSHandle<GlobalEnv> &env) const;
|
||||
|
||||
void InitializeDataView(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const;
|
||||
void InitializeDataView(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const;
|
||||
void LazyInitializeDataView(const JSHandle<GlobalEnv> &env) const;
|
||||
|
||||
void InitializeForPromiseFuncClass(const JSHandle<GlobalEnv> &env);
|
||||
|
@ -221,6 +221,16 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(ARRAY_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 4 : 4 More inlined entries in Array.prototype for the following functions/accessors:
|
||||
// (1) 'length' accessor
|
||||
// (2) Array.prototype.constructor, i.e. Array()
|
||||
// (3) Array.prototype[@@iterator]()
|
||||
// (4) Array.prototype[@@unscopables]()
|
||||
return GetArrayPrototypeFunctions().Size() + 4;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_ARRAY_FUNCTION_ENTRY(name, method, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsArray::method, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -360,11 +360,18 @@ JSTaggedValue BuiltinsDataView::GetViewValue(JSThread *thread, const JSHandle<JS
|
||||
if (!view->IsDataView()) {
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception());
|
||||
}
|
||||
// 3. Let numberIndex be ToNumber(requestIndex).
|
||||
JSTaggedNumber numberIndex = JSTaggedValue::ToNumber(thread, requestIndex);
|
||||
// 5. ReturnIfAbrupt(getIndex).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
int32_t indexInt = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber());
|
||||
|
||||
int32_t indexInt = 0;
|
||||
if (requestIndex->IsInt()) {
|
||||
// fast get index if requestIndex is int
|
||||
indexInt = requestIndex->GetInt();
|
||||
} else {
|
||||
// 3. Let numberIndex be ToNumber(requestIndex).
|
||||
JSTaggedNumber numberIndex = JSTaggedValue::ToNumber(thread, requestIndex);
|
||||
// 5. ReturnIfAbrupt(getIndex).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
indexInt = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber());
|
||||
}
|
||||
// 6. If numberIndex ≠ getIndex or getIndex < 0, throw a RangeError exception.
|
||||
if (indexInt < 0) {
|
||||
THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception());
|
||||
@ -415,17 +422,26 @@ JSTaggedValue BuiltinsDataView::SetViewValue(JSThread *thread, const JSHandle<JS
|
||||
if (!view->IsDataView()) {
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception());
|
||||
}
|
||||
// 3. Let numberIndex be ToNumber(requestIndex).
|
||||
JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex);
|
||||
// 5. ReturnIfAbrupt(getIndex).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
int64_t index = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber());
|
||||
int64_t index = 0;
|
||||
if (requestIndex->IsInt()) {
|
||||
// fast get index if requestIndex is int
|
||||
index = requestIndex->GetInt();
|
||||
} else {
|
||||
// 3. Let numberIndex be ToNumber(requestIndex).
|
||||
JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex);
|
||||
// 5. ReturnIfAbrupt(getIndex).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
index = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber());
|
||||
}
|
||||
// 6. If numberIndex ≠ getIndex or getIndex < 0, throw a RangeError exception.
|
||||
if (index < 0) {
|
||||
THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception());
|
||||
}
|
||||
JSHandle<JSTaggedValue> numValueHandle = JSTaggedValue::ToNumeric(thread, value);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSMutableHandle<JSTaggedValue> numValueHandle = JSMutableHandle<JSTaggedValue>(thread, value);
|
||||
if (!value->IsNumber()) {
|
||||
numValueHandle.Update(JSTaggedValue::ToNumeric(thread, value));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
// 7. Let isLittleEndian be ToBoolean(isLittleEndian).
|
||||
bool isLittleEndian = false;
|
||||
if (littleEndian->IsUndefined()) {
|
||||
|
@ -112,6 +112,17 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(DATA_VIEW_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 5 : 5 more inline properties in DataView.prototype:
|
||||
// (1) DataView.prototype.constructor
|
||||
// (2) DataView.prototype [ @@toStringTag ]
|
||||
// (3) get buffer
|
||||
// (4) get byteLength
|
||||
// (5) get byteOffset
|
||||
return GetDataViewPrototypeFunctions().Size() + 5;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_DATA_VIEW_FUNCTION_ENTRY(name, func, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsDataView::func, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -282,6 +282,14 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(DATE_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 2 : 2 more inline properties in Date.prototype:
|
||||
// (1) Date.prototype.constructor
|
||||
// (2) Date.prototype [ @@toPrimitive ]
|
||||
return GetDatePrototypeFunctions().Size() + 2;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_DATE_FUNCTION_ENTRY(name, func, length, builtinId) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsDate::func, length, kungfu::BuiltinsStubCSigns::builtinId),
|
||||
|
@ -271,8 +271,16 @@ JSTaggedValue BuiltinsFunction::FunctionPrototypeToString(EcmaRuntimeCallInfo *a
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<JSTaggedValue> thisValue = GetThis(argv);
|
||||
if (thisValue->IsJSObject() && thisValue->IsCallable()) {
|
||||
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(thisValue);
|
||||
JSHandle<Method> method(thread, func->GetMethod());
|
||||
JSHandle<Method> method;
|
||||
if (thisValue->IsBoundFunction()) {
|
||||
JSHandle<JSBoundFunction> func = JSHandle<JSBoundFunction>::Cast(thisValue);
|
||||
JSHandle<JSTaggedValue> methodHandle(thread, func->GetMethod());
|
||||
method = JSHandle<Method>::Cast(methodHandle);
|
||||
} else {
|
||||
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(thisValue);
|
||||
JSHandle<JSTaggedValue> methodHandle(thread, func->GetMethod());
|
||||
method = JSHandle<Method>::Cast(methodHandle);
|
||||
}
|
||||
if (method->IsNativeWithCallField()) {
|
||||
JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
|
||||
JSHandle<EcmaString> methodName(JSObject::GetProperty(thread, thisValue, nameKey).GetValue());
|
||||
|
@ -29,9 +29,10 @@ JSTaggedValue BuiltinsLazyCallback::Date(JSThread *thread, const JSHandle<JSObje
|
||||
ObjectFactory *factory = vm->GetFactory();
|
||||
auto env = vm->GetGlobalEnv();
|
||||
ResetLazyInternalAttr(thread, obj, "Date");
|
||||
JSHandle<JSHClass> objFuncClass(env->GetObjectFunctionClass());
|
||||
|
||||
JSHandle<JSTaggedValue> objFuncPrototypeVal = env->GetObjectFunctionPrototype();
|
||||
Builtins builtin(thread, factory, vm);
|
||||
builtin.InitializeDate(env, objFuncClass);
|
||||
builtin.InitializeDate(env, objFuncPrototypeVal);
|
||||
return env->GetDateFunction().GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -43,9 +44,10 @@ JSTaggedValue BuiltinsLazyCallback::Set(JSThread *thread, const JSHandle<JSObjec
|
||||
ObjectFactory *factory = vm->GetFactory();
|
||||
auto env = vm->GetGlobalEnv();
|
||||
ResetLazyInternalAttr(thread, obj, "Set");
|
||||
|
||||
Builtins builtin(thread, factory, vm);
|
||||
JSHandle<JSHClass> objFuncClass(env->GetObjectFunctionClass());
|
||||
builtin.InitializeSet(env, objFuncClass);
|
||||
JSHandle<JSTaggedValue> objFuncPrototypeVal = env->GetObjectFunctionPrototype();
|
||||
builtin.InitializeSet(env, objFuncPrototypeVal);
|
||||
return env->GetBuiltinsSetFunction().GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -57,9 +59,10 @@ JSTaggedValue BuiltinsLazyCallback::Map(JSThread *thread, const JSHandle<JSObjec
|
||||
ObjectFactory *factory = vm->GetFactory();
|
||||
auto env = vm->GetGlobalEnv();
|
||||
ResetLazyInternalAttr(thread, obj, "Map");
|
||||
|
||||
Builtins builtin(thread, factory, vm);
|
||||
JSHandle<JSHClass> objFuncClass(env->GetObjectFunctionClass());
|
||||
builtin.InitializeMap(env, objFuncClass);
|
||||
JSHandle<JSTaggedValue> objFuncPrototypeVal = env->GetObjectFunctionPrototype();
|
||||
builtin.InitializeMap(env, objFuncPrototypeVal);
|
||||
return env->GetBuiltinsMapFunction().GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -133,9 +136,10 @@ JSTaggedValue BuiltinsLazyCallback::TypedArray(JSThread *thread, const JSHandle<
|
||||
|
||||
ITERATE_TYPED_ARRAY(RESET_TYPED_ARRAY_INTERNAL_ATTR)
|
||||
#undef RESET_TYPED_ARRAY_INTERNAL_ATTR
|
||||
|
||||
Builtins builtin(thread, factory, vm);
|
||||
JSHandle<JSHClass> objFuncClass(env->GetObjectFunctionClass());
|
||||
builtin.InitializeTypedArray(env, objFuncClass);
|
||||
JSHandle<JSTaggedValue> objFuncPrototypeVal = env->GetObjectFunctionPrototype();
|
||||
builtin.InitializeTypedArray(env, objFuncPrototypeVal);
|
||||
return env->GetTypedArrayFunction().GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -175,9 +179,10 @@ JSTaggedValue BuiltinsLazyCallback::DataView(JSThread *thread, const JSHandle<JS
|
||||
ObjectFactory *factory = vm->GetFactory();
|
||||
auto env = vm->GetGlobalEnv();
|
||||
ResetLazyInternalAttr(thread, obj, "DataView");
|
||||
|
||||
Builtins builtin(thread, factory, vm);
|
||||
JSHandle<JSHClass> objFuncClass(env->GetObjectFunctionClass());
|
||||
builtin.InitializeDataView(env, objFuncClass);
|
||||
JSHandle<JSTaggedValue> objFuncPrototypeVal = env->GetObjectFunctionPrototype();
|
||||
builtin.InitializeDataView(env, objFuncPrototypeVal);
|
||||
return env->GetDataViewFunction().GetTaggedValue();
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,16 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(MAP_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 4 : 4 more inline properties in Map.prototype
|
||||
// (1) Map.prototype.constructor
|
||||
// (2) Map.prototype [ @@toStringTag ]
|
||||
// (3) Map.prototype [ @@iterator ] ( )
|
||||
// (4) get Map.prototype.size
|
||||
return GetMapPrototypeFunctions().Size() + 4;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_MAP_FUNCTION_ENTRY(name, func, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsMap::func, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -60,6 +60,37 @@ JSTaggedValue BuiltinsObject::ObjectConstructor(EcmaRuntimeCallInfo *argv)
|
||||
return JSTaggedValue::ToObject(thread, value).GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue BuiltinsObject::AssignTaggedValue(JSThread *thread, const JSHandle<JSTaggedValue> &source,
|
||||
const JSHandle<JSObject> &toAssign)
|
||||
{
|
||||
JSHandle<JSObject> from = JSTaggedValue::ToObject(thread, source);
|
||||
JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(from));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
|
||||
uint32_t keysLen = keys->GetLength();
|
||||
for (uint32_t j = 0; j < keysLen; j++) {
|
||||
PropertyDescriptor desc(thread);
|
||||
key.Update(keys->Get(j));
|
||||
bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(from), key, desc);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
if (success && desc.IsEnumerable()) {
|
||||
JSTaggedValue value = desc.GetValue().GetTaggedValue();
|
||||
if (value.IsUndefined() || JSHandle<JSTaggedValue>::Cast(from)->IsJSProxy()) {
|
||||
value = ObjectFastOperator::FastGetPropertyByValue(thread, from.GetTaggedValue(),
|
||||
key.GetTaggedValue());
|
||||
}
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
ObjectFastOperator::FastSetPropertyByValue(thread, toAssign.GetTaggedValue(), key.GetTaggedValue(),
|
||||
value);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
}
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
|
||||
// 19.1.2.1 Object.assign ( target, ...sources )
|
||||
JSTaggedValue BuiltinsObject::Assign(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@
|
||||
// - Object.getOwnPropertyDescriptors ( O )
|
||||
#define BUILTIN_OBJECT_FUNCTIONS(V) \
|
||||
/* Object.assign ( target, ...sources ) */ \
|
||||
V("assign", Assign, 2, INVALID) \
|
||||
V("assign", Assign, 2, ObjectAssign) \
|
||||
/* Object.create ( O, Properties ) */ \
|
||||
V("create", Create, 2, ObjectCreate) \
|
||||
/* Object.defineProperties ( O, Properties ) */ \
|
||||
@ -175,6 +175,8 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(OBJECT_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static JSTaggedValue AssignTaggedValue(JSThread *thread, const JSHandle<JSTaggedValue> &source,
|
||||
const JSHandle<JSObject> &toAssign);
|
||||
private:
|
||||
#define BUILTIN_OBJECT_FUNCTION_ENTRY(name, func, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsObject::func, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -185,15 +185,19 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv)
|
||||
// 1. Let R be the this value.
|
||||
JSHandle<JSTaggedValue> thisObj = GetThis(argv);
|
||||
JSHandle<JSTaggedValue> inputStr = GetCallArg(argv, 0);
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
if (!thisObj->IsECMAObject()) {
|
||||
// throw a TypeError exception.
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
|
||||
}
|
||||
// 3. Let string be ToString(S).
|
||||
// 4. ReturnIfAbrupt(string).
|
||||
JSHandle<EcmaString> stringHandle = JSTaggedValue::ToString(thread, inputStr);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSTaggedValue> string = JSHandle<JSTaggedValue>::Cast(stringHandle);
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
if (!thisObj->IsECMAObject()) {
|
||||
// throw a TypeError exception.
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
|
||||
// test fast path
|
||||
if (IsFastRegExp(thread, thisObj)) {
|
||||
return RegExpTestFast(thread, thisObj, string, true);
|
||||
}
|
||||
|
||||
// 5. Let match be RegExpExec(R, string).
|
||||
@ -204,6 +208,45 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv)
|
||||
return GetTaggedBoolean(!matchResult.IsNull());
|
||||
}
|
||||
|
||||
bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> ®exp)
|
||||
{
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
JSHClass *hclass = JSHandle<JSObject>::Cast(regexp)->GetJSHClass();
|
||||
JSHClass *originHClass = JSHClass::Cast(globalConst->GetJSRegExpClass().GetTaggedObject());
|
||||
// regexp instance hclass
|
||||
if (hclass != originHClass) {
|
||||
return false;
|
||||
}
|
||||
// RegExp.prototype hclass
|
||||
JSTaggedValue proto = hclass->GetPrototype();
|
||||
JSHClass *regexpHclass = proto.GetTaggedObject()->GetClass();
|
||||
JSHandle<JSTaggedValue> originRegexpClassValue = env->GetRegExpPrototypeClass();
|
||||
JSHClass *originRegexpHclass = JSHClass::Cast(originRegexpClassValue.GetTaggedValue().GetTaggedObject());
|
||||
if (regexpHclass != originRegexpHclass) {
|
||||
return false;
|
||||
}
|
||||
// RegExp.prototype.exec
|
||||
auto execVal = JSObject::Cast(proto)->GetPropertyInlinedProps(JSRegExp::EXEC_INLINE_PROPERTY_INDEX);
|
||||
if (execVal != env->GetTaggedRegExpExecFunction()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSTaggedValue BuiltinsRegExp::RegExpTestFast(JSThread *thread, JSHandle<JSTaggedValue> ®exp,
|
||||
const JSHandle<JSTaggedValue> &inputStr, bool useCache)
|
||||
{
|
||||
// 1. Assert: Type(S) is String.
|
||||
ASSERT(inputStr->IsString());
|
||||
// 2. If R does not have a [[RegExpMatcher]] internal slot, throw a TypeError exception.
|
||||
if (!regexp->IsJSRegExp()) {
|
||||
// throw a TypeError exception.
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have a [[RegExpMatcher]]", JSTaggedValue::Exception());
|
||||
}
|
||||
return RegExpExecForTestFast(thread, regexp, inputStr, useCache);
|
||||
}
|
||||
|
||||
// 20.2.5.14
|
||||
JSTaggedValue BuiltinsRegExp::ToString(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
@ -660,20 +703,26 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
|
||||
|
||||
std::string resultString;
|
||||
uint32_t nextPosition = 0;
|
||||
|
||||
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
|
||||
// 12. Let done be false.
|
||||
// 13. Repeat, while done is false
|
||||
for (;;) {
|
||||
if (lastIndex > inputLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
|
||||
auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced();
|
||||
const uint8_t *strBuffer = inputPtr.get();
|
||||
|
||||
RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, inputLength, lastIndex, isUtf16);
|
||||
if (!matchResult.isSuccess_) {
|
||||
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
|
||||
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
|
||||
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
|
||||
}
|
||||
const uint8_t *strBuffer;
|
||||
if (isUtf16) {
|
||||
strBuffer = reinterpret_cast<const uint8_t *>(flatStrInfo.GetDataUtf16());
|
||||
} else {
|
||||
strBuffer = flatStrInfo.GetDataUtf8();
|
||||
}
|
||||
bool matchResult = Matcher(thread, regexp, strBuffer, inputLength, lastIndex, isUtf16);
|
||||
if (!matchResult) {
|
||||
if (flags & (RegExpParser::FLAG_STICKY | RegExpParser::FLAG_GLOBAL)) {
|
||||
lastIndex = 0;
|
||||
ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(),
|
||||
@ -682,8 +731,8 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
|
||||
}
|
||||
break;
|
||||
}
|
||||
uint32_t startIndex = matchResult.index_;
|
||||
uint32_t endIndex = matchResult.endIndex_;
|
||||
uint32_t startIndex = globalTable->GetStartOfCaptureIndex(0).GetInt();
|
||||
uint32_t endIndex = globalTable->GetEndIndex().GetInt();
|
||||
lastIndex = endIndex;
|
||||
if (nextPosition < startIndex) {
|
||||
auto substr = EcmaStringAccessor::FastSubString(
|
||||
@ -1367,9 +1416,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||
RegExpExecutor::MatchResult BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle<JSTaggedValue> ®exp,
|
||||
const uint8_t *buffer, size_t length, int32_t lastIndex,
|
||||
bool isUtf16)
|
||||
bool BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle<JSTaggedValue> ®exp,
|
||||
const uint8_t *buffer, size_t length, int32_t lastIndex,
|
||||
bool isUtf16)
|
||||
{
|
||||
BUILTINS_API_TRACE(thread, RegExp, Matcher);
|
||||
// get bytecode
|
||||
@ -1383,8 +1432,10 @@ RegExpExecutor::MatchResult BuiltinsRegExp::Matcher(JSThread *thread, const JSHa
|
||||
lastIndex = 0;
|
||||
}
|
||||
bool ret = executor.Execute(buffer, lastIndex, static_cast<uint32_t>(length), bytecodeBuffer, isUtf16);
|
||||
RegExpExecutor::MatchResult result = executor.GetResult(thread, ret);
|
||||
return result;
|
||||
if (ret) {
|
||||
executor.GetResult(thread);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t BuiltinsRegExp::AdvanceStringIndex(const JSHandle<JSTaggedValue> &inputStr, uint32_t index,
|
||||
@ -1556,14 +1607,21 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return JSTaggedValue::Null();
|
||||
}
|
||||
JSHandle<EcmaString> inputString = JSTaggedValue::ToString(thread, inputStr);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
|
||||
auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced();
|
||||
const uint8_t *strBuffer = inputPtr.get();
|
||||
JSHandle<EcmaString> inputString = JSHandle<EcmaString>::Cast(inputStr);
|
||||
size_t stringLength = EcmaStringAccessor(inputString).GetLength();
|
||||
RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16);
|
||||
if (!matchResult.isSuccess_) {
|
||||
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
|
||||
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
|
||||
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
|
||||
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
|
||||
}
|
||||
const uint8_t *strBuffer;
|
||||
if (isUtf16) {
|
||||
strBuffer = reinterpret_cast<const uint8_t *>(flatStrInfo.GetDataUtf16());
|
||||
} else {
|
||||
strBuffer = flatStrInfo.GetDataUtf8();
|
||||
}
|
||||
bool matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16);
|
||||
if (!matchResult) {
|
||||
if (global || sticky) {
|
||||
JSHandle<JSTaggedValue> lastIndexValue(thread, JSTaggedValue(0));
|
||||
ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(),
|
||||
@ -1573,7 +1631,10 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
}
|
||||
return JSTaggedValue::Null();
|
||||
}
|
||||
uint32_t endIndex = matchResult.endIndex_;
|
||||
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
|
||||
globalTable->ResetDollar(thread);
|
||||
globalTable->SetInputString(thread, inputString.GetTaggedValue());
|
||||
uint32_t endIndex = globalTable->GetEndIndex().GetInt();
|
||||
if (global || sticky) {
|
||||
// a. Let setStatus be Set(R, "lastIndex", e, true).
|
||||
ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(),
|
||||
@ -1581,13 +1642,12 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
// b. ReturnIfAbrupt(setStatus).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
uint32_t capturesSize = matchResult.captures_.size();
|
||||
uint32_t capturesSize = globalTable->GetTotalCaptureCounts().GetInt();
|
||||
JSHandle<JSObject> results(JSArray::ArrayCreate(thread, JSTaggedNumber(capturesSize)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
uint32_t matchIndex = matchResult.index_;
|
||||
// 24. Perform CreateDataProperty(A, "index", matchIndex).
|
||||
JSHandle<JSTaggedValue> indexKey = globalConst->GetHandledIndexString();
|
||||
JSHandle<JSTaggedValue> indexValue(thread, JSTaggedValue(matchIndex));
|
||||
JSHandle<JSTaggedValue> indexValue(thread, globalTable->GetStartOfCaptureIndex(0));
|
||||
JSObject::CreateDataProperty(thread, results, indexKey, indexValue);
|
||||
// 25. Perform CreateDataProperty(A, "input", S).
|
||||
JSHandle<JSTaggedValue> inputKey = globalConst->GetHandledInputString();
|
||||
@ -1595,16 +1655,18 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
JSObject::CreateDataProperty(thread, results, inputKey, inputValue);
|
||||
|
||||
// 27. Perform CreateDataProperty(A, "0", matched_substr).
|
||||
JSHandle<JSTaggedValue> zeroValue(matchResult.captures_[0].second.capturedValue);
|
||||
uint32_t startIndex = globalTable->GetStartOfCaptureIndex(0).GetInt();
|
||||
uint32_t len = globalTable->GetEndOfCaptureIndex(0).GetInt() - startIndex;
|
||||
JSHandle<JSTaggedValue> zeroValue(thread, JSTaggedValue(EcmaStringAccessor::FastSubString(
|
||||
thread->GetEcmaVM(), inputString, startIndex, len)));
|
||||
JSObject::CreateDataProperty(thread, results, 0, zeroValue);
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
// Let indices be a new empty List.
|
||||
// Let groupNames be a new empty List.
|
||||
// Append match to indices.
|
||||
std::vector<std::pair<JSTaggedValue, JSTaggedValue>> indices;
|
||||
std::vector<JSHandle<JSTaggedValue>> groupNames;
|
||||
indices.emplace_back(std::make_pair(JSTaggedValue(matchIndex), JSTaggedValue(endIndex)));
|
||||
indices.emplace_back(std::make_pair(globalTable->GetStartOfCaptureIndex(0), JSTaggedValue(endIndex)));
|
||||
// If R contains any GroupName, then
|
||||
// a. Let groups be OrdinaryObjectCreate(null).
|
||||
// b. Let hasGroups be true.
|
||||
@ -1615,6 +1677,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
JSMutableHandle<JSTaggedValue> groups(thread, JSTaggedValue::Undefined());
|
||||
bool hasGroups = false;
|
||||
if (!groupName->IsUndefined()) {
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
|
||||
JSHandle<JSObject> nullObj = factory->OrdinaryNewJSObjectCreate(nullHandle);
|
||||
groups.Update(nullObj.GetTaggedValue());
|
||||
@ -1626,23 +1689,24 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
// Create a new RegExp on global
|
||||
uint32_t captureIndex = 1;
|
||||
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
|
||||
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
|
||||
JSMutableHandle<JSTaggedValue> iValue(thread, JSTaggedValue::Undefined());
|
||||
// 28. For each integer i such that i > 0 and i <= n
|
||||
for (; captureIndex < capturesSize; captureIndex++) {
|
||||
// a. Let capture_i be ith element of r's captures List
|
||||
JSTaggedValue capturedValue;
|
||||
if (matchResult.captures_[captureIndex].first) {
|
||||
capturedValue = JSTaggedValue::Undefined();
|
||||
uint32_t captureStartIndex = globalTable->GetStartOfCaptureIndex(captureIndex).GetInt();
|
||||
uint32_t captureEndIndex = globalTable->GetEndOfCaptureIndex(captureIndex).GetInt();
|
||||
int32_t subStrLen = captureEndIndex - captureStartIndex;
|
||||
if (subStrLen < 0) {
|
||||
iValue.Update(JSTaggedValue::Undefined());
|
||||
indices.emplace_back(std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined()));
|
||||
} else {
|
||||
auto captureI = matchResult.captures_[captureIndex].second;
|
||||
capturedValue = captureI.capturedValue.GetTaggedValue();
|
||||
indices.emplace_back(std::make_pair(JSTaggedValue(captureI.startIndex), JSTaggedValue(captureI.endIndex)));
|
||||
iValue.Update(JSTaggedValue(EcmaStringAccessor::FastSubString(
|
||||
thread->GetEcmaVM(), inputString, captureStartIndex, subStrLen)));
|
||||
indices.emplace_back(std::make_pair(captureStartIndex, captureEndIndex));
|
||||
}
|
||||
JSHandle<JSTaggedValue> iValue(thread, capturedValue);
|
||||
// add to RegExp.$i and i must <= 9
|
||||
if (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) {
|
||||
globalTable->SetCapture(thread, captureIndex, capturedValue);
|
||||
globalTable->SetCapture(thread, captureIndex, iValue.GetTaggedValue());
|
||||
}
|
||||
|
||||
JSObject::CreateDataProperty(thread, results, captureIndex, iValue);
|
||||
@ -1737,6 +1801,87 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle<JSTagg
|
||||
return RegExpBuiltinExec(thread, regexp, inputString, useCache);
|
||||
}
|
||||
|
||||
JSTaggedValue BuiltinsRegExp::RegExpExecForTestFast(JSThread *thread, JSHandle<JSTaggedValue> ®exp,
|
||||
const JSHandle<JSTaggedValue> &inputStr, bool useCache)
|
||||
{
|
||||
JSHandle<JSObject> object = JSHandle<JSObject>::Cast(regexp);
|
||||
JSTaggedValue lastIndexValue = object->GetPropertyInlinedProps(LAST_INDEX_OFFSET);
|
||||
// ASSERT GetPropertyInlinedProps(LAST_INDEX_OFFSET) is not hole
|
||||
ASSERT(!JSTaggedValue::SameValue(lastIndexValue, JSTaggedValue::Hole()));
|
||||
// 1. load lastIndex as length
|
||||
int32_t lastIndex = 0;
|
||||
if (lastIndexValue.IsInt()) {
|
||||
lastIndex = lastIndexValue.GetInt();
|
||||
} else {
|
||||
JSHandle<JSTaggedValue> lastIndexResult(thread, lastIndexValue);
|
||||
JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
lastIndex = lastIndexNumber.GetNumber();
|
||||
}
|
||||
// 2. Check whether the regexp is global or sticky, which determines whether we update last index later on.
|
||||
JSHandle<JSRegExp> regexpObj(regexp);
|
||||
JSMutableHandle<JSTaggedValue> pattern(thread, regexpObj->GetOriginalSource());
|
||||
JSMutableHandle<JSTaggedValue> flags(thread, regexpObj->GetOriginalFlags());
|
||||
JSHandle<RegExpExecResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache());
|
||||
uint8_t flagsBits = static_cast<uint8_t>(flags->GetInt());
|
||||
bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0;
|
||||
bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) != 0;
|
||||
if (!global && !sticky) {
|
||||
lastIndex = 0;
|
||||
}
|
||||
// 3. Search RegExpExecResult cache
|
||||
uint32_t lastIndexInput = lastIndex;
|
||||
if (useCache) {
|
||||
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputStr,
|
||||
RegExpExecResultCache::TEST_TYPE, regexp,
|
||||
JSTaggedValue(lastIndexInput));
|
||||
if (!cacheResult.IsUndefined()) {
|
||||
return cacheResult;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength();
|
||||
if (lastIndex > static_cast<int32_t>(length)) {
|
||||
object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0));
|
||||
return JSTaggedValue::False();
|
||||
}
|
||||
JSHandle<EcmaString> inputString = JSHandle<EcmaString>::Cast(inputStr);
|
||||
size_t stringLength = EcmaStringAccessor(inputString).GetLength();
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
|
||||
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
|
||||
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
|
||||
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
|
||||
}
|
||||
const uint8_t *strBuffer;
|
||||
if (isUtf16) {
|
||||
strBuffer = reinterpret_cast<const uint8_t *>(flatStrInfo.GetDataUtf16());
|
||||
} else {
|
||||
strBuffer = flatStrInfo.GetDataUtf8();
|
||||
}
|
||||
bool matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16);
|
||||
if (!matchResult) {
|
||||
if (global || sticky) {
|
||||
object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0));
|
||||
}
|
||||
return JSTaggedValue::False();
|
||||
}
|
||||
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
|
||||
globalTable->ResetDollar(thread);
|
||||
globalTable->SetInputString(thread, inputString.GetTaggedValue());
|
||||
JSTaggedValue endIndex = globalTable->GetEndIndex();
|
||||
if (global || sticky) {
|
||||
object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, endIndex);
|
||||
}
|
||||
if (useCache) {
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr,
|
||||
JSHandle<JSTaggedValue>(thread, JSTaggedValue(matchResult)),
|
||||
RegExpExecResultCache::TEST_TYPE,
|
||||
lastIndexInput, endIndex.GetInt());
|
||||
}
|
||||
return GetTaggedBoolean(matchResult);
|
||||
}
|
||||
|
||||
// 21.2.3.2.1
|
||||
JSTaggedValue BuiltinsRegExp::RegExpAlloc(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget)
|
||||
{
|
||||
@ -1804,7 +1949,7 @@ JSTaggedValue BuiltinsRegExp::FlagsBitsToString(JSThread *thread, uint8_t flags)
|
||||
{
|
||||
ASSERT((flags & 0x80) == 0); // 0x80: first bit of flags must be 0
|
||||
BUILTINS_API_TRACE(thread, RegExp, FlagsBitsToString);
|
||||
uint8_t *flagsStr = new uint8_t[7]; // 7: maximum 6 flags + '\0'
|
||||
uint8_t *flagsStr = new uint8_t[RegExpParser::FLAG_NUM + 1]; // FLAG_NUM flags + '\0'
|
||||
size_t flagsLen = 0;
|
||||
if (flags & RegExpParser::FLAG_HASINDICES) {
|
||||
flagsStr[flagsLen] = 'd';
|
||||
@ -1970,8 +2115,7 @@ EcmaString *BuiltinsRegExp::EscapeRegExpPattern(JSThread *thread, const JSHandle
|
||||
#define SET_GET_CAPTURE_IMPL(index) \
|
||||
JSTaggedValue BuiltinsRegExp::GetCapture##index(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &obj) \
|
||||
{ \
|
||||
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); \
|
||||
return globalTable->GetCapture<index>(); \
|
||||
return RegExpGlobalResult::GetCapture<index>(thread); \
|
||||
} \
|
||||
bool BuiltinsRegExp::SetCapture##index([[maybe_unused]] JSThread *thread, \
|
||||
[[maybe_unused]] const JSHandle<JSObject> &obj, \
|
||||
@ -2057,6 +2201,9 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread,
|
||||
case INTERMEDIATE_REPLACE_TYPE:
|
||||
result = Get(index + RESULT_INTERMEDIATE_REPLACE_INDEX);
|
||||
break;
|
||||
case TEST_TYPE:
|
||||
result = Get(index + RESULT_TEST_INDEX);
|
||||
break;
|
||||
default:
|
||||
LOG_ECMA(FATAL) << "this branch is unreachable";
|
||||
UNREACHABLE();
|
||||
@ -2193,6 +2340,9 @@ void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTag
|
||||
case INTERMEDIATE_REPLACE_TYPE:
|
||||
Set(thread, index + RESULT_INTERMEDIATE_REPLACE_INDEX, resultArray);
|
||||
break;
|
||||
case TEST_TYPE:
|
||||
Set(thread, index + RESULT_TEST_INDEX, resultArray);
|
||||
break;
|
||||
default:
|
||||
LOG_ECMA(FATAL) << "this branch is unreachable";
|
||||
UNREACHABLE();
|
||||
@ -2250,16 +2400,34 @@ bool RegExpExecResultCache::Match(int entry, JSTaggedValue &pattern, JSTaggedVal
|
||||
extendEqual;
|
||||
}
|
||||
|
||||
JSTaggedValue RegExpGlobalResult::CreateGloablResultTable(JSThread *thread)
|
||||
JSTaggedValue RegExpGlobalResult::CreateGlobalResultTable(JSThread *thread)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
uint32_t initialLength = GLOBAL_TABLE_SIZE + INITIAL_CAPTURE_INDICES;
|
||||
auto table = static_cast<RegExpGlobalResult *>(
|
||||
*factory->NewTaggedArray(GLOBAL_TABLE_SIZE, JSTaggedValue::Undefined()));
|
||||
*factory->NewTaggedArray(initialLength, JSTaggedValue::Undefined()));
|
||||
// initialize dollars with empty string
|
||||
JSTaggedValue emptyString = factory->GetEmptyString().GetTaggedValue();
|
||||
for (int i = 1; i <= DOLLAR_NUMBER; i++) {
|
||||
for (uint32_t i = 1; i <= DOLLAR_NUMBER; i++) {
|
||||
table->SetCapture(thread, CAPTURE_START_INDEX + i, emptyString);
|
||||
}
|
||||
// initialize match info
|
||||
table->SetTotalCaptureCounts(thread, JSTaggedValue(0));
|
||||
table->SetInputString(thread, emptyString);
|
||||
for (uint32_t i = 0; i < INITIAL_CAPTURE_INDICES / 2; i++) {
|
||||
table->SetStartOfCaptureIndex(thread, i, JSTaggedValue(0));
|
||||
table->SetEndOfCaptureIndex(thread, i, JSTaggedValue(0));
|
||||
}
|
||||
return JSTaggedValue(table);
|
||||
}
|
||||
|
||||
JSHandle<RegExpGlobalResult> RegExpGlobalResult::GrowCapturesCapacity(JSThread *thread,
|
||||
JSHandle<RegExpGlobalResult>result, uint32_t length)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> newResult = factory->ExtendArray(
|
||||
JSHandle<TaggedArray>(result), length, JSTaggedValue(0));
|
||||
thread->GetCurrentEcmaContext()->SetRegExpGlobalResult(newResult.GetTaggedValue());
|
||||
return JSHandle<RegExpGlobalResult>(newResult);
|
||||
}
|
||||
} // namespace panda::ecmascript::builtins
|
||||
|
@ -101,9 +101,10 @@ private:
|
||||
static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000;
|
||||
static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu;
|
||||
static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9;
|
||||
static constexpr uint32_t LAST_INDEX_OFFSET = 0;
|
||||
|
||||
static RegExpExecutor::MatchResult Matcher(JSThread *thread, const JSHandle<JSTaggedValue> ®exp,
|
||||
const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16);
|
||||
static bool Matcher(JSThread *thread, const JSHandle<JSTaggedValue> ®exp,
|
||||
const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16);
|
||||
|
||||
static bool GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
|
||||
const uint8_t mask);
|
||||
@ -124,6 +125,11 @@ private:
|
||||
const JSHandle<JSTaggedValue> &flags);
|
||||
static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle<JSTaggedValue> ®exp,
|
||||
JSHandle<EcmaString> inputString, uint32_t inputLength);
|
||||
static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle<JSTaggedValue> ®exp,
|
||||
const JSHandle<JSTaggedValue> &inputString, bool useCache);
|
||||
static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle<JSTaggedValue> ®exp,
|
||||
const JSHandle<JSTaggedValue> &inputStr, bool useCache);
|
||||
static bool IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> ®exp);
|
||||
// 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups )
|
||||
static JSHandle<JSTaggedValue> MakeMatchIndicesIndexPairArray(JSThread* thread,
|
||||
const std::vector<std::pair<JSTaggedValue, JSTaggedValue>>& indices,
|
||||
@ -137,7 +143,8 @@ public:
|
||||
SPLIT_TYPE,
|
||||
MATCH_TYPE,
|
||||
EXEC_TYPE,
|
||||
INTERMEDIATE_REPLACE_TYPE
|
||||
INTERMEDIATE_REPLACE_TYPE,
|
||||
TEST_TYPE
|
||||
};
|
||||
static RegExpExecResultCache *Cast(TaggedObject *object)
|
||||
{
|
||||
@ -252,9 +259,10 @@ private:
|
||||
static constexpr int RESULT_MATCH_INDEX = 7;
|
||||
static constexpr int RESULT_EXEC_INDEX = 8;
|
||||
static constexpr int RESULT_INTERMEDIATE_REPLACE_INDEX = 9;
|
||||
static constexpr int RESULT_TEST_INDEX = 10;
|
||||
// Extend index used for saving an additional parameter to judge cached
|
||||
static constexpr int EXTEND_INDEX = 10;
|
||||
static constexpr int ENTRY_SIZE = 11;
|
||||
static constexpr int EXTEND_INDEX = 11;
|
||||
static constexpr int ENTRY_SIZE = 12;
|
||||
};
|
||||
|
||||
class RegExpGlobalResult : public TaggedArray {
|
||||
@ -263,7 +271,7 @@ public:
|
||||
{
|
||||
return reinterpret_cast<RegExpGlobalResult *>(object);
|
||||
}
|
||||
static JSTaggedValue CreateGloablResultTable(JSThread *thread);
|
||||
static JSTaggedValue CreateGlobalResultTable(JSThread *thread);
|
||||
|
||||
void SetCapture(JSThread *thread, int index, JSTaggedValue value)
|
||||
{
|
||||
@ -271,17 +279,101 @@ public:
|
||||
Set(thread, CAPTURE_START_INDEX + index - 1, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
JSTaggedValue GetCapture()
|
||||
void ResetDollar(JSThread *thread)
|
||||
{
|
||||
return Get(CAPTURE_START_INDEX + N - 1);
|
||||
for (uint32_t i = 0; i < DOLLAR_NUMBER; i++) {
|
||||
Set(thread, CAPTURE_START_INDEX + i, JSTaggedValue::Hole());
|
||||
}
|
||||
}
|
||||
|
||||
template <int N>
|
||||
static JSTaggedValue GetCapture(JSThread *thread)
|
||||
{
|
||||
JSHandle<builtins::RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
|
||||
JSTaggedValue res = globalTable->Get(CAPTURE_START_INDEX + N - 1);
|
||||
int captureNum = globalTable->GetTotalCaptureCounts().GetInt();
|
||||
if (res.IsHole() && (N < captureNum)) {
|
||||
uint32_t startIndex = globalTable->GetStartOfCaptureIndex(N).GetInt();
|
||||
uint32_t endIndex = globalTable->GetEndOfCaptureIndex(N).GetInt();
|
||||
uint32_t len = endIndex - startIndex;
|
||||
if (len < 0) {
|
||||
res = JSTaggedValue::Undefined();
|
||||
} else {
|
||||
res = JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(),
|
||||
JSHandle<EcmaString>(thread, EcmaString::Cast(globalTable->GetInputString())), startIndex, len));
|
||||
}
|
||||
globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res);
|
||||
} else if (res.IsHole()) {
|
||||
res = thread->GetEcmaVM()->GetFactory()->GetEmptyString().GetTaggedValue();
|
||||
globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void SetTotalCaptureCounts(JSThread *thread, JSTaggedValue counts)
|
||||
{
|
||||
Set(thread, TOTAL_CAPTURE_COUNTS_INDEX, counts);
|
||||
}
|
||||
|
||||
JSTaggedValue GetTotalCaptureCounts()
|
||||
{
|
||||
return Get(TOTAL_CAPTURE_COUNTS_INDEX);
|
||||
}
|
||||
|
||||
void SetEndIndex(JSThread *thread, JSTaggedValue endIndex)
|
||||
{
|
||||
Set(thread, END_INDEX, endIndex);
|
||||
}
|
||||
|
||||
JSTaggedValue GetEndIndex()
|
||||
{
|
||||
return Get(END_INDEX);
|
||||
}
|
||||
|
||||
void SetInputString(JSThread *thread, JSTaggedValue string)
|
||||
{
|
||||
Set(thread, INPUT_STRING_INDEX, string);
|
||||
}
|
||||
|
||||
JSTaggedValue GetInputString()
|
||||
{
|
||||
return Get(INPUT_STRING_INDEX);
|
||||
}
|
||||
|
||||
void SetStartOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value)
|
||||
{
|
||||
Set(thread, FIRST_CAPTURE_INDEX + index * 2, value);
|
||||
}
|
||||
|
||||
void SetEndOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value)
|
||||
{
|
||||
Set(thread, FIRST_CAPTURE_INDEX + index * 2 + 1, value);
|
||||
}
|
||||
|
||||
JSTaggedValue GetStartOfCaptureIndex(uint32_t index)
|
||||
{
|
||||
return Get(FIRST_CAPTURE_INDEX + index * 2);
|
||||
}
|
||||
|
||||
JSTaggedValue GetEndOfCaptureIndex(uint32_t index)
|
||||
{
|
||||
return Get(FIRST_CAPTURE_INDEX + index * 2 + 1);
|
||||
}
|
||||
|
||||
static JSHandle<RegExpGlobalResult> GrowCapturesCapacity(JSThread *thread,
|
||||
JSHandle<RegExpGlobalResult>result, uint32_t length);
|
||||
|
||||
static constexpr int FIRST_CAPTURE_INDEX = 12; // capture index starts here
|
||||
|
||||
private:
|
||||
static constexpr int GLOBAL_TABLE_SIZE = 9;
|
||||
static constexpr int GLOBAL_TABLE_SIZE = 12; // initial length
|
||||
static constexpr int DOLLAR_NUMBER = 9;
|
||||
static constexpr int CAPTURE_START_INDEX = 0;
|
||||
};
|
||||
|
||||
static constexpr int TOTAL_CAPTURE_COUNTS_INDEX = 9; // save total capture size
|
||||
static constexpr int INPUT_STRING_INDEX = 10; // save input string
|
||||
static constexpr int END_INDEX = 11; // save last index
|
||||
static constexpr int INITIAL_CAPTURE_INDICES = 18; // length: pairs of capture start index and end index
|
||||
};
|
||||
} // namespace panda::ecmascript::builtins
|
||||
#endif // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H
|
||||
|
@ -71,6 +71,17 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(SET_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 5 : 5 more inline properties in Set.prototype
|
||||
// (1) Set.prototype.constructor
|
||||
// (2) Set.prototype [ @@toStringTag ]
|
||||
// (3) Set.prototype [ @@iterator ]
|
||||
// (4) get Set.prototype.size
|
||||
// (5) Set.prototype.keys, which is not included in BuiltinsSet::GetSetPrototypeFunctions()
|
||||
return GetSetPrototypeFunctions().Size() + 5;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_SET_FUNCTION_ENTRY(name, func, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsSet::func, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -1352,10 +1352,31 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
|
||||
// Let O be RequireObjectCoercible(this value).
|
||||
JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSObject> thisObj(thisTag);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSTaggedValue> seperatorTag = BuiltinsString::GetCallArg(argv, 0);
|
||||
JSHandle<JSTaggedValue> limitTag = BuiltinsString::GetCallArg(argv, 1);
|
||||
if (thisTag->IsString() && seperatorTag->IsString()) {
|
||||
JSHandle<EcmaString> thisString(thisTag);
|
||||
JSHandle<EcmaString> seperatorString(seperatorTag);
|
||||
auto thisLength = EcmaStringAccessor(thisString).GetLength();
|
||||
auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength();
|
||||
if (limitTag->IsUndefined() && thisLength != 0 && seperatorLength != 0) {
|
||||
return CreateArrayThisStringAndSeperatorStringAreNotEmpty(
|
||||
thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength);
|
||||
}
|
||||
uint32_t lim = UINT32_MAX - 1;
|
||||
if (!limitTag->IsUndefined()) {
|
||||
lim = JSTaggedValue::ToInteger(thread, limitTag).ToUint32();
|
||||
}
|
||||
// ReturnIfAbrupt(lim).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
if (lim == 0) {
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim);
|
||||
}
|
||||
|
||||
// If separator is neither undefined nor null, then
|
||||
if (seperatorTag->IsECMAObject()) {
|
||||
JSHandle<JSTaggedValue> splitKey = env->GetSplitSymbol();
|
||||
@ -1376,85 +1397,116 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
|
||||
// Let S be ToString(O).
|
||||
JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisTag);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// Let A be ArrayCreate(0).
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
uint32_t arrayLength = 0;
|
||||
|
||||
// If limit is undefined, let lim = 2^53–1; else let lim = ToLength(limit).
|
||||
uint32_t lim = 0;
|
||||
if (limitTag->IsUndefined()) {
|
||||
lim = UINT32_MAX - 1;
|
||||
} else {
|
||||
uint32_t lim = UINT32_MAX - 1;
|
||||
if (!limitTag->IsUndefined()) {
|
||||
lim = JSTaggedValue::ToInteger(thread, limitTag).ToUint32();
|
||||
}
|
||||
// ReturnIfAbrupt(lim).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// If lim = 0, return A.
|
||||
if (lim == 0) {
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
// Let s be the number of elements in S.
|
||||
int32_t thisLength = static_cast<int32_t>(EcmaStringAccessor(thisString).GetLength());
|
||||
auto thisLength = EcmaStringAccessor(thisString).GetLength();
|
||||
JSHandle<EcmaString> seperatorString = JSTaggedValue::ToString(thread, seperatorTag);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// If lim = 0, return A.
|
||||
if (lim == 0) {
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength();
|
||||
// If S is undefined or (this.length = 0 and S.length != 0), return array of size is 1 containing this string
|
||||
if (seperatorTag->IsUndefined()) {
|
||||
// Perform CreateDataProperty(A, "0", S).
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path
|
||||
JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString));
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception");
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
// If S.length = 0, then
|
||||
if (thisLength == 0) {
|
||||
if (EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString) != -1) {
|
||||
return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim);
|
||||
}
|
||||
|
||||
JSTaggedValue BuiltinsString::CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm,
|
||||
const JSHandle<EcmaString> &thisString, uint32_t thisLength, uint32_t lim)
|
||||
{
|
||||
uint32_t actualLength = std::min(thisLength, lim);
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(actualLength)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
for (uint32_t i = 0; i < actualLength; ++i) {
|
||||
EcmaString *elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, i, 1);
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
// Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path
|
||||
JSObject::CreateDataProperty(thread, resultArray, i, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
}
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue BuiltinsString::CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm,
|
||||
const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
|
||||
uint32_t thisLength, uint32_t seperatorLength, uint32_t lim)
|
||||
{
|
||||
if (thisLength != 0) {
|
||||
if (seperatorLength != 0) {
|
||||
return CreateArrayThisStringAndSeperatorStringAreNotEmpty(
|
||||
thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim);
|
||||
}
|
||||
return CreateArrayFromString(thread, ecmaVm, thisString, thisLength, lim);
|
||||
} else {
|
||||
if (seperatorLength != 0) {
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path
|
||||
JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString));
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception");
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString));
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception");
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t seperatorLength = static_cast<int32_t>(EcmaStringAccessor(seperatorString).GetLength());
|
||||
if (seperatorLength == 0) {
|
||||
for (int32_t i = 0; i < thisLength; ++i) {
|
||||
EcmaString *elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, i, 1);
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
++arrayLength;
|
||||
if (arrayLength == lim) {
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
}
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
JSTaggedValue BuiltinsString::CreateArrayThisStringAndSeperatorStringAreNotEmpty(JSThread *thread,
|
||||
EcmaVM *ecmaVm, const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
|
||||
uint32_t thisLength, uint32_t seperatorLength, uint32_t lim)
|
||||
{
|
||||
uint32_t arrayLength = 0;
|
||||
std::vector<int32_t> posArray;
|
||||
int32_t index = 0;
|
||||
int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString);
|
||||
while (pos != -1) {
|
||||
EcmaString *elementString;
|
||||
if (static_cast<uint32_t>(pos - index) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) {
|
||||
elementString = EcmaStringAccessor::GetSlicedString(ecmaVm, thisString, index, pos - index);
|
||||
} else {
|
||||
elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, index, pos - index);
|
||||
}
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
posArray.emplace_back(pos);
|
||||
++arrayLength;
|
||||
if (arrayLength == lim) {
|
||||
return resultArray.GetTaggedValue();
|
||||
break;
|
||||
}
|
||||
index = pos + seperatorLength;
|
||||
pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString, index);
|
||||
}
|
||||
EcmaString *elementString;
|
||||
if (static_cast<uint32_t>(thisLength - index) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) {
|
||||
elementString = EcmaStringAccessor::GetSlicedString(ecmaVm, thisString, index, thisLength - index);
|
||||
} else {
|
||||
elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, index, thisLength - index);
|
||||
uint32_t posArrLength = posArray.size();
|
||||
arrayLength = lim > posArrLength ? posArrLength + 1 : posArrLength;
|
||||
JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(arrayLength)));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
index = 0;
|
||||
for (uint32_t i = 0; i < posArrLength; i++) {
|
||||
pos = posArray[i];
|
||||
EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, pos - index);
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
// Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path
|
||||
JSObject::CreateDataProperty(thread, resultArray, i, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
index = pos + seperatorLength;
|
||||
}
|
||||
if (lim > posArrLength) {
|
||||
EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, thisLength - index);
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
// Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path
|
||||
JSObject::CreateDataProperty(thread, resultArray, posArrLength, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
}
|
||||
JSHandle<JSTaggedValue> elementTag(thread, elementString);
|
||||
JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag);
|
||||
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
|
||||
return resultArray.GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -1533,10 +1585,7 @@ JSTaggedValue BuiltinsString::Substring(EcmaRuntimeCallInfo *argv)
|
||||
int32_t from = std::min(start, end);
|
||||
int32_t to = std::max(start, end);
|
||||
int32_t len = to - from;
|
||||
if (static_cast<uint32_t>(len) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) {
|
||||
return JSTaggedValue(EcmaStringAccessor::GetSlicedString(thread->GetEcmaVM(), thisHandle, from, len));
|
||||
}
|
||||
return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisHandle, from, len));
|
||||
return JSTaggedValue(EcmaStringAccessor::GetSubString(thread->GetEcmaVM(), thisHandle, from, len));
|
||||
}
|
||||
|
||||
// 21.1.3.20
|
||||
|
@ -234,6 +234,15 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(STRING_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 3 : 3 more inline properties in String.prototype:
|
||||
// (1) String.prototype.constructor
|
||||
// (2) String.prototype [ @@iterator ]
|
||||
// (3) get length
|
||||
return GetStringPrototypeFunctions().Size() + 3;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_STRING_FUNCTION_ENTRY(name, method, length, builtinId) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsString::method, length, kungfu::BuiltinsStubCSigns::builtinId),
|
||||
@ -248,6 +257,15 @@ private:
|
||||
|
||||
static JSTaggedValue Pad(EcmaRuntimeCallInfo *argv, bool isStart);
|
||||
static int32_t ConvertDoubleToInt(double d);
|
||||
static JSTaggedValue CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm,
|
||||
const JSHandle<EcmaString> &thisString, uint32_t thisLength, uint32_t lim);
|
||||
static JSTaggedValue CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm,
|
||||
const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
|
||||
uint32_t thisLength, uint32_t seperatorLength, uint32_t lim);
|
||||
static JSTaggedValue CreateArrayThisStringAndSeperatorStringAreNotEmpty(
|
||||
JSThread *thread, EcmaVM *ecmaVm,
|
||||
const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
|
||||
uint32_t thisLength, uint32_t seperatorLength, uint32_t lim = UINT32_MAX - 1);
|
||||
// 21.1.3.17.1
|
||||
};
|
||||
} // namespace panda::ecmascript::builtins
|
||||
|
@ -240,6 +240,17 @@ public:
|
||||
return Span<const base::BuiltinFunctionEntry>(TYPED_ARRAY_PROTOTYPE_FUNCTIONS);
|
||||
}
|
||||
|
||||
static size_t GetNumPrototypeInlinedProperties()
|
||||
{
|
||||
// 4 : 4 more inline properties in %TypedArray%.prototype for the following functions/accessors:
|
||||
// (1) %TypedArray%.prototype.constructor
|
||||
// (2) %TypedArray%.prototype.toString, which is strictly equal to Array.prototype.toString
|
||||
// (3) %TypedArray%.prototype[@@iterator]
|
||||
// (4) %TypedArray%.prototype[@@toStringTag]
|
||||
return GetTypedArrayPrototypeFunctions().Size() +
|
||||
GetTypedArrayPrototypeAccessors().Size() + 4;
|
||||
}
|
||||
|
||||
private:
|
||||
#define BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY(name, func, length, id) \
|
||||
base::BuiltinFunctionEntry::Create(name, BuiltinsTypedArray::func, length, kungfu::BuiltinsStubCSigns::id),
|
||||
|
@ -647,4 +647,28 @@ HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_003)
|
||||
JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
|
||||
EXPECT_EQ(elements->GetLength(), 16U);
|
||||
}
|
||||
|
||||
// DateTimeFormat_004
|
||||
HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_004)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
|
||||
auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
|
||||
JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
|
||||
JSHandle<JSTaggedValue> fullValue(factory->NewFromASCII("full"));
|
||||
JSHandle<JSTaggedValue> falseValue(thread, JSTaggedValue(false));
|
||||
JSHandle<JSTaggedValue> dateStyleValue(factory->NewFromASCII("dateStyle"));
|
||||
JSHandle<JSTaggedValue> timeStyleeValue(factory->NewFromASCII("timeStyle"));
|
||||
JSHandle<JSTaggedValue> hour12Value(factory->NewFromASCII("hour12"));
|
||||
JSObject::SetProperty(thread, optionsObj, dateStyleValue, fullValue);
|
||||
JSObject::SetProperty(thread, optionsObj, timeStyleeValue, fullValue);
|
||||
JSObject::SetProperty(thread, optionsObj, hour12Value, falseValue);
|
||||
auto constructorResult = JSDateTimeFormatConstructor(thread, optionsObj, localesString);
|
||||
JSHandle<EcmaString> resultStr =
|
||||
JSDateTimeFormat::FormatDateTime(thread, JSHandle<JSDateTimeFormat>(thread, constructorResult), 0.0);
|
||||
EXPECT_STREQ("1970年1月1日星期四 中国标准时间 08:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
|
||||
}
|
||||
} // namespace panda::test
|
||||
|
||||
|
@ -156,13 +156,13 @@ using Address = uintptr_t;
|
||||
#ifdef PANDA_TARGET_32
|
||||
#define STATIC_ASSERT_EQ_ARCH32(a, b) static_assert(a == b)
|
||||
#else
|
||||
#define STATIC_ASSERT_EQ_ARCH32(a, b)
|
||||
#define STATIC_ASSERT_EQ_ARCH32(a, b) static_assert(true)
|
||||
#endif
|
||||
|
||||
#ifdef PANDA_TARGET_64
|
||||
#define STATIC_ASSERT_EQ_ARCH64(a, b) static_assert(a == b)
|
||||
#else
|
||||
#define STATIC_ASSERT_EQ_ARCH64(a, b)
|
||||
#define STATIC_ASSERT_EQ_ARCH64(a, b) static_assert(true)
|
||||
#endif
|
||||
|
||||
#if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS) || defined(PANDA_TARGET_IOS)
|
||||
@ -172,7 +172,7 @@ using Address = uintptr_t;
|
||||
#endif
|
||||
|
||||
#define STATIC_ASSERT_EQ_ARCH(expect, valueArch32, valueArch64) \
|
||||
STATIC_ASSERT_EQ_ARCH32(expect, valueArch32) \
|
||||
STATIC_ASSERT_EQ_ARCH32(expect, valueArch32); \
|
||||
STATIC_ASSERT_EQ_ARCH64(expect, valueArch64)
|
||||
} // namespace ecmascript
|
||||
} // namespace panda
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "ecmascript/js_runtime_options.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile_manager.h"
|
||||
#include "ecmascript/log.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/module/js_module_manager.h"
|
||||
#include "ecmascript/napi/include/jsnapi.h"
|
||||
#include "ecmascript/platform/file.h"
|
||||
@ -42,8 +43,7 @@ std::string GetHelper()
|
||||
return str;
|
||||
}
|
||||
|
||||
CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions,
|
||||
OhosPkgArgs &pkgArgs, arg_list_t &pandaFileNames)
|
||||
CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions)
|
||||
{
|
||||
triple_ = runtimeOptions.GetTargetTriple();
|
||||
if (runtimeOptions.GetAOTOutputFile().empty()) {
|
||||
@ -91,22 +91,21 @@ bool CompilationPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOpti
|
||||
bool CompilationPreprocessor::HandleOhosPkgArgs()
|
||||
{
|
||||
ASSERT(runtimeOptions_.IsTargetCompilerMode());
|
||||
OhosPkgArgs pkgArgs;
|
||||
if (!runtimeOptions_.GetCompilerPkgJsonInfo().empty()) {
|
||||
if (pkgArgs_.ParseFromJson(vm_, runtimeOptions_.GetCompilerPkgJsonInfo())) {
|
||||
if (pkgArgs.ParseFromJson(vm_, runtimeOptions_.GetCompilerPkgJsonInfo())) {
|
||||
LOG_COMPILER(INFO) << "Parse main pkg info success.";
|
||||
pkgArgs_.Dump();
|
||||
pandaFileNames_.emplace_back(pkgArgs_.GetFullName());
|
||||
pkgsArgs_[pkgArgs.GetFullName()] = pkgArgs;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// for external pkg, dump it first.
|
||||
if (!runtimeOptions_.GetCompilerExternalPkgJsonInfo().empty()) {
|
||||
std::list<OhosPkgArgs> externalList;
|
||||
OhosPkgArgs::ParseListFromJson(vm_, runtimeOptions_.GetCompilerExternalPkgJsonInfo(), externalList);
|
||||
for (const auto &externalPkg : externalList) {
|
||||
externalPkg.Dump();
|
||||
}
|
||||
if (runtimeOptions_.GetCompilerEnableExternalPkg() && !runtimeOptions_.GetCompilerExternalPkgJsonInfo().empty()) {
|
||||
OhosPkgArgs::ParseListFromJson(vm_, runtimeOptions_.GetCompilerExternalPkgJsonInfo(), pkgsArgs_);
|
||||
}
|
||||
for (const auto &pkgInfo : pkgsArgs_) {
|
||||
pandaFileNames_.emplace_back(pkgInfo.first);
|
||||
pkgInfo.second.Dump();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -125,7 +124,7 @@ void CompilationPreprocessor::HandleTargetModeInfo(CompilationOptions &cOptions)
|
||||
|
||||
bool CompilationPreprocessor::HandlePandaFileNames(const int argc, const char **argv)
|
||||
{
|
||||
if (runtimeOptions_.GetCompilerPkgJsonInfo().empty() || !pkgArgs_.Valid()) {
|
||||
if (runtimeOptions_.GetCompilerPkgJsonInfo().empty() || pkgsArgs_.empty()) {
|
||||
// if no pkgArgs, last param must be abc file
|
||||
std::string files = argv[argc - 1];
|
||||
if (!base::StringHelper::EndsWith(files, ".abc")) {
|
||||
@ -182,37 +181,14 @@ std::shared_ptr<JSPandaFile> CompilationPreprocessor::CreateAndVerifyJSPandaFile
|
||||
JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance();
|
||||
std::shared_ptr<JSPandaFile> jsPandaFile = nullptr;
|
||||
if (runtimeOptions_.IsTargetCompilerMode()) {
|
||||
std::string hapPath;
|
||||
uint32_t offset {};
|
||||
uint32_t size {};
|
||||
if (pkgArgs_.Valid()) {
|
||||
hapPath = pkgArgs_.GetPath();
|
||||
offset = pkgArgs_.GetOffset();
|
||||
size = pkgArgs_.GetSize();
|
||||
} else {
|
||||
// for legacy params
|
||||
hapPath = runtimeOptions_.GetHapPath();
|
||||
offset = runtimeOptions_.GetHapAbcOffset();
|
||||
size = runtimeOptions_.GetHapAbcSize();
|
||||
}
|
||||
if (size == 0) {
|
||||
LOG_ECMA(ERROR) << "buffer is empty in target compiler mode!";
|
||||
auto pkgArgsIter = pkgsArgs_.find(fileName);
|
||||
if (pkgArgsIter == pkgsArgs_.end()) {
|
||||
LOG_COMPILER(ERROR) << "Can not find file in ohos pkgs args. file name: " << fileName;
|
||||
return nullptr;
|
||||
}
|
||||
std::string realPath;
|
||||
if (!RealPath(hapPath, realPath, false)) {
|
||||
LOG_ECMA(ERROR) << "realpath for hap path failed!";
|
||||
if (!(pkgArgsIter->second.GetJSPandaFile(runtimeOptions_, jsPandaFile))) {
|
||||
return nullptr;
|
||||
}
|
||||
MemMap fileMapMem = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ);
|
||||
if (fileMapMem.GetOriginAddr() == nullptr) {
|
||||
LOG_ECMA(ERROR) << "File mmap failed";
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t *buffer = reinterpret_cast<uint8_t *>(fileMapMem.GetOriginAddr()) + offset;
|
||||
jsPandaFile = jsPandaFileManager->OpenJSPandaFileFromBuffer(buffer, size, fileName.c_str());
|
||||
FileUnMap(fileMapMem);
|
||||
fileMapMem.Reset();
|
||||
} else {
|
||||
jsPandaFile = jsPandaFileManager->OpenJSPandaFile(fileName.c_str());
|
||||
}
|
||||
@ -342,15 +318,15 @@ int Main(const int argc, const char **argv)
|
||||
{
|
||||
LocalScope scope(vm);
|
||||
arg_list_t pandaFileNames {};
|
||||
OhosPkgArgs pkgArgs;
|
||||
CompilationOptions cOptions(vm, runtimeOptions, pkgArgs, pandaFileNames);
|
||||
std::map<std::string, OhosPkgArgs> pkgArgsMap;
|
||||
CompilationOptions cOptions(vm, runtimeOptions);
|
||||
|
||||
CompilerLog log(cOptions.logOption_);
|
||||
log.SetEnableCompilerLogTime(cOptions.compilerLogTime_);
|
||||
AotMethodLogList logList(cOptions.logMethodsList_);
|
||||
PGOProfilerDecoder profilerDecoder(cOptions.profilerIn_, cOptions.hotnessThreshold_);
|
||||
|
||||
CompilationPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgs, profilerDecoder, pandaFileNames);
|
||||
CompilationPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgsMap, profilerDecoder, pandaFileNames);
|
||||
if (!cPreprocessor.HandleTargetCompilerMode(cOptions) ||
|
||||
!cPreprocessor.HandlePandaFileNames(argc, argv)) {
|
||||
return 1;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifndef ECMASCRIPT_COMPILER_AOT_COMPILER_H
|
||||
#define ECMASCRIPT_COMPILER_AOT_COMPILER_H
|
||||
|
||||
#include "ecmascript/compiler/ohos_pkg_args.h"
|
||||
#include "ecmascript/ohos/ohos_pkg_args.h"
|
||||
#include "ecmascript/compiler/pass_manager.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
|
||||
@ -33,8 +33,7 @@ struct AbcFileInfo {
|
||||
};
|
||||
|
||||
struct CompilationOptions {
|
||||
explicit CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions,
|
||||
OhosPkgArgs &pkgArgs, arg_list_t &pandaFileNames);
|
||||
explicit CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions);
|
||||
|
||||
std::string triple_;
|
||||
std::string outputFileName_;
|
||||
@ -64,9 +63,9 @@ struct CompilationOptions {
|
||||
|
||||
class CompilationPreprocessor {
|
||||
public:
|
||||
CompilationPreprocessor(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, OhosPkgArgs &pkgArgs,
|
||||
CompilationPreprocessor(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, std::map<std::string, OhosPkgArgs> &pkgsArgs,
|
||||
PGOProfilerDecoder &profilerDecoder, arg_list_t &pandaFileNames)
|
||||
: vm_(vm), runtimeOptions_(runtimeOptions), pkgArgs_(pkgArgs),
|
||||
: vm_(vm), runtimeOptions_(runtimeOptions), pkgsArgs_(pkgsArgs),
|
||||
profilerDecoder_(profilerDecoder), pandaFileNames_(pandaFileNames) {};
|
||||
~CompilationPreprocessor() = default;
|
||||
|
||||
@ -106,7 +105,7 @@ private:
|
||||
|
||||
EcmaVM *vm_;
|
||||
JSRuntimeOptions &runtimeOptions_;
|
||||
OhosPkgArgs &pkgArgs_;
|
||||
std::map<std::string, OhosPkgArgs> &pkgsArgs_;
|
||||
PGOProfilerDecoder &profilerDecoder_;
|
||||
arg_list_t &pandaFileNames_;
|
||||
CVector<AbcFileInfo> fileInfos_;
|
||||
|
@ -71,6 +71,9 @@ void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef n
|
||||
Bind(&thisIsEmpty);
|
||||
{
|
||||
Label isCallable(env);
|
||||
Label isHeapObject(env);
|
||||
Branch(TaggedIsHeapObject(GetCallArg0(numArgs)), &isHeapObject, slowPath);
|
||||
Bind(&isHeapObject);
|
||||
Branch(IsCallable(GetCallArg0(numArgs)), &isCallable, slowPath);
|
||||
// Creates an empty array on fast path
|
||||
Bind(&isCallable);
|
||||
@ -86,6 +89,7 @@ void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef th
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label thisIsEmpty(env);
|
||||
Label isHeapObject(env);
|
||||
// Fast path if all the conditions below are satisfied:
|
||||
// (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details);
|
||||
// (2) callbackFn is callable (otherwise a TypeError shall be thrown in the slow path)
|
||||
@ -94,6 +98,8 @@ void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef th
|
||||
Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
|
||||
Bind(&thisIsEmpty);
|
||||
// Do nothing on fast path
|
||||
Branch(TaggedIsHeapObject(GetCallArg0(numArgs)), &isHeapObject, slowPath);
|
||||
Bind(&isHeapObject);
|
||||
Branch(IsCallable(GetCallArg0(numArgs)), exit, slowPath);
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ namespace panda::ecmascript::kungfu {
|
||||
V(StringFromCharCode) \
|
||||
V(ObjectToString) \
|
||||
V(ObjectCreate) \
|
||||
V(ObjectAssign) \
|
||||
V(VectorForEach) \
|
||||
V(VectorReplaceAllElements) \
|
||||
V(StackForEach) \
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "ecmascript/compiler/typed_array_stub_builder.h"
|
||||
#include "ecmascript/js_arguments.h"
|
||||
#include "ecmascript/message_string.h"
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
GateRef BuiltinsObjectStubBuilder::CreateListFromArrayLike(GateRef glue, GateRef arrayObj)
|
||||
{
|
||||
@ -287,4 +289,462 @@ void BuiltinsObjectStubBuilder::Create(Variable *result, Label *exit, Label *slo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::AssignEnumElementProperty(Variable *result, Label *funcExit,
|
||||
GateRef toAssign, GateRef source)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryLabel(env);
|
||||
env->SubCfgEntry(&entryLabel);
|
||||
Label exit(env);
|
||||
|
||||
GateRef elements = GetElementsArray(source);
|
||||
Label dictionaryMode(env);
|
||||
Label notDictionaryMode(env);
|
||||
Branch(IsDictionaryMode(elements), &dictionaryMode, ¬DictionaryMode);
|
||||
Bind(¬DictionaryMode);
|
||||
{
|
||||
GateRef len = GetLengthOfTaggedArray(elements);
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label next(env);
|
||||
Label loopExit(env);
|
||||
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
{
|
||||
Branch(Int32LessThan(*idx, len), &next, &loopExit);
|
||||
Bind(&next);
|
||||
GateRef value = GetValueFromTaggedArray(elements, *idx);
|
||||
Label notHole(env);
|
||||
Branch(TaggedIsHole(value), &loopEnd, ¬Hole);
|
||||
Bind(¬Hole);
|
||||
{
|
||||
// key, value
|
||||
FastSetPropertyByIndex(glue_, toAssign, *idx, value);
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &loopEnd);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&loopEnd);
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
Bind(&loopExit);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&dictionaryMode);
|
||||
{
|
||||
// NumberDictionary::VisitAllEnumProperty
|
||||
GateRef sizeIndex = Int32(TaggedHashTable<NumberDictionary>::SIZE_INDEX);
|
||||
GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(elements, sizeIndex));
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label next(env);
|
||||
Label loopExit(env);
|
||||
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
{
|
||||
Branch(Int32LessThan(*idx, size), &next, &loopExit);
|
||||
Bind(&next);
|
||||
GateRef key = GetKeyFromDictionary<NumberDictionary>(elements, *idx);
|
||||
Label checkEnumerable(env);
|
||||
Branch(BoolOr(TaggedIsUndefined(key), TaggedIsHole(key)), &loopEnd, &checkEnumerable);
|
||||
Bind(&checkEnumerable);
|
||||
{
|
||||
GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, *idx);
|
||||
Label enumerable(env);
|
||||
Branch(IsEnumerable(attr), &enumerable, &loopEnd);
|
||||
Bind(&enumerable);
|
||||
{
|
||||
GateRef value = GetValueFromDictionary<NumberDictionary>(elements, *idx);
|
||||
Label notHole(env);
|
||||
Branch(TaggedIsHole(value), &loopEnd, ¬Hole);
|
||||
Bind(¬Hole);
|
||||
{
|
||||
// value
|
||||
FastSetPropertyByIndex(glue_, toAssign, *idx, value);
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &loopEnd);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&loopEnd);
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
Bind(&loopExit);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::LayoutInfoAssignAllEnumProperty(Variable *result, Label *funcExit,
|
||||
GateRef toAssign, GateRef source)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryLabel(env);
|
||||
env->SubCfgEntry(&entryLabel);
|
||||
Label exit(env);
|
||||
|
||||
// LayoutInfo::VisitAllEnumProperty
|
||||
GateRef cls = LoadHClass(source);
|
||||
GateRef num = GetNumberOfPropsFromHClass(cls);
|
||||
GateRef layout = GetLayoutFromHClass(cls);
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label next(env);
|
||||
Label loopExit(env);
|
||||
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
{
|
||||
Branch(Int32LessThan(*idx, num), &next, &loopExit);
|
||||
Bind(&next);
|
||||
|
||||
GateRef key = GetKeyFromLayoutInfo(layout, *idx);
|
||||
GateRef attr = TruncInt64ToInt32(GetPropAttrFromLayoutInfo(layout, *idx));
|
||||
Label stringKey(env);
|
||||
Branch(TaggedIsString(key), &stringKey, &loopEnd);
|
||||
Bind(&stringKey);
|
||||
{
|
||||
Label enumerable(env);
|
||||
Branch(IsEnumerable(attr), &enumerable, &loopEnd);
|
||||
Bind(&enumerable);
|
||||
{
|
||||
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
|
||||
value = JSObjectGetProperty(source, cls, attr);
|
||||
// exception
|
||||
Label exception0(env);
|
||||
Label noexception0(env);
|
||||
Branch(HasPendingException(glue_), &exception0, &noexception0);
|
||||
Bind(&exception0);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
Bind(&noexception0);
|
||||
Label propertyBox(env);
|
||||
Label checkAccessor(env);
|
||||
Label setValue(env);
|
||||
Branch(TaggedIsPropertyBox(*value), &propertyBox, &checkAccessor);
|
||||
Bind(&propertyBox);
|
||||
{
|
||||
value = GetValueFromPropertyBox(*value);
|
||||
Jump(&setValue);
|
||||
}
|
||||
Bind(&checkAccessor);
|
||||
Label isAccessor(env);
|
||||
Branch(IsAccessor(attr), &isAccessor, &setValue);
|
||||
Bind(&isAccessor);
|
||||
{
|
||||
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &setValue);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
Bind(&setValue);
|
||||
{
|
||||
FastSetPropertyByName(glue_, toAssign, key, *value);
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &loopEnd);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&loopEnd);
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
Bind(&loopExit);
|
||||
Jump(&exit);
|
||||
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::NameDictionaryAssignAllEnumProperty(Variable *result, Label *funcExit,
|
||||
GateRef toAssign, GateRef source, GateRef properties)
|
||||
{
|
||||
// NameDictionary::VisitAllEnumProperty
|
||||
auto env = GetEnvironment();
|
||||
Label entryLabel(env);
|
||||
env->SubCfgEntry(&entryLabel);
|
||||
Label exit(env);
|
||||
|
||||
GateRef sizeIndex = Int32(TaggedHashTable<NameDictionary>::SIZE_INDEX);
|
||||
GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(properties, sizeIndex));
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label next(env);
|
||||
Label loopExit(env);
|
||||
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
{
|
||||
Branch(Int32LessThan(*idx, size), &next, &loopExit);
|
||||
Bind(&next);
|
||||
GateRef key = GetKeyFromDictionary<NameDictionary>(properties, *idx);
|
||||
Label stringKey(env);
|
||||
Branch(TaggedIsString(key), &stringKey, &loopEnd);
|
||||
Bind(&stringKey);
|
||||
{
|
||||
GateRef attr = GetAttributesFromDictionary<NameDictionary>(properties, *idx);
|
||||
Label enumerable(env);
|
||||
Branch(IsEnumerable(attr), &enumerable, &loopEnd);
|
||||
Bind(&enumerable);
|
||||
{
|
||||
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
|
||||
value = GetValueFromDictionary<NameDictionary>(properties, *idx);
|
||||
Label notHole(env);
|
||||
Branch(TaggedIsHole(*value), &loopEnd, ¬Hole);
|
||||
Bind(¬Hole);
|
||||
{
|
||||
Label isAccessor(env);
|
||||
Label notAccessor(env);
|
||||
Branch(IsAccessor(attr), &isAccessor, ¬Accessor);
|
||||
Bind(&isAccessor);
|
||||
{
|
||||
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
|
||||
// exception
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, ¬Accessor);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
Bind(¬Accessor);
|
||||
{
|
||||
FastSetPropertyByName(glue_, toAssign, key, *value);
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &loopEnd);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&loopEnd);
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
Bind(&loopExit);
|
||||
Jump(&exit);
|
||||
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::AssignAllEnumProperty(Variable *res, Label *funcExit,
|
||||
GateRef toAssign, GateRef source)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryLabel(env);
|
||||
env->SubCfgEntry(&entryLabel);
|
||||
Label exit(env);
|
||||
|
||||
GateRef properties = GetPropertiesArray(source);
|
||||
Label dictionaryMode(env);
|
||||
Label notDictionaryMode(env);
|
||||
Branch(IsDictionaryMode(properties), &dictionaryMode, ¬DictionaryMode);
|
||||
Bind(¬DictionaryMode);
|
||||
{
|
||||
LayoutInfoAssignAllEnumProperty(res, funcExit, toAssign, source);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&dictionaryMode);
|
||||
{
|
||||
NameDictionaryAssignAllEnumProperty(res, funcExit, toAssign, source, properties);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::SlowAssign(Variable *result, Label *funcExit, GateRef toAssign, GateRef source)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryLabel(env);
|
||||
env->SubCfgEntry(&entryLabel);
|
||||
Label exit(env);
|
||||
CallRuntime(glue_, RTSTUB_ID(ObjectSlowAssign), { toAssign, source });
|
||||
|
||||
Label exception(env);
|
||||
Branch(HasPendingException(glue_), &exception, &exit);
|
||||
Bind(&exception);
|
||||
{
|
||||
*result = Exception();
|
||||
Jump(funcExit);
|
||||
}
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source)
|
||||
{
|
||||
// visit elements
|
||||
AssignEnumElementProperty(res, funcExit, toAssign, source);
|
||||
AssignAllEnumProperty(res, funcExit, toAssign, source);
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::Assign(Variable *res, Label *nextIt, Label *funcExit,
|
||||
GateRef toAssign, GateRef source)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label checkJsObj(env);
|
||||
Branch(BoolOr(TaggedIsNull(source), TaggedIsUndefined(source)), nextIt, &checkJsObj);
|
||||
Bind(&checkJsObj);
|
||||
{
|
||||
Label fastAssign(env);
|
||||
Label slowAssign(env);
|
||||
Branch(IsJSObjectType(source, JSType::JS_OBJECT), &fastAssign, &slowAssign);
|
||||
Bind(&fastAssign);
|
||||
{
|
||||
FastAssign(res, funcExit, toAssign, source);
|
||||
Jump(nextIt);
|
||||
}
|
||||
Bind(&slowAssign);
|
||||
{
|
||||
SlowAssign(res, funcExit, toAssign, source);
|
||||
Jump(nextIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsObjectStubBuilder::Assign(Variable *result, Label *exit, Label *slowPath)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label thisCollectionObj(env);
|
||||
|
||||
GateRef target = GetCallArg0(numArgs_);
|
||||
*result = target;
|
||||
Label jsObject(env);
|
||||
Branch(IsJSObjectType(target, JSType::JS_OBJECT), &jsObject, slowPath);
|
||||
Bind(&jsObject);
|
||||
{
|
||||
Label twoArg(env);
|
||||
Label notTwoArg(env);
|
||||
Branch(Int64Equal(numArgs_, IntPtr(2)), &twoArg, ¬TwoArg); // 2 : two args
|
||||
Bind(&twoArg);
|
||||
{
|
||||
GateRef source = GetCallArg1(numArgs_);
|
||||
Label next(env);
|
||||
Assign(result, &next, exit, target, source);
|
||||
Bind(&next);
|
||||
Jump(exit);
|
||||
}
|
||||
Bind(¬TwoArg);
|
||||
Label threeArg(env);
|
||||
Label notThreeArg(env);
|
||||
Branch(Int64Equal(numArgs_, IntPtr(3)), &threeArg, ¬ThreeArg); // 3 : three args
|
||||
Bind(&threeArg);
|
||||
{
|
||||
Label nextArg(env);
|
||||
GateRef source = GetCallArg1(numArgs_);
|
||||
Label next(env);
|
||||
Assign(result, &next, exit, target, source);
|
||||
Bind(&next);
|
||||
Label next1(env);
|
||||
GateRef source1 = GetCallArg2(numArgs_);
|
||||
Assign(result, &next1, exit, target, source1);
|
||||
Bind(&next1);
|
||||
Jump(exit);
|
||||
}
|
||||
Bind(¬ThreeArg);
|
||||
{
|
||||
Jump(slowPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GateRef BuiltinsObjectStubBuilder::CloneObjectLiteral(GateRef glue, GateRef objLiteral)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entry(env);
|
||||
Label loopHead(env);
|
||||
Label loopExit(env);
|
||||
Label loopBack(env);
|
||||
env->SubCfgEntry(&entry);
|
||||
auto klass = LoadHClass(objLiteral);
|
||||
NewObjectStubBuilder objBuilder(this);
|
||||
auto newObj = objBuilder.NewJSObject(glue, klass);
|
||||
|
||||
auto elements = GetElementsArray(objLiteral);
|
||||
auto newElements = CloneProperties(glue, elements);
|
||||
SetElementsArray(VariableType::JS_ANY(), glue, newObj, newElements);
|
||||
|
||||
auto properties = GetPropertiesArray(objLiteral);
|
||||
auto newProperties = CloneProperties(glue, properties);
|
||||
SetPropertiesArray(VariableType::JS_ANY(), glue, newObj, newProperties);
|
||||
|
||||
auto inlinedProperties = GetInlinedPropertiesFromHClass(klass);
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
Branch(Int32UnsignedLessThan(*idx, inlinedProperties), &loopBack, &loopExit);
|
||||
Bind(&loopBack);
|
||||
{
|
||||
auto value = GetPropertyInlinedProps(objLiteral, klass, *idx);
|
||||
SetPropertyInlinedProps(glue, newObj, klass, value, *idx, VariableType::JS_ANY());
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
}
|
||||
Bind(&loopExit);
|
||||
env->SubCfgExit();
|
||||
return newObj;
|
||||
}
|
||||
|
||||
GateRef BuiltinsObjectStubBuilder::CloneProperties(GateRef glue, GateRef old)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entry(env);
|
||||
env->SubCfgEntry(&entry);
|
||||
DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
|
||||
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
|
||||
auto newLength = GetLengthOfTaggedArray(old);
|
||||
Label exit(env);
|
||||
Label loopHead(env);
|
||||
Label loopBack(env);
|
||||
NewObjectStubBuilder newObjBuilder(GetEnvironment());
|
||||
auto newArray = newObjBuilder.NewTaggedArray(glue, newLength);
|
||||
Jump(&loopHead);
|
||||
LoopBegin(&loopHead);
|
||||
Branch(Int32UnsignedLessThan(*idx, newLength), &loopBack, &exit);
|
||||
Bind(&loopBack);
|
||||
auto value = GetValueFromTaggedArray(old, *idx);
|
||||
SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArray, *idx, value);
|
||||
idx = Int32Add(*idx, Int32(1));
|
||||
LoopEnd(&loopHead);
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
return newArray;
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
@ -31,14 +31,25 @@ public:
|
||||
GateRef CreateListFromArrayLike(GateRef glue, GateRef arrayObj);
|
||||
void ToString(Variable *result, Label *exit, Label *slowPath);
|
||||
void Create(Variable *result, Label *exit, Label *slowPath);
|
||||
void Assign(Variable *result, Label *exit, Label *slowPath);
|
||||
GateRef CloneObjectLiteral(GateRef glue, GateRef objLiteral);
|
||||
GateRef CloneProperties(GateRef glue, GateRef old);
|
||||
|
||||
private:
|
||||
GateRef OrdinaryNewJSObjectCreate(GateRef proto);
|
||||
GateRef TransProtoWithoutLayout(GateRef hClass, GateRef proto);
|
||||
void AssignEnumElementProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
void LayoutInfoAssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
void NameDictionaryAssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source,
|
||||
GateRef properties);
|
||||
void SlowAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
void FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
void AssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
void Assign(Variable *res, Label *nextIt, Label *funcExit, GateRef toAssign, GateRef source);
|
||||
|
||||
GateRef glue_;
|
||||
GateRef thisValue_;
|
||||
GateRef numArgs_;
|
||||
};
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_BUILTINS_OBJECT_STUB_BUILDER_H
|
||||
#endif // ECMASCRIPT_COMPILER_BUILTINS_OBJECT_STUB_BUILDER_H
|
||||
|
@ -359,9 +359,6 @@ void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateR
|
||||
Label startGreatEnd(env);
|
||||
Label startNotGreatEnd(env);
|
||||
Label thisIsHeapobject(env);
|
||||
Label flattenFastPath(env);
|
||||
Label sliceString(env);
|
||||
Label fastSubstring(env);
|
||||
|
||||
Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
|
||||
Bind(&objNotUndefinedAndNull);
|
||||
@ -465,28 +462,77 @@ void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateR
|
||||
Bind(&countRes);
|
||||
{
|
||||
GateRef len = Int32Sub(*to, *from);
|
||||
FlatStringStubBuilder thisFlat(this);
|
||||
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
|
||||
Bind(&flattenFastPath);
|
||||
{
|
||||
Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)),
|
||||
&sliceString, &fastSubstring);
|
||||
Bind(&sliceString);
|
||||
{
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
newBuilder.SetParameters(glue, 0);
|
||||
newBuilder.AllocSlicedStringObject(res, exit, *from, len, &thisFlat);
|
||||
}
|
||||
Bind(&fastSubstring);
|
||||
StringInfoGateRef stringInfoGate(&thisFlat);
|
||||
res->WriteVariable(FastSubString(glue, thisValue, *from, len, stringInfoGate));
|
||||
Jump(exit);
|
||||
}
|
||||
res->WriteVariable(GetSubString(glue, thisValue, *from, len));
|
||||
Jump(exit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GateRef BuiltinsStringStubBuilder::GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entry(env);
|
||||
env->SubCfgEntry(&entry);
|
||||
DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
|
||||
|
||||
Label exit(env);
|
||||
Label flattenFastPath(env);
|
||||
Label sliceString(env);
|
||||
Label mayGetSliceString(env);
|
||||
Label fastSubstring(env);
|
||||
Label isUtf16(env);
|
||||
Label isUtf8(env);
|
||||
Label afterNew(env);
|
||||
FlatStringStubBuilder thisFlat(this);
|
||||
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
|
||||
Bind(&flattenFastPath);
|
||||
{
|
||||
Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)),
|
||||
&mayGetSliceString, &fastSubstring);
|
||||
Bind(&mayGetSliceString);
|
||||
{
|
||||
Branch(IsUtf16String(thisValue), &isUtf16, &sliceString);
|
||||
Bind(&isUtf16);
|
||||
{
|
||||
StringInfoGateRef stringInfoGate(&thisFlat);
|
||||
GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
|
||||
GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
|
||||
GateRef canBeCompressed = CanBeCompressed(source, len, true);
|
||||
Branch(canBeCompressed, &isUtf8, &sliceString);
|
||||
Bind(&isUtf8);
|
||||
{
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
newBuilder.SetParameters(glue, 0);
|
||||
newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
|
||||
Bind(&afterNew);
|
||||
{
|
||||
GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
|
||||
GateRef dst =
|
||||
ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
|
||||
CopyUtf16AsUtf8(glue, dst, source1, len);
|
||||
Jump(&exit);
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&sliceString);
|
||||
{
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
newBuilder.SetParameters(glue, 0);
|
||||
newBuilder.AllocSlicedStringObject(&result, &exit, from, len, &thisFlat);
|
||||
}
|
||||
}
|
||||
Bind(&fastSubstring);
|
||||
StringInfoGateRef stringInfoGate(&thisFlat);
|
||||
result = FastSubString(glue, thisValue, from, len, stringInfoGate);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef BuiltinsStringStubBuilder::StringAt(const StringInfoGateRef &stringInfoGate, GateRef index)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
|
@ -67,6 +67,7 @@ private:
|
||||
GateRef GetSingleCharCodeFromConstantString(GateRef str, GateRef index);
|
||||
GateRef GetSingleCharCodeFromLineString(GateRef str, GateRef index);
|
||||
GateRef GetSingleCharCodeFromSlicedString(GateRef str, GateRef index);
|
||||
GateRef GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len);
|
||||
};
|
||||
|
||||
class FlatStringStubBuilder : public StubBuilder {
|
||||
|
@ -546,6 +546,8 @@ DECLARE_BUILTINS(type##method)
|
||||
DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, ToString, VariableType::JS_ANY(), Undefined());
|
||||
// Object.protetype.Create
|
||||
DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Create, VariableType::JS_ANY(), Undefined());
|
||||
// Object.protetype.Assign
|
||||
DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Assign, VariableType::JS_ANY(), Undefined());
|
||||
#undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER
|
||||
|
||||
#define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(type, method, retType, retDefaultValue) \
|
||||
|
@ -905,9 +905,16 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
|
||||
depend = gate;
|
||||
|
||||
if (!bb.catchs.empty()) {
|
||||
auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
|
||||
auto ifException = circuit_->NewGate(circuit_->IfException(), {gate, gate});
|
||||
auto &bbNext = bb.catchs.at(0);
|
||||
SetBlockPred(bb, *bbNext, gate, gate);
|
||||
SetBlockPred(bb, *bbNext, ifException, ifException);
|
||||
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
|
||||
auto constant = circuit_->GetConstantGate(MachineType::I64,
|
||||
JSTaggedValue::VALUE_EXCEPTION,
|
||||
GateType::TaggedValue());
|
||||
circuit_->NewGate(circuit_->Return(),
|
||||
{ ifSuccess, depend, constant, circuit_->GetReturnRoot() });
|
||||
} else {
|
||||
auto constant = circuit_->GetConstantGate(MachineType::I64,
|
||||
JSTaggedValue::VALUE_EXCEPTION,
|
||||
|
@ -128,7 +128,7 @@ void BytecodeInfoCollector::ProcessClasses()
|
||||
|
||||
SetMethodPcInfoIndex(methodOffset, processedMethod[methodOffset]);
|
||||
jsPandaFile_->SetMethodLiteralToMap(methodLiteral);
|
||||
pfDecoder_.MatchAndMarkMethod(recordName, name.c_str(), methodId);
|
||||
pfDecoder_.MatchAndMarkMethod(jsPandaFile_, recordName, name.c_str(), methodId);
|
||||
});
|
||||
}
|
||||
// class Construct need to use new target, can not fastcall
|
||||
|
@ -523,8 +523,11 @@ public:
|
||||
auto &item = cpInfo_.GetCPItem(type);
|
||||
for (auto &iter : item) {
|
||||
ConstantPoolInfo::ItemData &data = iter.second;
|
||||
data.recordName = &methodOffsetToRecordName_[data.outerMethodOffset];
|
||||
cb(data);
|
||||
auto recordNameIter = methodOffsetToRecordName_.find(data.outerMethodOffset);
|
||||
if (recordNameIter != methodOffsetToRecordName_.end()) {
|
||||
data.recordName = &recordNameIter->second;
|
||||
cb(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1748,6 +1748,20 @@ DEF_CALL_SIGNATURE(DoubleToLength)
|
||||
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(ComputeHashcode)
|
||||
{
|
||||
// 1 : 1 input parameters
|
||||
CallSignature index("ComputeHashcode", 0, 1, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
|
||||
*callSign = index;
|
||||
// 1 : 1 input parameters
|
||||
std::array<VariableType, 1> params = {
|
||||
VariableType::JS_ANY(),
|
||||
};
|
||||
callSign->SetParameters(params.data());
|
||||
callSign->SetGCLeafFunction(true);
|
||||
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(MarkingBarrier)
|
||||
{
|
||||
// 4 : 4 input parameters
|
||||
@ -2049,6 +2063,36 @@ DEF_CALL_SIGNATURE(CreateStringBySingleCharCode)
|
||||
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(Getpropiterator)
|
||||
{
|
||||
// 2 : 2 input parameters
|
||||
CallSignature signature("Getpropiterator", 0, 2,
|
||||
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
|
||||
*callSign = signature;
|
||||
// 2 : 2 input parameters
|
||||
std::array<VariableType, 2> params = {
|
||||
VariableType::NATIVE_POINTER(), // glue
|
||||
VariableType::JS_ANY(), // object
|
||||
};
|
||||
callSign->SetParameters(params.data());
|
||||
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(Getnextpropname)
|
||||
{
|
||||
// 2 : 2 input parameters
|
||||
CallSignature signature("Getnextpropname", 0, 2,
|
||||
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
|
||||
*callSign = signature;
|
||||
// 2 : 2 input parameters
|
||||
std::array<VariableType, 2> params = {
|
||||
VariableType::NATIVE_POINTER(), // glue
|
||||
VariableType::JS_ANY(), // iter
|
||||
};
|
||||
callSign->SetParameters(params.data());
|
||||
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(FastStringEqual)
|
||||
{
|
||||
// 3 : 3 input parameters
|
||||
|
@ -427,6 +427,7 @@ private:
|
||||
V(InsertOldToNewRSet) \
|
||||
V(DoubleToInt) \
|
||||
V(DoubleToLength) \
|
||||
V(ComputeHashcode) \
|
||||
V(FloatMod) \
|
||||
V(FloatSqrt) \
|
||||
V(FloatCos) \
|
||||
@ -464,6 +465,8 @@ private:
|
||||
V(GetSingleCharCodeByIndex) \
|
||||
V(CreateStringBySingleCharCode) \
|
||||
V(FastStringEqual) \
|
||||
V(Getpropiterator) \
|
||||
V(Getnextpropname) \
|
||||
V(JSHClassFindProtoTransitions)
|
||||
|
||||
#define DECL_CALL_SIGNATURE(name) \
|
||||
|
@ -56,7 +56,7 @@ GateRef CircuitBuilder::DoubleIsINF(GateRef x)
|
||||
// Js World
|
||||
// cast operation
|
||||
|
||||
GateRef CircuitBuilder::GetGlobalConstantString(ConstantIndex index)
|
||||
GateRef CircuitBuilder::GetGlobalConstantOffset(ConstantIndex index)
|
||||
{
|
||||
return PtrMul(IntPtr(sizeof(JSTaggedValue)), IntPtr(static_cast<int>(index)));
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/jspandafile/program_object.h"
|
||||
#include "ecmascript/mem/region.h"
|
||||
#include "ecmascript/method.h"
|
||||
|
||||
@ -563,13 +564,19 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
|
||||
}
|
||||
} else if (type == ConstPoolType::OBJECT_LITERAL) {
|
||||
Label isAOTLiteralInfo(env_);
|
||||
Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
|
||||
Label notAotLiteralInfo(env_);
|
||||
Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, ¬AotLiteralInfo);
|
||||
Bind(&isAOTLiteralInfo);
|
||||
{
|
||||
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
|
||||
{ constPool, Int32ToTaggedInt(index), module }, hirGate);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(¬AotLiteralInfo);
|
||||
{
|
||||
result = GetValueFromTaggedArray(cacheValue, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX));
|
||||
Jump(&exit);
|
||||
}
|
||||
} else {
|
||||
Jump(&exit);
|
||||
}
|
||||
@ -580,6 +587,57 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index,
|
||||
ConstPoolType type)
|
||||
{
|
||||
GateRef constPool = GetConstPoolFromFunction(jsFunc);
|
||||
GateRef module = GetModuleFromFunction(jsFunc);
|
||||
return GetObjectInfoFromConstPool(glue, hirGate, constPool, module, index, type);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module,
|
||||
GateRef index, ConstPoolType type)
|
||||
{
|
||||
Label entry(env_);
|
||||
SubCfgEntry(&entry);
|
||||
Label exit(env_);
|
||||
Label cacheMiss(env_);
|
||||
Label cache(env_);
|
||||
|
||||
auto cacheValue = GetValueFromTaggedArray(constPool, index);
|
||||
DEFVAlUE(result, env_, VariableType::JS_ANY(), cacheValue);
|
||||
Branch(BoolOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache);
|
||||
Bind(&cacheMiss);
|
||||
{
|
||||
if (type == ConstPoolType::OBJECT_LITERAL) {
|
||||
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralInfoFromCache), Gate::InvalidGateRef,
|
||||
{ constPool, Int32ToTaggedInt(index), module }, hirGate);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&cache);
|
||||
{
|
||||
if (type == ConstPoolType::OBJECT_LITERAL) {
|
||||
Label isAOTLiteralInfo(env_);
|
||||
Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
|
||||
Bind(&isAOTLiteralInfo);
|
||||
{
|
||||
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralInfoFromCache), Gate::InvalidGateRef,
|
||||
{ constPool, Int32ToTaggedInt(index), module }, hirGate);
|
||||
Jump(&exit);
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::GetFunctionLexicalEnv(GateRef function)
|
||||
{
|
||||
return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET));
|
||||
|
@ -220,6 +220,10 @@ public:
|
||||
GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index, ConstPoolType type);
|
||||
GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index,
|
||||
ConstPoolType type);
|
||||
GateRef GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc,
|
||||
GateRef index, ConstPoolType type);
|
||||
GateRef GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool,
|
||||
GateRef module, GateRef index, ConstPoolType type);
|
||||
GateRef GetFunctionLexicalEnv(GateRef function);
|
||||
GateRef GetGlobalEnv();
|
||||
GateRef GetGlobalEnvObj(GateRef env, size_t index);
|
||||
@ -231,7 +235,7 @@ public:
|
||||
GateRef GetModuleFromFunction(GateRef function);
|
||||
GateRef GetHomeObjectFromFunction(GateRef function);
|
||||
inline GateRef GetExpectedNumOfArgs(GateRef method);
|
||||
inline GateRef GetGlobalConstantString(ConstantIndex index); // shareir
|
||||
inline GateRef GetGlobalConstantOffset(ConstantIndex index); // shareir
|
||||
|
||||
// Set
|
||||
void SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value);
|
||||
@ -375,6 +379,9 @@ public:
|
||||
inline GateRef HasConstructorByHClass(GateRef hClass);
|
||||
inline GateRef IsDictionaryModeByHClass(GateRef hClass);
|
||||
inline GateRef LoadHClass(GateRef object);
|
||||
inline GateRef LoadHClassByConstOffset(GateRef object);
|
||||
inline GateRef LoadPrototype(GateRef hclass);
|
||||
inline GateRef LoadPrototypeHClass(GateRef object);
|
||||
void SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass,
|
||||
GateRef value, GateRef attrOffset, VariableType type);
|
||||
|
||||
@ -390,6 +397,7 @@ public:
|
||||
GateRef TypedArrayCheck(GateType type, GateRef gate);
|
||||
GateRef LoadTypedArrayLength(GateType type, GateRef gate);
|
||||
GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right);
|
||||
GateRef BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type);
|
||||
GateRef IndexCheck(GateType type, GateRef gate, GateRef index);
|
||||
GateRef ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
|
||||
GateRef ObjectTypeCompare(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
|
||||
@ -527,6 +535,7 @@ public:
|
||||
inline GateRef TaggedIsString(GateRef obj);
|
||||
inline GateRef TaggedIsStringOrSymbol(GateRef obj);
|
||||
inline GateRef TaggedIsSymbol(GateRef obj);
|
||||
inline GateRef TaggedIsProtoChangeMarker(GateRef obj);
|
||||
inline GateRef TaggedGetInt(GateRef x);
|
||||
inline GateRef TaggedObjectIsString(GateRef obj);
|
||||
inline GateRef TaggedObjectBothAreString(GateRef x, GateRef y);
|
||||
|
@ -919,6 +919,23 @@ void FastStringEqualStubBuilder::GenerateCircuit()
|
||||
Return(result);
|
||||
}
|
||||
|
||||
void GetpropiteratorStubBuilder::GenerateCircuit()
|
||||
{
|
||||
GateRef glue = PtrArgument(0);
|
||||
GateRef object = TaggedArgument(1);
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
GateRef result = newBuilder.EnumerateObjectProperties(glue, object);
|
||||
Return(result);
|
||||
}
|
||||
|
||||
void GetnextpropnameStubBuilder::GenerateCircuit()
|
||||
{
|
||||
GateRef glue = PtrArgument(0);
|
||||
GateRef iter = TaggedArgument(1);
|
||||
GateRef result = NextInternal(glue, iter);
|
||||
Return(result);
|
||||
}
|
||||
|
||||
CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS];
|
||||
|
||||
void CommonStubCSigns::Initialize()
|
||||
|
@ -78,6 +78,8 @@ namespace panda::ecmascript::kungfu {
|
||||
V(JsBoundCallInternal) \
|
||||
V(JsProxyCallInternal) \
|
||||
V(CreateStringBySingleCharCode) \
|
||||
V(Getpropiterator) \
|
||||
V(Getnextpropname) \
|
||||
V(GetSingleCharCodeByIndex) \
|
||||
V(FastStringEqual)
|
||||
|
||||
|
@ -160,7 +160,7 @@ void CompilationDriver::FetchPGOMismatchResult()
|
||||
uint32_t totalMethodCount = 0;
|
||||
uint32_t mismatchMethodCount = 0;
|
||||
std::set<std::pair<std::string, CString>> mismatchMethodSet {};
|
||||
pfDecoder_.GetMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
|
||||
pfDecoder_.GetMismatchResult(jsPandaFile_, totalMethodCount, mismatchMethodCount, mismatchMethodSet);
|
||||
log_->SetPGOMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ void CompilationDriver::UpdatePGO()
|
||||
SearchForCompilation(recordName, oldIds, newMethodIds, mainMethodOffset, false);
|
||||
return newMethodIds;
|
||||
};
|
||||
pfDecoder_.Update(dfs);
|
||||
pfDecoder_.Update(jsPandaFile_, dfs);
|
||||
FetchPGOMismatchResult();
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ bool CompilationDriver::FilterMethod(const CString &recordName, const MethodLite
|
||||
const MethodPcInfo &methodPCInfo, const std::string &methodName) const
|
||||
{
|
||||
if (methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize() ||
|
||||
!pfDecoder_.Match(recordName, methodLiteral->GetMethodId())) {
|
||||
!pfDecoder_.Match(jsPandaFile_, recordName, methodLiteral->GetMethodId())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
{
|
||||
const auto &methodList = bytecodeInfo_.GetMethodList();
|
||||
auto &resolvedMethodInfo = methodList.at(resolvedMethod.GetOffset());
|
||||
if (pfDecoder_.Match(recordName, resolvedMethod) && !resolvedMethodInfo.IsTypeInferAbort()) {
|
||||
if (pfDecoder_.Match(jsPandaFile_, recordName, resolvedMethod) && !resolvedMethodInfo.IsTypeInferAbort()) {
|
||||
return;
|
||||
}
|
||||
// update profile and update compile queue
|
||||
@ -66,7 +66,7 @@ public:
|
||||
return fullResolvedMethodSet;
|
||||
};
|
||||
|
||||
pfDecoder_.Update(recordName, dfs);
|
||||
pfDecoder_.Update(jsPandaFile_, recordName, dfs);
|
||||
|
||||
if (fullResolvedMethodSet.size() > 0) {
|
||||
bytecodeInfo_.AddRecordName(recordName);
|
||||
@ -279,7 +279,7 @@ private:
|
||||
}
|
||||
importNames.emplace_back(importRecord);
|
||||
mainMethodInfo.SetIsPGO(true);
|
||||
pfDecoder_.Update(importRecord, getMainMethodSet);
|
||||
pfDecoder_.Update(jsPandaFile_, importRecord, getMainMethodSet);
|
||||
AddDependList(importRecord, mainMethodOffset, importList);
|
||||
}
|
||||
};
|
||||
|
@ -84,6 +84,7 @@ GateRef EarlyElimination::VisitGate(GateRef gate)
|
||||
case OpCode::LOAD_GETTER:
|
||||
case OpCode::LOAD_SETTER:
|
||||
case OpCode::ECMA_STRING_CHECK:
|
||||
case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
|
||||
case OpCode::TYPE_OF_CHECK:
|
||||
return TryEliminateGate(gate);
|
||||
case OpCode::STATE_SPLIT:
|
||||
|
@ -197,6 +197,13 @@ ObjectTypeAccessor GateAccessor::GetObjectTypeAccessor(GateRef gate) const
|
||||
return ObjectTypeAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
|
||||
}
|
||||
|
||||
BuiltinPrototypeHClassAccessor GateAccessor::GetBuiltinHClassAccessor(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK);
|
||||
Gate *gatePtr = circuit_->LoadGatePtr(gate);
|
||||
return BuiltinPrototypeHClassAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
|
||||
}
|
||||
|
||||
bool GateAccessor::TypedOpIsTypedArray(GateRef gate, TypedOpKind kind) const
|
||||
{
|
||||
switch (kind) {
|
||||
@ -1537,6 +1544,14 @@ bool GateAccessor::MetaDataEqu(GateRef g1, GateRef g2) const
|
||||
return GetMetaData(g1) == GetMetaData(g2);
|
||||
}
|
||||
|
||||
bool GateAccessor::MetaDataValueEqu(GateRef g1, GateRef g2) const
|
||||
{
|
||||
const GateMetaData *g1Meta = GetMetaData(g1);
|
||||
const GateMetaData *g2Meta = GetMetaData(g2);
|
||||
|
||||
return g1Meta->equal(*g2Meta);
|
||||
}
|
||||
|
||||
bool GateAccessor::IsNop(GateRef g) const
|
||||
{
|
||||
return GetMetaData(g)->IsNop();
|
||||
|
@ -405,6 +405,7 @@ public:
|
||||
TypedJumpAccessor GetTypedJumpAccessor(GateRef gate) const;
|
||||
ArrayMetaDataAccessor GetArrayMetaDataAccessor(GateRef gate) const;
|
||||
ObjectTypeAccessor GetObjectTypeAccessor(GateRef gate) const;
|
||||
BuiltinPrototypeHClassAccessor GetBuiltinHClassAccessor(GateRef gate) const;
|
||||
uint64_t GetConstantValue(GateRef gate) const;
|
||||
const ChunkVector<char>& GetConstantString(GateRef gate) const;
|
||||
bool IsVtable(GateRef gate) const;
|
||||
@ -521,6 +522,7 @@ public:
|
||||
bool IsProlog(GateRef g) const;
|
||||
bool IsCFGMerge(GateRef g) const;
|
||||
bool MetaDataEqu(GateRef g1, GateRef g2) const;
|
||||
bool MetaDataValueEqu(GateRef g1, GateRef g2) const;
|
||||
bool IsNop(GateRef g) const;
|
||||
bool IsRoot(GateRef g) const;
|
||||
bool HasOuts(GateRef gate) const;
|
||||
|
@ -125,6 +125,23 @@ GateRef CircuitBuilder::LoadHClass(GateRef object)
|
||||
return Load(VariableType::JS_POINTER(), object, offset);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::LoadHClassByConstOffset(GateRef object)
|
||||
{
|
||||
return LoadConstOffset(VariableType::JS_POINTER(), object, TaggedObject::HCLASS_OFFSET);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::LoadPrototype(GateRef hclass)
|
||||
{
|
||||
return LoadConstOffset(VariableType::JS_POINTER(), hclass, JSHClass::PROTOTYPE_OFFSET);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::LoadPrototypeHClass(GateRef object)
|
||||
{
|
||||
GateRef objectHClass = LoadHClassByConstOffset(object);
|
||||
GateRef objectPrototype = LoadPrototype(objectHClass);
|
||||
return LoadHClass(objectPrototype);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::GetObjectSizeFromHClass(GateRef hClass)
|
||||
{
|
||||
// NOTE: check for special case of string and TAGGED_ARRAY
|
||||
|
@ -40,6 +40,20 @@ public:
|
||||
SetKind(GateMetaData::Kind::JSBYTECODE);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!GateMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const JSBytecodeMetaData *>(&other);
|
||||
if (opcode_ == cast_other->opcode_ &&
|
||||
pcOffset_ == cast_other->pcOffset_ && type_ == cast_other->type_ &&
|
||||
elementsKinds_ == cast_other->elementsKinds_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const JSBytecodeMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
meta->AssertKind(GateMetaData::Kind::JSBYTECODE);
|
||||
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
#include "ecmascript/compiler/ic_stub_builder.h"
|
||||
#include "ecmascript/compiler/stub_builder-inl.h"
|
||||
#include "ecmascript/compiler/typed_array_stub_builder.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler)
|
||||
@ -161,6 +162,7 @@ void ICStubBuilder::LoadICByValue(
|
||||
Label handlerInfoNotElement(env);
|
||||
Label handlerInfoIsStringElement(env);
|
||||
Label handlerInfoNotStringElement(env);
|
||||
Label handlerInfoIsTypedArrayElement(env);
|
||||
Label exit(env);
|
||||
|
||||
SetLabels(tryFastPath, slowPath, success);
|
||||
@ -182,11 +184,23 @@ void ICStubBuilder::LoadICByValue(
|
||||
Bind(&handlerInfoNotElement);
|
||||
{
|
||||
Branch(IsStringElement(handlerInfo), &handlerInfoIsStringElement, &handlerInfoNotStringElement);
|
||||
Bind(&handlerInfoNotStringElement);
|
||||
Jump(&exit);
|
||||
Bind(&handlerInfoIsStringElement);
|
||||
ret = LoadStringElement(glue_, receiver_, propKey_);
|
||||
Jump(&exit);
|
||||
{
|
||||
ret = LoadStringElement(glue_, receiver_, propKey_);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&handlerInfoNotStringElement);
|
||||
{
|
||||
Branch(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArrayElement, &exit);
|
||||
Bind(&handlerInfoIsTypedArrayElement);
|
||||
{
|
||||
GateRef hclass = LoadHClass(receiver_);
|
||||
GateRef jsType = GetObjectType(hclass);
|
||||
TypedArrayStubBuilder typedArrayBuilder(reinterpret_cast<StubBuilder*>(this));
|
||||
ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType);
|
||||
Jump(&exit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(&loadWithHandler);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ecmascript/base/number_helper.h"
|
||||
#include "ecmascript/compiler/access_object_stub_builder.h"
|
||||
#include "ecmascript/compiler/bc_call_signature.h"
|
||||
#include "ecmascript/compiler/builtins/builtins_object_stub_builder.h"
|
||||
#include "ecmascript/compiler/ic_stub_builder.h"
|
||||
#include "ecmascript/compiler/interpreter_stub-inl.h"
|
||||
#include "ecmascript/compiler/llvm_ir_builder.h"
|
||||
@ -32,6 +33,7 @@
|
||||
#include "ecmascript/js_array.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/js_generator_object.h"
|
||||
#include "ecmascript/jspandafile/program_object.h"
|
||||
#include "ecmascript/message_string.h"
|
||||
#include "ecmascript/tagged_hash_table.h"
|
||||
#include "libpandafile/bytecode_instruction-inl.h"
|
||||
@ -441,7 +443,8 @@ DECLARE_ASM_HANDLER(HandleDefinegettersetterbyvalueV8V8V8V8)
|
||||
DECLARE_ASM_HANDLER(HandleGetpropiterator)
|
||||
{
|
||||
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
|
||||
GateRef res = CallRuntime(glue, RTSTUB_ID(GetPropIterator), { *varAcc });
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
GateRef res = newBuilder.EnumerateObjectProperties(glue, *varAcc);
|
||||
CHECK_EXCEPTION_WITH_VARACC(res, INT_PTR(GETPROPITERATOR));
|
||||
}
|
||||
|
||||
@ -1145,7 +1148,7 @@ DECLARE_ASM_HANDLER(HandleGetnextpropnameV8)
|
||||
{
|
||||
GateRef v0 = ReadInst8_0(pc);
|
||||
GateRef iter = GetVregValue(sp, ZExtInt8ToPtr(v0));
|
||||
GateRef result = CallRuntime(glue, RTSTUB_ID(GetNextPropName), { iter });
|
||||
GateRef result = NextInternal(glue, iter);
|
||||
CHECK_EXCEPTION_WITH_ACC(result, INT_PTR(GETNEXTPROPNAME_V8));
|
||||
}
|
||||
|
||||
@ -3940,26 +3943,66 @@ DECLARE_ASM_HANDLER(HandleDeprecatedCreatearraywithbufferPrefImm16)
|
||||
|
||||
DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm8Id16)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
GateRef imm = ZExtInt16ToInt32(ReadInst16_1(pc));
|
||||
GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
|
||||
GateRef module = GetModuleFromFunction(currentFunc);
|
||||
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
|
||||
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
|
||||
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
|
||||
callback.ProfileCreateObject(res);
|
||||
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16));
|
||||
GateRef fixedArray = GetObjectLiteralInfoFromConstPool(glue, constpool, imm, module);
|
||||
GateRef result = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX));
|
||||
GateRef hasMethod = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_HAS_METHOD_INDEX));
|
||||
DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
|
||||
Label fastpath(env);
|
||||
Label slowpath(env);
|
||||
Label dispatch(env);
|
||||
GateRef flag = BoolOr(IsDictionaryModeByHClass(LoadHClass(result)), TaggedIsTrue(hasMethod));
|
||||
Branch(flag, &slowpath, &fastpath);
|
||||
Bind(&slowpath);
|
||||
{
|
||||
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
|
||||
res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
|
||||
Jump(&dispatch);
|
||||
}
|
||||
Bind(&fastpath);
|
||||
{
|
||||
BuiltinsObjectStubBuilder builder(this);
|
||||
res = builder.CloneObjectLiteral(glue, result);
|
||||
Jump(&dispatch);
|
||||
}
|
||||
Bind(&dispatch);
|
||||
callback.ProfileCreateObject(*res);
|
||||
CHECK_EXCEPTION_WITH_ACC(*res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16));
|
||||
}
|
||||
|
||||
DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm16Id16)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
GateRef imm = ZExtInt16ToInt32(ReadInst16_2(pc));
|
||||
GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
|
||||
GateRef module = GetModuleFromFunction(currentFunc);
|
||||
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
|
||||
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
|
||||
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
|
||||
callback.ProfileCreateObject(res);
|
||||
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16));
|
||||
GateRef fixedArray = GetObjectLiteralInfoFromConstPool(glue, constpool, imm, module);
|
||||
GateRef result = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX));
|
||||
GateRef hasMethod = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_HAS_METHOD_INDEX));
|
||||
DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
|
||||
Label fastpath(env);
|
||||
Label slowpath(env);
|
||||
Label dispatch(env);
|
||||
GateRef flag = BoolOr(IsDictionaryModeByHClass(LoadHClass(result)), TaggedIsTrue(hasMethod));
|
||||
Branch(flag, &slowpath, &fastpath);
|
||||
Bind(&slowpath);
|
||||
{
|
||||
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
|
||||
res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
|
||||
Jump(&dispatch);
|
||||
}
|
||||
Bind(&fastpath);
|
||||
{
|
||||
BuiltinsObjectStubBuilder builder(this);
|
||||
res = builder.CloneObjectLiteral(glue, result);
|
||||
Jump(&dispatch);
|
||||
}
|
||||
Bind(&dispatch);
|
||||
callback.ProfileCreateObject(*res);
|
||||
CHECK_EXCEPTION_WITH_ACC(*res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16));
|
||||
}
|
||||
|
||||
DECLARE_ASM_HANDLER(HandleDeprecatedCreateobjectwithbufferPrefImm16)
|
||||
|
@ -187,6 +187,20 @@ GateRef CircuitBuilder::RangeGuard(GateRef gate, uint32_t left, uint32_t right)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type)
|
||||
{
|
||||
auto currentLabel = env_->GetCurrentLabel();
|
||||
auto currentControl = currentLabel->GetControl();
|
||||
auto currentDepend = currentLabel->GetDepend();
|
||||
auto frameState = acc_.FindNearestFrameState(currentDepend);
|
||||
BuiltinPrototypeHClassAccessor accessor(type);
|
||||
GateRef ret = GetCircuit()->NewGate(circuit_->BuiltinPrototypeHClassCheck(accessor.ToValue()),
|
||||
MachineType::I1, {currentControl, currentDepend, gate, frameState}, GateType::NJSValue());
|
||||
currentLabel->SetControl(ret);
|
||||
currentLabel->SetDepend(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::IndexCheck(GateType type, GateRef gate, GateRef index)
|
||||
{
|
||||
auto currentLabel = env_->GetCurrentLabel();
|
||||
@ -908,8 +922,8 @@ GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
|
||||
Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
|
||||
Bind(&noRawHashcode);
|
||||
{
|
||||
hashcode = GetInt32OfTInt(
|
||||
CallRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, { value }, Circuit::NullGate()));
|
||||
hashcode =
|
||||
CallNGCRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, { value }, Circuit::NullGate());
|
||||
Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
|
||||
Jump(&exit);
|
||||
}
|
||||
|
@ -164,6 +164,26 @@ GateRef CircuitBuilder::TaggedIsStringOrSymbol(GateRef obj)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::TaggedIsProtoChangeMarker(GateRef obj)
|
||||
{
|
||||
Label entry(env_);
|
||||
SubCfgEntry(&entry);
|
||||
Label exit(env_);
|
||||
DEFVAlUE(result, env_, VariableType::BOOL(), False());
|
||||
Label isHeapObject(env_);
|
||||
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
|
||||
Bind(&isHeapObject);
|
||||
{
|
||||
GateRef objType = GetObjectType(LoadHClass(obj));
|
||||
result = Equal(objType, Int32(static_cast<int32_t>(JSType::PROTO_CHANGE_MARKER)));
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline GateRef CircuitBuilder::IsOptimizedAndNotFastCall(GateRef obj)
|
||||
{
|
||||
GateRef hClass = LoadHClass(obj);
|
||||
|
@ -173,6 +173,18 @@ public:
|
||||
SetKind(GateMetaData::Kind::TYPED_CALL);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!OneParameterMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const TypedCallMetaData *>(&other);
|
||||
if (noGC_ == cast_other->noGC_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const TypedCallMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
meta->AssertKind(GateMetaData::Kind::TYPED_CALL);
|
||||
@ -196,6 +208,19 @@ public:
|
||||
SetKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!OneParameterMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other =
|
||||
static_cast<const TypedCallTargetCheckMetaData *>(&other);
|
||||
if (checkOp_ == cast_other->checkOp_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const TypedCallTargetCheckMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
meta->AssertKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP);
|
||||
@ -219,6 +244,18 @@ public:
|
||||
SetKind(GateMetaData::Kind::TYPED_BINARY_OP);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!OneParameterMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const TypedBinaryMetaData *>(&other);
|
||||
if (binOp_ == cast_other->binOp_ && type_ == cast_other->type_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const TypedBinaryMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
meta->AssertKind(GateMetaData::Kind::TYPED_BINARY_OP);
|
||||
|
@ -55,22 +55,23 @@ namespace panda::ecmascript::kungfu {
|
||||
V(TypedCall, TYPEDCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value) \
|
||||
V(TypedFastCall, TYPEDFASTCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value)
|
||||
|
||||
#define MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \
|
||||
V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 1, 1, 2) \
|
||||
V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \
|
||||
V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \
|
||||
V(StoreMemory, STORE_MEMORY, GateFlags::NONE_FLAG, 1, 1, 3) \
|
||||
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(RangeGuard, RANGE_GUARD, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(GetGlobalEnvObj, GET_GLOBAL_ENV_OBJ, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(GetGlobalEnvObjHClass, GET_GLOBAL_ENV_OBJ_HCLASS, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(GetGlobalConstantValue, GET_GLOBAL_CONSTANT_VALUE, GateFlags::NO_WRITE, 0, 1, 0) \
|
||||
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(HeapAlloc, HEAP_ALLOC, GateFlags::NONE_FLAG, 1, 1, 1) \
|
||||
V(RangeCheckPredicate, RANGE_CHECK_PREDICATE, GateFlags::CHECKABLE, 1, 1, 2)
|
||||
#define MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \
|
||||
V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 1, 1, 2) \
|
||||
V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \
|
||||
V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \
|
||||
V(StoreMemory, STORE_MEMORY, GateFlags::NONE_FLAG, 1, 1, 3) \
|
||||
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(RangeGuard, RANGE_GUARD, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(GetGlobalEnvObj, GET_GLOBAL_ENV_OBJ, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(GetGlobalEnvObjHClass, GET_GLOBAL_ENV_OBJ_HCLASS, GateFlags::NO_WRITE, 0, 1, 1) \
|
||||
V(GetGlobalConstantValue, GET_GLOBAL_CONSTANT_VALUE, GateFlags::NO_WRITE, 0, 1, 0) \
|
||||
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(HeapAlloc, HEAP_ALLOC, GateFlags::NONE_FLAG, 1, 1, 1) \
|
||||
V(RangeCheckPredicate, RANGE_CHECK_PREDICATE, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(BuiltinPrototypeHClassCheck, BUILTIN_PROTOTYPE_HCLASS_CHECK, GateFlags::CHECKABLE, 1, 1, 1)
|
||||
|
||||
#define MCR_GATE_META_DATA_LIST_WITH_BOOL(V) \
|
||||
V(LoadProperty, LOAD_PROPERTY, GateFlags::NO_WRITE, 1, 1, 2)
|
||||
|
@ -207,6 +207,80 @@ GateRef NewObjectStubBuilder::NewTaggedArray(GateRef glue, GateRef len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef NewObjectStubBuilder::NewJSForinIterator(GateRef glue, GateRef receiver, GateRef keys, GateRef cachedHclass)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
|
||||
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
|
||||
GateRef hclass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::FOR_IN_ITERATOR_CLASS_INDEX);
|
||||
GateRef iter = NewJSObject(glue, hclass);
|
||||
// init JSForinIterator
|
||||
SetObjectOfForInIterator(glue, iter, receiver);
|
||||
SetCachedHclassOFForInIterator(glue, iter, cachedHclass);
|
||||
SetKeysOfForInIterator(glue, iter, keys);
|
||||
SetIndexOfForInIterator(glue, iter, Int32(EnumCache::ENUM_CACHE_HEADER_SIZE));
|
||||
GateRef length = GetLengthOfTaggedArray(keys);
|
||||
SetLengthOfForInIterator(glue, iter, length);
|
||||
return iter;
|
||||
}
|
||||
|
||||
GateRef NewObjectStubBuilder::EnumerateObjectProperties(GateRef glue, GateRef obj)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entry(env);
|
||||
env->SubCfgEntry(&entry);
|
||||
Label exit(env);
|
||||
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
|
||||
DEFVARIABLE(object, VariableType::JS_ANY(), Undefined());
|
||||
|
||||
Label isString(env);
|
||||
Label isNotString(env);
|
||||
Label afterObjectTransform(env);
|
||||
Label slowpath(env);
|
||||
Label empty(env);
|
||||
Label tryGetEnumCache(env);
|
||||
Label cacheHit(env);
|
||||
|
||||
Branch(TaggedIsString(obj), &isString, &isNotString);
|
||||
Bind(&isString);
|
||||
{
|
||||
object = CallRuntime(glue, RTSTUB_ID(PrimitiveStringCreate), { obj });;
|
||||
Jump(&afterObjectTransform);
|
||||
}
|
||||
Bind(&isNotString);
|
||||
{
|
||||
object = ToPrototypeOrObj(glue, obj);
|
||||
Jump(&afterObjectTransform);
|
||||
}
|
||||
Bind(&afterObjectTransform);
|
||||
Branch(TaggedIsUndefinedOrNull(*object), &empty, &tryGetEnumCache);
|
||||
Bind(&tryGetEnumCache);
|
||||
GateRef enumCache = TryGetEnumCache(glue, *object);
|
||||
Branch(TaggedIsUndefined(enumCache), &slowpath, &cacheHit);
|
||||
Bind(&cacheHit);
|
||||
{
|
||||
GateRef hclass = LoadHClass(obj);
|
||||
result = NewJSForinIterator(glue, *object, enumCache, hclass);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&empty);
|
||||
{
|
||||
GateRef emptyArray = GetEmptyArray(glue);
|
||||
result = NewJSForinIterator(glue, Undefined(), emptyArray, Undefined());
|
||||
Jump(&exit);
|
||||
}
|
||||
|
||||
Bind(&slowpath);
|
||||
{
|
||||
result = CallRuntime(glue, RTSTUB_ID(GetPropIteratorSlowpath), { *object });
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NewObjectStubBuilder::NewArgumentsList(Variable *result, Label *exit,
|
||||
GateRef sp, GateRef startIdx, GateRef numArgs)
|
||||
{
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
GateRef NewJSArray(GateRef glue, GateRef hclass);
|
||||
GateRef NewTaggedArray(GateRef glue, GateRef len);
|
||||
GateRef NewJSArrayWithSize(GateRef hclass, GateRef size);
|
||||
GateRef NewJSForinIterator(GateRef glue, GateRef receiver, GateRef keys, GateRef cachedHclass);
|
||||
GateRef EnumerateObjectProperties(GateRef glue, GateRef obj);
|
||||
void NewArgumentsList(Variable *result, Label *exit, GateRef sp, GateRef startIdx, GateRef numArgs);
|
||||
void NewArgumentsObj(Variable *result, Label *exit, GateRef argumentsList, GateRef numArgs);
|
||||
void AllocLineStringObject(Variable *result, Label *exit, GateRef length, bool compressed);
|
||||
|
@ -14,6 +14,8 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/object_access_helper.h"
|
||||
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
#include "ecmascript/ts_types/ts_type.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "ecmascript/compiler/type_mcr_lowering.h"
|
||||
#include "ecmascript/compiler/value_numbering.h"
|
||||
#include "ecmascript/compiler/verifier.h"
|
||||
#include "ecmascript/js_runtime_options.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
class PassContext;
|
||||
@ -580,11 +581,14 @@ public:
|
||||
if (!passOptions->EnableTypeLowering() || !passOptions->EnableValueNumbering()) {
|
||||
return false;
|
||||
}
|
||||
JSRuntimeOptions runtimeOption = data->GetPassContext()->GetEcmaVM()->GetJSOptions();
|
||||
TimeScope timescope("ValueNumberingPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
|
||||
Chunk chunk(data->GetNativeAreaAllocator());
|
||||
bool enableLog = data->GetLog()->EnableMethodCIRLog();
|
||||
CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk);
|
||||
ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk);
|
||||
ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk,
|
||||
runtimeOption.IsEnableNewValueNumbering(),
|
||||
runtimeOption.GetTraceValueNumbering());
|
||||
visitor.AddPass(&valueNumbering);
|
||||
visitor.VisitGraph();
|
||||
visitor.PrintLog("value numbering");
|
||||
|
@ -134,7 +134,9 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName,
|
||||
pipeline.RunPass<LaterEliminationPass>();
|
||||
pipeline.RunPass<EarlyEliminationPass>();
|
||||
pipeline.RunPass<LCRLoweringPass>();
|
||||
pipeline.RunPass<ValueNumberingPass>();
|
||||
pipeline.RunPass<SlowPathLoweringPass>();
|
||||
pipeline.RunPass<ValueNumberingPass>();
|
||||
pipeline.RunPass<VerifierPass>();
|
||||
pipeline.RunPass<GraphLinearizerPass>();
|
||||
pipeline.RunPass<LLVMIRGenPass>();
|
||||
|
@ -19,16 +19,15 @@
|
||||
#include <string>
|
||||
|
||||
#include "ecmascript/compiler/bytecodes.h"
|
||||
#include "ecmascript/compiler/share_opcodes.h"
|
||||
#include "ecmascript/compiler/type.h"
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/js_thread_hclass_entries.h"
|
||||
#include "ecmascript/mem/chunk.h"
|
||||
#include "ecmascript/mem/chunk_containers.h"
|
||||
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
|
||||
#include "libpandabase/macros.h"
|
||||
|
||||
#include "ecmascript/compiler/share_opcodes.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
using GateRef = int32_t;
|
||||
using PGOSampleType = pgo::PGOSampleType;
|
||||
@ -40,33 +39,34 @@ enum class TypedLoadOp : uint8_t;
|
||||
enum class TypedStoreOp : uint8_t;
|
||||
enum class TypedCallTargetCheckOp : uint8_t;
|
||||
|
||||
#define GATE_META_DATA_DEOPT_REASON(V) \
|
||||
V(NotInt, NOTINT) \
|
||||
V(NotDouble, NOTDOUBLE) \
|
||||
V(NotNumber, NOTNUMBER) \
|
||||
V(NotBool, NOTBOOL) \
|
||||
V(NotHeapObject, NOTHEAPOBJECT) \
|
||||
V(NotStableArray, NOTSARRAY) \
|
||||
V(NotArray, NOTARRAY) \
|
||||
V(NotOnHeap, NOTONHEAP) \
|
||||
V(InconsistentHClass, INCONSISTENTHCLASS) \
|
||||
V(NotNewObj, NOTNEWOBJ) \
|
||||
V(NotLegalIndex, NOTLEGALIDX) \
|
||||
V(NotIncOverflow, NOTINCOV) \
|
||||
V(NotDecOverflow, NOTDECOV) \
|
||||
V(NotNegativeOverflow, NOTNEGOV) \
|
||||
V(NotCallTarget, NOTCALLTGT) \
|
||||
V(NotJSCallTarget, NOTJSCALLTGT) \
|
||||
V(CowArray, COWARRAY) \
|
||||
V(DivideZero, DIVZERO) \
|
||||
V(InlineFail, INLINEFAIL) \
|
||||
V(NotJSFastCallTarget, NOTJSFASTCALLTGT) \
|
||||
V(LexVarIsHole, LEXVARISHOLE) \
|
||||
V(ModZero, MODZERO) \
|
||||
V(Int32Overflow, INT32OVERFLOW) \
|
||||
V(NotString, NOTSTRING) \
|
||||
V(InconsistentType, INCONSISTENTTYPE) \
|
||||
V(NotNull, NOTNULL)
|
||||
#define GATE_META_DATA_DEOPT_REASON(V) \
|
||||
V(NotInt, NOTINT) \
|
||||
V(NotDouble, NOTDOUBLE) \
|
||||
V(NotNumber, NOTNUMBER) \
|
||||
V(NotBool, NOTBOOL) \
|
||||
V(NotHeapObject, NOTHEAPOBJECT) \
|
||||
V(NotStableArray, NOTSARRAY) \
|
||||
V(NotArray, NOTARRAY) \
|
||||
V(NotOnHeap, NOTONHEAP) \
|
||||
V(InconsistentHClass, INCONSISTENTHCLASS) \
|
||||
V(NotNewObj, NOTNEWOBJ) \
|
||||
V(NotLegalIndex, NOTLEGALIDX) \
|
||||
V(NotIncOverflow, NOTINCOV) \
|
||||
V(NotDecOverflow, NOTDECOV) \
|
||||
V(NotNegativeOverflow, NOTNEGOV) \
|
||||
V(NotCallTarget, NOTCALLTGT) \
|
||||
V(NotJSCallTarget, NOTJSCALLTGT) \
|
||||
V(CowArray, COWARRAY) \
|
||||
V(DivideZero, DIVZERO) \
|
||||
V(InlineFail, INLINEFAIL) \
|
||||
V(NotJSFastCallTarget, NOTJSFASTCALLTGT) \
|
||||
V(LexVarIsHole, LEXVARISHOLE) \
|
||||
V(ModZero, MODZERO) \
|
||||
V(Int32Overflow, INT32OVERFLOW) \
|
||||
V(NotString, NOTSTRING) \
|
||||
V(InconsistentType, INCONSISTENTTYPE) \
|
||||
V(NotNull, NOTNULL) \
|
||||
V(BuiltinPrototypeHClassMismatch, BUILTINPROTOHCLASSMISMATCH)
|
||||
|
||||
enum class DeoptType : uint8_t {
|
||||
NOTCHECK = 0,
|
||||
@ -107,6 +107,15 @@ public:
|
||||
: opcode_(opcode), flags_(flags),
|
||||
statesIn_(statesIn), dependsIn_(dependsIn), valuesIn_(valuesIn) {}
|
||||
|
||||
virtual bool equal(const GateMetaData &other) const
|
||||
{
|
||||
if (opcode_ == other.opcode_ && kind_ == other.kind_ && flags_ == other.flags_ &&
|
||||
statesIn_ == other.statesIn_ && dependsIn_ == other.dependsIn_ && valuesIn_ == other.valuesIn_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t GetStateCount() const
|
||||
{
|
||||
return statesIn_;
|
||||
@ -282,6 +291,18 @@ public:
|
||||
SetKind(GateMetaData::Kind::IMMUTABLE_BOOL);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!GateMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const BoolMetaData *>(&other);
|
||||
if (value_ == cast_other->value_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const BoolMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
meta->AssertKind(GateMetaData::Kind::IMMUTABLE_BOOL);
|
||||
@ -306,6 +327,18 @@ public:
|
||||
SetKind(GateMetaData::Kind::IMMUTABLE_ONE_PARAMETER);
|
||||
}
|
||||
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!GateMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const OneParameterMetaData *>(&other);
|
||||
if (value_ == cast_other->value_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const OneParameterMetaData* Cast(const GateMetaData* meta)
|
||||
{
|
||||
ASSERT(meta->IsOneParameterKind());
|
||||
@ -341,6 +374,22 @@ public:
|
||||
}
|
||||
SetKind(GateMetaData::Kind::MUTABLE_STRING);
|
||||
}
|
||||
bool equal(const GateMetaData &other) const override
|
||||
{
|
||||
if (!GateMetaData::equal(other)) {
|
||||
return false;
|
||||
}
|
||||
auto cast_other = static_cast<const StringMetaData *>(&other);
|
||||
if (stringData_.size() != cast_other->GetString().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(stringData_.data(), cast_other->GetString().data(), stringData_.size()) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const ChunkVector<char> &GetString() const
|
||||
{
|
||||
@ -471,7 +520,8 @@ public:
|
||||
CREATE = 0,
|
||||
LOAD_ELEMENT,
|
||||
STORE_ELEMENT,
|
||||
LOAD_LENGTH
|
||||
LOAD_LENGTH,
|
||||
CALL_BUILTIN_METHOD
|
||||
};
|
||||
|
||||
static constexpr int BITS_SIZE = 8;
|
||||
@ -552,6 +602,29 @@ private:
|
||||
|
||||
uint64_t bitField_;
|
||||
};
|
||||
|
||||
class BuiltinPrototypeHClassAccessor {
|
||||
public:
|
||||
explicit BuiltinPrototypeHClassAccessor(uint64_t value): type_(value) {}
|
||||
// Only valid indices accepted
|
||||
explicit BuiltinPrototypeHClassAccessor(BuiltinTypeId type): type_(static_cast<uint64_t>(type))
|
||||
{
|
||||
ASSERT(BuiltinHClassEntries::GetEntryIndex(type) < BuiltinHClassEntries::N_ENTRIES);
|
||||
}
|
||||
|
||||
BuiltinTypeId GetBuiltinTypeId() const
|
||||
{
|
||||
return static_cast<BuiltinTypeId>(type_);
|
||||
}
|
||||
|
||||
uint64_t ToValue() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t type_;
|
||||
};
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
||||
#endif // ECMASCRIPT_COMPILER_SHARE_GATE_META_DATA_H
|
||||
|
@ -189,7 +189,18 @@ void SlowPathLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool
|
||||
*/
|
||||
void SlowPathLowering::ReplaceHirToThrowCall(GateRef hirGate, GateRef value)
|
||||
{
|
||||
acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
|
||||
auto condition = builder_.HasPendingException(glue_);
|
||||
GateRef state = builder_.GetState();
|
||||
GateRef depend = builder_.GetDepend();
|
||||
GateRef ifBranch = builder_.Branch(state, condition);
|
||||
GateRef ifTrue = builder_.IfTrue(ifBranch);
|
||||
GateRef ifFalse = builder_.IfFalse(ifBranch);
|
||||
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
|
||||
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
|
||||
|
||||
StateDepend success(ifFalse, sDepend);
|
||||
StateDepend exception(ifTrue, eDepend);
|
||||
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
|
||||
}
|
||||
|
||||
void SlowPathLowering::Lower(GateRef gate)
|
||||
@ -1269,10 +1280,10 @@ void SlowPathLowering::LowerGreaterEq(GateRef gate)
|
||||
|
||||
void SlowPathLowering::LowerGetPropIterator(GateRef gate)
|
||||
{
|
||||
const int id = RTSTUB_ID(GetPropIterator);
|
||||
// 1: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
||||
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
|
||||
GateRef object = {acc_.GetValueIn(gate, 0)};
|
||||
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getpropiterator, {glue_, object});
|
||||
ReplaceHirWithValue(gate, newGate);
|
||||
}
|
||||
|
||||
@ -1793,11 +1804,10 @@ void SlowPathLowering::LowerConditionJump(GateRef gate, bool isEqualJump)
|
||||
|
||||
void SlowPathLowering::LowerGetNextPropName(GateRef gate)
|
||||
{
|
||||
const int id = RTSTUB_ID(GetNextPropName);
|
||||
// 1: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
||||
GateRef iter = acc_.GetValueIn(gate, 0);
|
||||
GateRef newGate = LowerCallRuntime(gate, id, { iter });
|
||||
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getnextpropname, {glue_, iter});
|
||||
ReplaceHirWithValue(gate, newGate);
|
||||
}
|
||||
|
||||
@ -2498,14 +2508,14 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
|
||||
GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_,
|
||||
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit())));
|
||||
GateRef undefinedIndex = builder_.GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX);
|
||||
GateRef undefinedIndex = builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX);
|
||||
GateRef gConstUndefinedStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
|
||||
DEFVAlUE(result, (&builder_), VariableType::JS_POINTER(), gConstUndefinedStr);
|
||||
Label objIsTrue(&builder_);
|
||||
Label objNotTrue(&builder_);
|
||||
Label defaultLabel(&builder_);
|
||||
GateRef gConstBooleanStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::BOOLEAN_STRING_INDEX));
|
||||
builder_.Branch(builder_.TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
|
||||
builder_.Bind(&objIsTrue);
|
||||
{
|
||||
@ -2530,7 +2540,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsNull);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotNull);
|
||||
@ -2541,7 +2551,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsUndefined);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotUndefined);
|
||||
@ -2562,7 +2572,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsString);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::STRING_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotString);
|
||||
@ -2573,7 +2583,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsSymbol);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::SYMBOL_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotSymbol);
|
||||
@ -2584,7 +2594,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsCallable);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::FUNCTION_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotCallable);
|
||||
@ -2595,13 +2605,13 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsBigInt);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::BIGINT_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotBigInt);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
}
|
||||
@ -2616,7 +2626,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
|
||||
builder_.Bind(&objIsNum);
|
||||
{
|
||||
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
||||
builder_.GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX));
|
||||
builder_.GetGlobalConstantOffset(ConstantIndex::NUMBER_STRING_INDEX));
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(&objNotNum);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/js_array.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/js_for_in_iterator.h"
|
||||
#include "ecmascript/js_generator_object.h"
|
||||
#include "ecmascript/js_object.h"
|
||||
#include "ecmascript/js_tagged_value.h"
|
||||
@ -1004,6 +1005,16 @@ inline GateRef StubBuilder::GetLengthOfTaggedArray(GateRef array)
|
||||
return Load(VariableType::INT32(), array, IntPtr(TaggedArray::LENGTH_OFFSET));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetExtractLengthOfTaggedArray(GateRef array)
|
||||
{
|
||||
return Load(VariableType::INT32(), array, IntPtr(TaggedArray::EXTRACT_LENGTH_OFFSET));
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetExtractLengthOfTaggedArray(GateRef glue, GateRef array, GateRef extraLength)
|
||||
{
|
||||
return Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::EXTRACT_LENGTH_OFFSET), extraLength);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsJSHClass(GateRef obj)
|
||||
{
|
||||
ASM_ASSERT(GET_MESSAGE_STRING_ID(IsJSHClass), TaggedIsHeapObject(obj));
|
||||
@ -1089,8 +1100,21 @@ inline GateRef StubBuilder::TaggedObjectIsEcmaObject(GateRef obj)
|
||||
|
||||
inline GateRef StubBuilder::IsEcmaObject(GateRef obj)
|
||||
{
|
||||
auto isHeapObject = TaggedIsHeapObject(obj);
|
||||
return env_->GetBuilder()->LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj));
|
||||
auto env = GetEnvironment();
|
||||
Label entryPass(env);
|
||||
env->SubCfgEntry(&entryPass);
|
||||
DEFVARIABLE(result, VariableType::BOOL(), False());
|
||||
Label heapObj(env);
|
||||
Label exit(env);
|
||||
GateRef isHeapObject = TaggedIsHeapObject(obj);
|
||||
Branch(isHeapObject, &heapObj, &exit);
|
||||
Bind(&heapObj);
|
||||
result = env_->GetBuilder()->LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj));
|
||||
Jump(&exit);
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsJSObject(GateRef obj)
|
||||
@ -1182,6 +1206,32 @@ inline GateRef StubBuilder::IsJsProxy(GateRef obj)
|
||||
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_PROXY)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsJSGlobalObject(GateRef obj)
|
||||
{
|
||||
GateRef objectType = GetObjectType(LoadHClass(obj));
|
||||
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_GLOBAL_OBJECT)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsModuleNamespace(GateRef obj)
|
||||
{
|
||||
GateRef objectType = GetObjectType(LoadHClass(obj));
|
||||
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_MODULE_NAMESPACE)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::ObjIsSpecialContainer(GateRef obj)
|
||||
{
|
||||
GateRef objectType = GetObjectType(LoadHClass(obj));
|
||||
return BoolAnd(
|
||||
Int32GreaterThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::JS_API_ARRAY_LIST))),
|
||||
Int32LessThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::JS_API_QUEUE))));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsJSPrimitiveRef(GateRef obj)
|
||||
{
|
||||
GateRef objectType = GetObjectType(LoadHClass(obj));
|
||||
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_PRIMITIVE_REF)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsJsArray(GateRef obj)
|
||||
{
|
||||
GateRef objectType = GetObjectType(LoadHClass(obj));
|
||||
@ -1324,6 +1374,15 @@ inline GateRef StubBuilder::IsAccessor(GateRef attr)
|
||||
Int32(0));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsEnumerable(GateRef attr)
|
||||
{
|
||||
return Int32NotEqual(
|
||||
Int32And(Int32LSR(attr,
|
||||
Int32(PropertyAttributes::EnumerableField::START_BIT)),
|
||||
Int32((1LLU << PropertyAttributes::EnumerableField::SIZE) - 1)),
|
||||
Int32(0));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsInlinedProperty(GateRef attr)
|
||||
{
|
||||
return Int32NotEqual(
|
||||
@ -1389,6 +1448,86 @@ inline GateRef StubBuilder::HclassIsPropertyBox(GateRef hClass)
|
||||
Int32(static_cast<int32_t>(JSType::PROPERTY_BOX)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::TaggedIsProtoChangeMarker(GateRef obj)
|
||||
{
|
||||
return env_->GetBuilder()->TaggedIsProtoChangeMarker(obj);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetEmptyArray(GateRef glue)
|
||||
{
|
||||
GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
|
||||
IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
|
||||
GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
|
||||
return Load(VariableType::JS_ANY(), gConstAddr, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetLengthFromForInIterator(GateRef iter)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
|
||||
return Load(VariableType::INT32(), iter, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetIndexFromForInIterator(GateRef iter)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
|
||||
return Load(VariableType::INT32(), iter, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetKeysFromForInIterator(GateRef iter)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
|
||||
return Load(VariableType::JS_ANY(), iter, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetObjectFromForInIterator(GateRef iter)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
|
||||
return Load(VariableType::JS_ANY(), iter, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetCachedHclassFromForInIterator(GateRef iter)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
|
||||
return Load(VariableType::JS_ANY(), iter, offset);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
|
||||
Store(VariableType::INT32(), glue, iter, offset, length);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
|
||||
Store(VariableType::INT32(), glue, iter, offset, index);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
|
||||
Store(VariableType::JS_ANY(), glue, iter, offset, keys);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
|
||||
Store(VariableType::JS_ANY(), glue, iter, offset, object);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass)
|
||||
{
|
||||
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
|
||||
Store(VariableType::JS_ANY(), glue, iter, offset, hclass);
|
||||
}
|
||||
|
||||
inline void StubBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index)
|
||||
{
|
||||
GateRef newIndex = Int32Add(index, Int32(1));
|
||||
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
|
||||
Store(VariableType::INT32(), glue, iter, offset, newIndex);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsField(GateRef attr)
|
||||
{
|
||||
return Int32Equal(
|
||||
@ -1425,6 +1564,15 @@ inline GateRef StubBuilder::IsStringLength(GateRef attr)
|
||||
Int32(HandlerBase::HandlerKind::STRING_LENGTH));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsTypedArrayElement(GateRef attr)
|
||||
{
|
||||
return Int32Equal(
|
||||
Int32And(
|
||||
Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)),
|
||||
Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)),
|
||||
Int32(HandlerBase::HandlerKind::TYPED_ARRAY));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsNonExist(GateRef attr)
|
||||
{
|
||||
return Int32Equal(
|
||||
@ -1541,6 +1689,13 @@ inline GateRef StubBuilder::PropAttrGetOffset(GateRef attr)
|
||||
Int32((1LLU << PropertyAttributes::OffsetField::SIZE) - 1));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetSortedIndex(GateRef attr)
|
||||
{
|
||||
return Int32And(
|
||||
Int32LSR(attr, Int32(PropertyAttributes::SortedIndexField::START_BIT)),
|
||||
Int32((1LLU << PropertyAttributes::SortedIndexField::SIZE) - 1));
|
||||
}
|
||||
|
||||
// SetDictionaryOrder func in property_attribute.h
|
||||
inline GateRef StubBuilder::SetDictionaryOrderFieldInPropAttr(GateRef attr, GateRef value)
|
||||
{
|
||||
@ -1558,6 +1713,18 @@ inline GateRef StubBuilder::GetPrototypeFromHClass(GateRef hClass)
|
||||
return Load(VariableType::JS_ANY(), hClass, protoOffset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetEnumCacheFromHClass(GateRef hClass)
|
||||
{
|
||||
GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET);
|
||||
return Load(VariableType::JS_ANY(), hClass, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass)
|
||||
{
|
||||
GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET);
|
||||
return Load(VariableType::JS_ANY(), hClass, offset);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetLayoutFromHClass(GateRef hClass)
|
||||
{
|
||||
GateRef attrOffset = IntPtr(JSHClass::LAYOUT_OFFSET);
|
||||
@ -1715,6 +1882,15 @@ inline GateRef StubBuilder::GetNumberOfPropsFromHClass(GateRef hClass)
|
||||
Int32((1LLU << JSHClass::NumberOfPropsBits::SIZE) - 1));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::HasDeleteProperty(GateRef hClass)
|
||||
{
|
||||
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
|
||||
return Int32NotEqual(
|
||||
Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)),
|
||||
Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)),
|
||||
Int32(0));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::IsTSHClass(GateRef hClass)
|
||||
{
|
||||
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
|
||||
@ -2067,7 +2243,7 @@ inline GateRef StubBuilder::GetGlobalConstantAddr(GateRef index)
|
||||
return Int64Mul(Int64(sizeof(JSTaggedValue)), index);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetGlobalConstantString(ConstantIndex index)
|
||||
inline GateRef StubBuilder::GetGlobalConstantOffset(ConstantIndex index)
|
||||
{
|
||||
if (env_->Is32Bit()) {
|
||||
return Int32Mul(Int32(sizeof(JSTaggedValue)), Int32(static_cast<int>(index)));
|
||||
@ -2612,5 +2788,67 @@ inline GateRef StubBuilder::RemoveTaggedWeakTag(GateRef weak)
|
||||
{
|
||||
return Int64ToTaggedPtr(IntPtrAnd(ChangeTaggedPointerToInt64(weak), IntPtr(~JSTaggedValue::TAG_WEAK)));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetPropertiesCache(GateRef glue)
|
||||
{
|
||||
GateRef currentContextOffset = IntPtr(JSThread::GlueData::GetCurrentContextOffset(env_->Is32Bit()));
|
||||
GateRef currentContext = Load(VariableType::NATIVE_POINTER(), glue, currentContextOffset);
|
||||
return Load(VariableType::NATIVE_POINTER(), currentContext, IntPtr(0));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetSortedKey(GateRef layoutInfo, GateRef index)
|
||||
{
|
||||
GateRef fixedIdx = GetSortedIndex(layoutInfo, index);
|
||||
return GetKey(layoutInfo, fixedIdx);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetSortedIndex(GateRef layoutInfo, GateRef index)
|
||||
{
|
||||
return GetSortedIndex(GetAttr(layoutInfo, index));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetAttrIndex(GateRef index)
|
||||
{
|
||||
return Int32Add(Int32LSL(index, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)), Int32(LayoutInfo::ATTR_INDEX_OFFSET));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetKeyIndex(GateRef index)
|
||||
{
|
||||
return Int32LSL(index, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetAttr(GateRef layoutInfo, GateRef index)
|
||||
{
|
||||
GateRef fixedIdx = GetAttrIndex(index);
|
||||
return GetInt32OfTInt(GetValueFromTaggedArray(layoutInfo, fixedIdx));
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetKey(GateRef layoutInfo, GateRef index)
|
||||
{
|
||||
GateRef fixedIdx = GetKeyIndex(index);
|
||||
return GetValueFromTaggedArray(layoutInfo, fixedIdx);
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetToPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key, GateRef result)
|
||||
{
|
||||
GateRef hash = HashFromHclassAndKey(glue, cls, key);
|
||||
GateRef prop =
|
||||
PtrAdd(cache, PtrMul(ZExtInt32ToPtr(hash), IntPtr(PropertiesCache::PropertyKey::GetPropertyKeySize())));
|
||||
StoreWithNoBarrier(VariableType::JS_POINTER(), prop, IntPtr(PropertiesCache::PropertyKey::GetHclassOffset()), cls);
|
||||
StoreWithNoBarrier(VariableType::JS_ANY(), prop, IntPtr(PropertiesCache::PropertyKey::GetKeyOffset()), key);
|
||||
StoreWithNoBarrier(VariableType::INT32(), prop, IntPtr(PropertiesCache::PropertyKey::GetResultsOffset()), result);
|
||||
}
|
||||
|
||||
inline void StubBuilder::StoreWithNoBarrier(VariableType type, GateRef base, GateRef offset, GateRef value)
|
||||
{
|
||||
env_->GetBuilder()->StoreWithNoBarrier(type, base, offset, value);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::HashFromHclassAndKey(GateRef glue, GateRef cls, GateRef key)
|
||||
{
|
||||
GateRef clsHash = Int32LSR(ChangeIntPtrToInt32(TaggedCastToIntPtr(cls)), Int32(3)); // skip 8bytes
|
||||
GateRef keyHash = GetKeyHashCode(glue, key);
|
||||
return Int32And(Int32Xor(clsHash, keyHash), Int32(PropertiesCache::CACHE_LENGTH_MASK));
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_STUB_INL_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -146,6 +146,7 @@ public:
|
||||
GateRef Load(VariableType type, GateRef base, GateRef offset);
|
||||
GateRef Load(VariableType type, GateRef base);
|
||||
void Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value);
|
||||
inline void StoreWithNoBarrier(VariableType type, GateRef base, GateRef offset, GateRef value);
|
||||
// arithmetic
|
||||
GateRef TaggedCastToIntPtr(GateRef x);
|
||||
GateRef Int16Add(GateRef x, GateRef y);
|
||||
@ -222,6 +223,7 @@ public:
|
||||
GateRef BothAreString(GateRef x, GateRef y);
|
||||
GateRef TaggedIsStringOrSymbol(GateRef obj);
|
||||
GateRef TaggedIsSymbol(GateRef obj);
|
||||
GateRef TaggedIsProtoChangeMarker(GateRef obj);
|
||||
GateRef GetNextPositionForHash(GateRef last, GateRef count, GateRef size);
|
||||
GateRef DoubleIsNAN(GateRef x);
|
||||
GateRef DoubleIsINF(GateRef x);
|
||||
@ -287,6 +289,8 @@ public:
|
||||
void SetPropertiesArray(VariableType type, GateRef glue, GateRef object, GateRef propsArray);
|
||||
void SetHash(GateRef glue, GateRef object, GateRef hash);
|
||||
GateRef GetLengthOfTaggedArray(GateRef array);
|
||||
GateRef GetExtractLengthOfTaggedArray(GateRef array);
|
||||
void SetExtractLengthOfTaggedArray(GateRef glue, GateRef array, GateRef extraLength);
|
||||
// object operation
|
||||
GateRef IsJSHClass(GateRef obj);
|
||||
GateRef LoadHClass(GateRef object);
|
||||
@ -316,6 +320,10 @@ public:
|
||||
GateRef TaggedIsPropertyBox(GateRef obj);
|
||||
GateRef TaggedObjectIsBigInt(GateRef obj);
|
||||
GateRef IsJsProxy(GateRef obj);
|
||||
GateRef IsJSGlobalObject(GateRef obj);
|
||||
GateRef IsModuleNamespace(GateRef obj);
|
||||
GateRef ObjIsSpecialContainer(GateRef obj);
|
||||
GateRef IsJSPrimitiveRef(GateRef obj);
|
||||
GateRef IsJSFunctionBase(GateRef obj);
|
||||
GateRef IsConstructor(GateRef object);
|
||||
GateRef IsBase(GateRef func);
|
||||
@ -323,6 +331,7 @@ public:
|
||||
GateRef IsByteArray(GateRef obj);
|
||||
GateRef IsJsCOWArray(GateRef obj);
|
||||
GateRef IsJSObject(GateRef obj);
|
||||
GateRef IsEnumerable(GateRef attr);
|
||||
GateRef IsWritable(GateRef attr);
|
||||
GateRef IsAccessor(GateRef attr);
|
||||
GateRef IsInlinedProperty(GateRef attr);
|
||||
@ -330,6 +339,7 @@ public:
|
||||
GateRef IsElement(GateRef attr);
|
||||
GateRef IsStringElement(GateRef attr);
|
||||
GateRef IsStringLength(GateRef attr);
|
||||
GateRef IsTypedArrayElement(GateRef attr);
|
||||
GateRef IsNonExist(GateRef attr);
|
||||
GateRef IsJSAPIVector(GateRef attr);
|
||||
GateRef IsJSAPIStack(GateRef obj);
|
||||
@ -389,6 +399,8 @@ public:
|
||||
// SetDictionaryOrder func in property_attribute.h
|
||||
GateRef SetDictionaryOrderFieldInPropAttr(GateRef attr, GateRef value);
|
||||
GateRef GetPrototypeFromHClass(GateRef hClass);
|
||||
GateRef GetEnumCacheFromHClass(GateRef hClass);
|
||||
GateRef GetProtoChangeMarkerFromHClass(GateRef hClass);
|
||||
GateRef GetLayoutFromHClass(GateRef hClass);
|
||||
GateRef GetBitFieldFromHClass(GateRef hClass);
|
||||
GateRef GetLengthFromString(GateRef value);
|
||||
@ -417,6 +429,7 @@ public:
|
||||
|
||||
void IncNumberOfProps(GateRef glue, GateRef hClass);
|
||||
GateRef GetNumberOfPropsFromHClass(GateRef hClass);
|
||||
GateRef HasDeleteProperty(GateRef hClass);
|
||||
GateRef IsTSHClass(GateRef hClass);
|
||||
void SetNumberOfPropsToHClass(GateRef glue, GateRef hClass, GateRef value);
|
||||
void SetElementsKindToTrackInfo(GateRef glue, GateRef trackInfo, GateRef elementsKind);
|
||||
@ -464,7 +477,8 @@ public:
|
||||
GateRef IsInternalString(GateRef string);
|
||||
GateRef IsDigit(GateRef ch);
|
||||
GateRef StringToElementIndex(GateRef glue, GateRef string);
|
||||
GateRef ComputeNonInlinedFastPropsCapacity(GateRef oldLength, GateRef maxNonInlinedFastPropsCapacity);
|
||||
GateRef ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength,
|
||||
GateRef maxNonInlinedFastPropsCapacity);
|
||||
GateRef FindTransitions(GateRef glue, GateRef receiver, GateRef hClass, GateRef key, GateRef attr);
|
||||
void TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr);
|
||||
void TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind);
|
||||
@ -531,7 +545,7 @@ public:
|
||||
GateRef TruncInt64ToInt1(GateRef x);
|
||||
GateRef TruncInt32ToInt1(GateRef x);
|
||||
GateRef GetGlobalConstantAddr(GateRef index);
|
||||
GateRef GetGlobalConstantString(ConstantIndex index);
|
||||
GateRef GetGlobalConstantOffset(ConstantIndex index);
|
||||
GateRef IsCallableFromBitField(GateRef bitfield);
|
||||
GateRef IsCallable(GateRef obj);
|
||||
GateRef GetOffsetFieldInPropAttr(GateRef attr);
|
||||
@ -555,6 +569,9 @@ public:
|
||||
GateRef FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback);
|
||||
GateRef FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback);
|
||||
GateRef GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback);
|
||||
void FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, GateRef value,
|
||||
ProfileOperation callback = ProfileOperation());
|
||||
void FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, GateRef value);
|
||||
GateRef SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn);
|
||||
GateRef SetPropertyByName(GateRef glue, GateRef receiver, GateRef key,
|
||||
GateRef value, bool useOwn, ProfileOperation callback = ProfileOperation()); // Crawl prototype chain
|
||||
@ -586,6 +603,7 @@ public:
|
||||
GateRef GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module);
|
||||
GateRef GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module);
|
||||
GateRef GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module);
|
||||
GateRef GetObjectLiteralInfoFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module);
|
||||
void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible);
|
||||
|
||||
// fast path
|
||||
@ -604,6 +622,34 @@ public:
|
||||
GateRef GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType);
|
||||
GateRef JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index);
|
||||
|
||||
// for-in
|
||||
GateRef NextInternal(GateRef glue, GateRef iter);
|
||||
GateRef GetLengthFromForInIterator(GateRef iter);
|
||||
GateRef GetIndexFromForInIterator(GateRef iter);
|
||||
GateRef GetKeysFromForInIterator(GateRef iter);
|
||||
GateRef GetObjectFromForInIterator(GateRef iter);
|
||||
GateRef GetCachedHclassFromForInIterator(GateRef iter);
|
||||
void SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length);
|
||||
void SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index);
|
||||
void SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys);
|
||||
void SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object);
|
||||
void SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass);
|
||||
void IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index);
|
||||
GateRef GetEnumCacheKind(GateRef glue, GateRef enumCache);
|
||||
GateRef GetEmptyArray(GateRef glue);
|
||||
GateRef IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind);
|
||||
GateRef NeedCheckProperty(GateRef receiver);
|
||||
|
||||
GateRef EnumerateObjectProperties(GateRef glue, GateRef obj);
|
||||
GateRef GetFunctionPrototype(GateRef glue, size_t index);
|
||||
GateRef ToPrototypeOrObj(GateRef glue, GateRef obj);
|
||||
GateRef IsSpecialKeysObject(GateRef obj);
|
||||
GateRef IsSlowKeysObject(GateRef obj);
|
||||
GateRef TryGetEnumCache(GateRef glue, GateRef obj);
|
||||
GateRef GetNumberOfElements(GateRef obj);
|
||||
GateRef IsSimpleEnumCacheValid(GateRef obj);
|
||||
GateRef IsEnumCacheWithProtoChainInfoValid(GateRef obj);
|
||||
|
||||
// Exception handle
|
||||
GateRef HasPendingException(GateRef glue);
|
||||
void ReturnExceptionIfAbruptCompletion(GateRef glue);
|
||||
@ -663,6 +709,20 @@ public:
|
||||
GateRef RemoveTaggedWeakTag(GateRef weak);
|
||||
inline GateRef LoadHCIndexFromConstPool(GateRef cachedArray, GateRef cachedLength, GateRef traceId, Label *miss);
|
||||
inline GateRef LoadHCIndexInfosFromConstPool(GateRef jsFunc);
|
||||
inline GateRef GetPropertiesCache(GateRef glue);
|
||||
GateRef GetIndexFromPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key);
|
||||
inline void SetToPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key, GateRef result);
|
||||
GateRef HashFromHclassAndKey(GateRef glue, GateRef cls, GateRef key);
|
||||
GateRef GetKeyHashCode(GateRef glue, GateRef key);
|
||||
inline GateRef GetSortedKey(GateRef layoutInfo, GateRef index);
|
||||
inline GateRef GetSortedIndex(GateRef layoutInfo, GateRef index);
|
||||
inline GateRef GetSortedIndex(GateRef attr);
|
||||
inline GateRef GetAttrIndex(GateRef index);
|
||||
inline GateRef GetAttr(GateRef layoutInfo, GateRef index);
|
||||
inline GateRef GetKey(GateRef layoutInfo, GateRef index);
|
||||
inline GateRef GetKeyIndex(GateRef index);
|
||||
GateRef BinarySearch(GateRef glue, GateRef layoutInfo, GateRef key, GateRef propsNum);
|
||||
|
||||
private:
|
||||
using BinaryOperation = std::function<GateRef(Environment*, GateRef, GateRef)>;
|
||||
GateRef ChangeTaggedPointerToInt64(GateRef x);
|
||||
|
@ -101,12 +101,30 @@ host_unittest_action("LoopOptimizationTest") {
|
||||
]
|
||||
}
|
||||
|
||||
host_unittest_action("GlobalValueNumberingTest") {
|
||||
module_out_path = module_output_path
|
||||
|
||||
sources = [
|
||||
# test file
|
||||
"global_value_numbering_test.cpp",
|
||||
"meta_data_equal_test.cpp",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"$ark_root/libpandafile:libarkfile_static",
|
||||
"$js_root:libark_jsruntime_test_set",
|
||||
"$js_root/ecmascript/compiler:libark_jsoptimizer_set",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
}
|
||||
|
||||
group("host_unittest") {
|
||||
testonly = true
|
||||
|
||||
# deps file
|
||||
deps = [
|
||||
":AssemblerTestAction",
|
||||
":GlobalValueNumberingTestAction",
|
||||
":LoopOptimizationTestAction",
|
||||
":TypedArrayLoweringTestAction",
|
||||
]
|
||||
|
218
ecmascript/compiler/tests/global_value_numbering_test.cpp
Normal file
218
ecmascript/compiler/tests/global_value_numbering_test.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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/compiler/gate_accessor.h"
|
||||
#include "ecmascript/compiler/pass.h"
|
||||
#include "ecmascript/compiler/share_gate_meta_data.h"
|
||||
#include "ecmascript/compiler/share_opcodes.h"
|
||||
#include "ecmascript/compiler/value_numbering.h"
|
||||
#include "ecmascript/compiler/verifier.h"
|
||||
#include "ecmascript/compiler/ts_hcr_lowering.h"
|
||||
#include "ecmascript/compiler/type_mcr_lowering.h"
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/mem/concurrent_marker.h"
|
||||
#include "ecmascript/mem/native_area_allocator.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace panda::test {
|
||||
class GlobalValueNumberingTests : public testing::Test {};
|
||||
|
||||
using ecmascript::kungfu::Circuit;
|
||||
using ecmascript::kungfu::CircuitBuilder;
|
||||
using ecmascript::kungfu::CombinedPassVisitor;
|
||||
using ecmascript::kungfu::EcmaOpcode;
|
||||
using ecmascript::kungfu::Environment;
|
||||
using ecmascript::kungfu::GateAccessor;
|
||||
using ecmascript::kungfu::GateRef;
|
||||
using ecmascript::kungfu::PGOSampleType;
|
||||
using ecmascript::kungfu::ValueNumbering;
|
||||
using ecmascript::kungfu::Verifier;
|
||||
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, AllInputsCheckedTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
auto z = builder.Arguments(3);
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
auto add2 = builder.Int64Add(x, y);
|
||||
auto add3 = builder.Int64Add(x, z);
|
||||
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
|
||||
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
|
||||
EXPECT_EQ(valuenumber.VisitGate(add2), add1);
|
||||
EXPECT_EQ(valuenumber.VisitGate(add3), Circuit::NullGate());
|
||||
}
|
||||
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, DeadNodesTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
auto add2 = builder.Int64Add(x, y);
|
||||
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
|
||||
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
|
||||
acc.DeleteGate(add1);
|
||||
EXPECT_EQ(valuenumber.VisitGate(add2), Circuit::NullGate());
|
||||
}
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, WontReplaceNodeWithItself)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
|
||||
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
|
||||
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
|
||||
}
|
||||
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, E2ESimpleAddTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
|
||||
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
auto add2 = builder.Int64Add(x, y);
|
||||
auto add3 = builder.Int64Add(add1, add2);
|
||||
|
||||
builder.Return(add3);
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
visitor.AddPass(&valuenumber);
|
||||
visitor.VisitGraph();
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
EXPECT_TRUE(acc.GetValueIn(add3, 0) == acc.GetValueIn(add3, 1));
|
||||
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 1);
|
||||
}
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, GrowStressTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
std::vector<GateRef> results;
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
results.push_back(add1);
|
||||
}
|
||||
|
||||
GateRef before = results[0];
|
||||
for (int i = 1; i < 10000; i++) {
|
||||
before = builder.Int64Add(before, results[i]);
|
||||
}
|
||||
|
||||
builder.Return(before);
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
visitor.AddPass(&valuenumber);
|
||||
visitor.VisitGraph();
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 9999);
|
||||
}
|
||||
|
||||
|
||||
HWTEST_F_L0(GlobalValueNumberingTests, ComplexAddTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
auto x = builder.Arguments(1);
|
||||
auto y = builder.Arguments(2);
|
||||
|
||||
auto add1 = builder.Int64Add(x, y);
|
||||
auto add2 = builder.Int64Add(x, y);
|
||||
auto add3 = builder.Int64Add(add1, add2);
|
||||
|
||||
auto add4 = builder.Int64Add(x, y);
|
||||
auto add5 = builder.Int64Add(x, y);
|
||||
auto add6 = builder.Int64Add(add4, add5);
|
||||
|
||||
auto add7 = builder.Int64Add(add3, add6);
|
||||
builder.Return(add7);
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
|
||||
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
|
||||
visitor.AddPass(&valuenumber);
|
||||
visitor.VisitGraph();
|
||||
EXPECT_TRUE(Verifier::Run(&circuit));
|
||||
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 4);
|
||||
}
|
||||
|
||||
} // namespace panda::test
|
213
ecmascript/compiler/tests/meta_data_equal_test.cpp
Normal file
213
ecmascript/compiler/tests/meta_data_equal_test.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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/compiler/gate_accessor.h"
|
||||
#include "ecmascript/compiler/share_opcodes.h"
|
||||
#include "ecmascript/compiler/verifier.h"
|
||||
#include "ecmascript/compiler/ts_hcr_lowering.h"
|
||||
#include "ecmascript/compiler/type_mcr_lowering.h"
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/mem/concurrent_marker.h"
|
||||
#include "ecmascript/mem/native_area_allocator.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace panda::test {
|
||||
class MetaDataEqualTests : public testing::Test {};
|
||||
|
||||
using ecmascript::kungfu::Circuit;
|
||||
using ecmascript::kungfu::CircuitBuilder;
|
||||
using ecmascript::kungfu::EcmaOpcode;
|
||||
using ecmascript::kungfu::ElementsKind;
|
||||
using ecmascript::kungfu::Environment;
|
||||
using ecmascript::kungfu::GateAccessor;
|
||||
using ecmascript::kungfu::GateMetaData;
|
||||
using ecmascript::kungfu::GateType;
|
||||
using ecmascript::kungfu::JSBytecodeMetaData;
|
||||
using ecmascript::kungfu::MachineType;
|
||||
using ecmascript::kungfu::PGOSampleType;
|
||||
using ecmascript::kungfu::TypedBinOp;
|
||||
using ecmascript::kungfu::TypedCallTargetCheckOp;
|
||||
|
||||
HWTEST_F_L0(MetaDataEqualTests, StringMetaDataEqualTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
|
||||
|
||||
|
||||
auto stringGate2 = circuit.GetConstantStringGate(MachineType::ARCH, "test2", GateType::NJSValue());
|
||||
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, stringGate2));
|
||||
|
||||
auto stringGate3 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(stringGate1, stringGate3));
|
||||
}
|
||||
|
||||
HWTEST_F_L0(MetaDataEqualTests, ConstantMetaDataEqualTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
|
||||
auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
|
||||
auto constantValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(constantValue1, constantValue2));
|
||||
|
||||
auto constantValue3 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
|
||||
auto constantValue4 = circuit.GetConstantGate(MachineType::I64, 3, GateType::NJSValue());
|
||||
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(constantValue3, constantValue4));
|
||||
|
||||
|
||||
// MetaData is equal, but Gate is not equal
|
||||
auto constantValue5 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
|
||||
auto constantValue6 = circuit.GetConstantGate(MachineType::I32, 2, GateType::NJSValue());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(constantValue5, constantValue6));
|
||||
|
||||
// MetaData is equal, but Gate is not equal
|
||||
auto ConstGateNJSValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
|
||||
auto ConstGateUndefined =
|
||||
circuit.GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(ConstGateNJSValue2, ConstGateUndefined));
|
||||
}
|
||||
|
||||
HWTEST_F_L0(MetaDataEqualTests, TypeErrorMetaDataEqualTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
|
||||
auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(constantValue1, stringGate1));
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, constantValue1));
|
||||
}
|
||||
|
||||
HWTEST_F_L0(MetaDataEqualTests, HCRMetaDataEqualTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
// JSBytecodeMetaData
|
||||
auto meta = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false);
|
||||
auto gate =
|
||||
circuit.NewGate(meta, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
auto meta2 = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false);
|
||||
auto gate2 =
|
||||
circuit.NewGate(meta2, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
|
||||
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetElementsKind(ElementsKind::NUMBER);
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetElementsKind(ElementsKind::NUMBER);
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
|
||||
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetType(PGOSampleType::CreateProfileType(0, 0));
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetType(PGOSampleType::CreateProfileType(0, 0));
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
|
||||
|
||||
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetType(PGOSampleType::CreateProfileType(0, 0));
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetType(PGOSampleType::CreateProfileType(0, 1));
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2));
|
||||
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetElementsKind(ElementsKind::NUMBER);
|
||||
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetElementsKind(ElementsKind::HOLE_NUMBER);
|
||||
EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2));
|
||||
}
|
||||
|
||||
HWTEST_F_L0(MetaDataEqualTests, MCRMetaDataEqualTest)
|
||||
{
|
||||
// construct a circuit
|
||||
ecmascript::NativeAreaAllocator allocator;
|
||||
Circuit circuit(&allocator);
|
||||
ecmascript::Chunk chunk(&allocator);
|
||||
GateAccessor acc(&circuit);
|
||||
CircuitBuilder builder(&circuit);
|
||||
Environment env(0, &builder);
|
||||
builder.SetEnvironment(&env);
|
||||
|
||||
// TypedCallMetaData
|
||||
auto callGate =
|
||||
circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
auto callGate2 =
|
||||
circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate, callGate2));
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate2, callGate));
|
||||
|
||||
// TypedCallTargetCheckMetaData
|
||||
auto callGate3 =
|
||||
circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
auto callGate4 =
|
||||
circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate3, callGate4));
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate4, callGate3));
|
||||
|
||||
// TypedBinaryMetaData
|
||||
auto callGate5 = circuit.NewGate(
|
||||
circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
// TypedBinaryMetaData
|
||||
auto callGate6 = circuit.NewGate(
|
||||
circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64,
|
||||
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
||||
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate5, callGate6));
|
||||
EXPECT_TRUE(acc.MetaDataValueEqu(callGate6, callGate5));
|
||||
}
|
||||
|
||||
|
||||
} // namespace panda::test
|
@ -14,6 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/ts_class_analysis.h"
|
||||
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
#include "ecmascript/layout_info.h"
|
||||
#include "ecmascript/ts_types/ts_type_accessor.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
|
@ -15,8 +15,10 @@
|
||||
|
||||
#include "ecmascript/compiler/ts_hclass_generator.h"
|
||||
#include "ecmascript/global_env_constants-inl.h"
|
||||
#include "ecmascript/subtyping_operator.h"
|
||||
#include "ecmascript/layout_info.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/jspandafile/class_info_extractor.h"
|
||||
#include "ecmascript/subtyping_operator.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
using ClassInfoExtractor = panda::ecmascript::ClassInfoExtractor;
|
||||
|
@ -17,9 +17,9 @@
|
||||
#include "ecmascript/compiler/bytecodes.h"
|
||||
#include "ecmascript/compiler/builtins_lowering.h"
|
||||
#include "ecmascript/compiler/circuit.h"
|
||||
#include "ecmascript/enum_conversion.h"
|
||||
#include "ecmascript/dfx/vmstat/opt_code_profiler.h"
|
||||
#include "ecmascript/stackmap/llvm_stackmap_parser.h"
|
||||
#include "ecmascript/ts_types/ts_type.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
bool TSHCRLowering::RunTSHCRLowering()
|
||||
@ -694,22 +694,55 @@ void TSHCRLowering::BuildNamedPropertyAccessVerifier(GateRef gate, GateRef recei
|
||||
}
|
||||
|
||||
bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate, GateType receiverType, JSTaggedValue key)
|
||||
{
|
||||
// String: primitive string type only
|
||||
// e.g. let s1 = "ABC"; // OK
|
||||
// let s2 = new String("DEF"); // Not included, whose type is JSType::JS_PRIMITIVE_REF
|
||||
if (receiverType.IsStringType()) {
|
||||
return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::STRING);
|
||||
}
|
||||
// Array: created via either array literal or new Array(...)
|
||||
// e.g. let a1 = [1, 2, 3]; // OK
|
||||
// let a2 = new Array(1, 2, 3); // OK
|
||||
if (tsManager_->IsArrayTypeKind(receiverType) ||
|
||||
tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, receiverType)) {
|
||||
return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::ARRAY);
|
||||
}
|
||||
// Other valid types: let x = new X(...);
|
||||
const auto hclassEntries = thread_->GetBuiltinHClassEntries();
|
||||
for (BuiltinTypeId type: BuiltinHClassEntries::BUILTIN_TYPES) {
|
||||
if (type == BuiltinTypeId::ARRAY || type == BuiltinTypeId::STRING || !hclassEntries.EntryIsValid(type)) {
|
||||
continue; // Checked before or invalid
|
||||
}
|
||||
if (!tsManager_->IsBuiltinInstanceType(type, receiverType)) {
|
||||
continue; // Type mismatch
|
||||
}
|
||||
return TryLowerTypedLdObjByNameForBuiltin(gate, key, type);
|
||||
}
|
||||
return false; // No lowering performed
|
||||
}
|
||||
|
||||
bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate, JSTaggedValue key, BuiltinTypeId type)
|
||||
{
|
||||
EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
|
||||
// (1) get length
|
||||
EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject());
|
||||
if (propString == lengthString) {
|
||||
if (tsManager_->IsArrayTypeKind(receiverType)) {
|
||||
if (type == BuiltinTypeId::ARRAY) {
|
||||
LowerTypedLdArrayLength(gate);
|
||||
return true;
|
||||
} else if (tsManager_->IsValidTypedArrayType(receiverType)) {
|
||||
LowerTypedLdTypedArrayLength(gate);
|
||||
return true;
|
||||
} else if (receiverType.IsStringType()) {
|
||||
}
|
||||
if (type == BuiltinTypeId::STRING) {
|
||||
LowerTypedLdStringLength(gate);
|
||||
return true;
|
||||
}
|
||||
if (IsTypedArrayType(type)) {
|
||||
LowerTypedLdTypedArrayLength(gate);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return TryLowerTypedLdObjByNameForBuiltinMethod(gate, receiverType, key);
|
||||
// (2) other functions
|
||||
return TryLowerTypedLdObjByNameForBuiltinMethod(gate, key, type);
|
||||
}
|
||||
|
||||
bool TSHCRLowering::IsCreateArray(GateRef gate)
|
||||
@ -770,28 +803,38 @@ void TSHCRLowering::LowerTypedLdStringLength(GateRef gate)
|
||||
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
|
||||
}
|
||||
|
||||
bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, GateType receiverType, JSTaggedValue key)
|
||||
bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, JSTaggedValue key, BuiltinTypeId type)
|
||||
{
|
||||
JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
|
||||
if (receiverType.IsStringType()) {
|
||||
JSHClass *stringPhc = globalEnv->GetStringPrototype()->GetTaggedObject()->GetClass();
|
||||
PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, stringPhc, key);
|
||||
// Unable to handle accessor at the moment
|
||||
if (!plr.IsFound() || plr.IsAccessor()) {
|
||||
return false;
|
||||
}
|
||||
AddProfiling(gate);
|
||||
GateRef str = acc_.GetValueIn(gate, 2);
|
||||
if (!Uncheck()) {
|
||||
builder_.EcmaStringCheck(str);
|
||||
}
|
||||
GateRef plrGate = builder_.Int32(plr.GetData());
|
||||
GateRef strPrototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), GlobalEnv::STRING_PROTOTYPE_INDEX);
|
||||
GateRef result = builder_.LoadProperty(strPrototype, plrGate, plr.IsFunction());
|
||||
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
|
||||
return true;
|
||||
std::optional<GlobalEnvField> protoField = ToGlobelEnvPrototypeField(type);
|
||||
if (!protoField.has_value()) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
size_t protoFieldIndex = static_cast<size_t>(*protoField);
|
||||
JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
|
||||
PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, prototypeHClass, key);
|
||||
// Unable to handle accessor at the moment
|
||||
if (!plr.IsFound() || plr.IsAccessor()) {
|
||||
return false;
|
||||
}
|
||||
GateRef receiver = acc_.GetValueIn(gate, 2);
|
||||
if (!Uncheck()) {
|
||||
// For Array type only: array stability shall be ensured.
|
||||
if (type == BuiltinTypeId::ARRAY) {
|
||||
builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
|
||||
}
|
||||
// This check is not required by String, since string is a primitive type.
|
||||
if (type != BuiltinTypeId::STRING) {
|
||||
builder_.BuiltinPrototypeHClassCheck(receiver, type);
|
||||
}
|
||||
}
|
||||
// Successfully goes to typed path
|
||||
AddProfiling(gate);
|
||||
GateRef plrGate = builder_.Int32(plr.GetData());
|
||||
GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(*protoField));
|
||||
GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
|
||||
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TSHCRLowering::LowerTypedLdObjByIndex(GateRef gate)
|
||||
@ -1435,20 +1478,19 @@ void TSHCRLowering::LowerTypedCallthis1(GateRef gate)
|
||||
if (id != BuiltinsStubCSigns::ID::NONE) {
|
||||
AddProfiling(gate);
|
||||
SpeculateCallBuiltin(gate, func, { a0 }, id, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (a0Type.IsNumberType()) {
|
||||
} else if (a0Type.IsNumberType()) {
|
||||
AddProfiling(gate);
|
||||
SpeculateCallBuiltin(gate, func, { a0 }, id, false);
|
||||
} else {
|
||||
if (!CanOptimizeAsFastCall(func)) {
|
||||
return;
|
||||
}
|
||||
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
|
||||
EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
|
||||
LowerTypedThisCall(gate, func, actualArgc, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!CanOptimizeAsFastCall(func)) {
|
||||
return;
|
||||
}
|
||||
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
|
||||
EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
|
||||
LowerTypedThisCall(gate, func, actualArgc, 1);
|
||||
}
|
||||
|
||||
void TSHCRLowering::LowerTypedCallthis2(GateRef gate)
|
||||
|
@ -98,7 +98,8 @@ private:
|
||||
GateRef BuildNamedPropertyAccess(GateRef hir, ObjectAccessHelper accessHelper, PropertyLookupResult plr);
|
||||
void BuildNamedPropertyAccessVerifier(GateRef gate, GateRef receiver, AccessMode mode, GateRef value);
|
||||
bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate, GateType receiverType, JSTaggedValue key);
|
||||
bool TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, GateType receiverType, JSTaggedValue key);
|
||||
bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate, JSTaggedValue key, BuiltinTypeId type);
|
||||
bool TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, JSTaggedValue key, BuiltinTypeId type);
|
||||
void LowerTypedLdArrayLength(GateRef gate);
|
||||
void LowerTypedLdTypedArrayLength(GateRef gate);
|
||||
void LowerTypedLdStringLength(GateRef gate);
|
||||
|
@ -692,6 +692,9 @@ bool MethodTypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC)
|
||||
ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
|
||||
inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
|
||||
}
|
||||
if (!hasType_ && inValueType.IsUndefinedType()) {
|
||||
inValueType = GateType::AnyType();
|
||||
}
|
||||
if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) {
|
||||
stringIdToGateType_[stringId] = inValueType;
|
||||
} else {
|
||||
|
@ -14,6 +14,8 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/type_inference/pgo_type_infer_helper.h"
|
||||
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
#include "ecmascript/ts_types/ts_type_accessor.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
|
@ -33,6 +33,9 @@ GateRef TypeMCRLowering::VisitGate(GateRef gate)
|
||||
case OpCode::PRIMITIVE_TYPE_CHECK:
|
||||
LowerPrimitiveTypeCheck(gate);
|
||||
break;
|
||||
case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
|
||||
LowerBuiltinPrototypeHClassCheck(gate);
|
||||
break;
|
||||
case OpCode::STABLE_ARRAY_CHECK:
|
||||
LowerStableArrayCheck(gate);
|
||||
break;
|
||||
@ -284,6 +287,12 @@ void TypeMCRLowering::SetDeoptTypeInfo(BuiltinTypeId id, DeoptType &type, size_t
|
||||
case BuiltinTypeId::FLOAT64_ARRAY:
|
||||
funcIndex = GlobalEnv::FLOAT64_ARRAY_FUNCTION_INDEX;
|
||||
break;
|
||||
case BuiltinTypeId::BIGINT64_ARRAY:
|
||||
funcIndex = GlobalEnv::BIGINT64_ARRAY_FUNCTION_INDEX;
|
||||
break;
|
||||
case BuiltinTypeId::BIGUINT64_ARRAY:
|
||||
funcIndex = GlobalEnv::BIGUINT64_ARRAY_FUNCTION_INDEX;
|
||||
break;
|
||||
default:
|
||||
LOG_ECMA(FATAL) << "this branch is unreachable";
|
||||
UNREACHABLE();
|
||||
@ -539,6 +548,33 @@ void TypeMCRLowering::LowerRangeCheckPredicate(GateRef gate)
|
||||
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
|
||||
}
|
||||
|
||||
void TypeMCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
BuiltinPrototypeHClassAccessor accessor = acc_.GetBuiltinHClassAccessor(gate);
|
||||
BuiltinTypeId type = accessor.GetBuiltinTypeId();
|
||||
GateRef frameState = GetFrameState(gate);
|
||||
GateRef glue = acc_.GetGlueFromArgList();
|
||||
|
||||
GateRef receiver = acc_.GetValueIn(gate, 0);
|
||||
builder_.HeapObjectCheck(receiver, frameState);
|
||||
|
||||
JSThread *thread = tsManager_->GetThread();
|
||||
// Only HClasses recorded in the JSThread during builtin initialization are available
|
||||
[[maybe_unused]] JSHClass *initialPrototypeHClass = thread->GetBuiltinPrototypeHClass(type);
|
||||
ASSERT(initialPrototypeHClass != nullptr);
|
||||
|
||||
// Phc = PrototypeHClass
|
||||
size_t phcOffset = JSThread::GlueData::GetBuiltinPrototypeHClassOffset(type, env.IsArch32Bit());
|
||||
GateRef receiverPhcAddress = builder_.LoadPrototypeHClass(receiver);
|
||||
GateRef initialPhcAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, phcOffset);
|
||||
GateRef phcMatches = builder_.Equal(receiverPhcAddress, initialPhcAddress);
|
||||
// De-opt if HClass of X.prototype changed where X is the current builtin object.
|
||||
builder_.DeoptCheck(phcMatches, frameState, DeoptType::BUILTINPROTOHCLASSMISMATCH);
|
||||
|
||||
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
|
||||
}
|
||||
|
||||
void TypeMCRLowering::LowerIndexCheck(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
@ -1641,7 +1677,7 @@ void TypeMCRLowering::LowerTypeOf(GateRef gate, GateRef glue)
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, builder_.GetGlobalConstantString(index));
|
||||
GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, builder_.GetGlobalConstantOffset(index));
|
||||
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
@ -147,6 +147,7 @@ private:
|
||||
void LowerLoadFromTaggedArray(GateRef gate);
|
||||
void LowerStoreToTaggedArray(GateRef gate, GateRef glue);
|
||||
void LowerRangeCheckPredicate(GateRef gate);
|
||||
void LowerBuiltinPrototypeHClassCheck(GateRef gate);
|
||||
|
||||
enum class ArrayState : uint8_t {
|
||||
PACKED = 0,
|
||||
|
@ -179,7 +179,7 @@ void TypeRecorder::CreateTypesForPGO(const JSPandaFile *jsPandaFile, const Metho
|
||||
return;
|
||||
}
|
||||
// Target method was not compiled by AOT.
|
||||
if (!decoder_->Match(recordName, pgo::PGOMethodId(callTargetMethodOffset))) {
|
||||
if (!decoder_->Match(jsPandaFile, recordName, pgo::PGOMethodId(callTargetMethodOffset))) {
|
||||
tsManager->SetHotnessFunc(funcGT, false);
|
||||
}
|
||||
GateType callTargetType = GateType(funcGT);
|
||||
@ -374,6 +374,13 @@ std::vector<ElementsKind> TypeRecorder::LoadElementsKinds(int32_t offset) const
|
||||
elementsKinds.emplace_back(elementsKind);
|
||||
}
|
||||
|
||||
// fiterate ElementsKind::None
|
||||
for (uint32_t i = 0; i < elementsKinds.size(); i++) {
|
||||
if (elementsKinds[i] == ElementsKind::NONE) {
|
||||
elementsKinds[i] = ElementsKind::GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
return elementsKinds;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,88 @@ GateRef TypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef TypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRef index)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryPass(env);
|
||||
env->SubCfgEntry(&entryPass);
|
||||
DEFVARIABLE(result, VariableType::BOOL(), False());
|
||||
Label exit(env);
|
||||
Label indexIsvalid(env);
|
||||
Label indexNotLessZero(env);
|
||||
Branch(Int64LessThan(index, Int64(0)), &exit, &indexNotLessZero);
|
||||
Bind(&indexNotLessZero);
|
||||
{
|
||||
GateRef arrLen = GetArrayLength(array);
|
||||
Branch(Int64GreaterThanOrEqual(index, ZExtInt32ToInt64(arrLen)), &exit, &indexIsvalid);
|
||||
Bind(&indexIsvalid);
|
||||
{
|
||||
result = True();
|
||||
Jump(&exit);
|
||||
}
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef TypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryPass(env);
|
||||
env->SubCfgEntry(&entryPass);
|
||||
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
|
||||
Label exit(env);
|
||||
Label notDetached(env);
|
||||
Label indexIsvalid(env);
|
||||
GateRef buffer = GetViewedArrayBuffer(array);
|
||||
Branch(IsDetachedBuffer(buffer), &exit, ¬Detached);
|
||||
Bind(¬Detached);
|
||||
{
|
||||
GateRef index = TryToElementsIndex(glue, key);
|
||||
Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit);
|
||||
Bind(&indexIsvalid);
|
||||
{
|
||||
GateRef offset = GetByteOffset(array);
|
||||
result = GetValueFromBuffer(buffer, TruncInt64ToInt32(index), offset, jsType);
|
||||
Jump(&exit);
|
||||
}
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef TypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value,
|
||||
GateRef jsType)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entryPass(env);
|
||||
env->SubCfgEntry(&entryPass);
|
||||
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
|
||||
Label exit(env);
|
||||
Label notDetached(env);
|
||||
Label indexIsvalid(env);
|
||||
GateRef buffer = GetViewedArrayBuffer(array);
|
||||
Branch(IsDetachedBuffer(buffer), &exit, ¬Detached);
|
||||
Bind(¬Detached);
|
||||
{
|
||||
Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit);
|
||||
Bind(&indexIsvalid);
|
||||
{
|
||||
result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
|
||||
{ array, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
|
||||
Jump(&exit);
|
||||
}
|
||||
}
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef TypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
|
@ -31,6 +31,9 @@ public:
|
||||
void GenerateCircuit() override {}
|
||||
GateRef FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType);
|
||||
GateRef FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array);
|
||||
GateRef LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType);
|
||||
GateRef StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, GateRef jsType);
|
||||
GateRef CheckTypedArrayIndexInRange(GateRef array, GateRef index);
|
||||
GateRef GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType);
|
||||
GateRef IsDetachedBuffer(GateRef buffer);
|
||||
GateRef GetDataPointFromBuffer(GateRef arrBuf);
|
||||
|
@ -13,71 +13,169 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "ecmascript/compiler/value_numbering.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
|
||||
GateRef ValueNumbering::VisitGate(GateRef gate)
|
||||
{
|
||||
auto opcode = acc_.GetOpCode(gate);
|
||||
if (opcode != OpCode::CONVERT) {
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
size_t hash = HashCode(gate);
|
||||
if (entries_.size() == 0) {
|
||||
entries_.resize(CACHE_LENGTH, Circuit::NullGate());
|
||||
SetEntry(hash, gate);
|
||||
auto opcode = acc_.GetOpCode(gate);
|
||||
if (opcode != OpCode::CONVERT && !useNewGVN_) {
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
GateRef replacement = GetEntry(hash);
|
||||
if (replacement != Circuit::NullGate() &&
|
||||
CheckReplacement(gate, replacement)) {
|
||||
return replacement;
|
||||
if (entries_ == nullptr) {
|
||||
InitEntries(entriesLength_);
|
||||
SetEntry(hash, gate);
|
||||
entriesSize_++;
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_);
|
||||
const size_t mask = entriesLength_ - 1;
|
||||
size_t dead = entriesLength_;
|
||||
for (size_t i = hash & mask;; i = (i + 1) & mask) {
|
||||
GateRef entry = entries_[i];
|
||||
if (entry == Circuit::NullGate()) {
|
||||
if (dead != entriesLength_) {
|
||||
entries_[dead] = gate;
|
||||
} else {
|
||||
// Have to insert a new entry.
|
||||
entries_[i] = gate;
|
||||
entriesSize_++;
|
||||
// Resize to keep load factor below 80%
|
||||
EnsureCapacity();
|
||||
}
|
||||
ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_);
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
|
||||
if (entry == gate) {
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
|
||||
// Skip dead entries, but remember their indices so we can reuse them.
|
||||
if (acc_.IsNop(entry)) {
|
||||
dead = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckReplacement(gate, entry)) {
|
||||
optimizedGateCount++;
|
||||
if (enableLog_) {
|
||||
LOG_COMPILER(INFO) << "Found a replaceable node, before -> after";
|
||||
acc_.Print(gate);
|
||||
acc_.Print(entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
SetEntry(hash, gate);
|
||||
return Circuit::NullGate();
|
||||
}
|
||||
|
||||
void ValueNumbering::EnsureCapacity()
|
||||
{
|
||||
if (entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD >= entriesLength_) {
|
||||
Grow();
|
||||
}
|
||||
}
|
||||
|
||||
void ValueNumbering::Grow()
|
||||
{
|
||||
GateRef *const oldEntries = entries_;
|
||||
size_t const oldSize = entriesLength_;
|
||||
entriesLength_ *= 2;
|
||||
InitEntries(entriesLength_);
|
||||
size_t const mask = entriesLength_ - 1;
|
||||
|
||||
for (size_t i = 0; i < oldSize; i++) {
|
||||
GateRef oldEnrty = oldEntries[i];
|
||||
if (oldEnrty == Circuit::NullGate() || acc_.IsNop(oldEnrty)) {
|
||||
continue;
|
||||
}
|
||||
for (size_t j = HashCode(oldEnrty) & mask;; j = (j + 1) & mask) {
|
||||
GateRef entry = entries_[j];
|
||||
if (entry == oldEnrty) {
|
||||
break;
|
||||
}
|
||||
if (entry == Circuit::NullGate()) {
|
||||
entries_[j] = oldEnrty;
|
||||
entriesSize_++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk_->Free(oldEntries);
|
||||
if (enableLog_) {
|
||||
LOG_COMPILER(INFO) << "Grow happend";
|
||||
}
|
||||
}
|
||||
|
||||
void ValueNumbering::InitEntries(size_t initSize)
|
||||
{
|
||||
entries_ = chunk_->NewArray<int32_t>(initSize);
|
||||
for (size_t i = 0; i < initSize; i++) {
|
||||
entries_[i] = Circuit::NullGate();
|
||||
}
|
||||
entriesSize_ = 0;
|
||||
}
|
||||
|
||||
|
||||
size_t HashCombine(size_t seed, size_t value)
|
||||
{
|
||||
// In the meantime, we're not considering 32-bit systems
|
||||
assert(sizeof(void *) == 8);
|
||||
const uint64_t m = uint64_t{0xC6A4A7935BD1E995};
|
||||
const uint32_t r = 47;
|
||||
|
||||
value *= m;
|
||||
value ^= value >> r;
|
||||
value *= m;
|
||||
|
||||
seed ^= value;
|
||||
seed *= m;
|
||||
return seed;
|
||||
}
|
||||
|
||||
size_t ValueNumbering::HashCode(GateRef gate)
|
||||
{
|
||||
size_t hash = static_cast<size_t>(acc_.GetOpCode(gate));
|
||||
hash ^= acc_.TryGetValue(gate);
|
||||
size_t valueCount = acc_.GetNumValueIn(gate);
|
||||
size_t hash = HashCombine(static_cast<size_t>(acc_.GetOpCode(gate)), valueCount);
|
||||
for (size_t i = 0; i < valueCount; i++) {
|
||||
GateRef input = acc_.GetValueIn(gate);
|
||||
GateRef input = acc_.GetValueIn(gate, i);
|
||||
auto id = acc_.GetId(input);
|
||||
hash ^= id;
|
||||
hash = HashCombine(hash, id);
|
||||
}
|
||||
return hash % CACHE_LENGTH;
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Gates are considered replaceable only when their values are identical
|
||||
bool ValueNumbering::CheckReplacement(GateRef lhs, GateRef rhs)
|
||||
{
|
||||
if (!acc_.MetaDataEqu(lhs, rhs)) {
|
||||
if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) {
|
||||
if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs))
|
||||
return false;
|
||||
|
||||
size_t valueCount1 = acc_.GetNumIns(lhs);
|
||||
size_t valueCount2 = acc_.GetNumIns(rhs);
|
||||
if (valueCount1 != valueCount2)
|
||||
return false;
|
||||
for (size_t i = 0; i < valueCount1; i++) {
|
||||
if (acc_.GetIn(lhs, i) != acc_.GetIn(rhs, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
size_t valueCount = acc_.GetNumValueIn(lhs);
|
||||
for (size_t i = 0; i < valueCount; i++) {
|
||||
if (acc_.GetValueIn(lhs, i) != acc_.GetValueIn(rhs, i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (acc_.GetGateType(lhs) != acc_.GetGateType(rhs)) {
|
||||
return false;
|
||||
}
|
||||
if (acc_.HasFrameState(lhs)) {
|
||||
ASSERT(acc_.HasFrameState(rhs));
|
||||
if (acc_.GetFrameState(lhs) != acc_.GetFrameState(rhs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (acc_.GetMachineType(lhs) != acc_.GetMachineType(rhs)) {
|
||||
return false;
|
||||
}
|
||||
auto opcode = acc_.GetOpCode(lhs);
|
||||
if (opcode == OpCode::CONVERT) {
|
||||
if (acc_.GetSrcType(lhs) != acc_.GetSrcType(rhs)) {
|
||||
return false;
|
||||
}
|
||||
if (acc_.GetDstType(lhs) != acc_.GetDstType(rhs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!acc_.MetaDataValueEqu(lhs, rhs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
} // namespace panda::ecmascript::kungfu
|
@ -24,29 +24,37 @@
|
||||
namespace panda::ecmascript::kungfu {
|
||||
class ValueNumbering : public PassVisitor {
|
||||
public:
|
||||
ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk)
|
||||
: PassVisitor(circuit, chunk, visitor), entries_(chunk) {}
|
||||
ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk, bool useNewGVN, bool enableLog)
|
||||
: PassVisitor(circuit, chunk, visitor), entries_(nullptr), useNewGVN_(useNewGVN),
|
||||
enableLog_(enableLog) {}
|
||||
|
||||
~ValueNumbering() = default;
|
||||
|
||||
GateRef VisitGate(GateRef gate) override;
|
||||
bool CheckReplacement(GateRef lhs, GateRef rhs);
|
||||
private:
|
||||
size_t HashCode(GateRef gate);
|
||||
GateRef GetEntry(size_t hash)
|
||||
int GetoptimizedGateCount()
|
||||
{
|
||||
ASSERT(hash < entries_.size());
|
||||
return entries_[hash];
|
||||
return optimizedGateCount;
|
||||
}
|
||||
|
||||
private:
|
||||
void Grow();
|
||||
void EnsureCapacity();
|
||||
void InitEntries(size_t initSize);
|
||||
size_t HashCode(GateRef gate);
|
||||
void SetEntry(size_t hash, GateRef gate)
|
||||
{
|
||||
ASSERT(hash < entries_.size());
|
||||
entries_[hash] = gate;
|
||||
entries_[hash & (entriesLength_ - 1)] = gate;
|
||||
}
|
||||
static const uint32_t CACHE_LENGTH_BIT = 8;
|
||||
static const uint32_t CACHE_LENGTH = (1U << CACHE_LENGTH_BIT);
|
||||
|
||||
ChunkVector<GateRef> entries_;
|
||||
const uint8_t LOAD_FACTOR_THRESHOLD = 4;
|
||||
uint32_t entriesLength_ = (1U << CACHE_LENGTH_BIT);
|
||||
uint32_t entriesSize_ = 0;
|
||||
GateRef* entries_;
|
||||
bool useNewGVN_;
|
||||
int optimizedGateCount = 0;
|
||||
bool enableLog_ = false;
|
||||
};
|
||||
} // panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_VALUE_NUMBERING_H
|
@ -822,10 +822,10 @@ bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm)
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugInfoExtractor *DebuggerApi::GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url)
|
||||
std::vector<DebugInfoExtractor *> DebuggerApi::GetPatchExtractors(const EcmaVM *ecmaVm, const std::string &url)
|
||||
{
|
||||
const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
|
||||
return hotReloadManager->GetPatchExtractor(url);
|
||||
return hotReloadManager->GetPatchExtractors(url);
|
||||
}
|
||||
|
||||
const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile)
|
||||
|
@ -127,7 +127,7 @@ public:
|
||||
std::string_view entryPoint);
|
||||
|
||||
// HotReload
|
||||
static DebugInfoExtractor *GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url);
|
||||
static std::vector<DebugInfoExtractor *> GetPatchExtractors(const EcmaVM *ecmaVm, const std::string &url);
|
||||
static const JSPandaFile *GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile);
|
||||
static std::vector<void *> GetNativePointer(const EcmaVM *ecmaVm);
|
||||
|
||||
|
@ -52,11 +52,12 @@ const JSPandaFile *HotReloadManager::GetBaseJSPandaFile(const JSPandaFile *jsPan
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
DebugInfoExtractor *HotReloadManager::GetPatchExtractor(const std::string &url) const
|
||||
std::vector<DebugInfoExtractor *> HotReloadManager::GetPatchExtractors(const std::string &url) const
|
||||
{
|
||||
std::vector<DebugInfoExtractor *> extractors;
|
||||
auto iter = patchExtractors_.find(url);
|
||||
if (iter == patchExtractors_.end()) {
|
||||
return nullptr;
|
||||
return extractors;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
@ -78,7 +79,7 @@ void HotReloadManager::ExtractPatch(const JSPandaFile *jsPandaFile)
|
||||
continue;
|
||||
}
|
||||
notificationMgr->LoadModuleEvent(jsPandaFile->GetJSPandaFileDesc(), recordName);
|
||||
patchExtractors_[url] = patchExtractor;
|
||||
patchExtractors_[url].emplace_back(patchExtractor);
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript::tooling
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
void NotifyPatchLoaded(const JSPandaFile *baseFile, const JSPandaFile *patchFile);
|
||||
void NotifyPatchUnloaded(const JSPandaFile *patchFile);
|
||||
|
||||
DebugInfoExtractor *GetPatchExtractor(const std::string &url) const;
|
||||
std::vector<DebugInfoExtractor *> GetPatchExtractors(const std::string &url) const;
|
||||
const JSPandaFile *GetBaseJSPandaFile(const JSPandaFile *jsPandaFile) const;
|
||||
|
||||
private:
|
||||
@ -39,7 +39,7 @@ private:
|
||||
|
||||
const EcmaVM *vm_;
|
||||
CUnorderedMap<const JSPandaFile *, const JSPandaFile *> baseJSPandaFiles_ {};
|
||||
CUnorderedMap<std::string, DebugInfoExtractor *> patchExtractors_ {};
|
||||
CUnorderedMap<std::string, std::vector<DebugInfoExtractor *>> patchExtractors_ {};
|
||||
};
|
||||
} // namespace panda::ecmascript::tooling
|
||||
#endif // ECMASCRIPT_DEBUGGER_HOT_RELOAD_MANAGER_H
|
||||
|
@ -21,7 +21,10 @@
|
||||
#include "ecmascript/napi/include/jsnapi.h"
|
||||
#include "ecmascript/debugger/js_pt_location.h"
|
||||
|
||||
namespace panda::ecmascript::tooling {
|
||||
namespace panda::ecmascript {
|
||||
class Method;
|
||||
|
||||
namespace tooling {
|
||||
struct JSPtStepRange {
|
||||
uint32_t startBcOffset {0};
|
||||
uint32_t endBcOffset {0};
|
||||
@ -139,6 +142,7 @@ public:
|
||||
NO_COPY_SEMANTIC(JSDebugInterface);
|
||||
NO_MOVE_SEMANTIC(JSDebugInterface);
|
||||
};
|
||||
} // namespace panda::ecmascript::tooling
|
||||
} // namespace tooling
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_DEBUGGER_JS_DEBUG_INTERFACE_H
|
||||
|
@ -82,8 +82,8 @@ HWTEST_F_L0(HotReloadManagerTest, LoadAndUnload)
|
||||
EXPECT_TRUE(patchFile != nullptr);
|
||||
EXPECT_TRUE(hotReloadManager->GetBaseJSPandaFile(patchFile.get()) == baseFile.get());
|
||||
|
||||
[[maybe_unused]] auto *patchExtractor = hotReloadManager->GetPatchExtractor(sourceFile);
|
||||
EXPECT_TRUE(patchExtractor != nullptr);
|
||||
[[maybe_unused]] auto patchExtractors = hotReloadManager->GetPatchExtractors(sourceFile);
|
||||
EXPECT_TRUE(!patchExtractors.empty());
|
||||
|
||||
Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(ecmaVm);
|
||||
result = JSNApi::IsQuickFixCausedException(ecmaVm, exception, patchFileName);
|
||||
@ -92,6 +92,6 @@ HWTEST_F_L0(HotReloadManagerTest, LoadAndUnload)
|
||||
res = JSNApi::UnloadPatch(ecmaVm, patchFileName);
|
||||
EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
|
||||
EXPECT_TRUE(hotReloadManager->GetBaseJSPandaFile(patchFile.get()) != baseFile.get());
|
||||
EXPECT_TRUE(hotReloadManager->GetPatchExtractor(sourceFile) == nullptr);
|
||||
EXPECT_TRUE(hotReloadManager->GetPatchExtractors(sourceFile).empty());
|
||||
}
|
||||
} // namespace panda::test
|
||||
|
@ -127,18 +127,24 @@ void HeapProfiler::UpdateHeapObjects(HeapSnapshot *snapshot)
|
||||
}
|
||||
|
||||
bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress,
|
||||
bool isVmMode, bool isPrivate, bool captureNumericValue)
|
||||
bool isVmMode, bool isPrivate, bool captureNumericValue, bool isFullGC)
|
||||
{
|
||||
[[maybe_unused]] bool heapClean = ForceFullGC(vm_);
|
||||
ASSERT(heapClean);
|
||||
if (isFullGC) {
|
||||
[[maybe_unused]] bool heapClean = ForceFullGC(vm_);
|
||||
ASSERT(heapClean);
|
||||
}
|
||||
LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot start";
|
||||
size_t heapSize = vm_->GetHeap()->GetHeapObjectSize();
|
||||
LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot heap size " << heapSize;
|
||||
int32_t heapCount = static_cast<int32_t>(vm_->GetHeap()->GetHeapObjectCount());
|
||||
if (progress != nullptr) {
|
||||
progress->ReportProgress(0, heapCount);
|
||||
int32_t heapCount = 0;
|
||||
if (isFullGC) {
|
||||
heapCount = static_cast<int32_t>(vm_->GetHeap()->GetHeapObjectCount());
|
||||
if (progress != nullptr) {
|
||||
progress->ReportProgress(0, heapCount);
|
||||
}
|
||||
}
|
||||
HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue);
|
||||
HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue,
|
||||
false, isFullGC);
|
||||
ASSERT(snapshot != nullptr);
|
||||
entryIdMap_->RemoveDeadEntryId(snapshot);
|
||||
isProfiling_ = true;
|
||||
@ -278,11 +284,13 @@ bool HeapProfiler::ForceFullGC(const EcmaVM *vm)
|
||||
}
|
||||
|
||||
HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMode, bool isPrivate,
|
||||
bool captureNumericValue, bool traceAllocation)
|
||||
bool captureNumericValue, bool traceAllocation, bool isFullGC)
|
||||
{
|
||||
LOG_ECMA(INFO) << "HeapProfiler::MakeHeapSnapshot";
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
const_cast<Heap *>(vm_->GetHeap())->Prepare();
|
||||
if (isFullGC) {
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
const_cast<Heap *>(vm_->GetHeap())->Prepare();
|
||||
}
|
||||
switch (sampleType) {
|
||||
case SampleType::ONE_SHOT: {
|
||||
auto *snapshot = GetChunk()->New<HeapSnapshot>(vm_, isVmMode, isPrivate, captureNumericValue,
|
||||
|
@ -76,7 +76,8 @@ public:
|
||||
* dump the specific snapshot in target format
|
||||
*/
|
||||
bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr,
|
||||
bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false) override;
|
||||
bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false,
|
||||
bool isFullGC = true) override;
|
||||
|
||||
void AddSnapshot(HeapSnapshot *snapshot);
|
||||
|
||||
@ -110,7 +111,7 @@ private:
|
||||
*/
|
||||
HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, bool isVmMode = true,
|
||||
bool isPrivate = false, bool captureNumericValue = false,
|
||||
bool traceAllocation = false);
|
||||
bool traceAllocation = false, bool isFullGC = true);
|
||||
std::string GenDumpFileName(DumpFormat dumpFormat);
|
||||
CString GetTimeStamp();
|
||||
void UpdateHeapObjects(HeapSnapshot *snapshot);
|
||||
|
@ -41,7 +41,8 @@ public:
|
||||
virtual void AllocationEvent(TaggedObject *address, size_t size) = 0;
|
||||
virtual void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size)= 0;
|
||||
virtual bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr,
|
||||
bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false) = 0;
|
||||
bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false,
|
||||
bool isFullGC = true) = 0;
|
||||
|
||||
virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr,
|
||||
bool traceAllocation = false, bool newThread = true) = 0;
|
||||
|
@ -94,7 +94,7 @@ HWTEST_F_L0(HeapSamplingTest, ImplementSampling)
|
||||
int stackDepth = 128; // default depth
|
||||
std::unique_ptr<HeapSampling> heapSampling = std::make_unique<HeapSampling>(instance,
|
||||
const_cast<Heap *>(instance->GetHeap()), samplingInterval, stackDepth);
|
||||
int size = 1 << 15; // default size
|
||||
size_t size = 1U << 15U; // default size
|
||||
Address addr = 0;
|
||||
heapSampling->ImplementSampling(addr, size);
|
||||
const SamplingInfo *result = heapSampling->GetAllocationProfile();
|
||||
|
@ -1871,14 +1871,15 @@ void JSForInIterator::Dump(std::ostream &os) const
|
||||
{
|
||||
os << " - Object : ";
|
||||
GetObject().DumpTaggedValue(os);
|
||||
os << " - CachedHclass : ";
|
||||
GetCachedHclass().DumpTaggedValue(os);
|
||||
os << "\n";
|
||||
os << " - WasVisited : " << GetWasVisited();
|
||||
os << " - Keys : ";
|
||||
GetKeys().DumpTaggedValue(os);
|
||||
os << "\n";
|
||||
os << " - VisitedObjs : ";
|
||||
GetVisitedObjs().DumpTaggedValue(os);
|
||||
os << " - Index : " << GetIndex();
|
||||
os << "\n";
|
||||
os << " - RemainingKeys : ";
|
||||
GetRemainingKeys().DumpTaggedValue(os);
|
||||
os << " - Length : " << GetLength();
|
||||
os << "\n";
|
||||
JSObject::Dump(os);
|
||||
}
|
||||
@ -4557,9 +4558,10 @@ void JSMap::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
void JSForInIterator::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
{
|
||||
vec.emplace_back(CString("Object"), GetObject());
|
||||
vec.emplace_back(CString("WasVisited"), JSTaggedValue(GetWasVisited()));
|
||||
vec.emplace_back(CString("VisitedObjs"), GetVisitedObjs());
|
||||
vec.emplace_back(CString("RemainingKeys"), GetRemainingKeys());
|
||||
vec.emplace_back(CString("CachedHclass"), GetCachedHclass());
|
||||
vec.emplace_back(CString("Keys"), GetKeys());
|
||||
vec.emplace_back(CString("Index"), JSTaggedValue(GetIndex()));
|
||||
vec.emplace_back(CString("Length"), JSTaggedValue(GetLength()));
|
||||
JSObject::DumpForSnapshot(vec);
|
||||
}
|
||||
|
||||
|
@ -244,20 +244,9 @@ JSTaggedValue EcmaContext::ExecuteAot(size_t actualNumArgs, JSTaggedType *args,
|
||||
return res;
|
||||
}
|
||||
|
||||
Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
|
||||
std::string_view entryPoint, bool excuteFromJob)
|
||||
Expected<JSTaggedValue, bool> EcmaContext::CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
|
||||
std::string_view entryPoint, JSHandle<JSFunction> &func)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint);
|
||||
if (program.IsEmpty()) {
|
||||
LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
|
||||
return Unexpected(false);
|
||||
}
|
||||
// for debugger
|
||||
vm_->GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent(
|
||||
jsPandaFile->GetJSPandaFileDesc(), entryPoint);
|
||||
|
||||
JSHandle<JSFunction> func(thread_, program->GetMainFunction());
|
||||
JSHandle<Method> method(thread_, func->GetMethod());
|
||||
JSHandle<JSTaggedValue> global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject();
|
||||
JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
|
||||
@ -303,6 +292,25 @@ Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypoint(const JSPandaFil
|
||||
job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
|
||||
std::string_view entryPoint, bool excuteFromJob)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint);
|
||||
if (program.IsEmpty()) {
|
||||
LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
|
||||
return Unexpected(false);
|
||||
}
|
||||
// for debugger
|
||||
vm_->GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent(
|
||||
jsPandaFile->GetJSPandaFileDesc(), entryPoint);
|
||||
|
||||
JSHandle<JSFunction> func(thread_, program->GetMainFunction());
|
||||
Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func);
|
||||
|
||||
// print exception information
|
||||
if (!excuteFromJob && thread_->HasPendingException()) {
|
||||
HandleUncaughtException(thread_->GetException());
|
||||
@ -310,6 +318,31 @@ Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypoint(const JSPandaFil
|
||||
return result;
|
||||
}
|
||||
|
||||
Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypointForHotReload(
|
||||
const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool excuteFromJob)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint);
|
||||
|
||||
JSHandle<JSFunction> func(thread_, program->GetMainFunction());
|
||||
Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func);
|
||||
|
||||
JSHandle<JSTaggedValue> finalModuleRecord(thread_, func->GetModule());
|
||||
// avoid GC problems.
|
||||
GlobalHandleCollection gloalHandleCollection(thread_);
|
||||
JSHandle<JSTaggedValue> moduleRecordHandle =
|
||||
gloalHandleCollection.NewHandle<JSTaggedValue>(finalModuleRecord->GetRawData());
|
||||
CString recordName = entryPoint.data();
|
||||
AddPatchModule(recordName, moduleRecordHandle);
|
||||
|
||||
// print exception information
|
||||
if (!excuteFromJob && thread_->HasPendingException() &&
|
||||
Method::Cast(func->GetMethod())->GetMethodName() != JSPandaFile::PATCH_FUNCTION_NAME_0) {
|
||||
HandleUncaughtException(thread_->GetException());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void EcmaContext::CJSExecution(JSHandle<JSFunction> &func, JSHandle<JSTaggedValue> &thisArg,
|
||||
const JSPandaFile *jsPandaFile, std::string_view entryPoint)
|
||||
{
|
||||
@ -670,7 +703,7 @@ void EcmaContext::SetupRegExpResultCache()
|
||||
|
||||
void EcmaContext::SetupRegExpGlobalResult()
|
||||
{
|
||||
regexpGlobal_ = builtins::RegExpGlobalResult::CreateGloablResultTable(thread_);
|
||||
regexpGlobal_ = builtins::RegExpGlobalResult::CreateGlobalResultTable(thread_);
|
||||
}
|
||||
|
||||
void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "ecmascript/mem/visitor.h"
|
||||
#include "ecmascript/regexp/regexp_parser_cache.h"
|
||||
#include "ecmascript/waiter_list.h"
|
||||
#include "global_handle_collection.h"
|
||||
#include "libpandafile/file.h"
|
||||
|
||||
namespace panda {
|
||||
@ -403,6 +404,36 @@ public:
|
||||
return &globalConst_;
|
||||
}
|
||||
|
||||
void AddPatchModule(const CString &recordName, const JSHandle<JSTaggedValue> moduleRecord)
|
||||
{
|
||||
cachedPatchModules_.emplace(recordName, moduleRecord);
|
||||
}
|
||||
JSHandle<JSTaggedValue> FindPatchModule(const CString &recordName) const
|
||||
{
|
||||
auto iter = cachedPatchModules_.find(recordName);
|
||||
if (iter != cachedPatchModules_.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Hole());
|
||||
}
|
||||
void ClearPatchModules()
|
||||
{
|
||||
GlobalHandleCollection gloalHandleCollection(thread_);
|
||||
for (auto &item : cachedPatchModules_) {
|
||||
gloalHandleCollection.Dispose(item.second);
|
||||
}
|
||||
cachedPatchModules_.clear();
|
||||
}
|
||||
|
||||
int32_t GetStageOfHotReload() const
|
||||
{
|
||||
return stageOfHotReload_;
|
||||
}
|
||||
void SetStageOfHotReload(int32_t stageOfHotReload)
|
||||
{
|
||||
stageOfHotReload_ = stageOfHotReload;
|
||||
}
|
||||
|
||||
bool JoinStackPushFastPath(JSHandle<JSTaggedValue> receiver);
|
||||
bool JoinStackPush(JSHandle<JSTaggedValue> receiver);
|
||||
void JoinStackPopFastPath(JSHandle<JSTaggedValue> receiver);
|
||||
@ -431,10 +462,15 @@ private:
|
||||
CJSInfo *cjsInfo = nullptr);
|
||||
Expected<JSTaggedValue, bool> InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, std::string_view entryPoint,
|
||||
bool excuteFromJob = false);
|
||||
Expected<JSTaggedValue, bool> InvokeEcmaEntrypointForHotReload(
|
||||
const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool excuteFromJob);
|
||||
Expected<JSTaggedValue, bool> CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
|
||||
std::string_view entryPoint, JSHandle<JSFunction> &func);
|
||||
bool LoadAOTFiles(const std::string &aotFileName);
|
||||
NO_MOVE_SEMANTIC(EcmaContext);
|
||||
NO_COPY_SEMANTIC(EcmaContext);
|
||||
|
||||
PropertiesCache *propertiesCache_ {nullptr};
|
||||
JSThread *thread_ {nullptr};
|
||||
EcmaVM *vm_ {nullptr};
|
||||
|
||||
@ -453,6 +489,10 @@ private:
|
||||
|
||||
CMap<const JSPandaFile *, CMap<int32_t, JSTaggedValue>> cachedConstpools_ {};
|
||||
|
||||
// for HotReload of module.
|
||||
CMap<CString, JSHandle<JSTaggedValue>> cachedPatchModules_ {};
|
||||
int32_t stageOfHotReload_ = 0;
|
||||
|
||||
// VM resources.
|
||||
ModuleManager *moduleManager_ {nullptr};
|
||||
TSManager *tsManager_ {nullptr};
|
||||
@ -499,7 +539,6 @@ private:
|
||||
JSTaggedType *frameBase_ {nullptr};
|
||||
uint64_t stackStart_ {0};
|
||||
uint64_t stackLimit_ {0};
|
||||
PropertiesCache *propertiesCache_ {nullptr};
|
||||
GlobalEnvConstants globalConst_;
|
||||
// Join Stack
|
||||
static constexpr uint32_t MIN_JOIN_STACK_SIZE = 2;
|
||||
|
@ -144,9 +144,6 @@ EcmaString *EcmaString::GetSlicedString(const EcmaVM *vm,
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
|
||||
{
|
||||
ASSERT((start + length) <= src->GetLength());
|
||||
if (start == 0 && length == src->GetLength()) {
|
||||
return *src;
|
||||
}
|
||||
JSHandle<SlicedString> slicedString(vm->GetJSThread(), CreateSlicedString(vm));
|
||||
FlatStringInfo srcFlat = FlattenAllString(vm, src);
|
||||
slicedString->SetLength(length, srcFlat.GetString()->IsUtf8());
|
||||
@ -155,6 +152,30 @@ EcmaString *EcmaString::GetSlicedString(const EcmaVM *vm,
|
||||
return *slicedString;
|
||||
}
|
||||
|
||||
/* static */
|
||||
EcmaString *EcmaString::GetSubString(const EcmaVM *vm,
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
|
||||
{
|
||||
ASSERT((start + length) <= src->GetLength());
|
||||
if (static_cast<uint32_t>(length) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) {
|
||||
if (start == 0 && length == src->GetLength()) {
|
||||
return *src;
|
||||
}
|
||||
if (src->IsUtf16()) {
|
||||
FlatStringInfo srcFlat = FlattenAllString(vm, src);
|
||||
bool canBeCompressed = CanBeCompressed(srcFlat.GetDataUtf16() + start, length);
|
||||
if (canBeCompressed) {
|
||||
JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, canBeCompressed));
|
||||
srcFlat = FlattenAllString(vm, src);
|
||||
CopyChars(string->GetDataUtf8Writable(), srcFlat.GetDataUtf16() + start, length);
|
||||
return *string;
|
||||
}
|
||||
}
|
||||
return GetSlicedString(vm, src, start, length);
|
||||
}
|
||||
return FastSubString(vm, src, start, length);
|
||||
}
|
||||
|
||||
void EcmaString::WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length)
|
||||
{
|
||||
ASSERT(IsLineString() && !IsConstantString());
|
||||
@ -552,6 +573,9 @@ bool EcmaString::StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &s
|
||||
if (str1 == str2) {
|
||||
return true;
|
||||
}
|
||||
if (str1->IsInternString() && str2->IsInternString()) {
|
||||
return false;
|
||||
}
|
||||
uint32_t str1Len = str1->GetLength();
|
||||
if (str1Len != str2->GetLength()) {
|
||||
return false;
|
||||
|
@ -110,6 +110,8 @@ private:
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
|
||||
static EcmaString *GetSlicedString(const EcmaVM *vm,
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
|
||||
static EcmaString *GetSubString(const EcmaVM *vm,
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
|
||||
// require src is LineString
|
||||
// not change src data structure
|
||||
static inline EcmaString *FastSubUtf8String(const EcmaVM *vm,
|
||||
@ -919,10 +921,10 @@ public:
|
||||
}
|
||||
|
||||
// get
|
||||
static EcmaString *GetSlicedString(const EcmaVM *vm,
|
||||
static EcmaString *GetSubString(const EcmaVM *vm,
|
||||
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
|
||||
{
|
||||
return EcmaString::GetSlicedString(vm, src, start, length);
|
||||
return EcmaString::GetSubString(vm, src, start, length);
|
||||
}
|
||||
|
||||
bool IsUtf8() const
|
||||
|
@ -226,7 +226,7 @@ bool EcmaVM::Initialize()
|
||||
}
|
||||
|
||||
callTimer_ = new FunctionCallTimer();
|
||||
|
||||
strategy_ = new ThrouputJSObjectResizingStrategy();
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
@ -312,6 +312,11 @@ EcmaVM::~EcmaVM()
|
||||
callTimer_ = nullptr;
|
||||
}
|
||||
|
||||
if (strategy_ != nullptr) {
|
||||
delete strategy_;
|
||||
strategy_ = nullptr;
|
||||
}
|
||||
|
||||
if (thread_ != nullptr) {
|
||||
delete thread_;
|
||||
thread_ = nullptr;
|
||||
@ -699,13 +704,4 @@ void EcmaVM::ResumeWorkerVm(uint32_t tid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EcmaVM::RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode) const
|
||||
{
|
||||
if (requestAotCallback_ == nullptr) {
|
||||
LOG_ECMA(ERROR) << "Trigger aot failed. callback is null.";
|
||||
return false;
|
||||
}
|
||||
return (requestAotCallback_(bundleName, moduleName, static_cast<int32_t>(triggerMode)) == 0);
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user