mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
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:
commit
f6e99c783c
4
BUILD.gn
4
BUILD.gn
@ -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/*",
|
||||
]
|
||||
|
||||
|
@ -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)
|
||||
|
||||
字节码执行:
|
||||
```
|
||||
|
@ -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;
|
||||
|
@ -29,6 +29,7 @@ enum class ErrorType : uint8_t {
|
||||
URI_ERROR,
|
||||
AGGREGATE_ERROR,
|
||||
OOM_ERROR,
|
||||
TERMINATION_ERROR,
|
||||
};
|
||||
} // namespace panda::ecmascript::base
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -44,12 +44,14 @@ 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).
|
||||
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)).
|
||||
@ -60,6 +62,9 @@ JSTaggedValue BuiltinsNumber::NumberConstructor(EcmaRuntimeCallInfo *argv)
|
||||
// c. Otherwise, let n be prim.
|
||||
numberValue = JSTaggedNumber(numericVal.GetTaggedValue());
|
||||
}
|
||||
} else {
|
||||
numberValue = JSTaggedNumber(value.GetTaggedValue());
|
||||
}
|
||||
}
|
||||
// 3. If NewTarget is undefined, return n.
|
||||
if (newTarget->IsUndefined()) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -60,6 +60,7 @@ struct CompilationOptions {
|
||||
bool isEnableCollectLiteralInfo_;
|
||||
bool isEnableOptConstantFolding_;
|
||||
bool isEnableLexenvSpecialization_;
|
||||
bool isEnableNativeInline_;
|
||||
};
|
||||
|
||||
class CompilationPreprocessor {
|
||||
|
@ -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)
|
||||
|
@ -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, ¬Empty);
|
||||
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, ¬TrimStart);
|
||||
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(¬TrimStart);
|
||||
}
|
||||
Bind(¬TrimStart);
|
||||
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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, ¬NumberBranch);
|
||||
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_);
|
||||
|
@ -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);
|
||||
|
@ -471,6 +471,7 @@ private:
|
||||
V(CreateJSMapIterator) \
|
||||
V(JSHClassFindProtoTransitions) \
|
||||
V(NumberHelperStringToDouble) \
|
||||
V(LocaleCompareNoGc) \
|
||||
V(StringGetStart) \
|
||||
V(StringGetEnd)
|
||||
|
||||
|
@ -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, ¬X);
|
||||
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, ¬X);
|
||||
Bind(&isX);
|
||||
{
|
||||
|
@ -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);
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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); \
|
||||
{ \
|
||||
Jump(&dispatch); \
|
||||
} \
|
||||
Bind(&initialized); \
|
||||
|
@ -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
|
||||
|
@ -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, ¬Integer);
|
||||
Bind(&integer);
|
||||
{
|
||||
hash = Int32Or(rawHashcode, Int32(EcmaString::IS_INTEGER_MASK));
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(¬Integer);
|
||||
{
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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), ¬OverFlow, &isOverFlow);
|
||||
builder_.Bind(¬OverFlow);
|
||||
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);
|
||||
{
|
||||
|
239
ecmascript/compiler/native_inline_lowering.cpp
Normal file
239
ecmascript/compiler/native_inline_lowering.cpp
Normal 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
|
67
ecmascript/compiler/native_inline_lowering.h
Normal file
67
ecmascript/compiler/native_inline_lowering.h
Normal 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
|
@ -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);
|
||||
|
@ -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,9 +416,7 @@ 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);
|
||||
@ -425,6 +424,13 @@ public:
|
||||
visitor.VisitGraph();
|
||||
visitor.PrintLog("lexicalEnvSpecialization");
|
||||
lexicalEnvSpecialization.PrintSpecializeId();
|
||||
}
|
||||
|
||||
if (passOptions->EnableInlineNative()) {
|
||||
NativeInlineLowering nativeInline(data->GetCircuit(), data->GetPassContext(), enableLog,
|
||||
data->GetMethodName());
|
||||
nativeInline.RunNativeInlineLowering();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -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: \
|
||||
|
@ -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, ¬Number);
|
||||
builder_.Bind(¬Number);
|
||||
{
|
||||
@ -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, ¬Number);
|
||||
builder_.Bind(¬Number);
|
||||
{
|
||||
@ -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, ¬AsyncGeneratorObj);
|
||||
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));
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
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;
|
||||
|
@ -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 { \
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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];
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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") \
|
||||
|
@ -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) \
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */\
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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() &&
|
||||
|
@ -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();
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -459,22 +459,9 @@ JSHandle<SourceTextModule> SourceTextModule::GetModuleFromBinding(JSThread *thre
|
||||
return JSHandle<SourceTextModule>(thread, binding->GetModule());
|
||||
}
|
||||
|
||||
int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
|
||||
bool excuteFromJob)
|
||||
int SourceTextModule::HandleInstantiateException([[maybe_unused]] JSHandle<SourceTextModule> &module,
|
||||
const CVector<JSHandle<SourceTextModule>> &stack, int result)
|
||||
{
|
||||
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Instantiate");
|
||||
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::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".
|
||||
@ -492,6 +479,25 @@ int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
|
||||
// c. return result
|
||||
return result;
|
||||
}
|
||||
|
||||
int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
|
||||
bool excuteFromJob)
|
||||
{
|
||||
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Instantiate");
|
||||
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::InnerModuleInstantiation(thread, moduleRecord, stack, 0, excuteFromJob);
|
||||
// 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.
|
||||
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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) &&
|
||||
|
@ -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) \
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -38,9 +38,12 @@ int NameDictionary::Hash(const JSTaggedValue &key)
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// for ohmurl path to compute hash code
|
||||
int NameDictionary::Hash(const uint8_t* str, int strSize)
|
||||
{
|
||||
return EcmaString::ComputeHashForData(str, strSize, 0);
|
||||
uint32_t hash = EcmaString::ComputeHashForData(str, strSize, 0);
|
||||
// url path can not be small int.
|
||||
return EcmaString::MixHashcode(hash, EcmaString::NOT_INTEGER);
|
||||
}
|
||||
|
||||
bool NameDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
|
||||
|
@ -432,6 +432,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
|
||||
case JSType::JS_ARGUMENTS:
|
||||
case JSType::JS_SYNTAX_ERROR:
|
||||
case JSType::JS_OOM_ERROR:
|
||||
case JSType::JS_TERMINATION_ERROR:
|
||||
case JSType::JS_OBJECT: {
|
||||
CHECK_DUMP_FIELDS(ECMAObject::SIZE, JSObject::SIZE, 2U);
|
||||
JSHandle<JSObject> jsObj = NewJSObject(thread, factory, globalEnv);
|
||||
|
@ -388,4 +388,53 @@ HWTEST_F_L0(GCTest, NoFullConcurrentMarkOldGCTrigger)
|
||||
#endif
|
||||
}
|
||||
|
||||
HWTEST_F_L0(GCTest, ArkToolsHintGC)
|
||||
{
|
||||
Heap *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
|
||||
heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::CONFIG_DISABLE);
|
||||
auto getSizeAfterCreateAndCallHintGC = [this, heap] (size_t &newSize, size_t &finalSize) -> bool {
|
||||
{
|
||||
[[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
|
||||
for (int i = 0; i < 500; i++) {
|
||||
[[maybe_unused]] JSHandle<TaggedArray> obj = thread->GetEcmaVM()->GetFactory()->
|
||||
NewTaggedArray(10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
|
||||
}
|
||||
newSize = heap->GetCommittedSize();
|
||||
}
|
||||
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 0);
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
|
||||
JSTaggedValue result = builtins::BuiltinsArkTools::HintGC(ecmaRuntimeCallInfo);
|
||||
finalSize = heap->GetCommittedSize();
|
||||
|
||||
return result.ToBoolean();
|
||||
};
|
||||
{
|
||||
// Test HintGC() when sensitive.
|
||||
heap->CollectGarbage(TriggerGCType::FULL_GC);
|
||||
heap->NotifyHighSensitive(true);
|
||||
size_t originSize = heap->GetCommittedSize();
|
||||
size_t newSize = 0;
|
||||
size_t finalSize = 0;
|
||||
bool res = getSizeAfterCreateAndCallHintGC(newSize, finalSize);
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_TRUE(newSize > originSize);
|
||||
EXPECT_TRUE(finalSize == newSize);
|
||||
heap->NotifyHighSensitive(false);
|
||||
}
|
||||
{
|
||||
// Test HintGC() when in background.
|
||||
heap->CollectGarbage(TriggerGCType::FULL_GC);
|
||||
heap->ChangeGCParams(true);
|
||||
size_t originSize = heap->GetCommittedSize();
|
||||
size_t newSize = 0;
|
||||
size_t finalSize = 0;
|
||||
bool res = getSizeAfterCreateAndCallHintGC(newSize, finalSize);
|
||||
EXPECT_TRUE(res);
|
||||
EXPECT_TRUE(newSize > originSize);
|
||||
EXPECT_TRUE(finalSize < newSize);
|
||||
heap->ChangeGCParams(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::test
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user