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

Signed-off-by: 韩靖 <10335916+han_177@user.noreply.gitee.com>
This commit is contained in:
韩靖 2023-11-04 07:21:12 +00:00 committed by Gitee
commit f6e99c783c
135 changed files with 2664 additions and 367 deletions

View File

@ -198,6 +198,9 @@ group("ark_runtime_host_unittest") {
deps += [ "$js_root/test/regresstest:ark_regress_test" ]
}
# execution test
deps += [ "$js_root/test/executiontest:ark_execution_test" ]
# ts aot test and asm test
if (!run_with_asan) {
deps += [
@ -484,6 +487,7 @@ config("ark_jsruntime_common_config") {
config("ecma_test_config") {
visibility = [
"./ecmascript/*",
"./test/executiontest/*",
"./test/fuzztest/*",
]

View File

@ -69,7 +69,7 @@ NAPI接口说明参考[NAPI部件](https://gitee.com/openharmony/arkui_napi/blob
### 使用说明<a name="section129654513264"></a>
ArkTS生成字节码参考[方舟eTS编译器](docs/using-the-toolchain-zh.md)
ArkTS生成字节码参考[方舟eTS编译器]( https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/README_zh.md#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E)
字节码执行:
```

View File

@ -118,6 +118,9 @@ JSHandle<JSTaggedValue> ErrorHelper::GetErrorName(JSThread *thread, const JSHand
case ErrorType::OOM_ERROR:
errorKey = globalConst->GetHandledOOMErrorString();
break;
case ErrorType::TERMINATION_ERROR:
errorKey = globalConst->GetHandledTerminationErrorString();
break;
default:
errorKey = globalConst->GetHandledErrorString();
break;

View File

@ -29,6 +29,7 @@ enum class ErrorType : uint8_t {
URI_ERROR,
AGGREGATE_ERROR,
OOM_ERROR,
TERMINATION_ERROR,
};
} // namespace panda::ecmascript::base

View File

@ -484,6 +484,61 @@ int64_t NumberHelper::DoubleToInt64(double d)
return static_cast<int64_t>(d);
}
bool NumberHelper::IsDigitalString(const uint8_t *start, const uint8_t *end)
{
int len = end - start;
for (int i = 0; i < len; i++) {
if (*(start + i) < '0' || *(start + i) > '9') {
return false;
}
}
return true;
}
int NumberHelper::StringToInt(const uint8_t *start, const uint8_t *end)
{
int num = *start - '0';
for (int i = 1; i < (end - start); i++) {
num = 10 * num + (*(start + i) - '0');
}
return num;
}
// only for string is ordinary string and using UTF8 encoding
// Fast path for short integer and some special value
std::pair<bool, JSTaggedNumber> NumberHelper::FastStringToNumber(const uint8_t *start,
const uint8_t *end, JSTaggedValue string)
{
ASSERT(start < end);
EcmaStringAccessor strAccessor(string);
bool minus = (start[0] == '-');
int pos = (minus ? 1 : 0);
if (pos == (end - start)) {
return {true, JSTaggedNumber(NAN_VALUE)};
} else if (*(start + pos) > '9') {
// valid number's codes not longer than '9', except 'I' and non-breaking space.
if (*(start + pos) != 'I' && *(start + pos) != 0xA0) {
return {true, JSTaggedNumber(NAN_VALUE)};
}
} else if ((end - (start + pos)) <= MAX_ELEMENT_INDEX_LEN && IsDigitalString((start + pos), end)) {
int num = StringToInt((start + pos), end);
if (minus) {
if (num == 0) {
return {true, JSTaggedNumber(SignedZero(Sign::NEG))};
}
num = -num;
} else {
if (num != 0 || (num == 0 && (end - start == 1))) {
strAccessor.TryToSetIntegerHash(num);
}
}
return {true, JSTaggedNumber(num)};
}
return {false, JSTaggedNumber(NAN_VALUE)};
}
double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix, uint32_t flags)
{
auto p = const_cast<uint8_t *>(start);
@ -609,6 +664,7 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui
}
// 8. parse '.'
exponent = 0;
if (radix == DECIMAL && *p == '.') {
RETURN_IF_CONVERSION_END(++p, end, (digits > 0 || (digits == 0 && leadingZero)) ?
(number * std::pow(radix, exponent)) : NAN_VALUE);

View File

@ -108,6 +108,10 @@ public:
static JSHandle<EcmaString> NumberToString(const JSThread *thread, JSTaggedValue number);
static double TruncateDouble(double d);
static int64_t DoubleToInt64(double d);
static bool IsDigitalString(const uint8_t *start, const uint8_t *end);
static int StringToInt(const uint8_t *start, const uint8_t *end);
static std::pair<bool, JSTaggedNumber> FastStringToNumber(const uint8_t *start,
const uint8_t *end, JSTaggedValue string);
static double StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix, uint32_t flags = NO_FLAGS);
static int32_t DoubleToInt(double d, size_t bits);
static int32_t DoubleInRangeInt32(double d);

View File

@ -105,6 +105,7 @@ HWTEST_F_L0(ErrorHelperTest, ErrorCommonToString_002)
JSHandle<JSTaggedValue> syntaxErrorFunc = env->GetSyntaxErrorFunction();
JSHandle<JSTaggedValue> referenceErrorFunc = env->GetReferenceErrorFunction();
JSHandle<JSTaggedValue> aggregateErrorFunc = env->GetAggregateErrorFunction();
JSHandle<JSTaggedValue> terminationErrorFunc = env->GetTerminationErrorFunction();
JSHandle<JSObject> uriErrorObj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(uriErrorFunc), uriErrorFunc);
JSHandle<JSObject> oomErrorObj =
@ -115,6 +116,8 @@ HWTEST_F_L0(ErrorHelperTest, ErrorCommonToString_002)
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(referenceErrorFunc), referenceErrorFunc);
JSHandle<JSObject> aggregateErrorObj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(aggregateErrorFunc), aggregateErrorFunc);
JSHandle<JSObject> terminationErrorObj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(terminationErrorFunc), terminationErrorFunc);
EcmaRuntimeCallInfo* argv = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
argv->SetFunction(JSTaggedValue::Undefined());
@ -128,6 +131,12 @@ HWTEST_F_L0(ErrorHelperTest, ErrorCommonToString_002)
JSHandle<JSTaggedValue> oomError(thread, ErrorHelper::ErrorCommonToString(argv, ErrorType::OOM_ERROR));
TestHelper::TearDownFrame(thread, prev);
argv->SetThis(JSTaggedValue(*terminationErrorObj));
prev = TestHelper::SetupFrame(thread, argv);
JSHandle<JSTaggedValue> terminationError(thread,
ErrorHelper::ErrorCommonToString(argv, ErrorType::TERMINATION_ERROR));
TestHelper::TearDownFrame(thread, prev);
argv->SetThis(JSTaggedValue(*syntaxErrorObj));
prev = TestHelper::SetupFrame(thread, argv);
JSHandle<JSTaggedValue> syntaxError(thread, ErrorHelper::ErrorCommonToString(argv, ErrorType::SYNTAX_ERROR));

View File

@ -145,6 +145,7 @@ using URIError = builtins::BuiltinsURIError;
using SyntaxError = builtins::BuiltinsSyntaxError;
using EvalError = builtins::BuiltinsEvalError;
using OOMError = builtins::BuiltinsOOMError;
using TerminationError = builtins::BuiltinsTerminationError;
using ErrorType = base::ErrorType;
using RandomGenerator = base::RandomGenerator;
using Global = builtins::BuiltinsGlobal;
@ -258,15 +259,15 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread, bool
env->SetObjectFunction(thread_, objectFunction);
env->SetObjectFunctionPrototype(thread_, objFuncPrototype);
JSHandle<JSHClass> FunctionClass = factory_->CreateFunctionClass(FunctionKind::BASE_CONSTRUCTOR, JSFunction::SIZE,
JSHandle<JSHClass> functionClass = factory_->CreateFunctionClass(FunctionKind::BASE_CONSTRUCTOR, JSFunction::SIZE,
JSType::JS_FUNCTION, env->GetFunctionPrototype());
env->SetFunctionClassWithProto(thread_, FunctionClass);
FunctionClass = factory_->CreateFunctionClass(FunctionKind::NORMAL_FUNCTION, JSFunction::SIZE, JSType::JS_FUNCTION,
env->SetFunctionClassWithProto(thread_, functionClass);
functionClass = factory_->CreateFunctionClass(FunctionKind::NORMAL_FUNCTION, JSFunction::SIZE, JSType::JS_FUNCTION,
env->GetFunctionPrototype());
env->SetFunctionClassWithoutProto(thread_, FunctionClass);
FunctionClass = factory_->CreateFunctionClass(FunctionKind::CLASS_CONSTRUCTOR, JSFunction::SIZE,
env->SetFunctionClassWithoutProto(thread_, functionClass);
functionClass = factory_->CreateFunctionClass(FunctionKind::CLASS_CONSTRUCTOR, JSFunction::SIZE,
JSType::JS_FUNCTION, env->GetFunctionPrototype());
env->SetFunctionClassWithoutName(thread_, FunctionClass);
env->SetFunctionClassWithoutName(thread_, functionClass);
if (!isRealm) {
InitializeAllTypeError(env, objFuncClass);
@ -1009,6 +1010,7 @@ void Builtins::InitializeAllTypeError(const JSHandle<GlobalEnv> &env, const JSHa
InitializeError(env, errorNativeFuncInstanceHClass, JSType::JS_SYNTAX_ERROR);
InitializeError(env, errorNativeFuncInstanceHClass, JSType::JS_EVAL_ERROR);
InitializeError(env, errorNativeFuncInstanceHClass, JSType::JS_OOM_ERROR);
InitializeError(env, errorNativeFuncInstanceHClass, JSType::JS_TERMINATION_ERROR);
}
void Builtins::InitializeAllTypeErrorWithRealm(const JSHandle<GlobalEnv> &realm) const
@ -1026,6 +1028,7 @@ void Builtins::InitializeAllTypeErrorWithRealm(const JSHandle<GlobalEnv> &realm)
SetErrorWithRealm(realm, JSType::JS_SYNTAX_ERROR);
SetErrorWithRealm(realm, JSType::JS_EVAL_ERROR);
SetErrorWithRealm(realm, JSType::JS_OOM_ERROR);
SetErrorWithRealm(realm, JSType::JS_TERMINATION_ERROR);
}
void Builtins::SetErrorWithRealm(const JSHandle<GlobalEnv> &realm, const JSType &errorTag) const
@ -1076,6 +1079,11 @@ void Builtins::SetErrorWithRealm(const JSHandle<GlobalEnv> &realm, const JSType
nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledOOMErrorString());
realm->SetOOMErrorFunction(thread_, nativeErrorFunction);
break;
case JSType::JS_TERMINATION_ERROR:
nativeErrorFunction = env->GetTerminationErrorFunction();
nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledTerminationErrorString());
realm->SetTerminationErrorFunction(thread_, nativeErrorFunction);
break;
default:
break;
}
@ -1134,6 +1142,10 @@ void Builtins::InitializeError(const JSHandle<GlobalEnv> &env, const JSHandle<JS
GeneralUpdateError(&errorParameter, OOMError::OOMErrorConstructor, OOMError::ToString,
"OutOfMemoryError", JSType::JS_OOM_ERROR);
break;
case JSType::JS_TERMINATION_ERROR:
GeneralUpdateError(&errorParameter, TerminationError::TerminationErrorConstructor,
TerminationError::ToString, "TerminationError", JSType::JS_TERMINATION_ERROR);
break;
default:
break;
}
@ -1181,8 +1193,10 @@ void Builtins::InitializeError(const JSHandle<GlobalEnv> &env, const JSHandle<JS
env->SetSyntaxErrorFunction(thread_, nativeErrorFunction);
} else if (errorTag == JSType::JS_EVAL_ERROR) {
env->SetEvalErrorFunction(thread_, nativeErrorFunction);
} else {
} else if (errorTag == JSType::JS_OOM_ERROR) {
env->SetOOMErrorFunction(thread_, nativeErrorFunction);
} else {
env->SetTerminationErrorFunction(thread_, nativeErrorFunction);
}
} // namespace panda::ecmascript

View File

@ -189,6 +189,13 @@ JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info)
return JSTaggedValue::True();
}
JSTaggedValue BuiltinsArkTools::HintGC(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
return JSTaggedValue(const_cast<Heap *>(info->GetThread()->GetEcmaVM()->GetHeap())->
CheckAndTriggerHintGC());
}
JSTaggedValue BuiltinsArkTools::RemoveAOTFlag(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -32,6 +32,7 @@
V("getLexicalEnv", GetLexicalEnv, 1, INVALID) \
V("hasTSSubtyping", HasTSSubtyping, 1, INVALID) \
V("hiddenStackSourceFile", HiddenStackSourceFile, 0, INVALID) \
V("hintGC", HintGC, 0, INVALID) \
V("isNotHoleProperty", IsNotHoleProperty, 2, INVALID) \
V("isPrototype", IsPrototype, 1, INVALID) \
V("isRegExpReplaceDetectorValid", IsRegExpReplaceDetectorValid, 0, INVALID) \
@ -95,6 +96,8 @@ public:
static JSTaggedValue ForceFullGC(EcmaRuntimeCallInfo *info);
static JSTaggedValue HintGC(EcmaRuntimeCallInfo *info);
static JSTaggedValue HiddenStackSourceFile(EcmaRuntimeCallInfo *info);
static JSTaggedValue RemoveAOTFlag(EcmaRuntimeCallInfo *info);

View File

@ -207,4 +207,17 @@ JSTaggedValue BuiltinsOOMError::ToString(EcmaRuntimeCallInfo *argv)
BUILTINS_API_TRACE(argv->GetThread(), Error, OOMErrorToString);
return ErrorHelper::ErrorCommonToString(argv, ErrorType::OOM_ERROR);
}
// TerminationError
JSTaggedValue BuiltinsTerminationError::TerminationErrorConstructor(EcmaRuntimeCallInfo *argv)
{
BUILTINS_API_TRACE(argv->GetThread(), Error, TerminationErrorConstructor);
return ErrorHelper::ErrorCommonConstructor(argv, ErrorType::TERMINATION_ERROR);
}
JSTaggedValue BuiltinsTerminationError::ToString(EcmaRuntimeCallInfo *argv)
{
BUILTINS_API_TRACE(argv->GetThread(), Error, TerminationErrorToString);
return ErrorHelper::ErrorCommonToString(argv, ErrorType::TERMINATION_ERROR);
}
} // namespace panda::ecmascript::builtins

View File

@ -92,5 +92,12 @@ public:
static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
};
class BuiltinsTerminationError : public base::BuiltinsBase {
public:
static JSTaggedValue TerminationErrorConstructor(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_ERRORS_H

View File

@ -44,21 +44,26 @@ JSTaggedValue BuiltinsNumber::NumberConstructor(EcmaRuntimeCallInfo *argv)
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
// 1. If value is present, then a , b , c.
// 2. Else Let n be +0𝔽.
JSTaggedNumber numberValue(0);
if (argv->GetArgsNumber() > 0) {
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
// a. Let prim be ? ToNumeric(value).
JSHandle<JSTaggedValue> numericVal = JSTaggedValue::ToNumeric(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// b. If Type(prim) is BigInt, let n be 𝔽((prim)).
if (numericVal->IsBigInt()) {
JSHandle<BigInt> bigNumericVal(numericVal);
numberValue = BigInt::BigIntToNumber(bigNumericVal);
if (!value->IsNumber()) {
JSHandle<JSTaggedValue> numericVal = JSTaggedValue::ToNumeric(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// b. If Type(prim) is BigInt, let n be 𝔽((prim)).
if (numericVal->IsBigInt()) {
JSHandle<BigInt> bigNumericVal(numericVal);
numberValue = BigInt::BigIntToNumber(bigNumericVal);
} else {
// c. Otherwise, let n be prim.
numberValue = JSTaggedNumber(numericVal.GetTaggedValue());
}
} else {
// c. Otherwise, let n be prim.
numberValue = JSTaggedNumber(numericVal.GetTaggedValue());
numberValue = JSTaggedNumber(value.GetTaggedValue());
}
}
// 3. If NewTarget is undefined, return n.

View File

@ -722,7 +722,7 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
}
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
if (EcmaStringAccessor(inputString).IsTreeString()) { // use flattenedString as srcString
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
}
const uint8_t *strBuffer;
@ -1640,7 +1640,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
size_t stringLength = EcmaStringAccessor(inputString).GetLength();
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
if (EcmaStringAccessor(inputString).IsTreeString()) { // use flattenedString as srcString
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
}
const uint8_t *strBuffer;
@ -1879,7 +1879,7 @@ JSTaggedValue BuiltinsRegExp::RegExpExecForTestFast(JSThread *thread, JSHandle<J
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16();
FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString);
if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString
if (EcmaStringAccessor(inputString).IsTreeString()) { // use flattenedString as srcString
inputString = JSHandle<EcmaString>(thread, flatStrInfo.GetString());
}
const uint8_t *strBuffer;

View File

@ -568,6 +568,30 @@ JSTaggedValue BuiltinsString::LocaleCompare(EcmaRuntimeCallInfo *argv)
#endif
}
JSTaggedValue BuiltinsString::LocaleCompareGC(JSThread *thread, JSHandle<JSTaggedValue> locales,
JSHandle<EcmaString> thisHandle, JSHandle<EcmaString> thatHandle,
JSHandle<JSTaggedValue> options, bool cacheable)
{
EcmaVM *ecmaVm = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVm->GetFactory();
JSHandle<JSTaggedValue> ctor = ecmaVm->GetGlobalEnv()->GetCollatorFunction();
JSHandle<JSCollator> collator =
JSHandle<JSCollator>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor)));
JSHandle<JSCollator> initCollator =
JSCollator::InitializeCollator(thread, collator, locales, options, cacheable);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
icu::Collator *icuCollator = nullptr;
if (cacheable) {
icuCollator = JSCollator::GetCachedIcuCollator(thread, locales);
ASSERT(icuCollator != nullptr);
} else {
icuCollator = initCollator->GetIcuCollator();
}
JSTaggedValue result = JSCollator::CompareStrings(icuCollator, thisHandle, thatHandle);
return result;
}
// 21.1.3.11
JSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv)
{

View File

@ -159,6 +159,9 @@ public:
static JSTaggedValue LastIndexOf(EcmaRuntimeCallInfo *argv);
// 21.1.3.10
static JSTaggedValue LocaleCompare(EcmaRuntimeCallInfo *argv);
static JSTaggedValue LocaleCompareGC(JSThread *thread, JSHandle<JSTaggedValue> locales,
JSHandle<EcmaString> thisHandle, JSHandle<EcmaString> thatHandle,
JSHandle<JSTaggedValue> options, bool cacheable);
// 21.1.3.11
static JSTaggedValue Match(EcmaRuntimeCallInfo *argv);

View File

@ -2735,7 +2735,7 @@ HWTEST_F_L0(BuiltinsMathTest, Max_3)
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo);
JSTaggedValue result = BuiltinsMath::Max(ecmaRuntimeCallInfo);
TestHelper::TearDownFrame(thread_, prev);
JSTaggedValue expect = BuiltinsBase::GetTaggedDouble(100.0);
JSTaggedValue expect = BuiltinsBase::GetTaggedInt(100);
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}

View File

@ -116,6 +116,7 @@ ohos_source_set("libark_jsoptimizer_set") {
"mcr_circuit_builder.cpp",
"mcr_gate_meta_data.cpp",
"mcr_lowering.cpp",
"native_inline_lowering.cpp",
"new_object_stub_builder.cpp",
"ntype_bytecode_lowering.cpp",
"ntype_hcr_lowering.cpp",

View File

@ -102,6 +102,7 @@ CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOpti
isEnableOptConstantFolding_ = runtimeOptions.IsEnableOptConstantFolding();
isEnableCollectLiteralInfo_ = false;
isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization();
isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline();
}
bool CompilationPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOptions)
@ -336,7 +337,8 @@ int Main(const int argc, const char **argv)
cOptions.isEnableOptLoopInvariantCodeMotion_,
cOptions.isEnableCollectLiteralInfo_,
cOptions.isEnableOptConstantFolding_,
cOptions.isEnableLexenvSpecialization_);
cOptions.isEnableLexenvSpecialization_,
cOptions.isEnableNativeInline_);
std::string entrypoint = GetEntryPoint(runtimeOptions);
PassManager passManager(vm,
entrypoint,

View File

@ -60,6 +60,7 @@ struct CompilationOptions {
bool isEnableCollectLiteralInfo_;
bool isEnableOptConstantFolding_;
bool isEnableLexenvSpecialization_;
bool isEnableNativeInline_;
};
class CompilationPreprocessor {

View File

@ -29,7 +29,8 @@ namespace panda::ecmascript::kungfu {
// AOT_BUILTINS_STUB_LIST is used in AOT only.
#define BUILTINS_STUB_LIST(V) \
BUILTINS_METHOD_STUB_LIST(V) \
BUILTINS_CONSTRUCTOR_STUB_LIST(V)
BUILTINS_CONSTRUCTOR_STUB_LIST(V) \
AOT_AND_BUILTINS_STUB_LIST(V)
#define BUILTINS_METHOD_STUB_LIST(V) \
V(StringCharCodeAt) \
@ -89,6 +90,9 @@ namespace panda::ecmascript::kungfu {
V(DateConstructor) \
V(ArrayConstructor)
#define AOT_AND_BUILTINS_STUB_LIST(V) \
V(LocaleCompare)
#define AOT_BUILTINS_STUB_LIST(V) \
V(SQRT) /* list start and math list start */ \
V(COS) \
@ -97,7 +101,6 @@ namespace panda::ecmascript::kungfu {
V(ATAN) \
V(ABS) \
V(FLOOR) /* math list end */ \
V(LocaleCompare) \
V(SORT) \
V(STRINGIFY) \
V(MAP_PROTO_ITERATOR) \
@ -163,8 +166,9 @@ public:
static bool IsTypedBuiltin(ID builtinId)
{
return (BuiltinsStubCSigns::ID::TYPED_BUILTINS_FIRST <= builtinId) &&
(builtinId <= BuiltinsStubCSigns::ID::TYPED_BUILTINS_LAST);
return (BuiltinsStubCSigns::ID::LocaleCompare == builtinId) ||
((BuiltinsStubCSigns::ID::TYPED_BUILTINS_FIRST <= builtinId) &&
(builtinId <= BuiltinsStubCSigns::ID::TYPED_BUILTINS_LAST));
}
static bool IsTypedBuiltinMath(ID builtinId)

View File

@ -1840,7 +1840,59 @@ GateRef BuiltinsStringStubBuilder::StringConcat(GateRef glue, GateRef leftString
return ret;
}
GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef srcString, GateRef trimMode)
void BuiltinsStringStubBuilder::LocaleCompare([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
[[maybe_unused]] Variable *res, [[maybe_unused]] Label *exit,
Label *slowPath)
{
auto env = GetEnvironment();
Label thisIsHeapObj(env);
Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
Bind(&thisIsHeapObj);
{
Label thisValueIsString(env);
Label fristArgIsString(env);
Label arg0IsHeapObj(env);
Branch(IsString(thisValue), &thisValueIsString, slowPath);
Bind(&thisValueIsString);
GateRef arg0 = GetCallArg0(numArgs);
Branch(TaggedIsHeapObject(arg0), &arg0IsHeapObj, slowPath);
Bind(&arg0IsHeapObj);
Branch(IsString(arg0), &fristArgIsString, slowPath);
Bind(&fristArgIsString);
#ifdef ARK_SUPPORT_INTL
GateRef locales = GetCallArg1(numArgs);
GateRef options = GetCallArg2(numArgs);
GateRef localesIsUndef = TaggedIsUndefined(locales);
GateRef optionsIsUndef = TaggedIsUndefined(options);
GateRef cacheable = BoolAnd(BoolOr(localesIsUndef, TaggedObjectIsString(locales)), optionsIsUndef);
Label optionsIsString(env);
Label cacheAble(env);
Label uncacheable(env);
Branch(cacheable, &cacheAble, &uncacheable);
Bind(&cacheAble);
{
Label defvalue(env);
GateRef resValue = CallNGCRuntime(glue, RTSTUB_ID(LocaleCompareNoGc), {glue, locales, thisValue, arg0});
Branch(TaggedIsUndefined(resValue), slowPath, &defvalue);
Bind(&defvalue);
*res = resValue;
Jump(exit);
}
Bind(&uncacheable);
{
res->WriteVariable(CallRuntime(glue, RTSTUB_ID(LocaleCompareWithGc), {locales, thisValue, arg0, options}));
Jump(exit);
}
#else
Jump(slowPath);
#endif
}
}
GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef thisValue, GateRef trimMode)
{
auto env = GetEnvironment();
@ -1853,7 +1905,7 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef srcStrin
Label notEmpty(env);
Label exit(env);
GateRef srcLen = GetLengthFromString(srcString);
GateRef srcLen = GetLengthFromString(thisValue);
Branch(Int32Equal(srcLen, Int32(0)), &emptyString, &notEmpty);
Bind(&emptyString);
{
@ -1866,10 +1918,10 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef srcStrin
Label srcFlattenFastPath(env);
FlatStringStubBuilder srcFlat(this);
srcFlat.FlattenString(glue, srcString, &srcFlattenFastPath);
srcFlat.FlattenString(glue, thisValue, &srcFlattenFastPath);
Bind(&srcFlattenFastPath);
StringInfoGateRef srcStringInfoGate(&srcFlat);
result = EcmaStringTrimBody(glue, srcStringInfoGate, trimMode, IsUtf8String(srcString));
result = EcmaStringTrimBody(glue, thisValue, srcStringInfoGate, trimMode, IsUtf8String(thisValue));
Jump(&exit);
}
Bind(&exit);
@ -1878,8 +1930,8 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef srcStrin
return ret;
}
GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, StringInfoGateRef srcStringInfoGate,
GateRef trimMode, GateRef isUtf8)
GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, GateRef thisValue,
StringInfoGateRef srcStringInfoGate, GateRef trimMode, GateRef isUtf8)
{
auto env = GetEnvironment();
@ -1888,6 +1940,7 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, StringInfoGa
GateRef srcLen = srcStringInfoGate.GetLength();
GateRef srcString = srcStringInfoGate.GetString();
GateRef startIndex = srcStringInfoGate.GetStartIndex();
DEFVARIABLE(start, VariableType::INT32(), Int32(0));
DEFVARIABLE(end, VariableType::INT32(), Int32Sub(srcLen, Int32(1)));
@ -1899,7 +1952,7 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, StringInfoGa
Branch(Int32GreaterThanOrEqual(trimMode, Int32(0)), &trimOrTrimStart, &notTrimStart);
Bind(&trimOrTrimStart); // mode = TrimMode::TRIM or TrimMode::TRIM_START
{
start = CallNGCRuntime(glue, RTSTUB_ID(StringGetStart), {isUtf8, srcString, srcLen});
start = CallNGCRuntime(glue, RTSTUB_ID(StringGetStart), {isUtf8, srcString, srcLen, startIndex});
Jump(&notTrimStart);
}
Bind(&notTrimStart);
@ -1908,13 +1961,13 @@ GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, StringInfoGa
Branch(Int32LessThanOrEqual(trimMode, Int32(0)), &trimOrTrimEnd, &next);
Bind(&trimOrTrimEnd); // mode = TrimMode::TRIM or TrimMode::TRIM_END
{
end = CallNGCRuntime(glue, RTSTUB_ID(StringGetEnd), {isUtf8, srcString, *start, srcLen});
end = CallNGCRuntime(glue, RTSTUB_ID(StringGetEnd), {isUtf8, srcString, *start, srcLen, startIndex});
Jump(&next);
}
}
Bind(&next);
{
auto ret = FastSubString(glue, srcString, *start,
auto ret = FastSubString(glue, thisValue, *start,
Int32Add(Int32Sub(*end, *start), Int32(1)), srcStringInfoGate);
env->SubCfgExit();
return ret;

View File

@ -38,6 +38,7 @@ public:
void Replace(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath);
void Trim(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath);
void Slice(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath);
void LocaleCompare(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath);
GateRef ConvertAndClampRelativeIndex(GateRef index, GateRef length);
GateRef StringAt(const StringInfoGateRef &stringInfoGate, GateRef index);
@ -59,7 +60,8 @@ public:
GateRef CreateFromEcmaString(GateRef glue, GateRef index, const StringInfoGateRef &stringInfoGate);
GateRef StringConcat(GateRef glue, GateRef leftString, GateRef rightString);
GateRef EcmaStringTrim(GateRef glue, GateRef srcString, GateRef trimMode);
GateRef EcmaStringTrimBody(GateRef glue, StringInfoGateRef srcStringInfoGate, GateRef trimMode, GateRef isUtf8);
GateRef EcmaStringTrimBody(GateRef glue, GateRef thisValue, StringInfoGateRef srcStringInfoGate,
GateRef trimMode, GateRef isUtf8);
void StoreParent(GateRef glue, GateRef object, GateRef parent);
void StoreStartIndex(GateRef glue, GateRef object, GateRef startIndex);
private:

View File

@ -177,6 +177,24 @@ DECLARE_BUILTINS(String##method)
V(Trim, JS_ANY, Undefined()) \
V(Slice, JS_ANY, Undefined())
DECLARE_BUILTINS(LocaleCompare)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
Label exit(env);
Label slowPath(env);
BuiltinsStringStubBuilder stringStubBuilder(this);
stringStubBuilder.LocaleCompare(glue, thisValue, numArgs, &res, &exit, &slowPath);
Bind(&slowPath);
{
auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(LocaleCompare));
res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str());
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
BUILTINS_WITH_STRING_STUB_BUILDER(DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER)
#undef DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER

View File

@ -79,7 +79,7 @@ GateRef BuiltinLowering::TypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID
Label exit(&builder_);
GateRef para1 = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
builder_.Branch(builder_.TaggedIsNumber(para1), &numberBranch, &notNumberBranch);
builder_.Bind(&numberBranch);
@ -172,7 +172,7 @@ GateRef BuiltinLowering::TypedAbs(GateRef gate)
Label exit(&builder_);
GateRef para1 = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
Label isInt(&builder_);
Label notInt(&builder_);

View File

@ -1209,6 +1209,23 @@ DEF_CALL_SIGNATURE(BigIntEquals)
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(LocaleCompareNoGc)
{
// 4 : 4 input parameters
CallSignature localeCompareNoGc("LocaleCompareNoGc", 0, 4,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = localeCompareNoGc;
std::array<VariableType, 4> params = { // 4 : 4 input parameters
VariableType::NATIVE_POINTER(),
VariableType::JS_POINTER(),
VariableType::JS_POINTER(),
VariableType::JS_POINTER(),
};
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(BigIntSameValueZero)
{
// 1 : 1 input parameters
@ -1226,12 +1243,13 @@ DEF_CALL_SIGNATURE(BigIntSameValueZero)
DEF_CALL_SIGNATURE(StringGetStart)
{
CallSignature stringGetStart("StringGetStart", 0, 2, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
CallSignature stringGetStart("StringGetStart", 0, 4, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
*callSign = stringGetStart;
std::array<VariableType, 3> params = { // 3 : three input parameters
std::array<VariableType, 4> params = { // 4 : four input parameters
VariableType::BOOL(),
VariableType::JS_POINTER(),
VariableType::INT32(),
VariableType::INT32(),
};
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);
@ -1240,13 +1258,14 @@ DEF_CALL_SIGNATURE(StringGetStart)
DEF_CALL_SIGNATURE(StringGetEnd)
{
CallSignature stringGetEnd("StringGetEnd", 0, 3, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
CallSignature stringGetEnd("StringGetEnd", 0, 5, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
*callSign = stringGetEnd;
std::array<VariableType, 4> params = { // 4 : four input parameters
std::array<VariableType, 5> params = { // 5 : five input parameters
VariableType::BOOL(),
VariableType::JS_POINTER(),
VariableType::INT32(),
VariableType::INT32(),
VariableType::INT32(),
};
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);

View File

@ -471,6 +471,7 @@ private:
V(CreateJSMapIterator) \
V(JSHClassFindProtoTransitions) \
V(NumberHelperStringToDouble) \
V(LocaleCompareNoGc) \
V(StringGetStart) \
V(StringGetEnd)

View File

@ -77,7 +77,7 @@ GateRef CircuitBuilder::LogicAnd(GateRef x, GateRef y)
Label exit(env_);
Label isX(env_);
Label notX(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), x);
DEFVALUE(result, env_, VariableType::BOOL(), x);
Branch(x, &isX, &notX);
Bind(&isX);
{
@ -101,7 +101,7 @@ GateRef CircuitBuilder::LogicOr(GateRef x, GateRef y)
Label exit(env_);
Label isX(env_);
Label notX(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), x);
DEFVALUE(result, env_, VariableType::BOOL(), x);
Branch(x, &isX, &notX);
Bind(&isX);
{

View File

@ -622,7 +622,7 @@ GateRef CircuitBuilder::IsEcmaObject(GateRef obj)
{
Label entryPass(env_);
SubCfgEntry(&entryPass);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label heapObj(env_);
Label exit(env_);
GateRef isHeapObject = TaggedIsHeapObject(obj);
@ -646,7 +646,7 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
Label cache(env_);
auto cacheValue = GetValueFromTaggedArray(constPool, index);
DEFVAlUE(result, env_, VariableType::JS_ANY(), cacheValue);
DEFVALUE(result, env_, VariableType::JS_ANY(), cacheValue);
Branch(BoolOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache);
Bind(&cacheMiss);
{

View File

@ -33,7 +33,7 @@
namespace panda::ecmascript::kungfu {
using namespace panda::ecmascript;
#define DEFVAlUE(varname, cirBuilder, type, val) \
#define DEFVALUE(varname, cirBuilder, type, val) \
Variable varname(cirBuilder, type, cirBuilder->NextVariableId(), val)
class BuiltinsStringStubBuilder;
@ -45,6 +45,7 @@ class SlowPathLowering;
class StubBuilder;
class TypeBytecodeLowering;
class Variable;
class NativeInlineLowering;
#define BINARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(V) \
V(Int16Add, Add, MachineType::I16) \
@ -382,6 +383,7 @@ public:
inline GateRef IsCallableFromBitField(GateRef bitfield);
GateRef IsJSHClass(GateRef obj);
inline void StoreHClass(GateRef glue, GateRef object, GateRef hClass);
GateRef IsStabelArray(GateRef glue, GateRef obj);
// WeakRef
inline GateRef CreateWeakRef(GateRef x);
@ -576,6 +578,9 @@ public:
GateRef GetLengthFromString(GateRef value);
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
GateRef TryGetHashcodeFromString(GateRef string);
GateRef IsIntegerString(GateRef string);
GateRef GetRawHashFromString(GateRef value);
void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger);
// for in
GateRef GetEnumCacheKind(GateRef glue, GateRef enumCache);
@ -694,6 +699,7 @@ private:
friend TypeBytecodeLowering;
friend NTypeBytecodeLowering;
friend SlowPathLowering;
friend NativeInlineLowering;
};
} // namespace panda::ecmascript::kungfu

View File

@ -15,6 +15,7 @@
#include "ecmascript/compiler/hcr_circuit_builder.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/js_thread.h"
namespace panda::ecmascript::kungfu {
@ -428,4 +429,32 @@ void CircuitBuilder::SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef
Int32(JSTaggedValue::TaggedTypeSize()));
Store(type, glue, obj, ZExtInt32ToPtr(propOffset), value);
}
GateRef CircuitBuilder::IsStabelArray(GateRef glue, GateRef obj)
{
Label subentry(env_);
env_->SubCfgEntry(&subentry);
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label exit(env_);
Label targetIsHeapObject(env_);
Label targetIsStableArray(env_);
Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
Bind(&targetIsHeapObject);
{
GateRef jsHclass = LoadHClass(obj);
Branch(IsStableArray(jsHclass), &targetIsStableArray, &exit);
Bind(&targetIsStableArray);
{
GateRef guardiansOffset =
IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false));
result = Load(VariableType::BOOL(), glue, guardiansOffset);
Jump(&exit);
}
}
Bind(&exit);
auto res = *result;
env_->SubCfgExit();
return res;
}
}

View File

@ -131,12 +131,20 @@ void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef sp, GateRef pc
Int8Equal(interruptsFlag, Int8(VmThreadControl::VM_NEED_SUSPENSION))), \
&callRuntime, &initialized); \
Bind(&callRuntime); \
if (!(callback).IsEmpty()) { \
varProfileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { func }); \
} else { \
varProfileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounter), { func }); \
} \
Label handleException(env); \
Label noException(env); \
Branch(HasPendingException(glue), &handleException, &noException); \
Bind(&handleException); \
{ \
DISPATCH_LAST(); \
} \
Bind(&noException); \
{ \
if (!(callback).IsEmpty()) { \
varProfileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { func }); \
} else { \
varProfileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounter), { func }); \
} \
Jump(&dispatch); \
} \
Bind(&initialized); \

View File

@ -114,7 +114,7 @@ GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x)
Label isInt(env_);
Label isDouble(env_);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::FLOAT64(), Double(0));
DEFVALUE(result, env_, VariableType::FLOAT64(), Double(0));
Branch(TaggedIsInt(x), &isInt, &isDouble);
Bind(&isInt);
{
@ -137,7 +137,7 @@ GateRef CircuitBuilder::DoubleToInt(GateRef x, Label *exit)
Label overflow(env_);
GateRef xInt = ChangeFloat64ToInt32(x);
DEFVAlUE(result, env_, VariableType::INT32(), xInt);
DEFVALUE(result, env_, VariableType::INT32(), xInt);
GateRef xInt64 = CastDoubleToInt64(x);
// exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS

View File

@ -14,6 +14,9 @@
*/
#include "ecmascript/compiler/mcr_circuit_builder.h"
#include "ecmascript/message_string.h"
#include "ecmascript/stubs/runtime_stubs-inl.h"
#include "ecmascript/stubs/runtime_stubs.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/global_env.h"
@ -958,6 +961,47 @@ GateRef CircuitBuilder::InsertLoadArrayLength(GateRef array, bool isTypedArray)
return Circuit::NullGate();
}
GateRef CircuitBuilder::IsIntegerString(GateRef string)
{
// compressedStringsEnabled fixed to true constant
GateRef hash = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_HASHCODE_OFFSET));
return Int32Equal(
Int32And(hash, Int32(EcmaString::IS_INTEGER_MASK)),
Int32(EcmaString::IS_INTEGER_MASK));
}
GateRef CircuitBuilder::GetRawHashFromString(GateRef value)
{
GateRef hash = Load(VariableType::INT32(), value, IntPtr(EcmaString::MIX_HASHCODE_OFFSET));
return Int32And(hash, Int32(~EcmaString::IS_INTEGER_MASK));
}
void CircuitBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger)
{
Label subentry(env_);
SubCfgEntry(&subentry);
Label integer(env_);
Label notInteger(env_);
Label exit(env_);
DEFVALUE(hash, env_, VariableType::INT32(), Int32(0));
Branch(isInteger, &integer, &notInteger);
Bind(&integer);
{
hash = Int32Or(rawHashcode, Int32(EcmaString::IS_INTEGER_MASK));
Jump(&exit);
}
Bind(&notInteger);
{
hash = Int32And(rawHashcode, Int32(~EcmaString::IS_INTEGER_MASK));
Jump(&exit);
}
Bind(&exit);
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::MIX_HASHCODE_OFFSET), *hash);
SubCfgExit();
return;
}
GateRef CircuitBuilder::GetLengthFromString(GateRef value)
{
GateRef len = Load(VariableType::INT32(), value, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
@ -971,14 +1015,14 @@ GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
SubCfgEntry(&subentry);
Label noRawHashcode(env_);
Label exit(env_);
DEFVAlUE(hashcode, env_, VariableType::INT32(), Int32(0));
hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
DEFVALUE(hashcode, env_, VariableType::INT32(), Int32(0));
hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::MIX_HASHCODE_OFFSET));
Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
Bind(&noRawHashcode);
{
hashcode =
CallNGCRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, { value }, Circuit::NullGate());
Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::MIX_HASHCODE_OFFSET), *hashcode);
Jump(&exit);
}
Bind(&exit);
@ -994,8 +1038,8 @@ GateRef CircuitBuilder::TryGetHashcodeFromString(GateRef string)
Label noRawHashcode(env_);
Label storeHash(env_);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::INT64(), Int64(-1));
GateRef hashCode = ZExtInt32ToInt64(Load(VariableType::INT32(), string, IntPtr(EcmaString::HASHCODE_OFFSET)));
DEFVALUE(result, env_, VariableType::INT64(), Int64(-1));
GateRef hashCode = ZExtInt32ToInt64(Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_HASHCODE_OFFSET)));
Branch(Int64Equal(hashCode, Int64(0)), &noRawHashcode, &storeHash);
Bind(&noRawHashcode);
{
@ -1023,7 +1067,7 @@ GateRef CircuitBuilder::GetEnumCacheKind(GateRef glue, GateRef enumCache)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::INT32(), Int32(static_cast<int32_t>(EnumCacheKind::NONE)));
DEFVALUE(result, env_, VariableType::INT32(), Int32(static_cast<int32_t>(EnumCacheKind::NONE)));
Label enumCacheIsArray(env_);
Label isEmptyArray(env_);
@ -1056,7 +1100,7 @@ GateRef CircuitBuilder::IsEnumCacheValid(GateRef receiver, GateRef cachedHclass,
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isSameHclass(env_);
Label isSimpleEnumCache(env_);
@ -1106,8 +1150,8 @@ GateRef CircuitBuilder::NeedCheckProperty(GateRef receiver)
Label isJSObject(env_);
Label hasNoDeleteProperty(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), True());
DEFVAlUE(current, env_, VariableType::JS_ANY(), receiver);
DEFVALUE(result, env_, VariableType::BOOL(), True());
DEFVALUE(current, env_, VariableType::JS_ANY(), receiver);
Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop);
LoopBegin(&loopHead);

View File

@ -84,7 +84,7 @@ GateRef CircuitBuilder::TaggedIsBigInt(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
@ -104,7 +104,7 @@ GateRef CircuitBuilder::TaggedIsString(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
@ -123,7 +123,7 @@ GateRef CircuitBuilder::TaggedIsSymbol(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
@ -143,7 +143,7 @@ GateRef CircuitBuilder::TaggedIsStringOrSymbol(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
@ -170,7 +170,7 @@ GateRef CircuitBuilder::TaggedIsProtoChangeMarker(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
@ -239,7 +239,7 @@ GateRef CircuitBuilder::BothAreString(GateRef x, GateRef y)
Label bothAreHeapObjet(env_);
Label bothAreStringType(env_);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Branch(BoolAnd(TaggedIsHeapObject(x), TaggedIsHeapObject(y)), &bothAreHeapObjet, &exit);
Bind(&bothAreHeapObjet);
{
@ -328,7 +328,7 @@ GateRef CircuitBuilder::TaggedIsJSArray(GateRef obj)
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
DEFVALUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);

View File

@ -113,7 +113,7 @@ void MCRLowering::LowerConvertHoleAsUndefined(GateRef gate)
Label returnUndefined(&builder_);
Label exit(&builder_);
GateRef receiver = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), receiver);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), receiver);
builder_.Branch(builder_.TaggedIsHole(*result), &returnUndefined, &exit, 1, BranchWeight::DEOPT_WEIGHT);
builder_.Bind(&returnUndefined);
@ -340,7 +340,7 @@ StateDepend MCRLowering::LowerConvert(StateDepend stateDepend, GateRef gate)
GateRef MCRLowering::ConvertTaggedNumberToBool(GateRef gate, Label *exit)
{
DEFVAlUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(false));
DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(false));
Label isInt(&builder_);
Label isDouble(&builder_);
Label toInt32(&builder_);
@ -363,7 +363,7 @@ GateRef MCRLowering::ConvertTaggedNumberToBool(GateRef gate, Label *exit)
GateRef MCRLowering::ConvertTaggedNumberToInt32(GateRef gate, Label *exit)
{
DEFVAlUE(result, (&builder_), VariableType::INT32(), builder_.Int32(0));
DEFVALUE(result, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label isInt(&builder_);
Label isDouble(&builder_);
Label toInt32(&builder_);
@ -380,7 +380,7 @@ GateRef MCRLowering::ConvertTaggedNumberToInt32(GateRef gate, Label *exit)
GateRef MCRLowering::ConvertTaggedNumberToFloat64(GateRef gate, Label *exit)
{
DEFVAlUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
Label isInt(&builder_);
Label isDouble(&builder_);
builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble);
@ -592,7 +592,7 @@ GateRef MCRLowering::ConvertUInt32ToTaggedNumber(GateRef gate, Label *exit)
Label isOverFlow(&builder_);
Label notOverFlow(&builder_);
GateRef upperBound = builder_.Int32(INT32_MAX);
DEFVAlUE(taggedVal, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(taggedVal, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
builder_.Branch(builder_.Int32UnsignedLessThanOrEqual(gate, upperBound), &notOverFlow, &isOverFlow);
builder_.Bind(&notOverFlow);
taggedVal = builder_.Int32ToTaggedPtr(gate);
@ -700,7 +700,7 @@ void MCRLowering::HeapAllocateInYoung(GateRef gate)
{
Label exit(&builder_);
GateRef size = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
#ifndef ARK_ASAN_ON
Label success(&builder_);
Label callRuntime(&builder_);
@ -829,7 +829,7 @@ void MCRLowering::InitializeWithSpeicalValue(Label *exit, GateRef object, GateRe
Label storeValue(&builder_);
Label endLoop(&builder_);
DEFVAlUE(startOffset, (&builder_), VariableType::INT32(), start);
DEFVALUE(startOffset, (&builder_), VariableType::INT32(), start);
builder_.Jump(&begin);
builder_.LoopBegin(&begin);
{

View File

@ -0,0 +1,239 @@
/*
* 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/native_inline_lowering.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/circuit_builder_helper.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/message_string.h"
namespace panda::ecmascript::kungfu {
void NativeInlineLowering::RunNativeInlineLowering()
{
std::vector<GateRef> gateList;
circuit_->GetAllGates(gateList);
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
if (op == OpCode::JS_BYTECODE) {
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
switch (ecmaOpcode) {
case EcmaOpcode::CALLTHIS0_IMM8_V8:
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
TryInlineNativeCallThis(gate);
break;
case EcmaOpcode::CALLARG0_IMM8:
case EcmaOpcode::CALLARG1_IMM8_V8:
case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
break;
default:
break;
}
}
}
if (EnableLog()) {
LOG_COMPILER(INFO) << " ";
LOG_COMPILER(INFO) << "\033[34m" << "================="
<< " After Native Inline Lowering "
<< "[" << GetMethodName() << "] "
<< "=================" << "\033[0m";
circuit_->PrintAllGatesWithBytecode();
LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
}
}
void NativeInlineLowering::TryInlineNativeCallThis(GateRef gate)
{
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateType thisType = acc_.GetGateType(thisObj);
if (tsManager_->IsArrayTypeKind(thisType)) {
TryInlineBuiltinsArrayFunc(gate);
}
}
void NativeInlineLowering::TryInlineBuiltinsArrayFunc(GateRef gate)
{
GateRef func = acc_.GetValueIn(gate, acc_.GetNumValueIn(gate) - 1); // 1: last value in
GateType funcType = acc_.GetGateType(func);
if (tsManager_->IsBuiltinObjectMethod(BuiltinTypeId::ARRAY, funcType)) {
std::string name = tsManager_->GetFuncName(funcType);
if (name == "forEach") {
RunArrayForeachInline(gate);
}
}
}
void NativeInlineLowering::RunArrayForeachInline(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef callBack = acc_.GetValueIn(gate, 1);
GateRef thisArg = builder_.Undefined();
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
if (ecmaOpcode == EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8) {
thisArg = acc_.GetValueIn(gate, 2); // 2: this arg parameter
}
builder_.BuiltinPrototypeHClassCheck(thisObj, BuiltinTypeId::ARRAY);
ElementsKind kind = acc_.TryGetArrayElementsKind(thisObj);
if (!IsCreateArray(thisObj)) {
builder_.StableArrayCheck(thisObj, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
}
Label callBackIsCallable(&builder_);
Label callBackNotCallable(&builder_);
builder_.Branch(builder_.IsCallable(callBack), &callBackIsCallable, &callBackNotCallable);
builder_.Bind(&callBackNotCallable);
{
GateRef taggedId = builder_.Int64(GET_MESSAGE_STRING_ID(NonCallable));
LowerCallRuntime(glue_, gate, RTSTUB_ID(ThrowTypeError), { builder_.ToTaggedIntPtr(taggedId) }, true);
GateRef exception = builder_.ExceptionConstant();
builder_.Return(exception);
}
builder_.Bind(&callBackIsCallable);
Label exit(&builder_);
ArrayForeachCall(gate, thisObj, callBack, thisArg, &exit);
builder_.Bind(&exit);
ReplaceHirDirectly(gate, builder_.Undefined());
}
void NativeInlineLowering::ArrayForeachCall(GateRef gate, GateRef thisObj, GateRef callBack, GateRef thisArg,
Label *exit)
{
GateRef length = builder_.LoadArrayLength(thisObj);
Label loopHead(&builder_);
Label loopEnd(&builder_);
Label exitloop(&builder_);
Label slowForeach(&builder_);
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i)));
DEFVALUE(value, (&builder_), VariableType::JS_ANY(), builder_.Hole());
builder_.Branch(builder_.Int32LessThan(*i, length), &loopHead, &exitloop);
builder_.LoopBegin(&loopHead);
ElementsKind kind = acc_.TryGetArrayElementsKind(thisObj);
value = LoadArrayElement(kind, thisObj, *i);
Label NotHole(&builder_);
Label merge(&builder_);
builder_.Branch(builder_.NotEqual(*value, builder_.Hole()), &NotHole, &exitloop);
builder_.Bind(&NotHole);
{
auto depend = builder_.GetDepend();
GateRef nativeCall = NativeCallTS(gate, depend,
{glue_, builder_.Int64(6), callBack, builder_.Undefined(), thisArg, *value, *propKey, thisObj}); // 6: args
builder_.SetDepend(nativeCall);
i = builder_.Int32Add(*i, builder_.Int32(1));
propKey = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i));
builder_.Branch(builder_.IsStabelArray(glue_, thisObj), &merge, &exitloop);
}
builder_.Bind(&merge);
builder_.Branch(builder_.Int32LessThan(*i, length), &loopEnd, &exitloop);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
builder_.Bind(&exitloop);
builder_.Branch(builder_.Int32LessThan(*i, length), &slowForeach, exit);
builder_.Bind(&slowForeach);
{
GateRef taggedLength = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(length));
GateRef slowPathCall = LowerCallRuntime(glue_, gate, RTSTUB_ID(ArrayForEachContinue),
{thisArg, *propKey, thisObj, callBack, taggedLength}, true);
builder_.SetDepend(slowPathCall);
builder_.Jump(exit);
}
}
bool NativeInlineLowering::IsCreateArray(GateRef gate)
{
if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
return false;
}
EcmaOpcode ecmaop = acc_.GetByteCodeOpcode(gate);
switch (ecmaop) {
case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
return true;
default:
return false;
}
UNREACHABLE();
return false;
}
GateRef NativeInlineLowering::LoadArrayElement(ElementsKind kind, GateRef gate, GateRef index)
{
switch (kind) {
case ElementsKind::INT:
return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(gate, index);
case ElementsKind::NUMBER:
return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(gate, index);
case ElementsKind::OBJECT:
return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(gate, index);
default:
if (!Elements::IsHole(kind)) {
return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(gate, index);
}
}
return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(gate, index);
}
void NativeInlineLowering::ReplaceHirDirectly(GateRef gate, GateRef value)
{
GateRef state = builder_.GetState();
GateRef depend = builder_.GetDepend();
auto uses = acc_.Uses(gate);
for (auto it = uses.begin(); it != uses.end();) {
if (acc_.IsStateIn(it)) {
ASSERT(acc_.GetOpCode(*it) != OpCode::IF_SUCCESS &&
acc_.GetOpCode(*it) != OpCode::IF_EXCEPTION);
it = acc_.ReplaceIn(it, state);
} else if (acc_.IsDependIn(it)) {
it = acc_.ReplaceIn(it, depend);
} else {
ASSERT(acc_.IsValueIn(it));
it = acc_.ReplaceIn(it, value);
}
}
acc_.DeleteGate(gate);
}
GateRef NativeInlineLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index,
const std::vector<GateRef> &args, bool useLabel)
{
if (useLabel) {
GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate);
return result;
} else {
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
GateRef target = builder_.IntPtr(index);
GateRef result = builder_.Call(cs, glue, target, acc_.GetDependRoot(), args, hirGate);
return result;
}
}
GateRef NativeInlineLowering::NativeCallTS(GateRef gate, GateRef depend, const std::vector<GateRef> &args)
{
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
GateRef call = builder_.Call(cs, glue_, target, depend, args, gate);
return call;
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,67 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_COMPILER_BUILTIN_INLINE_H
#define ECMASCRIPT_COMPILER_BUILTIN_INLINE_H
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/pass_manager.h"
#include "ecmascript/ts_types/ts_manager.h"
namespace panda::ecmascript::kungfu {
class NativeInlineLowering {
public:
explicit NativeInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name)
: circuit_(circuit),
builder_(circuit),
acc_(circuit),
glue_(acc_.GetGlueFromArgList()),
tsManager_(ctx->GetTSManager()),
enableLog_(enableLog),
methodName_(name) {}
~NativeInlineLowering() = default;
void RunNativeInlineLowering();
private:
void RunArrayForeachInline(GateRef gate);
void ArrayForeachCall(GateRef gate, GateRef thisObj, GateRef callBack, GateRef thisArg, Label *exit);
void TryInlineNativeCallThis(GateRef gate);
void TryInlineBuiltinsArrayFunc(GateRef gate);
bool IsCreateArray(GateRef gate);
GateRef LoadArrayElement(ElementsKind kind, GateRef gate, GateRef index);
void ReplaceHirDirectly(GateRef gate, GateRef value);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args, bool useLabel);
GateRef NativeCallTS(GateRef gate, GateRef depend, const std::vector<GateRef> &args);
bool EnableLog() const
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
Circuit *circuit_ {nullptr};
CircuitBuilder builder_;
GateAccessor acc_;
GateRef glue_;
TSManager *tsManager_;
bool enableLog_;
std::string methodName_;
};
}
#endif // ECMASCRIPT_COMPILER_BUILTIN_INLINE_H

View File

@ -527,7 +527,7 @@ void NewObjectStubBuilder::AllocLineStringObject(Variable *result, Label *exit,
ConstantIndex::LINE_STRING_CLASS_INDEX);
StoreHClass(glue_, result->ReadVariable(), stringClass);
SetLength(glue_, result->ReadVariable(), length, compressed);
SetRawHashcode(glue_, result->ReadVariable(), Int32(0));
SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False());
Jump(exit);
}
@ -547,7 +547,7 @@ void NewObjectStubBuilder::AllocSlicedStringObject(Variable *result, Label *exit
GateRef mixLength = Load(VariableType::INT32(), flatString->GetFlatString(), IntPtr(EcmaString::MIX_LENGTH_OFFSET));
GateRef isCompressed = Int32And(Int32(EcmaString::STRING_COMPRESSED_BIT), mixLength);
SetLength(glue_, result->ReadVariable(), length, isCompressed);
SetRawHashcode(glue_, result->ReadVariable(), Int32(0));
SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False());
BuiltinsStringStubBuilder builtinsStringStubBuilder(this);
builtinsStringStubBuilder.StoreParent(glue_, result->ReadVariable(), flatString->GetFlatString());
builtinsStringStubBuilder.StoreStartIndex(glue_, result->ReadVariable(),
@ -569,7 +569,7 @@ void NewObjectStubBuilder::AllocTreeStringObject(Variable *result, Label *exit,
ConstantIndex::TREE_STRING_CLASS_INDEX);
StoreHClass(glue_, result->ReadVariable(), stringClass);
SetLength(glue_, result->ReadVariable(), length, compressed);
SetRawHashcode(glue_, result->ReadVariable(), Int32(0));
SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False());
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(TreeEcmaString::FIRST_OFFSET), first);
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(TreeEcmaString::SECOND_OFFSET), second);
Jump(exit);

View File

@ -33,6 +33,7 @@
#include "ecmascript/compiler/llvm_codegen.h"
#include "ecmascript/compiler/loop_analysis.h"
#include "ecmascript/compiler/loop_peeling.h"
#include "ecmascript/compiler/native_inline_lowering.h"
#include "ecmascript/compiler/ntype_bytecode_lowering.h"
#include "ecmascript/compiler/ntype_hcr_lowering.h"
#include "ecmascript/compiler/number_speculative_runner.h"
@ -415,16 +416,21 @@ public:
TSInlineLowering inlining(data->GetCircuit(), data->GetPassContext(), enableLog, data->GetMethodName(),
data->GetNativeAreaAllocator(), passOptions, data->GetMethodOffset());
inlining.RunTSInlineLowering();
if (!passOptions->EnableLexenvSpecialization()) {
return false;
if (passOptions->EnableLexenvSpecialization()) {
Chunk chunk(data->GetNativeAreaAllocator());
CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk);
LexicalEnvSpecialization lexicalEnvSpecialization(data->GetCircuit(), &visitor, &chunk, enableLog);
visitor.AddPass(&lexicalEnvSpecialization);
visitor.VisitGraph();
visitor.PrintLog("lexicalEnvSpecialization");
lexicalEnvSpecialization.PrintSpecializeId();
}
if (passOptions->EnableInlineNative()) {
NativeInlineLowering nativeInline(data->GetCircuit(), data->GetPassContext(), enableLog,
data->GetMethodName());
nativeInline.RunNativeInlineLowering();
}
Chunk chunk(data->GetNativeAreaAllocator());
CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk);
LexicalEnvSpecialization lexicalEnvSpecialization(data->GetCircuit(), &visitor, &chunk, enableLog);
visitor.AddPass(&lexicalEnvSpecialization);
visitor.VisitGraph();
visitor.PrintLog("lexicalEnvSpecialization");
lexicalEnvSpecialization.PrintSpecializeId();
return true;
}
};

View File

@ -130,7 +130,7 @@ public:
bool enableLaterElimination, bool enableValueNumbering, bool enableTypeInfer,
bool enableOptInlining, bool enableOptPGOType, bool enableOptTrackField, bool enableOptLoopPeeling,
bool enableOptOnHeapCheck, bool enableOptLoopInvariantCodeMotion, bool enableCollectLiteralInfo,
bool enableOptConstantFolding, bool enableLexenvSpecialization)
bool enableOptConstantFolding, bool enableLexenvSpecialization, bool enableInlineNative)
: enableArrayBoundsCheckElimination_(enableArrayBoundsCheckElimination),
enableTypeLowering_(enableTypeLowering),
enableEarlyElimination_(enableEarlyElimination),
@ -145,7 +145,8 @@ public:
enableOptLoopInvariantCodeMotion_(enableOptLoopInvariantCodeMotion),
enableCollectLiteralInfo_(enableCollectLiteralInfo),
enableOptConstantFolding_(enableOptConstantFolding),
enableLexenvSpecialization_(enableLexenvSpecialization)
enableLexenvSpecialization_(enableLexenvSpecialization),
enableInlineNative_(enableInlineNative)
{
}
@ -166,7 +167,8 @@ public:
V(OptLoopInvariantCodeMotion, false) \
V(CollectLiteralInfo, false) \
V(OptConstantFolding, true) \
V(LexenvSpecialization, false)
V(LexenvSpecialization, false) \
V(InlineNative, false)
#define DECL_OPTION(NAME, DEFAULT) \
public: \

View File

@ -119,7 +119,7 @@ void SlowPathLowering::LowerToJSCall(GateRef hirGate, const std::vector<GateRef>
const std::vector<GateRef> &argsFastCall)
{
Label exit(&builder_);
DEFVAlUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef func = args[static_cast<size_t>(CommonArgIdx::FUNC)];
GateRef argc = args[static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC)];
LowerFastCall(hirGate, glue_, func, argc, args, argsFastCall, &res, &exit, false);
@ -1321,7 +1321,7 @@ void SlowPathLowering::LowerToNumber(GateRef gate)
Label notNumber(&builder_);
Label checkResult(&builder_);
GateRef value = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), value);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
builder_.Branch(builder_.TaggedIsNumber(value), &checkResult, &notNumber);
builder_.Bind(&notNumber);
{
@ -1571,7 +1571,7 @@ void SlowPathLowering::LowerToNumeric(GateRef gate)
Label notNumber(&builder_);
Label checkResult(&builder_);
GateRef value = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), value);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
builder_.Branch(builder_.TaggedIsNumeric(value), &checkResult, &notNumber);
builder_.Bind(&notNumber);
{
@ -1673,7 +1673,7 @@ void SlowPathLowering::LowerIsTrueOrFalse(GateRef gate, bool flag)
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
auto value = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), value);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::ToBoolean, { glue_, value });
if (!flag) {
builder_.Branch(builder_.TaggedIsTrue(*result), &isTrue, &isFalse);
@ -1700,7 +1700,7 @@ void SlowPathLowering::LowerNewObjRange(GateRef gate)
Label successExit(&builder_);
Label exit(&builder_);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef ctor = acc_.GetValueIn(gate, 0);
GateRef thisObj = builder_.CallStub(glue_, gate, CommonStubCSigns::NewThisObjectChecked, { glue_, ctor });
@ -1808,7 +1808,7 @@ void SlowPathLowering::LowerGetNextPropName(GateRef gate)
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef iter = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label notFinish(&builder_);
Label notEnumCacheValid(&builder_);
@ -1891,7 +1891,7 @@ void SlowPathLowering::LowerStOwnByValue(GateRef gate)
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
Label isHeapObject(&builder_);
Label slowPath(&builder_);
Label exit(&builder_);
@ -1926,7 +1926,7 @@ void SlowPathLowering::LowerStOwnByIndex(GateRef gate)
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
Label isHeapObject(&builder_);
Label slowPath(&builder_);
Label exit(&builder_);
@ -1964,7 +1964,7 @@ void SlowPathLowering::LowerStOwnByName(GateRef gate)
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
Label isJSObject(&builder_);
Label slowPath(&builder_);
Label exit(&builder_);
@ -2226,7 +2226,7 @@ void SlowPathLowering::LowerLdObjByIndex(GateRef gate)
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef holeConst = builder_.HoleConstant();
DEFVAlUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
DEFVALUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef receiver = acc_.GetValueIn(gate, 1);
@ -2261,7 +2261,7 @@ void SlowPathLowering::LowerStObjByIndex(GateRef gate)
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &fastPath, &slowPath);
builder_.Bind(&fastPath);
{
@ -2394,7 +2394,7 @@ void SlowPathLowering::LowerLdLexVar(GateRef gate)
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
DEFVAlUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
@ -2404,7 +2404,7 @@ void SlowPathLowering::LowerLdLexVar(GateRef gate)
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVAlUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
builder_.Branch(builder_.Int32LessThan(*i, level), &loopHead, &exit);
@ -2428,7 +2428,7 @@ void SlowPathLowering::LowerStLexVar(GateRef gate)
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
GateRef value = acc_.GetValueIn(gate, 3);
DEFVAlUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
@ -2438,7 +2438,7 @@ void SlowPathLowering::LowerStLexVar(GateRef gate)
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVAlUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
builder_.Branch(builder_.Int32LessThan(*i, level), &loopHead, &exit);
@ -2542,7 +2542,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate)
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef undefinedIndex = builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX);
GateRef gConstUndefinedStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
DEFVAlUE(result, (&builder_), VariableType::JS_POINTER(), gConstUndefinedStr);
DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), gConstUndefinedStr);
Label objIsTrue(&builder_);
Label objNotTrue(&builder_);
Label defaultLabel(&builder_);
@ -2713,7 +2713,7 @@ void SlowPathLowering::LowerResumeGenerator(GateRef gate)
Label isAsyncGeneratorObj(&builder_);
Label notAsyncGeneratorObj(&builder_);
Label exit(&builder_);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
builder_.Branch(builder_.TaggedIsAsyncGeneratorObject(obj), &isAsyncGeneratorObj, &notAsyncGeneratorObj);
builder_.Bind(&isAsyncGeneratorObj);
{
@ -2735,7 +2735,7 @@ void SlowPathLowering::LowerGetResumeMode(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label isAsyncGeneratorObj(&builder_);
Label notAsyncGeneratorObj(&builder_);
Label exit(&builder_);
@ -3027,7 +3027,7 @@ void SlowPathLowering::LowerConstruct(GateRef gate)
GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
GateRef argc = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC));
Label exit(&builder_);
DEFVAlUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
LowerFastCall(gate, glue_, ctor, argc, args, argsFastCall, &res, &exit, true);
builder_.Bind(&exit);
GateRef thisObj = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::THIS_OBJECT));

View File

@ -1147,6 +1147,25 @@ inline GateRef StubBuilder::IsString(GateRef obj)
return res;
}
inline GateRef StubBuilder::TaggedObjectIsString(GateRef 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()->TaggedObjectIsString(obj);
Jump(&exit);
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
inline GateRef StubBuilder::IsLineString(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
@ -2622,9 +2641,19 @@ inline void StubBuilder::SetLength(GateRef glue, GateRef str, GateRef length, Ga
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::MIX_LENGTH_OFFSET), mixLength);
}
inline void StubBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode)
inline GateRef StubBuilder::IsIntegerString(GateRef string)
{
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::HASHCODE_OFFSET), rawHashcode);
return env_->GetBuilder()->IsIntegerString(string);
}
inline GateRef StubBuilder::GetRawHashFromString(GateRef value)
{
return env_->GetBuilder()->GetRawHashFromString(value);
}
inline void StubBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger)
{
env_->GetBuilder()->SetRawHashcode(glue, str, rawHashcode, isInteger);
}
inline GateRef StubBuilder::TryGetHashcodeFromString(GateRef string)

View File

@ -1530,6 +1530,27 @@ GateRef StubBuilder::IsDigit(GateRef ch)
Int32GreaterThanOrEqual(ch, Int32('0')));
}
void StubBuilder::TryToGetInteger(GateRef string, Variable *num, Label *success, Label *failed)
{
auto env = GetEnvironment();
Label exit(env);
Label inRange(env);
Label isInteger(env);
GateRef len = GetLengthFromString(string);
Branch(Int32LessThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &inRange, failed);
Bind(&inRange);
{
Branch(IsIntegerString(string), &isInteger, failed);
Bind(&isInteger);
{
GateRef integerNum = ZExtInt32ToInt64(GetRawHashFromString(string));
num->WriteVariable(integerNum);
Jump(success);
}
}
}
GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
{
auto env = GetEnvironment();
@ -1551,6 +1572,9 @@ GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
Branch(isUtf16String, &exit, &isUtf8);
Bind(&isUtf8);
{
Label getFailed(env);
TryToGetInteger(string, &result, &exit, &getFailed);
Bind(&getFailed);
DEFVARIABLE(c, VariableType::INT32(), Int32(0));
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, string, &flattenFastPath);
@ -5957,24 +5981,7 @@ void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
{
auto env = GetEnvironment();
Label subentry(env);
env->SubCfgEntry(&subentry);
Label noRawHashcode(env);
Label exit(env);
DEFVARIABLE(hashcode, VariableType::INT32(), Int32(0));
hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
Bind(&noRawHashcode);
{
hashcode = CallNGCRuntime(glue, RTSTUB_ID(ComputeHashcode), { value });
Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
Jump(&exit);
}
Bind(&exit);
auto ret = *hashcode;
env->SubCfgExit();
return ret;
return env_->GetBuilder()->GetHashcodeFromString(glue, value);
}
GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj)
@ -7125,7 +7132,7 @@ GateRef StubBuilder::TaggedGetNumber(GateRef x)
Label targetIsInt(env);
Label targetIsDouble(env);
DEFVAlUE(number, env_, VariableType::FLOAT64(), Double(0));
DEFVALUE(number, env_, VariableType::FLOAT64(), Double(0));
Branch(TaggedIsInt(x), &targetIsInt, &targetIsDouble);
Bind(&targetIsInt);
{

View File

@ -310,6 +310,7 @@ public:
GateRef IsEcmaObject(GateRef obj);
GateRef IsSymbol(GateRef obj);
GateRef IsString(GateRef obj);
GateRef TaggedObjectIsString(GateRef obj);
GateRef IsLineString(GateRef obj);
GateRef IsSlicedString(GateRef obj);
GateRef IsConstantString(GateRef obj);
@ -406,6 +407,9 @@ public:
GateRef GetBitFieldFromHClass(GateRef hClass);
GateRef GetLengthFromString(GateRef value);
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
inline GateRef IsIntegerString(GateRef string);
inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger);
inline GateRef GetRawHashFromString(GateRef value);
GateRef TryGetHashcodeFromString(GateRef string);
GateRef GetFirstFromTreeString(GateRef string);
GateRef GetSecondFromTreeString(GateRef string);
@ -478,6 +482,7 @@ public:
GateRef IsUtf8String(GateRef string);
GateRef IsInternalString(GateRef string);
GateRef IsDigit(GateRef ch);
void TryToGetInteger(GateRef string, Variable *num, Label *success, Label *failed);
GateRef StringToElementIndex(GateRef glue, GateRef string);
GateRef ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength,
GateRef maxNonInlinedFastPropsCapacity);
@ -701,7 +706,6 @@ public:
std::initializer_list<GateRef> args, JSCallMode mode);
inline void SetLength(GateRef glue, GateRef str, GateRef length, bool compressed);
inline void SetLength(GateRef glue, GateRef str, GateRef length, GateRef isCompressed);
inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode);
void Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel);
GateRef GetNormalStringData(const StringInfoGateRef &stringInfoGate);

View File

@ -66,8 +66,8 @@ HWTEST_F_L0(ConstantFoldingTest, ConstantFoldingTypedBinOpTest)
builder.SetEnvironment(&env);
DEFVAlUE(number1, (&builder), VariableType::INT32(), builder.Int32(14));
DEFVAlUE(number2, (&builder), VariableType::INT32(), builder.Int32(7));
DEFVALUE(number1, (&builder), VariableType::INT32(), builder.Int32(14));
DEFVALUE(number2, (&builder), VariableType::INT32(), builder.Int32(7));
auto sum = builder.Int32Add(*number1, *number2);
auto convert = builder.ConvertInt32ToTaggedInt(sum);

View File

@ -67,8 +67,8 @@ HWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest)
builder.SetEnvironment(&env);
auto array = builder.Arguments(1);
DEFVAlUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVAlUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
Label loopHead(&env);
Label loopBody(&env);
@ -148,8 +148,8 @@ HWTEST_F_L0(LoopOptimizationTest, LoopNumberCalculationOptimizationTest)
auto arg = builder.Arguments(1);
acc.SetMachineType(arg, MachineType::I32);
DEFVAlUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVAlUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
Label loopHead(&env);
Label loopBody(&env);
@ -198,8 +198,8 @@ HWTEST_F_L0(LoopOptimizationTest, LoopLoadConstOptimizationTest)
GateRef invariant = circuit.NewGate(circuit.Load(), MachineType::I32,
{ circuit.GetDependRoot(), arg2 }, GateType::NJSValue());
DEFVAlUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVAlUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
Label loopHead(&env);
Label loopBody(&env);

View File

@ -340,7 +340,7 @@ void TypeHCRLowering::LowerFlattenTreeStringCheck(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef str = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_POINTER(), str);
DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), str);
Label isTreeString(&builder_);
Label exit(&builder_);
@ -482,7 +482,7 @@ GateRef TypeHCRLowering::BuildCompareSubTyping(GateRef gate, GateRef frameState,
return builder_.Equal(aotHCGate, GetValueFromSupers(supers, level), "checkHClass");
}
DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
DEFVALUE(check, (&builder_), VariableType::BOOL(), builder_.False());
GateRef levelGate = builder_.Int32(level);
GateRef length = GetLengthFromSupers(supers);
@ -619,7 +619,7 @@ void TypeHCRLowering::LowerTypeConvert(GateRef gate)
void TypeHCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType)
{
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
if (srcType.IsBooleanType()) {
Label exit(&builder_);
Label isTrue(&builder_);
@ -696,7 +696,7 @@ void TypeHCRLowering::LowerCallGetter(GateRef gate, GateRef glue)
GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
GateRef getter = builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::GETTER_OFFSET);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
Label callGetter(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.IsSpecial(getter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callGetter);
@ -958,8 +958,8 @@ GateRef TypeHCRLowering::BuildTypedArrayLoadElement(GateRef receiver, GateRef of
{
GateRef byteArrayOrArraybuffer =
builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
DEFVAlUE(data, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVAlUE(result, (&builder_), type, builder_.Double(0));
DEFVALUE(data, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(result, (&builder_), type, builder_.Double(0));
GateRef isOnHeap = builder_.Load(VariableType::BOOL(), receiver, builder_.IntPtr(JSTypedArray::ON_HEAP_OFFSET));
builder_.Branch(isOnHeap, isByteArray, isArrayBuffer);
@ -1104,7 +1104,7 @@ void TypeHCRLowering::BuildTypedArrayStoreElement(GateRef receiver, GateRef offs
GateRef byteArrayOrArraybuffer = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver,
JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
GateRef isOnHeap = builder_.Load(VariableType::BOOL(), receiver, builder_.IntPtr(JSTypedArray::ON_HEAP_OFFSET));
DEFVAlUE(data, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(data, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
builder_.Branch(isOnHeap, isByteArray, isArrayBuffer);
builder_.Bind(isByteArray);
{
@ -1137,7 +1137,7 @@ void TypeHCRLowering::LowerUInt8ClampedArrayStoreElement(GateRef gate)
GateRef offset = builder_.PtrMul(index, elementSize);
GateRef value = acc_.GetValueIn(gate, 2);
DEFVAlUE(result, (&builder_), VariableType::INT32(), value);
DEFVALUE(result, (&builder_), VariableType::INT32(), value);
GateRef topValue = builder_.Int32(static_cast<uint32_t>(UINT8_MAX));
GateRef bottomValue = builder_.Int32(static_cast<uint32_t>(0));
Label isOverFlow(&builder_);
@ -1374,7 +1374,7 @@ void TypeHCRLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
GateRef ctor = acc_.GetValueIn(gate, 0);
DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label allocate(&builder_);
Label exit(&builder_);
@ -1404,7 +1404,7 @@ void TypeHCRLowering::LowerTypedSuperAllocateThis(GateRef gate, GateRef glue)
GateRef superCtor = acc_.GetValueIn(gate, 0);
GateRef newTarget = acc_.GetValueIn(gate, 1);
DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label allocate(&builder_);
Label exit(&builder_);
@ -1567,7 +1567,7 @@ void TypeHCRLowering::LowerInlineAccessorCheck(GateRef gate)
Label levelValid(&builder_);
Label exit(&builder_);
DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
DEFVALUE(check, (&builder_), VariableType::BOOL(), builder_.False());
GateRef levelGate = builder_.Int32(level);
GateRef length = GetLengthFromSupers(supers);
@ -1592,7 +1592,7 @@ void TypeHCRLowering::LowerStringEqual(GateRef gate, GateRef glue)
GateRef leftLength = GetLengthFromString(left);
GateRef rightLength = GetLengthFromString(right);
DEFVAlUE(result, (&builder_), VariableType::BOOL(), builder_.False());
DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.False());
Label lenEqual(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.Equal(leftLength, rightLength), &lenEqual, &exit);

View File

@ -276,7 +276,7 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
case JSType::JS_FUNCTION_BASE:
return GetString("JSFunctionBase");
case JSType::JS_FUNCTION:
return GetString("JSFunction");
return GetString(CString(ParseFunctionName(entry)));
case JSType::JS_ERROR:
return GetString("Error");
case JSType::JS_EVAL_ERROR:
@ -295,6 +295,8 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
return GetString("Syntax Error");
case JSType::JS_OOM_ERROR:
return GetString("OutOfMemory Error");
case JSType::JS_TERMINATION_ERROR:
return GetString("Termination Error");
case JSType::JS_REG_EXP:
return GetString("Regexp");
case JSType::JS_SET:
@ -966,16 +968,10 @@ void HeapSnapshot::RenameFunction(const CString &edgeName, Node *entryFrom, Node
if (edgeName != "name") {
return;
}
auto fromName = *entryFrom->GetName();
if (*entryTo->GetName() != "" && (fromName == "JSFunctionBase" ||
fromName == "JSFunction" || fromName == "PromiseValueThunkOrThrowerFunction" ||
fromName == "JSGeneratorFunction" || fromName == "PromiseAllSettledElementFunction" ||
fromName == "Bound Function" || fromName == "PromiseAnyRejectElementFunction" ||
fromName == "PromiseReactionsFunction" || fromName == "PromiseExecutorFunction" ||
fromName == "PromiseAllResolveElementFunction" || fromName == "AsyncFunction" ||
fromName == "ProxyRevocFunction" || fromName == "AsyncFromSyncIterUnwarpFunction" ||
fromName == "PromiseFinallyFunction" || fromName == "JSIntlBoundFunction" ||
fromName == "JSAsyncGeneratorFunction" || fromName == "AsyncAwaitStatusFunction")) {
if (entryFrom->GetType() > NodeType::JS_BOUND_FUNCTION || entryFrom->GetType() < NodeType::JS_FUNCTION_BASE) {
return;
}
if (*entryTo->GetName() != "" && *entryTo->GetName() != "InternalAccessor") {
entryFrom->SetName(GetString(*entryTo->GetName()));
}
}
@ -1000,6 +996,23 @@ CString *HeapSnapshot::GenerateEdgeName([[maybe_unused]] TaggedObject *from, [[m
return GetString("[]"); // unAnalysed
}
std::string HeapSnapshot::ParseFunctionName(TaggedObject *obj)
{
JSFunctionBase *func = JSFunctionBase::Cast(obj);
Method *method = Method::Cast(func->GetMethod().GetTaggedObject());
MethodLiteral *methodLiteral = method->GetMethodLiteral();
if (methodLiteral == nullptr) {
return "JSFunction";
}
const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
const std::string &nameStr = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
if (nameStr.empty()) {
return "anonymous";
}
return nameStr;
}
Node *HeapSnapshot::InsertNodeUnique(Node *node)
{
AccumulateNodeSize(node->GetSelfSize());
@ -1154,7 +1167,7 @@ FrontType NodeTypeConverter::Convert(NodeType type)
} else if (type == NodeType::JS_OBJECT) {
fType = FrontType::OBJECT;
} else if (type >= NodeType::JS_FUNCTION_FIRST && type <= NodeType::JS_FUNCTION_LAST) {
fType = FrontType::DEFAULT;
fType = FrontType::CLOSURE;
} else if (type == NodeType::JS_BOUND_FUNCTION) {
fType = FrontType::DEFAULT;
} else if (type == NodeType::JS_FUNCTION_BASE) {

View File

@ -493,6 +493,7 @@ private:
void RenameFunction(const CString &edgeName, Node *entryFrom, Node *entryTo);
void BridgeAllReferences();
CString *GenerateEdgeName(TaggedObject *from, TaggedObject *to);
std::string ParseFunctionName(TaggedObject *obj);
Node *InsertNodeUnique(Node *node);
void EraseNodeUnique(Node *node);

View File

@ -36,6 +36,12 @@ bool VmThreadControl::NotifyVMThreadSuspension() // block caller thread
return true;
}
void VmThreadControl::RequestTerminateExecution()
{
SetTerminationRequest(true);
thread_->SetCheckSafePointStatus();
}
void VmThreadControl::SetVMNeedSuspension(bool flag)
{
thread_->SetVMNeedSuspension(flag);
@ -46,6 +52,11 @@ bool VmThreadControl::VMNeedSuspension() const
return thread_->VMNeedSuspension();
}
void VmThreadControl::SetTerminationRequest(bool flag)
{
thread_->SetTerminationRequest(flag);
}
void VmThreadControl::SetVMSuspended(bool flag)
{
thread_->SetVMSuspended(flag);

View File

@ -32,6 +32,8 @@ public:
void SetVMNeedSuspension(bool flag);
void SetTerminationRequest(bool flag);
bool VMNeedSuspension() const;
void SuspendVM();
@ -40,6 +42,8 @@ public:
bool NotifyVMThreadSuspension();
void RequestTerminateExecution();
void SetVMSuspended(bool flag);
bool IsSuspended() const;

View File

@ -183,6 +183,8 @@ CString JSHClass::DumpJSType(JSType type)
return "Syntax Error";
case JSType::JS_OOM_ERROR:
return "OutOfMemory Error";
case JSType::JS_TERMINATION_ERROR:
return "Termination Error";
case JSType::JS_REG_EXP:
return "Regexp";
case JSType::JS_SET:
@ -685,6 +687,7 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_TERMINATION_ERROR:
case JSType::JS_ARGUMENTS:
needDumpHClass = true;
JSObject::Cast(obj)->Dump(os);
@ -2389,6 +2392,8 @@ void GlobalEnv::Dump(std::ostream &os) const
GetEvalErrorFunction().GetTaggedValue().Dump(os);
os << " - OOMErrorFunction: ";
GetOOMErrorFunction().GetTaggedValue().Dump(os);
os << " - TerminationErrorFunction: ";
GetTerminationErrorFunction().GetTaggedValue().Dump(os);
os << " - RegExpFunction: ";
GetRegExpFunction().GetTaggedValue().Dump(os);
os << " - BuiltinsSetFunction: ";
@ -3801,6 +3806,7 @@ static void DumpObject(TaggedObject *obj, std::vector<Reference> &vec, bool isVm
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_TERMINATION_ERROR:
case JSType::JS_ARGUMENTS:
case JSType::JS_GLOBAL_OBJECT:
JSObject::Cast(obj)->DumpForSnapshot(vec);
@ -4841,6 +4847,7 @@ void GlobalEnv::DumpForSnapshot(std::vector<Reference> &vec) const
vec.emplace_back(CString("SyntaxErrorFunction"), GetSyntaxErrorFunction().GetTaggedValue());
vec.emplace_back(CString("EvalErrorFunction"), GetEvalErrorFunction().GetTaggedValue());
vec.emplace_back(CString("OOMErrorFunction"), GetOOMErrorFunction().GetTaggedValue());
vec.emplace_back(CString("TerminationErrorFunction"), GetTerminationErrorFunction().GetTaggedValue());
vec.emplace_back(CString("RegExpFunction"), GetRegExpFunction().GetTaggedValue());
vec.emplace_back(CString("BuiltinsSetFunction"), GetBuiltinsSetFunction().GetTaggedValue());
vec.emplace_back(CString("BuiltinsMapFunction"), GetBuiltinsMapFunction().GetTaggedValue());

View File

@ -628,8 +628,8 @@ void EcmaContext::PrintJSErrorInfo(JSThread *thread, const JSHandle<JSTaggedValu
bool EcmaContext::HasPendingJob()
{
if (isProcessingPendingJob_) {
return true;
if (UNLIKELY(thread_->HasTerminated())) {
return false;
}
return job::MicroJobQueue::HasPendingJob(thread_, GetMicroJobQueue());
}

View File

@ -75,7 +75,8 @@ enum class IcuFormatterType {
SIMPLE_DATE_FORMAT_DATE,
SIMPLE_DATE_FORMAT_TIME,
NUMBER_FORMATTER,
COLLATOR
COLLATOR,
ICU_FORMATTER_TYPE_COUNT
};
using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm,
@ -103,6 +104,11 @@ public:
bool Initialize();
bool IsExecutingPendingJob() const
{
return isProcessingPendingJob_.load();
}
bool HasPendingJob();
bool ExecutePromisePendingJob();
@ -273,32 +279,27 @@ public:
IcuDeleteEntry deleteEntry = nullptr)
{
EcmaContext::IcuFormatter icuFormatter = IcuFormatter(locale, icuObj, deleteEntry);
icuObjCache_.insert_or_assign(type, std::move(icuFormatter));
icuObjCache_[static_cast<int>(type)] = icuFormatter;
}
void *GetIcuFormatterFromCache(IcuFormatterType type, std::string locale)
ARK_INLINE void *GetIcuFormatterFromCache(IcuFormatterType type, std::string &locale)
{
auto iter = icuObjCache_.find(type);
if (iter != icuObjCache_.end()) {
EcmaContext::IcuFormatter icuFormatter = iter->second;
if (icuFormatter.locale == locale) {
return icuFormatter.icuObj;
}
auto &icuFormatter = icuObjCache_[static_cast<int>(type)];
if (icuFormatter.locale == locale) {
return icuFormatter.icuObj;
}
return nullptr;
}
void ClearIcuCache()
{
auto iter = icuObjCache_.begin();
while (iter != icuObjCache_.end()) {
EcmaContext::IcuFormatter icuFormatter = iter->second;
for (uint32_t i = 0; i < static_cast<uint32_t>(IcuFormatterType::ICU_FORMATTER_TYPE_COUNT); i++) {
auto &icuFormatter = icuObjCache_[i];
IcuDeleteEntry deleteEntry = icuFormatter.deleteEntry;
if (deleteEntry != nullptr) {
deleteEntry(icuFormatter.icuObj, vm_);
}
iter->second = EcmaContext::IcuFormatter{};
iter++;
icuFormatter = EcmaContext::IcuFormatter{};
}
}
@ -498,8 +499,8 @@ private:
EcmaVM *vm_ {nullptr};
bool isUncaughtExceptionRegistered_ {false};
bool isProcessingPendingJob_ {false};
bool initialized_ {false};
std::atomic<bool> isProcessingPendingJob_ {false};
ObjectFactory *factory_ {nullptr};
// VM execution states.
@ -545,8 +546,7 @@ private:
IcuFormatter(const std::string &locale, void *icuObj, IcuDeleteEntry deleteEntry = nullptr)
: locale(locale), icuObj(icuObj), deleteEntry(deleteEntry) {}
};
std::unordered_map<IcuFormatterType, IcuFormatter> icuObjCache_;
IcuFormatter icuObjCache_[static_cast<uint32_t>(IcuFormatterType::ICU_FORMATTER_TYPE_COUNT)];
// Handlescope
static const uint32_t NODE_BLOCK_SIZE_LOG2 = 10;
static const uint32_t NODE_BLOCK_SIZE = 1U << NODE_BLOCK_SIZE_LOG2;

View File

@ -363,6 +363,10 @@
#define THROW_OOM_ERROR(thread, message) \
THROW_ERROR(thread, ErrorType::OOM_ERROR, message)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define THROW_TERMINATION_ERROR(thread, message) \
THROW_ERROR(thread, ErrorType::TERMINATION_ERROR, message)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define RETURN_STACK_BEFORE_THROW_IF_ASM(thread) \
do { \

View File

@ -281,6 +281,14 @@ inline uint16_t EcmaString::At(int32_t index) const
}
}
inline Span<const uint8_t> EcmaString::FastToUtf8Span() const
{
uint32_t strLen = GetLength();
ASSERT(IsUtf8());
const uint8_t *data = GetDataUtf8();
return Span<const uint8_t>(data, strLen);
}
inline void EcmaString::WriteData(uint32_t index, uint16_t src)
{
ASSERT(index < GetLength());
@ -406,5 +414,10 @@ inline void EcmaStringAccessor::ReadData(EcmaString *dst, EcmaString *src,
{
dst->WriteData(src, start, destSize, length);
}
inline Span<const uint8_t> EcmaStringAccessor::FastToUtf8Span()
{
return string_->FastToUtf8Span();
}
} // namespace panda::ecmascript
#endif

View File

@ -675,43 +675,112 @@ bool EcmaString::MemCopyChars(Span<T> &dst, size_t dstMax, Span<const T> &src, s
return true;
}
uint32_t EcmaString::ComputeHashcode(uint32_t hashSeed) const
bool EcmaString::HashIntegerString(uint32_t length, uint32_t *hash, const uint32_t hashSeed) const
{
uint32_t hash;
ASSERT(length >= 0);
Span<const uint8_t> str = FastToUtf8Span();
return HashIntegerString(str.data(), length, hash, hashSeed);
}
uint32_t EcmaString::ComputeHashcode() const
{
auto [hash, isInteger] = ComputeRawHashcode();
return MixHashcode(hash, isInteger);
}
// hashSeed only be used when computing two separate strings merged hashcode.
std::pair<uint32_t, bool> EcmaString::ComputeRawHashcode() const
{
uint32_t hash = 0;
uint32_t length = GetLength();
if (length == 0) {
return {hash, false};
}
if (IsUtf8()) {
// String using UTF8 encoding, and length smaller than 10, try to compute integer hash.
if (length < MAX_ELEMENT_INDEX_LEN && this->HashIntegerString(length, &hash, 0)) {
return {hash, true};
}
CVector<uint8_t> buf;
const uint8_t *data = EcmaString::GetUtf8DataFlat(this, buf);
hash = ComputeHashForData(data, length, hashSeed);
// String can not convert to integer number, using normal hashcode computing algorithm.
hash = this->ComputeHashForData(data, length, 0);
return {hash, false};
} else {
CVector<uint16_t> buf;
const uint16_t *data = EcmaString::GetUtf16DataFlat(this, buf);
hash = ComputeHashForData(data, length, hashSeed);
// If rawSeed has certain value, and second string uses UTF16 encoding,
// then merged string can not be small integer number.
hash = this->ComputeHashForData(data, length, 0);
return {hash, false};
}
}
// hashSeed only be used when computing two separate strings merged hashcode.
uint32_t EcmaString::ComputeHashcode(uint32_t rawHashSeed, bool isInteger) const
{
uint32_t hash;
uint32_t length = GetLength();
if (length == 0) {
return MixHashcode(rawHashSeed, isInteger);
}
if (IsUtf8()) {
// String using UTF8 encoding, and length smaller than 10, try to compute integer hash.
if ((rawHashSeed == 0 || isInteger) &&
length < MAX_ELEMENT_INDEX_LEN && this->HashIntegerString(length, &hash, rawHashSeed)) {
return hash;
}
CVector<uint8_t> buf;
const uint8_t *data = EcmaString::GetUtf8DataFlat(this, buf);
// String can not convert to integer number, using normal hashcode computing algorithm.
hash = this->ComputeHashForData(data, length, rawHashSeed);
return MixHashcode(hash, NOT_INTEGER);
} else {
CVector<uint16_t> buf;
const uint16_t *data = EcmaString::GetUtf16DataFlat(this, buf);
// If rawSeed has certain value, and second string uses UTF16 encoding,
// then merged string can not be small integer number.
hash = this->ComputeHashForData(data, length, rawHashSeed);
return MixHashcode(hash, NOT_INTEGER);
}
return hash;
}
/* static */
uint32_t EcmaString::ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress)
{
uint32_t hash = 0;
uint32_t mixHash = 0;
if (canBeCompress) {
hash = ComputeHashForData(utf8Data, utf8Len, 0);
// String using UTF8 encoding, and length smaller than 10, try to compute integer hash.
if (utf8Len < MAX_ELEMENT_INDEX_LEN && HashIntegerString(utf8Data, utf8Len, &mixHash, 0)) {
return mixHash;
}
uint32_t hash = ComputeHashForData(utf8Data, utf8Len, 0);
return MixHashcode(hash, NOT_INTEGER);
} else {
auto utf16Len = base::utf_helper::Utf8ToUtf16Size(utf8Data, utf8Len);
CVector<uint16_t> tmpBuffer(utf16Len);
[[maybe_unused]] auto len = base::utf_helper::ConvertRegionUtf8ToUtf16(utf8Data, tmpBuffer.data(), utf8Len,
utf16Len, 0);
ASSERT(len == utf16Len);
hash = ComputeHashForData(tmpBuffer.data(), utf16Len, 0);
uint32_t hash = ComputeHashForData(tmpBuffer.data(), utf16Len, 0);
return MixHashcode(hash, NOT_INTEGER);
}
return hash;
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
/* static */
uint32_t EcmaString::ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length)
{
return ComputeHashForData(utf16Data, length, 0);
uint32_t mixHash = 0;
// String length smaller than 10, try to compute integer hash.
if (length < MAX_ELEMENT_INDEX_LEN && HashIntegerString(utf16Data, length, &mixHash, 0)) {
return mixHash;
}
uint32_t hash = ComputeHashForData(utf16Data, length, 0);
return MixHashcode(hash, NOT_INTEGER);
}
/* static */
@ -751,6 +820,11 @@ bool EcmaString::ToElementIndex(uint32_t *index)
return false;
}
// fast path: get integer from string's hash value
if (TryToGetInteger(index)) {
return true;
}
CVector<uint8_t> buf;
const uint8_t *data = EcmaString::GetUtf8DataFlat(this, buf);
uint32_t c = data[0];

View File

@ -52,24 +52,36 @@ class FlatStringInfo;
}
class EcmaString : public TaggedObject {
/* Mix Hash Code: -- { 0 | [31 bits raw hash code] } computed through string
\ { 1 | [31 bits integer numbers] } fastpath for string to number
*/
public:
CAST_CHECK(EcmaString, IsString);
static constexpr uint32_t IS_INTEGER_MASK = 1U << 31;
static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1;
static constexpr uint32_t STRING_INTERN_BIT = 0x2;
static constexpr size_t MAX_STRING_LENGTH = 0x40000000U; // 30 bits for string length, 2 bits for special meaning
static constexpr uint32_t STRING_LENGTH_SHIFT_COUNT = 2U;
static constexpr uint32_t MAX_INTEGER_HASH_NUMBER = 0x3B9AC9FF;
static constexpr uint32_t MAX_CACHED_INTEGER_SIZE = 9;
static constexpr size_t MIX_LENGTH_OFFSET = TaggedObjectSize();
// In last bit of mix_length we store if this string is compressed or not.
ACCESSORS_PRIMITIVE_FIELD(MixLength, uint32_t, MIX_LENGTH_OFFSET, HASHCODE_OFFSET)
ACCESSORS_PRIMITIVE_FIELD(RawHashcode, uint32_t, HASHCODE_OFFSET, SIZE)
ACCESSORS_PRIMITIVE_FIELD(MixLength, uint32_t, MIX_LENGTH_OFFSET, MIX_HASHCODE_OFFSET)
// In last bit of mix_hash we store if this string is small-integer number or not.
ACCESSORS_PRIMITIVE_FIELD(MixHashcode, uint32_t, MIX_HASHCODE_OFFSET, SIZE)
enum CompressedStatus {
STRING_COMPRESSED,
STRING_UNCOMPRESSED,
};
enum IsIntegerStatus {
NOT_INTEGER = 0,
IS_INTEGER,
};
enum TrimMode : uint8_t {
TRIM,
TRIM_START,
@ -121,16 +133,21 @@ private:
static inline EcmaString *FastSubUtf16String(const EcmaVM *vm,
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
bool IsUtf8() const
inline bool IsUtf8() const
{
return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_COMPRESSED;
}
bool IsUtf16() const
inline bool IsUtf16() const
{
return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_UNCOMPRESSED;
}
inline bool IsInteger() const
{
return (GetMixHashcode() & IS_INTEGER_MASK) == IS_INTEGER_MASK;
}
// require is LineString
inline uint16_t *GetData() const;
inline const uint8_t *GetDataUtf8() const;
@ -140,38 +157,54 @@ private:
inline uint8_t *GetDataUtf8Writable();
inline uint16_t *GetDataUtf16Writable();
uint32_t GetLength() const
inline uint32_t GetLength() const
{
return GetMixLength() >> STRING_LENGTH_SHIFT_COUNT;
}
void SetLength(uint32_t length, bool compressed = false)
inline void SetLength(uint32_t length, bool compressed = false)
{
ASSERT(length < MAX_STRING_LENGTH);
// Use 0u for compressed/utf8 expression
SetMixLength((length << STRING_LENGTH_SHIFT_COUNT) | (compressed ? STRING_COMPRESSED : STRING_UNCOMPRESSED));
}
inline uint32_t GetRawHashcode() const
{
return GetMixHashcode() & (~IS_INTEGER_MASK);
}
static inline uint32_t MixHashcode(uint32_t hashcode, bool isInteger)
{
return isInteger ? (hashcode | IS_INTEGER_MASK) : (hashcode & (~IS_INTEGER_MASK));
}
inline void SetRawHashcode(uint32_t hashcode, bool isInteger = false)
{
// Use 0u for not integer string's expression
SetMixHashcode(MixHashcode(hashcode, isInteger));
}
inline size_t GetUtf8Length(bool modify = true) const;
void SetIsInternString()
inline void SetIsInternString()
{
SetMixLength(GetMixLength() | STRING_INTERN_BIT);
}
bool IsInternString() const
inline bool IsInternString() const
{
return (GetMixLength() & STRING_INTERN_BIT) != 0;
}
void ClearInternStringFlag()
inline void ClearInternStringFlag()
{
SetMixLength(GetMixLength() & ~STRING_INTERN_BIT);
}
bool TryGetHashCode(uint32_t *hash)
inline bool TryGetHashCode(uint32_t *hash)
{
uint32_t hashcode = GetRawHashcode();
uint32_t hashcode = GetMixHashcode();
if (hashcode == 0 && GetLength() != 0) {
return false;
}
@ -179,22 +212,90 @@ private:
return true;
}
inline uint32_t GetIntegerCode()
{
ASSERT(GetMixHashcode() & IS_INTEGER_MASK);
return GetRawHashcode();
}
// not change this data structure.
// if string is not flat, this func has low efficiency.
uint32_t PUBLIC_API GetHashcode()
{
uint32_t hashcode = GetRawHashcode();
uint32_t hashcode = GetMixHashcode();
// GetLength() == 0 means it's an empty array.No need to computeHashCode again when hashseed is 0.
if (hashcode == 0 && GetLength() != 0) {
hashcode = ComputeHashcode(0);
hashcode = ComputeHashcode();
SetRawHashcode(hashcode);
}
return hashcode;
}
template<typename T>
inline static bool IsDecimalDigitChar(const T c)
{
return (c >= '0' && c <= '9');
}
static uint32_t ComputeIntegerHash(uint32_t *num, uint8_t c)
{
if (!IsDecimalDigitChar(c)) {
return false;
}
int charDate = c - '0';
*num = (*num) * 10 + charDate; // 10: decimal factor
return true;
}
bool HashIntegerString(uint32_t length, uint32_t *hash, uint32_t hashSeed) const;
template<typename T>
static bool HashIntegerString(const T *data, size_t size, uint32_t *hash, uint32_t hashSeed)
{
ASSERT(size >= 0);
if (hashSeed == 0) {
if (IsDecimalDigitChar(data[0]) && data[0] != '0') {
uint32_t num = data[0] - '0';
uint32_t i = 1;
do {
if (i == size) {
// compute mix hash
if (num <= MAX_INTEGER_HASH_NUMBER) {
*hash = MixHashcode(num, IS_INTEGER);
return true;
}
return false;
}
} while (ComputeIntegerHash(&num, data[i++]));
}
if (size == 1 && (data[0] == '0')) {
*hash = MixHashcode(0, IS_INTEGER);
return true;
}
} else {
if (IsDecimalDigitChar(data[0])) {
uint32_t num = hashSeed * 10 + (data[0] - '0'); // 10: decimal factor
uint32_t i = 1;
do {
if (i == size) {
// compute mix hash
if (num <= MAX_INTEGER_HASH_NUMBER) {
*hash = MixHashcode(num, IS_INTEGER);
return true;
}
return false;
}
} while (ComputeIntegerHash(&num, data[i++]));
}
}
return false;
}
// not change this data structure.
// if string is not flat, this func has low efficiency.
uint32_t PUBLIC_API ComputeHashcode(uint32_t hashSeed) const;
uint32_t PUBLIC_API ComputeHashcode() const;
std::pair<uint32_t, bool> PUBLIC_API ComputeRawHashcode() const;
uint32_t PUBLIC_API ComputeHashcode(uint32_t rawHashSeed, bool isInteger) const;
static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress);
static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length);
@ -460,6 +561,29 @@ private:
return str;
}
inline Span<const uint8_t> FastToUtf8Span() const;
bool TryToGetInteger(uint32_t *result)
{
if (!IsInteger()) {
return false;
}
ASSERT(GetLength() <= MAX_CACHED_INTEGER_SIZE);
*result = GetIntegerCode();
return true;
}
// using integer number set into hash
inline bool TryToSetIntegerHash(int32_t num)
{
uint32_t hashcode = GetMixHashcode();
if (hashcode == 0 && GetLength() != 0) {
SetRawHashcode(static_cast<uint32_t>(num), IS_INTEGER);
return true;
}
return false;
}
void WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length);
static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len);
@ -1019,6 +1143,20 @@ public:
return string_->ToUtf8Span(buf);
}
// only for string is flat and using UTF8 encoding
inline Span<const uint8_t> FastToUtf8Span();
// Using string's hash to figure out whether the string can be converted to integer
inline bool TryToGetInteger(uint32_t *result)
{
return string_->TryToGetInteger(result);
}
inline bool TryToSetIntegerHash(int32_t num)
{
return string_->TryToSetIntegerHash(num);
}
// not change string data structure.
// if string is not flat, this func has low efficiency.
std::string ToStdString(StringConvertedUsage usage = StringConvertedUsage::PRINT);
@ -1077,11 +1215,26 @@ public:
return string_->GetHashcode();
}
uint32_t GetRawHashcode()
{
return string_->GetRawHashcode();
}
// not change src data structure.
// if src is not flat, this func has low efficiency.
uint32_t ComputeHashcode(uint32_t hashSeed)
std::pair<uint32_t, bool> ComputeRawHashcode()
{
return string_->ComputeHashcode(hashSeed);
return string_->ComputeRawHashcode();
}
uint32_t ComputeHashcode()
{
return string_->ComputeHashcode();
}
uint32_t ComputeHashcode(uint32_t rawHashSeed, bool isInteger)
{
return string_->ComputeHashcode(rawHashSeed, isInteger);
}
static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress)

View File

@ -30,8 +30,9 @@ EcmaString *EcmaStringTable::GetString(const JSHandle<EcmaString> &firstString,
{
ASSERT(EcmaStringAccessor(firstString).NotTreeString());
ASSERT(EcmaStringAccessor(secondString).NotTreeString());
uint32_t hashCode = EcmaStringAccessor(firstString).GetHashcode();
hashCode = EcmaStringAccessor(secondString).ComputeHashcode(hashCode);
auto [hashCode, isInteger] = EcmaStringAccessor(firstString).ComputeRawHashcode();
hashCode = EcmaStringAccessor(secondString).ComputeHashcode(hashCode, isInteger);
auto range = table_.equal_range(hashCode);
for (auto item = range.first; item != range.second; ++item) {
auto foundString = item->second;

View File

@ -257,6 +257,7 @@ class ObjectFactory;
V(SyntaxErrorString, SYNTAX_ERROR_STRING_INDEX, "SyntaxError") \
V(EvalErrorString, EVAL_ERROR_STRING_INDEX, "EvalError") \
V(OOMErrorString, OOM_ERROR_STRING_INDEX, "OutOfMemoryError") \
V(TerminationErrorString, TERMINATION_ERROR_STRING_INDEX, "TerminationError") \
V(ErrorFuncString, ERROR_FUNC_STRING_INDEX, "errorfunc") \
V(StackString, STACK_STRING_INDEX, "stack") \
V(StackEmptyString, STACK_EMPTY_STRING_INDEX, "stackisempty") \

View File

@ -78,6 +78,7 @@
V(JSTaggedValue, SyntaxErrorFunction, SYNTAX_ERROR_FUNCTION_INDEX) \
V(JSTaggedValue, EvalErrorFunction, EVAL_ERROR_FUNCTION_INDEX) \
V(JSTaggedValue, OOMErrorFunction, OOM_ERROR_FUNCTION_INDEX) \
V(JSTaggedValue, TerminationErrorFunction, TERMINATION_ERROR_FUNCTION_INDEX) \
V(JSTaggedValue, IntlFunction, INTL_FUNCTION_INDEX) \
V(JSTaggedValue, LocaleFunction, LOCALE_FUNCTION_INDEX) \
V(JSTaggedValue, DateTimeFormatFunction, DATE_TIME_FORMAT_FUNCTION_INDEX) \

View File

@ -544,6 +544,7 @@ using CommonStubCSigns = kungfu::CommonStubCSigns;
#define UPDATE_HOTNESS_COUNTER(offset) \
do { \
if (UpdateHotnessCounter(thread, sp, acc, offset)) { \
HANDLE_EXCEPTION_IF_ABRUPT_COMPLETION(thread); \
RESTORE_ACC(); \
} \
} while (false)
@ -4854,7 +4855,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
uint16_t length = READ_INST_8_3();
LOG_INST() << "intrinsics::definefunc length: " << length;
auto constpool = GetConstantPool(sp);
auto module = GetEcmaModule(sp);
Method *method = Method::Cast(GET_METHOD_FROM_CACHE(methodId).GetTaggedObject());
ASSERT(method != nullptr);

View File

@ -70,6 +70,11 @@ void MicroJobQueue::ExecutePendingJob(JSThread *thread, JSHandle<MicroJobQueue>
if (thread->HasPendingException()) {
return;
}
if (thread->HasTerminated()) {
JSHandle<TaggedQueue> emptyQueue(thread->GlobalConstants()->GetHandledEmptyTaggedQueue());
jobQueue->SetPromiseJobQueue(thread, emptyQueue);
return;
}
promiseQueue.Update(jobQueue->GetPromiseJobQueue());
}

View File

@ -20,6 +20,7 @@
#include "ecmascript/mem/c_string.h"
#include "ecmascript/mem/barriers-inl.h"
#include "ecmascript/object_factory-inl.h"
#include "ecmascript/ecma_string-inl.h"
#include "unicode/udata.h"
@ -315,9 +316,9 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
return collator;
}
icu::Collator *JSCollator::GetCachedIcuCollator(JSThread *thread, const JSHandle<JSTaggedValue> &locales)
icu::Collator *JSCollator::GetCachedIcuCollator(JSThread *thread, const JSTaggedValue &locales)
{
std::string cacheEntry = locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString();
std::string cacheEntry = locales.IsUndefined() ? "" : EcmaStringAccessor(locales).ToStdString();
void *cachedCollator =
thread->GetCurrentEcmaContext()->GetIcuFormatterFromCache(IcuFormatterType::COLLATOR, cacheEntry);
if (cachedCollator != nullptr) {
@ -326,6 +327,11 @@ icu::Collator *JSCollator::GetCachedIcuCollator(JSThread *thread, const JSHandle
return nullptr;
}
icu::Collator *JSCollator::GetCachedIcuCollator(JSThread *thread, const JSHandle<JSTaggedValue> &locales)
{
return GetCachedIcuCollator(thread, locales.GetTaggedValue());
}
UColAttributeValue JSCollator::OptionToUColAttribute(CaseFirstOption caseFirstOption)
{
auto iter = uColAttributeValueMap.find(caseFirstOption);
@ -455,22 +461,49 @@ JSHandle<JSObject> JSCollator::ResolvedOptions(JSThread *thread, const JSHandle<
return options;
}
icu::UnicodeString EcmaStringToUString(const JSHandle<EcmaString> &string)
ARK_INLINE icu::UnicodeString EcmaStringToUString(EcmaString *string)
{
std::string stdString(ConvertToString(*string, StringConvertedUsage::LOGICOPERATION));
icu::StringPiece sp(stdString);
CVector<uint8_t> buf;
Span<const uint8_t> span = EcmaStringAccessor(string).ToUtf8Span(buf);
icu::StringPiece sp(reinterpret_cast<const char*>(span.begin()), span.size());
icu::UnicodeString uString = icu::UnicodeString::fromUTF8(sp);
return uString;
}
icu::UnicodeString EcmaStringToUString(const JSHandle<EcmaString> &string)
{
return EcmaStringToUString(string.GetObject<EcmaString>());
}
JSTaggedValue JSCollator::CompareStrings(const icu::Collator *icuCollator, const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2)
{
return CompareStrings(icuCollator, string1.GetObject<EcmaString>(), string2.GetObject<EcmaString>());
}
JSTaggedValue JSCollator::CompareStrings(const icu::Collator *icuCollator, EcmaString *string1, EcmaString *string2)
{
UCollationResult result;
UErrorCode status = U_ZERO_ERROR;
if (string1 == string2) {
return JSTaggedValue(UCollationResult::UCOL_EQUAL);
}
{
EcmaStringAccessor string1Acc(string1);
EcmaStringAccessor string2Acc(string2);
if (string1Acc.IsUtf8() && string1Acc.IsLineOrConstantString() &&
string2Acc.IsUtf8() && string2Acc.IsLineOrConstantString()) {
icu::StringPiece stringPiece1(reinterpret_cast<const char*>(string1Acc.GetDataUtf8()),
string1Acc.GetLength());
icu::StringPiece stringPiece2(reinterpret_cast<const char*>(string2Acc.GetDataUtf8()),
string2Acc.GetLength());
result = icuCollator->compareUTF8(stringPiece1, stringPiece2, status);
return JSTaggedValue(result);
}
}
icu::UnicodeString uString1 = EcmaStringToUString(string1);
icu::UnicodeString uString2 = EcmaStringToUString(string2);
UCollationResult result;
UErrorCode status = U_ZERO_ERROR;
result = icuCollator->compare(uString1, uString2, status);
ASSERT(U_SUCCESS(status));

View File

@ -88,6 +88,7 @@ public:
bool enableLocaleCache = false);
static icu::Collator *GetCachedIcuCollator(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
static icu::Collator *GetCachedIcuCollator(JSThread *thread, const JSTaggedValue &locales);
// 11.3.4 Intl.Collator.prototype.resolvedOptions ()
static JSHandle<JSObject> ResolvedOptions(JSThread *thread, const JSHandle<JSCollator> &collator);
@ -97,6 +98,8 @@ public:
static JSTaggedValue CompareStrings(const icu::Collator *icuCollator, const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2);
static JSTaggedValue CompareStrings(const icu::Collator *icuCollator, EcmaString *string1, EcmaString *string2);
static JSTaggedValue FastCompareStrings(JSThread *thread, const icu::Collator *icuCollator,
const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2);

View File

@ -103,7 +103,8 @@ struct Reference;
JS_AGGREGATE_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_URI_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_SYNTAX_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_OOM_ERROR, /* JS_ERROR_LAST /////////////////////////////////////////////////////////////////////// */\
JS_OOM_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_TERMINATION_ERROR, /* JS_ERROR_LAST ///////////////////////////////////////////////////////////////////// */\
\
JS_REG_EXP, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_SET, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \
@ -274,7 +275,7 @@ struct Reference;
ECMA_OBJECT_LAST = JS_PROXY, /* /////////////////////////////////////////////////////////////////-PADDING */\
\
JS_ERROR_FIRST = JS_ERROR, /* ////////////////////////////////////////////////////////////////-PADDING */ \
JS_ERROR_LAST = JS_OOM_ERROR, /* ////////////////////////////////////////////////////////////////-PADDING */\
JS_ERROR_LAST = JS_TERMINATION_ERROR, /* ////////////////////////////////////////////////////////-PADDING */\
\
JS_ITERATOR_FIRST = JS_ITERATOR, /* //////////////////////////////////////////////////////////-PADDING */ \
JS_ITERATOR_LAST = JS_STRING_ITERATOR, /* //////////////////////////////////////////////////////////-PADDING */\

View File

@ -153,6 +153,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG =
"--compiler-external-pkg-info Specify the external package json info for ark aot compiler\n"
"--compiler-enable-external-pkg Enable compile with external package for ark aot compiler\n"
"--compiler-enable-lexenv-specialization: Enable replace ldlexvar with specific values: Default: 'true'\n"
"--compiler-enable-native-inline: Enable inline native function: Default: 'false'\n"
"--compiler-opt-array-onheap-check: Enable TypedArray on heap check for aot compiler: Default: 'false'\n\n";
bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
@ -245,6 +246,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{"compiler-enable-external-pkg", required_argument, nullptr, OPTION_COMPILER_ENABLE_EXTERNAL_PKG},
{"compiler-enable-lexenv-specialization", required_argument, nullptr,
OPTION_COMPILER_ENABLE_LEXENV_SPECIALIZATION},
{"compiler-enable-native-inline", required_argument, nullptr, OPTION_COMPILER_ENBALE_NATIVE_INLINE},
{nullptr, 0, nullptr, 0},
};
@ -838,6 +840,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_ENBALE_NATIVE_INLINE:
ret = ParseBoolParam(&argBool);
if (ret) {
SetEnableNativeInline(argBool);
} else {
return false;
}
break;
default:
LOG_ECMA(ERROR) << "Invalid option\n";
return false;

View File

@ -150,6 +150,7 @@ enum CommandValues {
OPTION_COMPILER_TRACE_VALUE_NUMBERING,
OPTION_COMPILER_OPT_INSTRUCTIONE_COMBINE,
OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING,
OPTION_COMPILER_ENBALE_NATIVE_INLINE,
};
class PUBLIC_API JSRuntimeOptions {
@ -1312,6 +1313,16 @@ public:
enableLexenvSpecialization_ = value;
}
bool IsEnableNativeInline() const
{
return enableNativeInline_;
}
void SetEnableNativeInline(bool value)
{
enableNativeInline_ = value;
}
private:
static bool StartsWith(const std::string &haystack, const std::string &needle)
{
@ -1419,6 +1430,7 @@ private:
bool enableOptOnHeapCheck_ {true};
bool enableOptLoopInvariantCodeMotion_ {false};
bool enableLexenvSpecialization_ {true};
bool enableNativeInline_ {false};
};
} // namespace panda::ecmascript

View File

@ -292,6 +292,7 @@ bool JSSerializer::WriteTaggedObject(const JSHandle<JSTaggedValue> &value)
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_TERMINATION_ERROR:
return WriteJSError(value);
case JSType::JS_DATE:
return WriteJSDate(value);
@ -554,6 +555,8 @@ bool JSSerializer::WriteJSErrorHeader(JSType type)
return WriteType(SerializationUID::SYNTAX_ERROR);
case JSType::JS_OOM_ERROR:
return WriteType(SerializationUID::OOM_ERROR);
case JSType::JS_TERMINATION_ERROR:
return WriteType(SerializationUID::TERMINATION_ERROR);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
@ -1153,6 +1156,7 @@ JSHandle<JSTaggedValue> JSDeserializer::DeserializeJSTaggedValue()
case SerializationUID::URI_ERROR:
case SerializationUID::SYNTAX_ERROR:
case SerializationUID::OOM_ERROR:
case SerializationUID::TERMINATION_ERROR:
return ReadJSError(uid);
case SerializationUID::JS_DATE:
return ReadJSDate();
@ -1419,6 +1423,9 @@ JSHandle<JSTaggedValue> JSDeserializer::ReadJSError(SerializationUID uid)
case SerializationUID::OOM_ERROR:
errorType = base::ErrorType::OOM_ERROR;
break;
case SerializationUID::TERMINATION_ERROR:
errorType = base::ErrorType::TERMINATION_ERROR;
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();

View File

@ -91,6 +91,7 @@ enum class SerializationUID : uint8_t {
URI_ERROR,
SYNTAX_ERROR,
OOM_ERROR,
TERMINATION_ERROR,
ERROR_MESSAGE_BEGIN,
ERROR_MESSAGE_END,
// Function begin

View File

@ -329,7 +329,17 @@ JSTaggedValue JSStableArray::HandleFindIndexOfStable(JSThread *thread, JSHandle<
while (k < len) {
// Elements of thisObjHandle may change.
array.Update(thisObjHandle->GetElements());
kValue.Update(array->Get(k));
JSTaggedValue val = array->Get(k);
if (val.IsHole()) {
auto res = JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue();
if (res.IsHole()) {
kValue.Update(JSTaggedValue::Undefined());
} else {
kValue.Update(res);
}
} else {
kValue.Update(val);
}
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);

View File

@ -82,13 +82,14 @@ inline bool JSTaggedValue::ToBoolean() const
UNREACHABLE();
}
inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, JSTaggedValue tagged)
{
if (tagged->IsInt() || tagged->IsDouble()) {
return JSTaggedNumber(tagged.GetTaggedValue());
DISALLOW_GARBAGE_COLLECTION;
if (tagged.IsInt() || tagged.IsDouble()) {
return JSTaggedNumber(tagged);
}
switch (tagged->GetRawData()) {
switch (tagged.GetRawData()) {
case JSTaggedValue::VALUE_UNDEFINED:
case JSTaggedValue::VALUE_HOLE: {
return JSTaggedNumber(base::NAN_VALUE);
@ -105,23 +106,29 @@ inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<J
}
}
if (tagged->IsString()) {
return StringToDouble(tagged.GetTaggedValue());
if (tagged.IsString()) {
return StringToNumber(tagged);
}
if (tagged->IsECMAObject()) {
JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
if (tagged.IsECMAObject()) {
JSHandle<JSTaggedValue>taggedHandle(thread, tagged);
JSTaggedValue primValue = ToPrimitive(thread, taggedHandle, PREFER_NUMBER);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
return ToNumber(thread, primValue);
}
if (tagged->IsSymbol()) {
if (tagged.IsSymbol()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
}
if (tagged->IsBigInt()) {
if (tagged.IsBigInt()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
}
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
}
inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
{
return ToNumber(thread, tagged.GetTaggedValue());
}
inline JSTaggedValue JSTaggedValue::ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
{
JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged));

View File

@ -16,6 +16,7 @@
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_string-inl.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/interpreter/interpreter.h"
@ -1247,14 +1248,43 @@ bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTagg
return false;
}
JSTaggedNumber JSTaggedValue::StringToNumber(JSTaggedValue tagged)
{
EcmaStringAccessor strAccessor(tagged);
size_t strLen = strAccessor.GetLength();
if (strLen == 0) {
return JSTaggedNumber(0);
}
if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
uint32_t index;
// fast path: get integer from string's hash value
if (strAccessor.TryToGetInteger(&index)) {
return JSTaggedNumber(index);
}
Span<const uint8_t> str = strAccessor.FastToUtf8Span();
if (strAccessor.GetLength() == 0) {
return JSTaggedNumber(0);
}
auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged);
if (isSuccess) {
return result;
}
}
CVector<uint8_t> buf;
Span<const uint8_t> str = strAccessor.ToUtf8Span(buf);
double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
return JSTaggedNumber(d);
}
JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
{
// 1. Let primValue be ? ToPrimitive(value, number)
JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
// 2. If Type(primValue) is BigInt, return primValue.
if (primValue->IsBigInt()) {
return primValue;
if (primValue.IsBigInt()) {
return JSHandle<JSTaggedValue>(thread, primValue);
}
// 3. Return ? ToNumber(primValue).
JSTaggedNumber number = ToNumber(thread, primValue);

View File

@ -414,6 +414,7 @@ public:
static JSTaggedValue ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
PreferredPrimitiveType type = NO_PREFERENCE);
bool ToBoolean() const;
static JSTaggedNumber ToNumber(JSThread *thread, JSTaggedValue tagged);
static JSTaggedNumber ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static JSTaggedValue ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static JSTaggedValue ToBigInt64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
@ -435,6 +436,7 @@ public:
static JSTaggedValue CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static JSTaggedNumber ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
static JSTaggedNumber StringToDouble(JSTaggedValue tagged);
static JSTaggedNumber StringToNumber(JSTaggedValue tagged);
static bool ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output);
static bool ToElementIndex(JSTaggedValue key, uint32_t *output);

View File

@ -480,9 +480,22 @@ void JSThread::CheckOrSwitchPGOStubs()
}
}
void JSThread::TerminateExecution()
{
// set the TERMINATE_ERROR to exception
ObjectFactory *factory = GetEcmaVM()->GetFactory();
JSHandle<JSObject> error = factory->GetJSError(ErrorType::TERMINATION_ERROR, "Terminate execution!");
SetException(error.GetTaggedValue());
}
bool JSThread::CheckSafepoint()
{
ResetCheckSafePointStatus();
if (HasTerminationRequest()) {
TerminateExecution();
SetVMTerminated(true);
SetTerminationRequest(false);
}
if (vmThreadControl_->VMNeedSuspension()) {
vmThreadControl_->SuspendVM();
}

View File

@ -70,6 +70,8 @@ public:
using CheckSafePointBit = BitField<bool, 0, BOOL_BITFIELD_NUM>;
using VMNeedSuspensionBit = BitField<bool, CHECK_SAFEPOINT_BITFIELD_NUM, BOOL_BITFIELD_NUM>;
using VMHasSuspendedBit = VMNeedSuspensionBit::NextFlag;
using VMNeedTerminationBit = VMHasSuspendedBit::NextFlag;
using VMHasTerminatedBit = VMNeedTerminationBit::NextFlag;
using PGOStatusBits = BitField<PGOProfilerStatus, PGO_PROFILER_BITFIELD_START, BOOL_BITFIELD_NUM>;
using BCStubStatusBits = PGOStatusBits::NextField<BCStubStatus, BOOL_BITFIELD_NUM>;
using ThreadId = uint32_t;
@ -455,36 +457,68 @@ public:
void SetCheckSafePointStatus()
{
LockHolder lock(interruptMutex_);
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & 0xFF) <= 1);
CheckSafePointBit::Set(true, &glueData_.interruptVector_);
}
void ResetCheckSafePointStatus()
{
LockHolder lock(interruptMutex_);
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & 0xFF) <= 1);
CheckSafePointBit::Set(false, &glueData_.interruptVector_);
}
void SetVMNeedSuspension(bool flag)
{
LockHolder lock(interruptMutex_);
VMNeedSuspensionBit::Set(flag, &glueData_.interruptVector_);
}
bool VMNeedSuspension()
{
LockHolder lock(interruptMutex_);
return VMNeedSuspensionBit::Decode(glueData_.interruptVector_);
}
void SetVMSuspended(bool flag)
{
LockHolder lock(interruptMutex_);
VMHasSuspendedBit::Set(flag, &glueData_.interruptVector_);
}
bool IsVMSuspended()
{
LockHolder lock(interruptMutex_);
return VMHasSuspendedBit::Decode(glueData_.interruptVector_);
}
bool HasTerminationRequest() const
{
LockHolder lock(interruptMutex_);
return VMNeedTerminationBit::Decode(glueData_.interruptVector_);
}
void SetTerminationRequest(bool flag)
{
LockHolder lock(interruptMutex_);
VMNeedTerminationBit::Set(flag, &glueData_.interruptVector_);
}
void SetVMTerminated(bool flag)
{
LockHolder lock(interruptMutex_);
VMHasTerminatedBit::Set(flag, &glueData_.interruptVector_);
}
bool HasTerminated() const
{
LockHolder lock(interruptMutex_);
return VMHasTerminatedBit::Decode(glueData_.interruptVector_);
}
void TerminateExecution();
static uintptr_t GetCurrentStackPosition()
{
return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
@ -966,6 +1000,8 @@ private:
CMap<ElementsKind, ConstantIndex> arrayHClassIndexMap_;
CVector<EcmaContext *> contexts_;
EcmaContext *currentContext_ {nullptr};
mutable Mutex interruptMutex_;
friend class GlobalHandleCollection;
friend class EcmaVM;
friend class EcmaContext;

View File

@ -149,4 +149,33 @@ uint32_t MethodLiteral::GetCodeSize(const JSPandaFile *jsPandaFile, EntityId met
panda_file::CodeDataAccessor cda(*pandaFile, codeId);
return cda.GetCodeSize();
}
std::optional<std::set<uint32_t>> MethodLiteral::GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const
{
const panda_file::File *pf = jsPandaFile->GetPandaFile();
EntityId methodId = GetMethodId();
panda_file::MethodDataAccessor mda(*pf, methodId);
std::set<uint32_t> requestedModules;
bool hasRequestedModules = false;
mda.EnumerateAnnotations([&](EntityId annotationId) {
panda_file::AnnotationDataAccessor ada(*pf, annotationId);
auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data);
if (::strcmp("L_ESConcurrentModuleRequestsAnnotation;", annotationName) == 0) {
hasRequestedModules = true;
uint32_t elemCount = ada.GetCount();
for (uint32_t i = 0; i < elemCount; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data);
if (::strcmp("ConcurrentModuleRequest", elemName) == 0) {
uint32_t index = adae.GetScalarValue().GetValue();
requestedModules.insert(index);
}
}
}
});
if (!hasRequestedModules) {
return std::nullopt;
}
return requestedModules;
}
} // namespace panda::ecmascript

View File

@ -341,6 +341,8 @@ public:
return extraLiteralInfo_;
}
std::optional<std::set<uint32_t>> GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const;
private:
enum class Index : size_t {
CALL_FIELD_INDEX = 0,

View File

@ -742,6 +742,22 @@ bool Heap::CheckAndTriggerOldGC(size_t size)
return false;
}
bool Heap::CheckAndTriggerHintGC()
{
if (IsInBackground()) {
CollectGarbage(TriggerGCType::FULL_GC, GCReason::EXTERNAL_TRIGGER);
return true;
}
if (InSensitiveStatus()) {
return false;
}
if (memController_->GetPredictedSurvivalRate() < SURVIVAL_RATE_THRESHOLD) {
CollectGarbage(TriggerGCType::FULL_GC, GCReason::EXTERNAL_TRIGGER);
return true;
}
return false;
}
bool Heap::CheckOngoingConcurrentMarking()
{
if (concurrentMarker_->IsEnabled() && !thread_->IsReadyToMark() &&

View File

@ -279,6 +279,7 @@ public:
void CollectGarbage(TriggerGCType gcType, GCReason reason = GCReason::OTHER);
bool CheckAndTriggerOldGC(size_t size = 0);
bool CheckAndTriggerHintGC();
TriggerGCType SelectGCType() const;
/*
* Parallel GC related configurations and utilities.
@ -575,6 +576,8 @@ private:
static constexpr int ALLOCATE_SIZE_LIMIT = 100_KB;
static constexpr int IDLE_MAINTAIN_TIME = 500;
static constexpr int BACKGROUND_GROW_LIMIT = 2_MB;
// Threadshold that HintGC will actually trigger GC.
static constexpr double SURVIVAL_RATE_THRESHOLD = 0.5;
void FatalOutOfMemoryError(size_t size, std::string functionName);
void RecomputeLimits();
void AdjustOldSpaceLimit();

View File

@ -17,6 +17,8 @@
#define ECMASCRIPT_MEM_MEM_CONTROLLER_H
#include <chrono>
#include <cmath>
#include <limits>
#include "ecmascript/base/gc_ring_buffer.h"
#include "ecmascript/mem/heap.h"
@ -117,6 +119,11 @@ public:
void AddSurvivalRate(double rate)
{
recordedSurvivalRates_.Push(rate);
if (UNLIKELY(std::isnan(predictedSurvivalRate_))) {
predictedSurvivalRate_ = rate;
} else {
predictedSurvivalRate_ = ALPHA * rate + (1 - ALPHA) * predictedSurvivalRate_;
}
}
double GetAverageSurvivalRate() const
@ -129,6 +136,14 @@ public:
return result / count;
}
double GetPredictedSurvivalRate() const
{
if (UNLIKELY(std::isnan(predictedSurvivalRate_))) {
return 0;
}
return predictedSurvivalRate_;
}
void ResetRecordedSurvivalRates()
{
recordedSurvivalRates_.Reset();
@ -136,6 +151,8 @@ public:
private:
static constexpr int LENGTH = 10;
// Decayed weight for predicting survival rate.
static constexpr double ALPHA = 0.8;
static double CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer);
static double CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer,
const BytesAndDuration &initial, const double timeMs);
@ -163,6 +180,8 @@ private:
int startCounter_ {0};
double markCompactSpeedCache_ {0.0};
double predictedSurvivalRate_ {std::numeric_limits<double>::quiet_NaN()};
base::GCRingBuffer<BytesAndDuration, LENGTH> recordedMarkCompacts_;
base::GCRingBuffer<BytesAndDuration, LENGTH> recordedNewSpaceAllocations_;
base::GCRingBuffer<BytesAndDuration, LENGTH> recordedOldSpaceAllocations_;

View File

@ -136,6 +136,7 @@ public:
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_TERMINATION_ERROR:
case JSType::JS_ASYNCITERATOR:
case JSType::JS_ITERATOR:
JSObject::Cast(object)->VisitRangeSlot(visitor);

View File

@ -111,7 +111,7 @@ JSTaggedValue ModuleManager::GetModuleValueOutterInternal(int32_t index, JSTagge
JSTaggedValue resolvedModule = binding->GetModule();
ASSERT(resolvedModule.IsSourceTextModule());
SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject());
// Support for only modifying var value of HotReload.
// Cause patchFile exclude the record of importing modifying var. Can't reresolve moduleRecord.
EcmaContext *context = thread->GetCurrentEcmaContext();

View File

@ -112,7 +112,7 @@ private:
bool excuteFromJob = false);
JSHandle<JSTaggedValue> ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
const CString &recordName, bool excuteFromJob = false);
JSHandle<JSTaggedValue> CommonResolveImportedModuleWithMerge(const CString &moduleFileName,
const CString &recordName, bool excuteFromJob = false);

View File

@ -459,6 +459,27 @@ JSHandle<SourceTextModule> SourceTextModule::GetModuleFromBinding(JSThread *thre
return JSHandle<SourceTextModule>(thread, binding->GetModule());
}
int SourceTextModule::HandleInstantiateException([[maybe_unused]] JSHandle<SourceTextModule> &module,
const CVector<JSHandle<SourceTextModule>> &stack, int result)
{
// a. For each module m in stack, do
for (auto mm : stack) {
// i. Assert: m.[[Status]] is "instantiating".
ASSERT(mm->GetStatus() == ModuleStatus::INSTANTIATING);
// ii. Set m.[[Status]] to "uninstantiated".
mm->SetStatus(ModuleStatus::UNINSTANTIATED);
// iii. Set m.[[Environment]] to undefined.
// iv. Set m.[[DFSIndex]] to undefined.
mm->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX);
// v. Set m.[[DFSAncestorIndex]] to undefined.
mm->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX);
}
// b. Assert: module.[[Status]] is "uninstantiated".
ASSERT(module->GetStatus() == ModuleStatus::UNINSTANTIATED);
// c. return result
return result;
}
int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
bool excuteFromJob)
{
@ -475,22 +496,7 @@ int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
int result = SourceTextModule::InnerModuleInstantiation(thread, moduleRecord, stack, 0, excuteFromJob);
// 5. If result is an abrupt completion, then
if (thread->HasPendingException()) {
// a. For each module m in stack, do
for (auto mm : stack) {
// i. Assert: m.[[Status]] is "instantiating".
ASSERT(mm->GetStatus() == ModuleStatus::INSTANTIATING);
// ii. Set m.[[Status]] to "uninstantiated".
mm->SetStatus(ModuleStatus::UNINSTANTIATED);
// iii. Set m.[[Environment]] to undefined.
// iv. Set m.[[DFSIndex]] to undefined.
mm->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX);
// v. Set m.[[DFSAncestorIndex]] to undefined.
mm->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX);
}
// b. Assert: module.[[Status]] is "uninstantiated".
ASSERT(module->GetStatus() == ModuleStatus::UNINSTANTIATED);
// c. return result
return result;
return HandleInstantiateException(module, stack, result);
}
// 6. Assert: module.[[Status]] is "instantiated" or "evaluated".
ASSERT(module->GetStatus() == ModuleStatus::INSTANTIATED || module->GetStatus() == ModuleStatus::EVALUATED);
@ -500,6 +506,114 @@ int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
return SourceTextModule::UNDEFINED_INDEX;
}
std::optional<std::set<uint32_t>> SourceTextModule::GetConcurrentRequestedModules(const JSHandle<Method> &method)
{
const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
const MethodLiteral *methodLiteral = method->GetMethodLiteral();
return methodLiteral->GetConcurrentRequestedModules(jsPandaFile);
}
int SourceTextModule::InstantiateForConcurrent(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
const JSHandle<Method> &method)
{
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::InstantiateForConcurrent");
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleHdl);
// 1. Let module be this Source Text Module Record.
// 2. Assert: module.[[Status]] is not "instantiating" or "evaluating".
ASSERT(module->GetStatus() != ModuleStatus::INSTANTIATING && module->GetStatus() != ModuleStatus::EVALUATING);
// 3. Let stack be a new empty List.
CVector<JSHandle<SourceTextModule>> stack;
// 4. Let result be InnerModuleInstantiation(module, stack, 0).
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
int result = SourceTextModule::ModuleInstantiation(thread, moduleRecord, stack, 0, method);
// 5. If result is an abrupt completion, then
if (thread->HasPendingException()) {
return HandleInstantiateException(module, stack, result);
}
// 6. Assert: module.[[Status]] is "instantiated" or "evaluated".
ASSERT(module->GetStatus() == ModuleStatus::INSTANTIATED || module->GetStatus() == ModuleStatus::EVALUATED);
// 7. Assert: stack is empty.
ASSERT(stack.empty());
// 8. Return undefined.
return SourceTextModule::UNDEFINED_INDEX;
}
void SourceTextModule::DFSModuleInstantiation(JSHandle<SourceTextModule> &module,
CVector<JSHandle<SourceTextModule>> &stack)
{
// 1. Assert: module occurs exactly once in stack.
// 2. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]].
int dfsAncIdx = module->GetDFSAncestorIndex();
int dfsIdx = module->GetDFSIndex();
ASSERT(dfsAncIdx <= dfsIdx);
// 3. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then
if (dfsAncIdx == dfsIdx) {
// a. Let done be false.
bool done = false;
// b. Repeat, while done is false,
while (!done) {
// i. Let requiredModule be the last element in stack.
JSHandle<SourceTextModule> requiredModule = stack.back();
// ii. Remove the last element of stack.
stack.pop_back();
// iii. Set requiredModule.[[Status]] to "instantiated".
requiredModule->SetStatus(ModuleStatus::INSTANTIATED);
// iv. If requiredModule and module are the same Module Record, set done to true.
if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
done = true;
}
}
}
}
std::optional<int> SourceTextModule::HandleInnerModuleInstantiation(JSThread *thread,
JSHandle<SourceTextModule> &module,
JSMutableHandle<JSTaggedValue> &required,
CVector<JSHandle<SourceTextModule>> &stack,
int &index, bool excuteFromJob)
{
// a. Let requiredModule be ? HostResolveImportedModule(module, required).
JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
if (moduleRecordName.IsUndefined()) {
JSHandle<JSTaggedValue> requiredVal =
SourceTextModule::HostResolveImportedModule(thread, module, required);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
ModuleDeregister::InitForDeregisterModule(thread, requiredVal, excuteFromJob);
requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
} else {
ASSERT(moduleRecordName.IsString());
JSHandle<JSTaggedValue> requiredVal =
SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
ModuleDeregister::InitForDeregisterModule(thread, requiredVal, excuteFromJob);
requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
}
// b. Set index to ? InnerModuleInstantiation(requiredModule, stack, index).
JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
index = SourceTextModule::InnerModuleInstantiation(thread,
requiredModuleRecord, stack, index, excuteFromJob);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
// c. Assert: requiredModule.[[Status]] is either "instantiating", "instantiated", or "evaluated".
ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
ASSERT((requiredModuleStatus == ModuleStatus::INSTANTIATING ||
requiredModuleStatus == ModuleStatus::INSTANTIATED || requiredModuleStatus == ModuleStatus::EVALUATED));
// d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
// e. If requiredModule.[[Status]] is "instantiating", then
if (requiredModuleStatus == ModuleStatus::INSTANTIATING) {
// d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end());
// i. Assert: requiredModule is a Source Text Module Record.
// ii. Set module.[[DFSAncestorIndex]] to min(
// module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
module->SetDFSAncestorIndex(dfsAncIdx);
}
return std::nullopt;
}
int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index, bool excuteFromJob)
{
@ -538,43 +652,9 @@ int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<
JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
for (size_t idx = 0; idx < requestedModulesLen; idx++) {
required.Update(requestedModules->Get(idx));
// a. Let requiredModule be ? HostResolveImportedModule(module, required).
JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
if (moduleRecordName.IsUndefined()) {
JSHandle<JSTaggedValue> requiredVal =
SourceTextModule::HostResolveImportedModule(thread, module, required);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
ModuleDeregister::InitForDeregisterModule(thread, requiredVal, excuteFromJob);
requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
} else {
ASSERT(moduleRecordName.IsString());
JSHandle<JSTaggedValue> requiredVal =
SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
ModuleDeregister::InitForDeregisterModule(thread, requiredVal, excuteFromJob);
requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
}
// b. Set index to ? InnerModuleInstantiation(requiredModule, stack, index).
JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
index = SourceTextModule::InnerModuleInstantiation(thread,
requiredModuleRecord, stack, index, excuteFromJob);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
// c. Assert: requiredModule.[[Status]] is either "instantiating", "instantiated", or "evaluated".
ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
ASSERT((requiredModuleStatus == ModuleStatus::INSTANTIATING ||
requiredModuleStatus == ModuleStatus::INSTANTIATED || requiredModuleStatus == ModuleStatus::EVALUATED));
// d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
// e. If requiredModule.[[Status]] is "instantiating", then
if (requiredModuleStatus == ModuleStatus::INSTANTIATING) {
// d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end());
// i. Assert: requiredModule is a Source Text Module Record.
// ii. Set module.[[DFSAncestorIndex]] to min(
// module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
module->SetDFSAncestorIndex(dfsAncIdx);
auto result = HandleInnerModuleInstantiation(thread, module, required, stack, index, excuteFromJob);
if (UNLIKELY(result.has_value())) { // exception occurs
return result.value();
}
}
}
@ -586,29 +666,70 @@ int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<
SourceTextModule::ModuleDeclarationEnvironmentSetup(thread, module);
}
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
// 11. Assert: module occurs exactly once in stack.
// 12. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]].
int dfsAncIdx = module->GetDFSAncestorIndex();
int dfsIdx = module->GetDFSIndex();
ASSERT(dfsAncIdx <= dfsIdx);
// 13. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then
if (dfsAncIdx == dfsIdx) {
// a. Let done be false.
bool done = false;
// b. Repeat, while done is false,
while (!done) {
// i. Let requiredModule be the last element in stack.
JSHandle<SourceTextModule> requiredModule = stack.back();
// ii. Remove the last element of stack.
stack.pop_back();
// iii. Set requiredModule.[[Status]] to "instantiated".
requiredModule->SetStatus(ModuleStatus::INSTANTIATED);
// iv. If requiredModule and module are the same Module Record, set done to true.
if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
done = true;
DFSModuleInstantiation(module, stack);
return index;
}
int SourceTextModule::ModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index,
const JSHandle<Method> &method)
{
// 1. If module is not a Source Text Module Record, then
if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
// a. Perform ? module.Instantiate().
ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
// b. Return index.
return index;
}
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
// 2. If module.[[Status]] is "instantiating", "instantiated", or "evaluated", then Return index.
ModuleStatus status = module->GetStatus();
if (status == ModuleStatus::INSTANTIATING ||
status == ModuleStatus::INSTANTIATED ||
status == ModuleStatus::EVALUATED) {
return index;
}
// 3. Assert: module.[[Status]] is "uninstantiated".
ASSERT(status == ModuleStatus::UNINSTANTIATED);
// 4. Set module.[[Status]] to "instantiating".
module->SetStatus(ModuleStatus::INSTANTIATING);
// 5. Set module.[[DFSIndex]] to index.
module->SetDFSIndex(index);
// 6. Set module.[[DFSAncestorIndex]] to index.
module->SetDFSAncestorIndex(index);
// 7. Set index to index + 1.
index++;
// 8. Append module to stack.
stack.emplace_back(module);
// 9. For each String required that is an element of module.[[RequestedModules]], do
if (!module->GetRequestedModules().IsUndefined()) {
JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
size_t requestedModulesLen = requestedModules->GetLength();
JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
auto coRequestedModules = GetConcurrentRequestedModules(method);
for (size_t idx = 0; idx < requestedModulesLen; idx++) {
if (coRequestedModules.has_value() && coRequestedModules.value().count(idx) == 0) {
// skip the unused module
continue;
}
required.Update(requestedModules->Get(idx));
auto result = HandleInnerModuleInstantiation(thread, module, required, stack, index, false);
if (UNLIKELY(result.has_value())) { // exception occurs
return result.value();
}
}
}
// Adapter new opcode
// 10. Perform ? ModuleDeclarationEnvironmentSetup(module).
if (module->GetIsNewBcVersion()) {
SourceTextModule::ModuleDeclarationArrayEnvironmentSetup(thread, module);
} else {
SourceTextModule::ModuleDeclarationEnvironmentSetup(thread, module);
}
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
DFSModuleInstantiation(module, stack);
return index;
}
@ -864,7 +985,8 @@ int SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule
return SourceTextModule::UNDEFINED_INDEX;
}
int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module)
int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<Method> &method)
{
// 1. Let module be this Source Text Module Record.
// 2. Assert: module.[[Status]] is "instantiated" or "evaluated".
@ -874,7 +996,7 @@ int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<Sou
CVector<JSHandle<SourceTextModule>> stack;
// 4. Let result be InnerModuleEvaluation(module, stack, 0)
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, stack, 0);
int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, stack, 0, method);
// 5. If result is an abrupt completion, then
if (thread->HasPendingException()) {
// a. For each module m in stack, do
@ -1028,14 +1150,20 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
}
int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index)
CVector<JSHandle<SourceTextModule>> &stack, int index,
const JSHandle<Method> &method)
{
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
if (!module->GetRequestedModules().IsUndefined()) {
JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
size_t requestedModulesLen = requestedModules->GetLength();
JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
auto coRequestedModules = GetConcurrentRequestedModules(method);
for (size_t idx = 0; idx < requestedModulesLen; idx++) {
if (coRequestedModules.has_value() && coRequestedModules.value().count(idx) == 0) {
// skip the unused module
continue;
}
required.Update(requestedModules->Get(idx));
JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();

View File

@ -83,8 +83,6 @@ public:
static int InnerModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index, const void *buffer = nullptr,
size_t size = 0, bool excuteFromJob = false);
static int ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index);
// 15.2.1.16.5.2 ModuleExecution ( module )
static void ModuleExecution(JSThread *thread, const JSHandle<SourceTextModule> &module,
@ -153,7 +151,6 @@ public:
// 15.2.1.16.5 Evaluate()
static int Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &module,
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
static int EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module);
// 15.2.1.16.4 Instantiate()
static int Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
@ -178,6 +175,20 @@ public:
static JSTaggedValue GetModuleName(JSTaggedValue currentModule);
static bool IsDynamicModule(LoadingTypes types);
// taskpool
static std::optional<std::set<uint32_t>> GetConcurrentRequestedModules(const JSHandle<Method> &method);
static int InstantiateForConcurrent(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
const JSHandle<Method> &method);
static int ModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index,
const JSHandle<Method> &method);
static int EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<Method> &method);
static int ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index,
const JSHandle<Method> &method);
private:
static void SetExportName(JSThread *thread,
const JSHandle<JSTaggedValue> &moduleRequest, const JSHandle<SourceTextModule> &module,
@ -208,6 +219,15 @@ private:
static JSTaggedValue FindByExport(const JSTaggedValue &exportEntriesTv, const JSTaggedValue &key,
const JSTaggedValue &dictionary);
static JSHandle<SourceTextModule> GetModuleFromBinding(JSThread *thread, const JSTaggedValue &JSTaggedValue);
static void DFSModuleInstantiation(JSHandle<SourceTextModule> &module,
CVector<JSHandle<SourceTextModule>> &stack);
static std::optional<int> HandleInnerModuleInstantiation(JSThread *thread,
JSHandle<SourceTextModule> &module,
JSMutableHandle<JSTaggedValue> &required,
CVector<JSHandle<SourceTextModule>> &stack,
int &index, bool excuteFromJob);
static int HandleInstantiateException(JSHandle<SourceTextModule> &module,
const CVector<JSHandle<SourceTextModule>> &stack, int result);
};
class ResolvedBinding final : public Record {

View File

@ -184,7 +184,7 @@ CString ModulePathHelper::ParsePrefixBundle(JSThread *thread, const JSPandaFile
if (bundleName != vm->GetBundleName()) {
entryPoint = PREVIEW_OF_ACROSS_HAP_FLAG;
if (vm->EnableReportModuleResolvingFailure()) {
CString msg = "[ArkRuntime Log] Cannot preview this HSP module as" \
CString msg = "[ArkRuntime Log] Cannot preview this HSP module as " \
"it is imported from outside the current application.";
LOG_NO_TAG(ERROR) << msg;
}

View File

@ -542,6 +542,12 @@ bool DFXJSNApi::IsSuspended([[maybe_unused]] const EcmaVM *vm)
#endif
}
void DFXJSNApi::TerminateExecution(const EcmaVM *vm)
{
ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
vmThreadControl->RequestTerminateExecution();
}
bool DFXJSNApi::CheckSafepoint([[maybe_unused]] const EcmaVM *vm)
{
#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)

View File

@ -110,6 +110,7 @@ public:
static void ResumeVM(const EcmaVM *vm);
static bool SuspendVM(const EcmaVM *vm);
static bool IsSuspended(const EcmaVM *vm);
static void TerminateExecution(const EcmaVM *vm);
static bool CheckSafepoint(const EcmaVM *vm);
static void ResumeVMById(EcmaVM *vm, uint32_t tid);
static bool SuspendVMById(EcmaVM *vm, uint32_t tid);

View File

@ -1004,6 +1004,7 @@ public:
static Local<JSValueRef> AggregateError(const EcmaVM *vm, Local<StringRef> message);
static Local<JSValueRef> EvalError(const EcmaVM *vm, Local<StringRef> message);
static Local<JSValueRef> OOMError(const EcmaVM *vm, Local<StringRef> message);
static Local<JSValueRef> TerminationError(const EcmaVM *vm, Local<StringRef> message);
};
using LOG_PRINT = int (*)(int id, int level, const char *tag, const char *fmt, const char *message);
@ -1384,6 +1385,7 @@ public:
static void PrintExceptionInfo(const EcmaVM *vm);
static Local<ObjectRef> GetAndClearUncaughtException(const EcmaVM *vm);
static Local<ObjectRef> GetUncaughtException(const EcmaVM *vm);
static bool IsExecutingPendingJob(const EcmaVM *vm);
static bool HasPendingException(const EcmaVM *vm);
static bool HasPendingJob(const EcmaVM *vm);
static void EnableUserUncaughtErrorHandler(EcmaVM *vm);

View File

@ -706,6 +706,11 @@ bool JSNApi::HasPendingException(const EcmaVM *vm)
return vm->GetJSThread()->HasPendingException();
}
bool JSNApi::IsExecutingPendingJob(const EcmaVM *vm)
{
return vm->GetJSThread()->GetCurrentEcmaContext()->IsExecutingPendingJob();
}
bool JSNApi::HasPendingJob(const EcmaVM *vm)
{
return vm->GetJSThread()->GetCurrentEcmaContext()->HasPendingJob();
@ -3663,10 +3668,10 @@ bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local<JSValueRef> function, v
LOG_ECMA(DEBUG) << "CompileMode is esmodule";
moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(moduleName, recordName);
}
ecmascript::SourceTextModule::Instantiate(thread, moduleRecord);
ecmascript::SourceTextModule::InstantiateForConcurrent(thread, moduleRecord, method);
JSHandle<ecmascript::SourceTextModule> module = JSHandle<ecmascript::SourceTextModule>::Cast(moduleRecord);
module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED);
ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module);
ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module, method);
method->SetModule(thread, module);
return true;
}

View File

@ -65,7 +65,8 @@
V(TypeError, TYPE_ERROR) \
V(AggregateError, AGGREGATE_ERROR) \
V(EvalError, EVAL_ERROR) \
V(OOMError, OOM_ERROR)
V(OOMError, OOM_ERROR) \
V(TerminationError, TERMINATION_ERROR)
namespace panda {
using NativeFinalize = void (*)(EcmaVM *);

View File

@ -801,7 +801,8 @@ JSHandle<JSObject> ObjectFactory::GetJSError(const ErrorType &errorType, const c
ASSERT_PRINT(errorType == ErrorType::ERROR || errorType == ErrorType::EVAL_ERROR ||
errorType == ErrorType::RANGE_ERROR || errorType == ErrorType::REFERENCE_ERROR ||
errorType == ErrorType::SYNTAX_ERROR || errorType == ErrorType::TYPE_ERROR ||
errorType == ErrorType::URI_ERROR || errorType == ErrorType::OOM_ERROR,
errorType == ErrorType::URI_ERROR || errorType == ErrorType::OOM_ERROR ||
errorType == ErrorType::TERMINATION_ERROR,
"The error type is not in the valid range.");
if (data != nullptr) {
JSHandle<EcmaString> handleMsg = NewFromUtf8(data);
@ -854,6 +855,9 @@ JSHandle<JSObject> ObjectFactory::NewJSError(const ErrorType &errorType, const J
case ErrorType::OOM_ERROR:
nativeConstructor = env->GetOOMErrorFunction();
break;
case ErrorType::TERMINATION_ERROR:
nativeConstructor = env->GetTerminationErrorFunction();
break;
default:
nativeConstructor = env->GetErrorFunction();
break;
@ -937,6 +941,7 @@ void ObjectFactory::InitializeJSObject(const JSHandle<JSObject> &obj, const JSHa
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_TERMINATION_ERROR:
case JSType::JS_ASYNCITERATOR:
case JSType::JS_ITERATOR: {
break;

View File

@ -20,7 +20,6 @@
namespace panda::ecmascript {
static constexpr uint16_t THOUSAND = 1000;
static constexpr int SEC_PER_MINUTE = 60;
static constexpr int MIN_PER_HOUR = 60;
int64_t GetLocalOffsetFromOS(int64_t timeMs, bool isLocal)
{
@ -38,7 +37,7 @@ int64_t GetLocalOffsetFromOS(int64_t timeMs, bool isLocal)
return 0;
}
return (t->tm_gmtoff / SEC_PER_MINUTE - (t->tm_isdst > 0 ? MIN_PER_HOUR : 0));
return t->tm_gmtoff / SEC_PER_MINUTE;
}
bool IsDst(int64_t timeMs)

View File

@ -117,7 +117,7 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
preIsWord = IsWordChar(PeekPrevChar(currentPtr_, input_));
}
bool currentIsWord = IsWordChar(PeekChar(currentPtr_, inputEnd_));
bool currentIsWord = !IsEOF() && IsWordChar(PeekChar(currentPtr_, inputEnd_));
if (((opCode == RegExpOpCode::OP_WORD_BOUNDARY) &&
((!preIsWord && currentIsWord) || (preIsWord && !currentIsWord))) ||
((opCode == RegExpOpCode::OP_NOT_WORD_BOUNDARY) &&

View File

@ -398,6 +398,8 @@ namespace panda::ecmascript {
V(Error, AggregateErrorToString) \
V(Error, OOMErrorConstructor) \
V(Error, OOMErrorToString) \
V(Error, TerminationErrorConstructor) \
V(Error, TerminationErrorToString) \
V(Function, Constructor) \
V(Function, PrototypeApply) \
V(Function, PrototypeBind) \

View File

@ -54,7 +54,8 @@ void Snapshot::Serialize(TaggedObject *objectHeader, const JSPandaFile *jsPandaF
std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
if (!writer.good()) {
writer.close();
LOG_FULL(FATAL) << "snapshot open file failed";
LOG_FULL(ERROR) << "snapshot open file failed";
return;
}
SnapshotProcessor processor(vm_);
@ -82,7 +83,8 @@ void Snapshot::Serialize(uintptr_t startAddr, size_t size, const CString &fileNa
std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
if (!writer.good()) {
writer.close();
LOG_FULL(FATAL) << "snapshot open file failed";
LOG_FULL(ERROR) << "snapshot open file failed";
return;
}
SnapshotProcessor processor(vm_);
@ -109,7 +111,8 @@ void Snapshot::SerializeBuiltins(const CString &fileName)
std::fstream write(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::app);
if (!write.good()) {
write.close();
LOG_FULL(FATAL) << "snapshot open file failed";
LOG_FULL(ERROR) << "snapshot open file failed";
return;
}
// if builtins.snapshot file has exist, return directly
if (write.tellg()) {

View File

@ -2718,30 +2718,30 @@ void RuntimeStubs::EndCallTimer(uintptr_t argGlue, JSTaggedType func)
uint32_t RuntimeStubs::ComputeHashcode(JSTaggedType ecmaString)
{
auto string = reinterpret_cast<EcmaString *>(ecmaString);
uint32_t result = EcmaStringAccessor(string).ComputeHashcode(0);
return result;
return EcmaStringAccessor(string).ComputeHashcode();
}
int32_t RuntimeStubs::StringGetStart(bool isUtf8, EcmaString *srcString, int32_t length)
int32_t RuntimeStubs::StringGetStart(bool isUtf8, EcmaString *srcString, int32_t length, int32_t startIndex)
{
DISALLOW_GARBAGE_COLLECTION;
if (isUtf8) {
Span<const uint8_t> data(EcmaStringAccessor(srcString).GetDataUtf8(), length);
Span<const uint8_t> data(EcmaStringAccessor(srcString).GetDataUtf8() + startIndex, length);
return static_cast<int32_t>(base::StringHelper::GetStart(data, length));
} else {
Span<const uint16_t> data(EcmaStringAccessor(srcString).GetDataUtf16(), length);
Span<const uint16_t> data(EcmaStringAccessor(srcString).GetDataUtf16() + startIndex, length);
return static_cast<int32_t>(base::StringHelper::GetStart(data, length));
}
}
int32_t RuntimeStubs::StringGetEnd(bool isUtf8, EcmaString *srcString, int32_t start, int32_t length)
int32_t RuntimeStubs::StringGetEnd(bool isUtf8, EcmaString *srcString,
int32_t start, int32_t length, int32_t startIndex)
{
DISALLOW_GARBAGE_COLLECTION;
if (isUtf8) {
Span<const uint8_t> data(EcmaStringAccessor(srcString).GetDataUtf8(), length);
Span<const uint8_t> data(EcmaStringAccessor(srcString).GetDataUtf8() + startIndex, length);
return base::StringHelper::GetEnd(data, start, length);
} else {
Span<const uint16_t> data(EcmaStringAccessor(srcString).GetDataUtf16(), length);
Span<const uint16_t> data(EcmaStringAccessor(srcString).GetDataUtf16() + startIndex, length);
return base::StringHelper::GetEnd(data, start, length);
}
}
@ -2784,6 +2784,63 @@ DEF_RUNTIME_STUBS(ObjectSlowAssign)
return builtins::BuiltinsObject::AssignTaggedValue(thread, source, toAssign).GetRawData();
}
DEF_RUNTIME_STUBS(LocaleCompareWithGc)
{
RUNTIME_STUBS_HEADER(LocaleCompareWithGc);
JSHandle<JSTaggedValue> locales = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<EcmaString> thisHandle = GetHArg<EcmaString>(argv, argc, 1); // 1: means the first parameter
JSHandle<EcmaString> thatHandle = GetHArg<EcmaString>(argv, argc, 2); // 2: means the second parameter
JSHandle<JSTaggedValue> options = GetHArg<JSTaggedValue>(argv, argc, 3); // 3: means the third parameter
bool cacheable = options->IsUndefined() && (locales->IsUndefined() || locales->IsString());
return builtins::BuiltinsString::LocaleCompareGC(thread, locales, thisHandle, thatHandle,
options, cacheable).GetRawData();
}
JSTaggedValue RuntimeStubs::LocaleCompareNoGc(uintptr_t argGlue, JSTaggedType locales, EcmaString *thisHandle,
EcmaString *thatHandle)
{
DISALLOW_GARBAGE_COLLECTION;
auto thread = JSThread::GlueToJSThread(argGlue);
auto collator = JSCollator::GetCachedIcuCollator(thread, JSTaggedValue(locales));
JSTaggedValue result = JSTaggedValue::Undefined();
if (collator != nullptr) {
result = JSCollator::CompareStrings(collator, thisHandle, thatHandle);
}
return result;
}
DEF_RUNTIME_STUBS(ArrayForEachContinue)
{
RUNTIME_STUBS_HEADER(ArrayForEachContinue);
JSHandle<JSTaggedValue> thisArgHandle = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSMutableHandle<JSTaggedValue> key(thread, GetHArg<JSTaggedValue>(argv, argc, 1)); // 1: means the first parameter
JSHandle<JSTaggedValue> thisObjVal = GetHArg<JSTaggedValue>(argv, argc, 2); // 2: means the second parameter
JSHandle<JSTaggedValue> callbackFnHandle = GetHArg<JSTaggedValue>(argv, argc, 3); // 3: means the third parameter
JSHandle<JSTaggedValue> lengthHandle = GetHArg<JSTaggedValue>(argv, argc, 4); // 4: means the fourth parameter
const uint32_t argsLength = 3; // 3: «kValue, k, O»
uint32_t i = key->GetInt();
uint32_t len = lengthHandle->GetInt();
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
while (i < len) {
bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, i);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
if (exists) {
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, i);
key.Update(JSTaggedValue(i));
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult.GetRawData());
}
i++;
}
return JSTaggedValue::Undefined().GetRawData();
}
void RuntimeStubs::Initialize(JSThread *thread)
{
#define DEF_RUNTIME_STUB(name) kungfu::RuntimeStubCSigns::ID_##name

View File

@ -130,6 +130,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(ComputeHashcode) \
V(JSHClassFindProtoTransitions) \
V(NumberHelperStringToDouble) \
V(LocaleCompareNoGc) \
V(StringGetStart) \
V(StringGetEnd)
@ -336,7 +337,9 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(LinkedHashMapComputeCapacity) \
V(LinkedHashSetComputeCapacity) \
V(JSObjectGrowElementsCapacity) \
V(HClassCloneWithAddProto)
V(HClassCloneWithAddProto) \
V(LocaleCompareWithGc) \
V(ArrayForEachContinue)
#define RUNTIME_STUB_LIST(V) \
RUNTIME_ASM_STUB_LIST(V) \
@ -413,6 +416,8 @@ public:
static bool BigIntSameValueZero(JSTaggedType key, JSTaggedType other);
static JSTaggedValue JSHClassFindProtoTransitions(JSHClass *cls, JSTaggedValue key, JSTaggedValue proto);
static JSTaggedValue NumberHelperStringToDouble(EcmaString *str);
static JSTaggedValue LocaleCompareNoGc(uintptr_t argGlue, JSTaggedType locales, EcmaString *thisHandle,
EcmaString *thatHandle);
static double TimeClip(double time);
static double SetDateValues(double year, double month, double day);
static void StartCallTimer(uintptr_t argGlue, JSTaggedType func, bool isAot);
@ -422,8 +427,8 @@ public:
static JSTaggedValue CallBoundFunction(EcmaRuntimeCallInfo *info);
static uint32_t ComputeHashcode(JSTaggedType ecmaString);
static int32_t StringGetStart(bool isUtf8, EcmaString *srcString, int32_t length);
static int32_t StringGetEnd(bool isUtf8, EcmaString *srcString, int32_t start, int32_t length);
static int32_t StringGetStart(bool isUtf8, EcmaString *srcString, int32_t length, int32_t startIndex);
static int32_t StringGetEnd(bool isUtf8, EcmaString *srcString, int32_t start, int32_t length, int32_t startIndex);
private:
static void DumpToStreamWithHint(std::ostream &out, std::string_view prompt, JSTaggedValue value);
static void PrintHeapReginInfo(uintptr_t argGlue);

Some files were not shown because too many files have changed in this diff Show More