Merge branch 'master' of gitee.com:openharmony/arkcompiler_ets_runtime into master

Signed-off-by: 王笑佳 <wangxiaojia5@huawei.com>
This commit is contained in:
王笑佳 2023-10-24 02:16:43 +00:00 committed by Gitee
commit fc1b6f3890
355 changed files with 11056 additions and 2890 deletions

View File

@ -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"
}

View File

@ -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": [

View File

@ -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 {

View File

@ -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++) {

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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),

View File

@ -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()) {

View File

@ -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),

View File

@ -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),

View File

@ -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());

View File

@ -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();
}

View File

@ -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),

View File

@ -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)
{

View File

@ -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),

View File

@ -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> &regexp)
{
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> &regexp,
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> &regexp,
const uint8_t *buffer, size_t length, int32_t lastIndex,
bool isUtf16)
bool BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
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> &regexp,
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

View File

@ -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> &regexp,
const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16);
static bool Matcher(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
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> &regexp,
JSHandle<EcmaString> inputString, uint32_t inputLength);
static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputString, bool useCache);
static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputStr, bool useCache);
static bool IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> &regexp);
// 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

View File

@ -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),

View File

@ -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^531; 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

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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_;

View File

@ -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);
}

View File

@ -39,6 +39,7 @@ namespace panda::ecmascript::kungfu {
V(StringFromCharCode) \
V(ObjectToString) \
V(ObjectCreate) \
V(ObjectAssign) \
V(VectorForEach) \
V(VectorReplaceAllElements) \
V(StackForEach) \

View File

@ -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, &notDictionaryMode);
Bind(&notDictionaryMode);
{
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, &notHole);
Bind(&notHole);
{
// 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, &notHole);
Bind(&notHole);
{
// 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, &notHole);
Bind(&notHole);
{
Label isAccessor(env);
Label notAccessor(env);
Branch(IsAccessor(attr), &isAccessor, &notAccessor);
Bind(&isAccessor);
{
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
// exception
Label exception(env);
Branch(HasPendingException(glue_), &exception, &notAccessor);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
Bind(&notAccessor);
{
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, &notDictionaryMode);
Bind(&notDictionaryMode);
{
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, &notTwoArg); // 2 : two args
Bind(&twoArg);
{
GateRef source = GetCallArg1(numArgs_);
Label next(env);
Assign(result, &next, exit, target, source);
Bind(&next);
Jump(exit);
}
Bind(&notTwoArg);
Label threeArg(env);
Label notThreeArg(env);
Branch(Int64Equal(numArgs_, IntPtr(3)), &threeArg, &notThreeArg); // 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(&notThreeArg);
{
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

View File

@ -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

View File

@ -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();

View File

@ -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 {

View File

@ -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) \

View File

@ -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,

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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) \

View File

@ -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)));
}

View File

@ -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, &notAotLiteralInfo);
Bind(&isAOTLiteralInfo);
{
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
{ constPool, Int32ToTaggedInt(index), module }, hirGate);
Jump(&exit);
}
Bind(&notAotLiteralInfo);
{
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));

View File

@ -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);

View File

@ -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()

View File

@ -78,6 +78,8 @@ namespace panda::ecmascript::kungfu {
V(JsBoundCallInternal) \
V(JsProxyCallInternal) \
V(CreateStringBySingleCharCode) \
V(Getpropiterator) \
V(Getnextpropname) \
V(GetSingleCharCodeByIndex) \
V(FastStringEqual)

View File

@ -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;
}

View File

@ -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);
}
};

View File

@ -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:

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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)
{

View File

@ -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);

View File

@ -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 {

View File

@ -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");

View File

@ -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>();

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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",
]

View 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

View 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

View File

@ -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 {

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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, &notDetached);
Bind(&notDetached);
{
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, &notDetached);
Bind(&notDetached);
{
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();

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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