From 3c9d7548508a75c9b3569bf0f565d3beab390583 Mon Sep 17 00:00:00 2001 From: huangzhenghua Date: Tue, 30 May 2023 15:10:53 +0800 Subject: [PATCH 001/438] add IsJSArray in jsnapi issue: https://gitee.com/openharmony/arkui_napi/issues/I78C8E Signed-off-by: huangzhenghua Change-Id: I4ac15f8348a2312f965ec36f547c9cbe71e012df --- ecmascript/napi/include/jsnapi.h | 1 + ecmascript/napi/jsnapi.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 05e5ede69..0f92461fe 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -412,6 +412,7 @@ public: bool IsSymbol(); bool IsObject(); bool IsArray(const EcmaVM *vm); + bool IsJSArray(const EcmaVM *vm); bool IsConstructor(); bool IsFunction(); bool IsProxy(); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index d74e81629..ab91f0433 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -2744,6 +2744,12 @@ bool JSValueRef::IsArray(const EcmaVM *vm) return JSNApiHelper::ToJSTaggedValue(this).IsArray(thread); } +bool JSValueRef::IsJSArray(const EcmaVM *vm) +{ + CHECK_HAS_PENDING_EXCEPTION(vm, false); + return JSNApiHelper::ToJSTaggedValue(this).IsJSArray(); +} + bool JSValueRef::IsConstructor() { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); -- Gitee From 137aebc5be46b6eebea390f59c542b53f1c8e959 Mon Sep 17 00:00:00 2001 From: huangtianzhi Date: Tue, 27 Jun 2023 15:47:45 +0800 Subject: [PATCH 002/438] Optimized local variables display logic to only show them in their scope Signed-off-by: huangtianzhi --- ecmascript/debugger/debugger_api.cpp | 9 ++++---- .../jspandafile/debug_info_extractor.cpp | 22 +++++++++++++++++-- ecmascript/jspandafile/debug_info_extractor.h | 11 ++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/ecmascript/debugger/debugger_api.cpp b/ecmascript/debugger/debugger_api.cpp index 65e2e8a22..b79a901cb 100644 --- a/ecmascript/debugger/debugger_api.cpp +++ b/ecmascript/debugger/debugger_api.cpp @@ -149,11 +149,12 @@ int32_t DebuggerApi::GetVregIndex(const FrameHandler *frameHandler, std::string_ return -1; } auto table = extractor->GetLocalVariableTable(method->GetMethodId()); - auto iter = table.find(name.data()); - if (iter == table.end()) { - return -1; + for (auto iter = table.begin(); iter != table.end(); iter++) { + if (iter->name == name.data()) { + return iter->reg_number; + } } - return iter->second; + return -1; } Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, diff --git a/ecmascript/jspandafile/debug_info_extractor.cpp b/ecmascript/jspandafile/debug_info_extractor.cpp index 01176395b..c2e52c5a2 100644 --- a/ecmascript/jspandafile/debug_info_extractor.cpp +++ b/ecmascript/jspandafile/debug_info_extractor.cpp @@ -55,6 +55,13 @@ public: void ProcessEnd() { + // When process ends, update any variableInfo + // with end_offset = 0, set it to the state address. + for (auto iter = lvt_.begin(); iter != lvt_.end(); iter++) { + if (iter->end_offset == 0) { + iter->end_offset = state_->GetAddress(); + } + } } bool HandleAdvanceLine(int32_t lineDiff) const @@ -93,21 +100,32 @@ public: bool HandleStartLocal(int32_t regNumber, uint32_t nameId, [[maybe_unused]] uint32_t typeId) { + // start_offset is the current state address, end_offset will temporarily be 0 here, + // then being updated inside the HandleEndLocal method. + uint32_t start_offset = state_->GetAddress(), end_offset = 0; const char *name = GetStringFromConstantPool(state_->GetPandaFile(), nameId); - lvt_.emplace(name, regNumber); + lvt_.push_back({name, regNumber, start_offset, end_offset}); return true; } bool HandleStartLocalExtended(int32_t regNumber, uint32_t nameId, [[maybe_unused]] uint32_t typeId, [[maybe_unused]] uint32_t typeSignatureId) { + uint32_t start_offset = state_->GetAddress(), end_offset = 0; const char *name = GetStringFromConstantPool(state_->GetPandaFile(), nameId); - lvt_.emplace(name, regNumber); + lvt_.push_back({name, regNumber, start_offset, end_offset}); return true; } bool HandleEndLocal([[maybe_unused]] int32_t regNumber) { + for (auto iter = lvt_.rbegin(); iter != lvt_.rend(); iter++) { + // reversely finds the variable and updates its end_offset to be state address + if (iter->reg_number == regNumber) { + iter->end_offset = state_->GetAddress(); + break; + } + } return true; } diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h index a205f880f..372155255 100644 --- a/ecmascript/jspandafile/debug_info_extractor.h +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -56,7 +56,8 @@ using ColumnNumberTable = CVector; using JSPtLocation = tooling::JSPtLocation; /* - * LocalVariableInfo define in frontend, now only use name and regNumber: + * Full version of LocalVariableInfo is defined in frontend, + * here only using name, reg_number, start_offset, and end_offset: * std::string name * std::string type * std::string typeSignature @@ -64,7 +65,13 @@ using JSPtLocation = tooling::JSPtLocation; * uint32_t startOffset * uint32_t endOffset */ -using LocalVariableTable = CUnorderedMap; // name, regNumber +struct LocalVariableInfo { + std::string name + int32_t reg_number; + uint32_t start_offset; + uint32_t end_offset; +}; +using LocalVariableTable = CVector; // public for debugger class PUBLIC_API DebugInfoExtractor { -- Gitee From c50539a27b69826d7f66252b7866b49a70e0d8b2 Mon Sep 17 00:00:00 2001 From: "zha.wei" Date: Tue, 27 Jun 2023 21:09:25 +0800 Subject: [PATCH 003/438] =?UTF-8?q?description:ECMA=202022=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E6=94=AF=E6=8C=81TaggedArray.At?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zha.wei --- ecmascript/builtins/builtins_array.cpp | 3 ++ ecmascript/js_stable_array.cpp | 23 +++++++++ ecmascript/js_stable_array.h | 1 + ecmascript/tests/js_stable_array_test.cpp | 63 +++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index e82fa47d7..83c20baf1 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -2935,6 +2935,9 @@ JSTaggedValue BuiltinsArray::At(EcmaRuntimeCallInfo *argv) // 1. Let O be ToObject(this value). JSHandle thisHandle = GetThis(argv); + if (thisHandle->IsStableJSArray(thread)) { + return JSStableArray::At(JSHandle::Cast(thisHandle), argv); + } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 94f85eb80..2cd9c1393 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -658,4 +658,27 @@ JSTaggedValue JSStableArray::FastCopyFromArrayToTypedArray(JSThread *thread, JSH } return JSTaggedValue::Undefined(); } + +JSTaggedValue JSStableArray::At(JSHandle receiver, EcmaRuntimeCallInfo *argv) +{ + JSThread *thread = argv->GetThread(); + uint32_t thisLen = receiver->GetArrayLength(); + if (thisLen == 0) { + return JSTaggedValue::Undefined(); + } + JSTaggedNumber index = JSTaggedValue::ToInteger(thread, base::BuiltinsBase::GetCallArg(argv, 0)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int64_t relativeIndex = index.GetNumber(); + int64_t k = 0; + if (relativeIndex >= 0) { + k = relativeIndex; + } else { + k = thisLen + relativeIndex; + } + if (k < 0 || k >= thisLen) { + return JSTaggedValue::Undefined(); + } + TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); + return elements->Get(k); +} } // namespace panda::ecmascript diff --git a/ecmascript/js_stable_array.h b/ecmascript/js_stable_array.h index 48da8cb0f..96e59ffc9 100644 --- a/ecmascript/js_stable_array.h +++ b/ecmascript/js_stable_array.h @@ -53,6 +53,7 @@ public: static JSTaggedValue FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle &target, DataViewType targetType, uint32_t targetOffset, uint32_t srcLength, JSHandle &elements); + static JSTaggedValue At(JSHandle receiver, EcmaRuntimeCallInfo *argv); }; } // namespace panda::ecmascript #endif // ECMASCRIPT_JS_STABLE_ARRAY_H diff --git a/ecmascript/tests/js_stable_array_test.cpp b/ecmascript/tests/js_stable_array_test.cpp index f9edeccf3..93dade959 100644 --- a/ecmascript/tests/js_stable_array_test.cpp +++ b/ecmascript/tests/js_stable_array_test.cpp @@ -342,4 +342,67 @@ HWTEST_F_L0(JSStableArrayTest, Join_StringElements_DefinedSep) EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "a <> a <> a <> a <> a <> a <> a <> a <> a <> a"); } + +/** + * @tc.name: At + * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the + EcmaRuntimeCallInfo an number as the index, check whether the element returned through calling + At function with the source Array and the EcmaRuntimeCallInfo is within expectations. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JSStableArrayTest, At_NUMBER_INDEX) +{ + ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); + + int32_t lengthArr = 10; + JSHandle handleTagArr(objFactory->NewTaggedArray(lengthArr)); + for (int i = 0; i < lengthArr; i++) { + handleTagArr->Set(thread, i, JSTaggedValue(i)); + } + JSHandle handleArr(JSArray::CreateArrayFromList(thread, handleTagArr)); + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(0)); + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + JSTaggedValue thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 0); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(9)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 9); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(-1)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 9); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(10)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue, JSTaggedValue::Undefined()); +} } // namespace panda::test \ No newline at end of file -- Gitee From f8e4c5ea4abf30bb92da8a5cf4cd8e5b0ad9b110 Mon Sep 17 00:00:00 2001 From: "zha.wei" Date: Tue, 27 Jun 2023 21:09:25 +0800 Subject: [PATCH 004/438] =?UTF-8?q?description:ECMA=202022=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E6=94=AF=E6=8C=81TaggedArray.At?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zha.wei --- ecmascript/builtins/builtins_array.cpp | 3 ++ ecmascript/js_stable_array.cpp | 25 +++++++++ ecmascript/js_stable_array.h | 1 + ecmascript/tests/js_stable_array_test.cpp | 63 +++++++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index e82fa47d7..83c20baf1 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -2935,6 +2935,9 @@ JSTaggedValue BuiltinsArray::At(EcmaRuntimeCallInfo *argv) // 1. Let O be ToObject(this value). JSHandle thisHandle = GetThis(argv); + if (thisHandle->IsStableJSArray(thread)) { + return JSStableArray::At(JSHandle::Cast(thisHandle), argv); + } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 94f85eb80..8ec6c3e94 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -658,4 +658,29 @@ JSTaggedValue JSStableArray::FastCopyFromArrayToTypedArray(JSThread *thread, JSH } return JSTaggedValue::Undefined(); } + +JSTaggedValue JSStableArray::At(JSHandle receiver, EcmaRuntimeCallInfo *argv) +{ + JSThread *thread = argv->GetThread(); + uint32_t thisLen = receiver->GetArrayLength(); + if (thisLen == 0) { + return JSTaggedValue::Undefined(); + } + JSTaggedNumber index = JSTaggedValue::ToInteger(thread, base::BuiltinsBase::GetCallArg(argv, 0)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int64_t relativeIndex = index.GetNumber(); + int64_t k = 0; + if (relativeIndex >= 0) { + k = relativeIndex; + } else { + k = thisLen + relativeIndex; + } + if (k < 0 || k >= thisLen) { + return JSTaggedValue::Undefined(); + } + + JSHandle taggedValue = JSArray::FastGetPropertyByValue(thread, JSHandle(receiver), k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return taggedValue.GetTaggedValue(); +} } // namespace panda::ecmascript diff --git a/ecmascript/js_stable_array.h b/ecmascript/js_stable_array.h index 48da8cb0f..96e59ffc9 100644 --- a/ecmascript/js_stable_array.h +++ b/ecmascript/js_stable_array.h @@ -53,6 +53,7 @@ public: static JSTaggedValue FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle &target, DataViewType targetType, uint32_t targetOffset, uint32_t srcLength, JSHandle &elements); + static JSTaggedValue At(JSHandle receiver, EcmaRuntimeCallInfo *argv); }; } // namespace panda::ecmascript #endif // ECMASCRIPT_JS_STABLE_ARRAY_H diff --git a/ecmascript/tests/js_stable_array_test.cpp b/ecmascript/tests/js_stable_array_test.cpp index f9edeccf3..93dade959 100644 --- a/ecmascript/tests/js_stable_array_test.cpp +++ b/ecmascript/tests/js_stable_array_test.cpp @@ -342,4 +342,67 @@ HWTEST_F_L0(JSStableArrayTest, Join_StringElements_DefinedSep) EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "a <> a <> a <> a <> a <> a <> a <> a <> a <> a"); } + +/** + * @tc.name: At + * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the + EcmaRuntimeCallInfo an number as the index, check whether the element returned through calling + At function with the source Array and the EcmaRuntimeCallInfo is within expectations. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JSStableArrayTest, At_NUMBER_INDEX) +{ + ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); + + int32_t lengthArr = 10; + JSHandle handleTagArr(objFactory->NewTaggedArray(lengthArr)); + for (int i = 0; i < lengthArr; i++) { + handleTagArr->Set(thread, i, JSTaggedValue(i)); + } + JSHandle handleArr(JSArray::CreateArrayFromList(thread, handleTagArr)); + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(0)); + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + JSTaggedValue thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 0); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(9)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 9); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(-1)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue.GetNumber(), 9); + + ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(10)); + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + + thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(thisTagValue, JSTaggedValue::Undefined()); +} } // namespace panda::test \ No newline at end of file -- Gitee From 8dfe6ffd1697a934fa951f5384b161bc5c578229 Mon Sep 17 00:00:00 2001 From: huangtianzhi Date: Thu, 29 Jun 2023 09:39:13 +0800 Subject: [PATCH 005/438] fix grammar error Signed-off-by: huangtianzhi --- ecmascript/jspandafile/debug_info_extractor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h index 372155255..a7266e852 100644 --- a/ecmascript/jspandafile/debug_info_extractor.h +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -66,7 +66,7 @@ using JSPtLocation = tooling::JSPtLocation; * uint32_t endOffset */ struct LocalVariableInfo { - std::string name + std::string name; int32_t reg_number; uint32_t start_offset; uint32_t end_offset; -- Gitee From 2e8a9716f9027e111b4be7120ef0a3e40fbf37b2 Mon Sep 17 00:00:00 2001 From: huangtianzhi Date: Thu, 29 Jun 2023 20:50:27 +0800 Subject: [PATCH 006/438] optimize HandleEndLocal logic Signed-off-by: huangtianzhi --- ecmascript/jspandafile/debug_info_extractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecmascript/jspandafile/debug_info_extractor.cpp b/ecmascript/jspandafile/debug_info_extractor.cpp index c2e52c5a2..5b93a2102 100644 --- a/ecmascript/jspandafile/debug_info_extractor.cpp +++ b/ecmascript/jspandafile/debug_info_extractor.cpp @@ -121,7 +121,7 @@ public: { for (auto iter = lvt_.rbegin(); iter != lvt_.rend(); iter++) { // reversely finds the variable and updates its end_offset to be state address - if (iter->reg_number == regNumber) { + if (iter->reg_number == regNumber && iter->end_offset == 0) { iter->end_offset = state_->GetAddress(); break; } -- Gitee From 70fa8fe91d651b54ee06ce0a4bb7c5a280230397 Mon Sep 17 00:00:00 2001 From: wuwenlu Date: Wed, 28 Jun 2023 01:14:38 -0700 Subject: [PATCH 007/438] cause property for Error objects Signed-off-by: wuwenlu --- ecmascript/base/error_helper.cpp | 18 +++++- ecmascript/base/tests/error_helper_test.cpp | 52 ++++++++++++++++ ecmascript/builtins/builtins_errors.cpp | 16 +++++ .../builtins/tests/builtins_errors_test.cpp | 52 ++++++++++++++++ ecmascript/global_env_constants.cpp | 1 + ecmascript/global_env_constants.h | 1 + test/moduletest/BUILD.gn | 3 + test/moduletest/errorcause/BUILD.gn | 18 ++++++ test/moduletest/errorcause/errorcause.js | 60 +++++++++++++++++++ test/moduletest/errorcause/expect_output.txt | 21 +++++++ 10 files changed, 241 insertions(+), 1 deletion(-) create mode 100755 test/moduletest/errorcause/BUILD.gn create mode 100755 test/moduletest/errorcause/errorcause.js create mode 100755 test/moduletest/errorcause/expect_output.txt diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index 78a0422f1..7b282bd9c 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -166,7 +166,23 @@ JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, [[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread, nativeInstanceObj, msgKey, msgDesc); ASSERT_PRINT(status == true, "return result exception!"); } - + // InstallErrorCause + JSHandle options = BuiltinsBase::GetCallArg(argv, 1); + // If options is an Object and ? HasProperty(options, "cause") is true, then + // a. Let cause be ? Get(options, "cause"). + // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause). + if (options->IsECMAObject()) { + JSHandle causeKey = globalConst->GetHandledCauseString(); + bool causePresent = JSTaggedValue::HasProperty(thread, options, causeKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (causePresent) { + JSHandle cause = JSObject::GetProperty(thread, options, causeKey).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + PropertyDescriptor causeDesc(thread, cause, true, false, true); + [[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread, nativeInstanceObj, causeKey, causeDesc); + ASSERT_PRINT(status == true, "return result exception!"); + } + } JSHandle errorFunc = GetErrorJSFunction(thread); if (!errorFunc->IsUndefined()) { JSHandle errorFunckey = globalConst->GetHandledErrorFuncString(); diff --git a/ecmascript/base/tests/error_helper_test.cpp b/ecmascript/base/tests/error_helper_test.cpp index 3cad7ef13..c006c0dbc 100644 --- a/ecmascript/base/tests/error_helper_test.cpp +++ b/ecmascript/base/tests/error_helper_test.cpp @@ -324,4 +324,56 @@ HWTEST_F_L0(ErrorHelperTest, ErrorCommonConstructor_003) EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(aggregateNameValue)).ToCString().c_str(), "AggregateError"); } + +HWTEST_F_L0(ErrorHelperTest, ErrorCommonConstructor_004) +{ + auto factory = instance->GetFactory(); + auto env = instance->GetGlobalEnv(); + JSHandle msgKey = thread->GlobalConstants()->GetHandledMessageString(); + JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); + JSHandle causeKey = thread->GlobalConstants()->GetHandledCauseString(); + + JSHandle error(env->GetErrorFunction()); + JSHandle typeError(env->GetTypeErrorFunction()); + JSHandle objFun = env->GetObjectFunction(); + JSHandle optionsObj = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); + JSHandle causeValue(factory->NewFromASCII("error cause")); // test error cause + JSObject::SetProperty(thread, optionsObj, causeKey, causeValue); + + JSHandle errorMsg(factory->NewFromASCII("You have an Error!")); + EcmaRuntimeCallInfo *argv1 = + TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*error), 8); // 8 means 2 call args + argv1->SetFunction(error.GetTaggedValue()); + argv1->SetThis(JSTaggedValue(*error)); + argv1->SetCallArg(0, errorMsg.GetTaggedValue()); + argv1->SetCallArg(1, optionsObj.GetTaggedValue()); + auto prev1 = TestHelper::SetupFrame(thread, argv1); + JSHandle errorResult(thread, ErrorHelper::ErrorCommonConstructor(argv1, ErrorType::ERROR)); + TestHelper::TearDownFrame(thread, prev1); + JSHandle errorMsgValue(JSObject::GetProperty(thread, errorResult, msgKey).GetValue()); + JSHandle errorNameValue(JSObject::GetProperty(thread, errorResult, nameKey).GetValue()); + JSHandle errorCauseValue(JSObject::GetProperty(thread, errorResult, causeKey).GetValue()); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(errorMsgValue)).ToCString().c_str(), + "You have an Error!"); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(errorNameValue)).ToCString().c_str(), "Error"); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(errorCauseValue)).ToCString().c_str(), "error cause"); + + JSHandle typeErrorMsg(factory->NewFromASCII("You have a type error!")); + EcmaRuntimeCallInfo *argv2 = + TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*typeError), 8); // 8 means 2 call args + argv2->SetFunction(typeError.GetTaggedValue()); + argv2->SetThis(JSTaggedValue(*typeError)); + argv2->SetCallArg(0, typeErrorMsg.GetTaggedValue()); + argv2->SetCallArg(1, optionsObj.GetTaggedValue()); + auto prev2 = TestHelper::SetupFrame(thread, argv2); + JSHandle typeErrorResult(thread, ErrorHelper::ErrorCommonConstructor(argv2, ErrorType::TYPE_ERROR)); + TestHelper::TearDownFrame(thread, prev2); + JSHandle typeMsgValue(JSObject::GetProperty(thread, typeErrorResult, msgKey).GetValue()); + JSHandle typeNameValue(JSObject::GetProperty(thread, typeErrorResult, nameKey).GetValue()); + JSHandle typeCauseValue(JSObject::GetProperty(thread, typeErrorResult, causeKey).GetValue()); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(typeMsgValue)).ToCString().c_str(), + "You have a type error!"); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(typeNameValue)).ToCString().c_str(), "TypeError"); + EXPECT_STREQ(EcmaStringAccessor(JSHandle::Cast(typeCauseValue)).ToCString().c_str(), "error cause"); +} } // namespace panda::test diff --git a/ecmascript/builtins/builtins_errors.cpp b/ecmascript/builtins/builtins_errors.cpp index 8af25081c..4b68aa0f5 100644 --- a/ecmascript/builtins/builtins_errors.cpp +++ b/ecmascript/builtins/builtins_errors.cpp @@ -159,6 +159,22 @@ JSTaggedValue BuiltinsAggregateError::AggregateErrorConstructor(EcmaRuntimeCallI PropertyDescriptor msgDesc(thread, JSHandle::Cast(handleStr), true, false, true); JSTaggedValue::DefinePropertyOrThrow(thread, taggedObj, msgKey, msgDesc); } + // InstallErrorCause + JSHandle options = BuiltinsBase::GetCallArg(argv, 2); + // If options is an Object and ? HasProperty(options, "cause") is true, then + // a. Let cause be ? Get(options, "cause"). + // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause). + if (options->IsECMAObject()) { + JSHandle causeKey = globalConst->GetHandledCauseString(); + bool causePresent = JSTaggedValue::HasProperty(thread, options, causeKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (causePresent) { + JSHandle cause = JSObject::GetProperty(thread, options, causeKey).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + PropertyDescriptor causeDesc(thread, cause, true, false, true); + JSTaggedValue::DefinePropertyOrThrow(thread, taggedObj, causeKey, causeDesc); + } + } // 4. Let errorsList be ? IterableToList(errors). JSHandle errorsList = JSObject::IterableToList(thread, errors); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/ecmascript/builtins/tests/builtins_errors_test.cpp b/ecmascript/builtins/tests/builtins_errors_test.cpp index 307341fd7..025e62012 100644 --- a/ecmascript/builtins/tests/builtins_errors_test.cpp +++ b/ecmascript/builtins/tests/builtins_errors_test.cpp @@ -40,6 +40,7 @@ using TypeError = builtins::BuiltinsTypeError; using URIError = builtins::BuiltinsURIError; using EvalError = builtins::BuiltinsEvalError; using SyntaxError = builtins::BuiltinsSyntaxError; +using AggregateError = builtins::BuiltinsAggregateError; using JSType = ecmascript::JSType; class BuiltinsErrorsTest : public testing::Test { @@ -980,4 +981,55 @@ HWTEST_F_L0(BuiltinsErrorsTest, EvalErrorToString) EXPECT_EQ(EcmaStringAccessor::Compare(instance, factory->NewFromASCII("EvalError: This is EvalError!"), resultHandle), 0); } + +/* + * @tc.name: AggregateErrorParameterConstructor + * @tc.desc: new AggregateError([], "Hello AggregateError", {cause: "error cause"}) + * @tc.type: FUNC + */ +HWTEST_F_L0(BuiltinsErrorsTest, AggregateErrorParameterConstructor) +{ + ObjectFactory *factory = instance->GetFactory(); + JSHandle env = instance->GetGlobalEnv(); + + JSHandle error(env->GetAggregateErrorFunction()); + JSHandle paramMsg(factory->NewFromASCII("Hello AggregateError!")); + + JSHandle errayFunc = env->GetArrayFunction(); + JSHandle newArray = factory->NewJSObjectByConstructor(JSHandle(errayFunc), errayFunc); + + JSHandle causeKey = thread->GlobalConstants()->GetHandledCauseString(); + JSHandle objFun = env->GetObjectFunction(); + JSHandle optionsObj = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); + JSHandle causeValue(factory->NewFromASCII("error cause")); // test error cause + JSObject::SetProperty(thread, optionsObj, causeKey, causeValue); + + auto ecmaRuntimeCallInfo = + TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*error), 10); // 10 means 3 call args + ecmaRuntimeCallInfo->SetFunction(error.GetTaggedValue()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue(*error)); + ecmaRuntimeCallInfo->SetCallArg(0, newArray.GetTaggedValue()); + ecmaRuntimeCallInfo->SetCallArg(1, paramMsg.GetTaggedValue()); + ecmaRuntimeCallInfo->SetCallArg(2, optionsObj.GetTaggedValue()); // 2 means the options arg + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); + JSTaggedValue result = AggregateError::AggregateErrorConstructor(ecmaRuntimeCallInfo); + EXPECT_TRUE(result.IsECMAObject()); + + JSHandle errorObject(thread, reinterpret_cast(result.GetRawData())); + JSHandle msgKey(factory->NewFromASCII("message")); + JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); + + JSHandle msgValue(JSObject::GetProperty(thread, errorObject, msgKey).GetValue()); + ASSERT_EQ(EcmaStringAccessor::Compare(instance, + factory->NewFromASCII("Hello AggregateError!"), JSHandle(msgValue)), 0); + + JSHandle nameValue(JSObject::GetProperty(thread, errorObject, nameKey).GetValue()); + ASSERT_EQ(EcmaStringAccessor::Compare(instance, + factory->NewFromASCII("AggregateError"), JSHandle(nameValue)), 0); + + JSHandle errCauseValue(JSObject::GetProperty(thread, errorObject, causeKey).GetValue()); + ASSERT_EQ(EcmaStringAccessor::Compare(instance, + factory->NewFromASCII("error cause"), JSHandle(errCauseValue)), 0); +} } // namespace panda::test diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 47b2ae39d..f70ecec6b 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -385,6 +385,7 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) SetConstant(ConstantIndex::TO_JSON_STRING_INDEX, factory->NewFromASCIINonMovable("toJSON")); SetConstant(ConstantIndex::GLOBAL_STRING_INDEX, factory->NewFromASCIINonMovable("global")); SetConstant(ConstantIndex::MESSAGE_STRING_INDEX, factory->NewFromASCIINonMovable("message")); + SetConstant(ConstantIndex::CAUSE_STRING_INDEX, factory->NewFromASCIINonMovable("cause")); SetConstant(ConstantIndex::ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("Error")); SetConstant(ConstantIndex::ERRORS_STRING_INDEX, factory->NewFromASCII("errors")); SetConstant(ConstantIndex::AGGREGATE_ERROR_STRING_INDEX, factory->NewFromASCII("AggregateError")); diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 22e0cf14b..74edc91ed 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -246,6 +246,7 @@ class ObjectFactory; V(JSTaggedValue, ToJsonString, TO_JSON_STRING_INDEX, toJSON) \ V(JSTaggedValue, GlobalString, GLOBAL_STRING_INDEX, global) \ V(JSTaggedValue, MessageString, MESSAGE_STRING_INDEX, message) \ + V(JSTaggedValue, CauseString, CAUSE_STRING_INDEX, cause) \ V(JSTaggedValue, ErrorString, ERROR_STRING_INDEX, Error) \ V(JSTaggedValue, RangeErrorString, RANGE_ERROR_STRING_INDEX, RangeError) \ V(JSTaggedValue, ReferenceErrorString, REFERENCE_ERROR_STRING_INDEX, ReferenceError) \ diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 22deccaa5..73dcda71c 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -43,6 +43,7 @@ group("ark_js_moduletest") { "ecmastringtable", "equal", "errorhelper", + "errorcause", "forawaitof", "forin", "fortest", @@ -142,6 +143,7 @@ group("ark_asm_test") { "dyninstruction", "ecmastringtable", "equal", + "errorcause", "forin", "fortest", "generator", @@ -224,6 +226,7 @@ group("ark_asm_single_step_test") { "dynamicimport", "dyninstruction", "ecmastringtable", + "errorcause", "forin", "fortest", "generator", diff --git a/test/moduletest/errorcause/BUILD.gn b/test/moduletest/errorcause/BUILD.gn new file mode 100755 index 000000000..989440cfb --- /dev/null +++ b/test/moduletest/errorcause/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("errorcause") { + deps = [] +} diff --git a/test/moduletest/errorcause/errorcause.js b/test/moduletest/errorcause/errorcause.js new file mode 100755 index 000000000..0b0c33bfc --- /dev/null +++ b/test/moduletest/errorcause/errorcause.js @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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. + */ + +/* + * @tc.name:errorcause + * @tc.desc:test Error Constructors with cause + * @tc.type: FUNC + * @tc.require: issueI7F4Y5 + */ +[ + Error, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError, +].forEach(function (ctor, i) { + if (testErrorCause(ctor)) { + print(ctor.name + " test success !!!") + } else { + print(ctor.name + " test fail !!!") + } +}); + +function testErrorCause(ctor) { + try { + let err = new ctor("message", { cause: "error cause" }); + throw err; + } catch (e) { + if (e.cause == "error cause") { + return true; + } else { + return false; + } + } +} + +let err2 = new AggregateError([], "message", { cause: "error cause" }); +try { + throw err2; +} catch (e) { + if (e.cause == "error cause") { + print(e.name + " test success !!!") + } else { + print(e.name + " test fail !!!") + } +} \ No newline at end of file diff --git a/test/moduletest/errorcause/expect_output.txt b/test/moduletest/errorcause/expect_output.txt new file mode 100755 index 000000000..b0629cc11 --- /dev/null +++ b/test/moduletest/errorcause/expect_output.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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. + +Error test success !!! +EvalError test success !!! +RangeError test success !!! +ReferenceError test success !!! +SyntaxError test success !!! +TypeError test success !!! +URIError test success !!! +AggregateError test success !!! -- Gitee From ba689d6f1fc0e20e719760ab136be37149be64eb Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Wed, 5 Jul 2023 12:03:02 +0800 Subject: [PATCH 008/438] Fix Nan test Fix Nan test fail Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7IJVT Signed-off-by: wengchangcheng Change-Id: I92e86445a647e661f3ad29e447ce03be4d91011f --- ecmascript/tests/js_tagged_number_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ecmascript/tests/js_tagged_number_test.cpp b/ecmascript/tests/js_tagged_number_test.cpp index 22ba97f2a..4df0ae967 100644 --- a/ecmascript/tests/js_tagged_number_test.cpp +++ b/ecmascript/tests/js_tagged_number_test.cpp @@ -68,9 +68,7 @@ HWTEST_F_L0(JSTaggedNumberTest, TaggedNumber_Minus) EXPECT_EQ(result, JSTaggedNumber(static_cast(246.912))); // number is NAN JSTaggedNumber number5(NAN_VALUE); - JSTaggedNumber number6(-NAN_VALUE); - result = number5 - number6; - EXPECT_EQ(result, JSTaggedNumber(NAN_VALUE * 2)); + EXPECT_FALSE(number5.IsImpureNaN(number5.GetNumber())); } HWTEST_F_L0(JSTaggedNumberTest, TaggedNumber_Multiply) -- Gitee From 9d009cfb99aef1f3b4b4453df7e07dd9a4b11840 Mon Sep 17 00:00:00 2001 From: lukai Date: Thu, 18 May 2023 10:57:54 +0800 Subject: [PATCH 009/438] Bugfix: napi_call_function runs microjobs immediately Introduce concept of calldepth to functionref::call, and only the top level of calldepth will run run microjobs Issue: https://gitee.com/openharmony/arkui_napi/issues/I6G7VN?from=project-issue Signed-off-by: lukai Change-Id: I775e0c46491ab16c3be748048153a29a705a973c --- ecmascript/ecma_vm.h | 19 +++++++++++++++++++ ecmascript/napi/include/jsnapi.h | 11 ++++++++++- ecmascript/napi/jsnapi.cpp | 21 +++++++++++++++++---- ecmascript/napi/test/jsnapi_tests.cpp | 9 +++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index cd900d6ce..57f79d4e3 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -417,6 +417,23 @@ public: ASSERT(stringTable_ != nullptr); return stringTable_; } + + void IncreaseCallDepth() + { + callDepth_++; + } + + void DecreaseCallDepth() + { + ASSERT(callDepth_ > 0); + callDepth_--; + } + + bool IsTopLevelCallDepth() + { + return callDepth_ == 0; + } + protected: void PrintJSErrorInfo(const JSHandle &exceptionInfo) const; @@ -489,6 +506,8 @@ private: // PGO Profiler PGOProfiler *pgoProfiler_ {nullptr}; + // c++ call js + size_t callDepth_ {0}; friend class Snapshot; friend class SnapshotProcessor; diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index d9b800922..90103bb1e 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -743,7 +743,7 @@ public: void *data, bool callNapi = false, size_t nativeBindingsize = 0); Local Call(const EcmaVM *vm, Local thisObj, const Local argv[], - int32_t length, bool isNapi = false); + int32_t length); Local Constructor(const EcmaVM *vm, const Local argv[], int32_t length); Local GetFunctionPrototype(const EcmaVM *vm); @@ -1470,6 +1470,15 @@ private: friend class FunctionRef; }; +class PUBLIC_API FunctionCallScope { +public: + FunctionCallScope(EcmaVM *vm); + ~FunctionCallScope(); + +private: + EcmaVM *vm_; +}; + template template Global::Global(const EcmaVM *vm, const Local ¤t) : vm_(vm) diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 13ba56539..1e102842a 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -982,6 +982,20 @@ void JSNApi::DestroyAnDataManager() ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAllData(); } +FunctionCallScope::FunctionCallScope(EcmaVM *vm) : vm_(vm) +{ + vm_->IncreaseCallDepth(); +} + +FunctionCallScope::~FunctionCallScope() +{ + vm_->DecreaseCallDepth(); + if (vm_->IsTopLevelCallDepth()) { + JSThread *thread = vm_->GetJSThread(); + thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); + } +} + // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { @@ -1688,10 +1702,11 @@ Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback na Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) - int32_t length, bool isNapi) + int32_t length) { CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); EscapeLocalScope scope(vm); + FunctionCallScope callScope(EcmaVM::ConstCast(vm)); JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); @@ -1712,9 +1727,6 @@ Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); - if (!isNapi) { - vm->GetJSThread()->GetCurrentEcmaContext()->ExecutePromisePendingJob(); - } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); vm->GetHeap()->ClearKeptObjects(); @@ -1726,6 +1738,7 @@ Local FunctionRef::Constructor(const EcmaVM *vm, int32_t length) { CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); + FunctionCallScope callScope(EcmaVM::ConstCast(vm)); JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index 1d391fdcd..95791ed04 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -1508,4 +1508,13 @@ HWTEST_F_L0(JSNApiTests, PromiseRejectInfo_GetData) void* dataRes = promisereject.GetData(); ASSERT_EQ(dataRes, data); } + +HWTEST_F_L0(JSNApiTests, FunctionCallScope) +{ + { + FunctionCallScope callScope(vm_); + ASSERT_FALSE(vm_->IsTopLevelCallDepth()); + } + ASSERT_TRUE(vm_->IsTopLevelCallDepth()); +} } // namespace panda::test -- Gitee From b8dea93bc9d7ae43bf8ba4dd78f1c5830b1814d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=A5=E7=BB=B4?= Date: Thu, 6 Jul 2023 05:49:07 +0000 Subject: [PATCH 010/438] update ecmascript/js_stable_array.cpp. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 查维 --- ecmascript/js_stable_array.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 8ec6c3e94..526960e16 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -679,8 +679,9 @@ JSTaggedValue JSStableArray::At(JSHandle receiver, EcmaRuntimeCallInfo return JSTaggedValue::Undefined(); } - JSHandle taggedValue = JSArray::FastGetPropertyByValue(thread, JSHandle(receiver), k); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - return taggedValue.GetTaggedValue(); + TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); + auto result = JSTaggedValue::Hole(); + result = elements->Get(k); + return result.IsHole() ? JSTaggedValue::Undefined() : result; } } // namespace panda::ecmascript -- Gitee From 54510590fca0e30931656b4e82d44666451e2d6d Mon Sep 17 00:00:00 2001 From: hwx1163501 Date: Tue, 4 Jul 2023 16:48:15 +0800 Subject: [PATCH 011/438] Rectification of safety problems Signed-off-by: hwx1163501 issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7IC7Y --- ecmascript/compiler/state_split_linearizer.cpp | 2 +- ecmascript/debugger/debugger_api.cpp | 8 ++++---- ecmascript/dfx/cpu_profiler/samples_record.cpp | 8 ++++---- ecmascript/ecma_string.cpp | 4 ++-- ecmascript/js_api/js_api_arraylist.cpp | 4 ++-- ecmascript/js_array.cpp | 8 ++++---- ecmascript/pgo_profiler/pgo_profiler_info.h | 2 +- ecmascript/platform/unix/file.cpp | 2 +- .../containersvectorcommon_fuzzer.h | 4 ++-- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ecmascript/compiler/state_split_linearizer.cpp b/ecmascript/compiler/state_split_linearizer.cpp index 4ffd2dded..17a5c26a4 100644 --- a/ecmascript/compiler/state_split_linearizer.cpp +++ b/ecmascript/compiler/state_split_linearizer.cpp @@ -134,7 +134,7 @@ public: void VisitRegion(GateRegion* curRegion) { replacement_.SetState(curRegion->GetState()); - currentIndex_ = curRegion->gateList_.size() - 1; // 1: -1 for size + currentIndex_ = static_cast(curRegion->gateList_.size() - 1); // 1: -1 for size TryLoadDependStart(curRegion); // 0: is state for (; currentIndex_ > 0; currentIndex_--) { diff --git a/ecmascript/debugger/debugger_api.cpp b/ecmascript/debugger/debugger_api.cpp index a38c47463..4fc1fd14b 100644 --- a/ecmascript/debugger/debugger_api.cpp +++ b/ecmascript/debugger/debugger_api.cpp @@ -422,8 +422,8 @@ int32_t DebuggerApi::GetRequestModuleIndex(const EcmaVM *ecmaVm, JSTaggedValue m SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required)); JSTaggedValue requireModule = requiredModule->GetEcmaModuleRecordName(); JSHandle requestedModules(thread, module->GetRequestedModules()); - int32_t requestedModulesLen = static_cast(requestedModules->GetLength()); - for (int32_t idx = 0; idx < requestedModulesLen; idx++) { + uint32_t requestedModulesLen = requestedModules->GetLength(); + for (uint32_t idx = 0; idx < requestedModulesLen; idx++) { JSTaggedValue requestModule = requestedModules->Get(idx); if (JSTaggedValue::SameValue(requireModule, requestModule)) { return idx; @@ -608,12 +608,12 @@ void DebuggerApi::GetImportVariables(const EcmaVM *ecmaVm, Local &mod JSThread *thread = ecmaVm->GetJSThread(); JSHandle importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject())); - int32_t importEntriesLen = static_cast(importArray->GetLength()); + uint32_t importEntriesLen = importArray->GetLength(); JSHandle environment(thread, TaggedArray::Cast(moduleEnvironment.GetTaggedObject())); JSHandle starString = thread->GlobalConstants()->GetHandledStarString(); JSMutableHandle ee(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle name(thread, thread->GlobalConstants()->GetUndefined()); - for (int32_t idx = 0; idx < importEntriesLen; idx++) { + for (uint32_t idx = 0; idx < importEntriesLen; idx++) { ee.Update(importArray->Get(idx)); JSTaggedValue key = ee->GetImportName(); JSTaggedValue localName = ee->GetLocalName(); diff --git a/ecmascript/dfx/cpu_profiler/samples_record.cpp b/ecmascript/dfx/cpu_profiler/samples_record.cpp index 3041c6356..976cf4245 100644 --- a/ecmascript/dfx/cpu_profiler/samples_record.cpp +++ b/ecmascript/dfx/cpu_profiler/samples_record.cpp @@ -788,10 +788,10 @@ void SamplesQueue::PostNapiFrame(CVector &napiFrameInfoTemps, { os::memory::LockHolder holder(mtx_); if (!IsFull()) { - int frameInfoTempsLength = static_cast(napiFrameInfoTemps.size()); - int frameStackLength = static_cast(napiFrameStack.size()); + size_t frameInfoTempsLength = napiFrameInfoTemps.size(); + size_t frameStackLength = napiFrameStack.size(); // napiFrameInfoTemps - for (int i = 0; i < frameInfoTempsLength; i++) { + for (size_t i = 0; i < frameInfoTempsLength; i++) { CheckAndCopy(frames_[rear_].frameInfoTemps[i].functionName, sizeof(frames_[rear_].frameInfoTemps[i].functionName), napiFrameInfoTemps[i].functionName); frames_[rear_].frameInfoTemps[i].columnNumber = napiFrameInfoTemps[i].columnNumber; @@ -804,7 +804,7 @@ void SamplesQueue::PostNapiFrame(CVector &napiFrameInfoTemps, frames_[rear_].frameInfoTemps[i].methodKey.state = napiFrameInfoTemps[i].methodKey.state; } // napiFrameStack - for (int i = 0; i < frameStackLength; i++) { + for (size_t i = 0; i < frameStackLength; i++) { frames_[rear_].frameStack[i].methodIdentifier = napiFrameStack[i].methodIdentifier; frames_[rear_].frameStack[i].state = napiFrameStack[i].state; } diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index c79380735..aae5acf74 100644 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -743,10 +743,10 @@ EcmaString *EcmaString::TrimBody(const JSThread *thread, const JSHandleGetLength(); int32_t start = 0; - int32_t end = srcLen - 1; + int32_t end = static_cast(srcLen) - 1; if (mode == TrimMode::TRIM || mode == TrimMode::TRIM_START) { - start = base::StringHelper::GetStart(data, srcLen); + start = static_cast(base::StringHelper::GetStart(data, srcLen)); } if (mode == TrimMode::TRIM || mode == TrimMode::TRIM_END) { end = base::StringHelper::GetEnd(data, start, srcLen); diff --git a/ecmascript/js_api/js_api_arraylist.cpp b/ecmascript/js_api/js_api_arraylist.cpp index ac0770a3c..ab46d6ea7 100644 --- a/ecmascript/js_api/js_api_arraylist.cpp +++ b/ecmascript/js_api/js_api_arraylist.cpp @@ -376,12 +376,12 @@ JSHandle JSAPIArrayList::GrowCapacity(const JSThread *thread, const bool JSAPIArrayList::Has(const JSTaggedValue value) const { TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject()); - int32_t length = GetSize(); + uint32_t length = GetSize(); if (length == 0) { return false; } - for (int32_t i = 0; i < length; i++) { + for (uint32_t i = 0; i < length; i++) { if (JSTaggedValue::SameValue(elements->Get(i), value)) { return true; } diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index 60b2b31a5..c42cd300c 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -439,14 +439,14 @@ bool JSArray::IncludeInSortedValue(JSThread *thread, const JSHandleIsJSArray()); JSHandle arrayObj = JSHandle::Cast(obj); - int32_t length = static_cast(arrayObj->GetArrayLength()); + uint32_t length = arrayObj->GetArrayLength(); if (length == 0) { return false; } - int32_t left = 0; - int32_t right = length - 1; + uint32_t left = 0; + uint32_t right = length - 1; while (left <= right) { - int32_t middle = (left + right) / 2; + uint32_t middle = (left + right) / 2; JSHandle vv = JSArray::FastGetPropertyByValue(thread, obj, middle); ComparisonResult res = JSTaggedValue::Compare(thread, vv, value); if (res == ComparisonResult::EQUAL) { diff --git a/ecmascript/pgo_profiler/pgo_profiler_info.h b/ecmascript/pgo_profiler/pgo_profiler_info.h index c0a53f359..d092f1039 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_info.h +++ b/ecmascript/pgo_profiler/pgo_profiler_info.h @@ -290,7 +290,7 @@ public: void IncreaseCount(int32_t inc) { - count_ += inc; + count_ += static_cast(inc); } void ClearCount() diff --git a/ecmascript/platform/unix/file.cpp b/ecmascript/platform/unix/file.cpp index 359cb65d4..6f902c597 100644 --- a/ecmascript/platform/unix/file.cpp +++ b/ecmascript/platform/unix/file.cpp @@ -80,7 +80,7 @@ MemMap FileMap(const char *fileName, int flag, int prot, int64_t offset) return MemMap(); } - size_t size = static_cast(lseek(fd, 0, SEEK_END)); + off_t size = lseek(fd, 0, SEEK_END); if (size <= 0) { close(fd); LOG_ECMA(ERROR) << fileName << " file is empty"; diff --git a/test/fuzztest/containersvectorcommon_fuzzer/containersvectorcommon_fuzzer.h b/test/fuzztest/containersvectorcommon_fuzzer/containersvectorcommon_fuzzer.h index 0300b6966..63659479d 100644 --- a/test/fuzztest/containersvectorcommon_fuzzer/containersvectorcommon_fuzzer.h +++ b/test/fuzztest/containersvectorcommon_fuzzer/containersvectorcommon_fuzzer.h @@ -481,7 +481,7 @@ public: return JSTaggedValue::Undefined(); } }; - + static void ContainersVectorReplaceAllElementsFuzzTest(const uint8_t* data, size_t size) { if (size <= 0) { @@ -847,7 +847,7 @@ public: JSNApi::DestroyJSVM(vm); } - + }; } #endif \ No newline at end of file -- Gitee From e8aea4be807c2ea80c8dddd2bada58b270595e0d Mon Sep 17 00:00:00 2001 From: "yingguofeng@huawei.com" Date: Tue, 4 Jul 2023 20:01:42 +0800 Subject: [PATCH 012/438] Test(PGO): Add UT test for PGO profile Issue: #I7IESY Change-Id: I3b7d2216aa2ba2cb3352a2f026738846567fa43f Signed-off-by: yingguofeng@huawei.com --- ecmascript/pgo_profiler/tests/BUILD.gn | 38 ++++ .../pgo_profiler/tests/pgo_profiler_test.cpp | 196 ++++++++++++++++++ .../tests/pgo_test_case/call_test.js | 33 +++ .../tests/pgo_test_case/class_test.js | 51 +++++ .../tests/pgo_test_case/op_type_test.js | 69 ++++++ test/resource/js_runtime/ohos_test.xml | 5 +- 6 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 ecmascript/pgo_profiler/tests/pgo_test_case/call_test.js create mode 100644 ecmascript/pgo_profiler/tests/pgo_test_case/class_test.js create mode 100644 ecmascript/pgo_profiler/tests/pgo_test_case/op_type_test.js diff --git a/ecmascript/pgo_profiler/tests/BUILD.gn b/ecmascript/pgo_profiler/tests/BUILD.gn index dcd1868b1..97f98c2cd 100644 --- a/ecmascript/pgo_profiler/tests/BUILD.gn +++ b/ecmascript/pgo_profiler/tests/BUILD.gn @@ -16,6 +16,33 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") module_output_path = "arkcompiler/ets_runtime" +test_js_path = + "//arkcompiler/ets_runtime/ecmascript/pgo_profiler/tests/pgo_test_case/" + +test_js_files = [ + "op_type_test", + "class_test", + "call_test", +] + +foreach(file, test_js_files) { + es2abc_gen_abc("gen_${file}_abc") { + test_js = "${test_js_path}${file}.js" + test_abc = "$target_out_dir/${file}.abc" + + # Only targets in this file can depend on this. + extra_visibility = [ ":*" ] + src_js = rebase_path(test_js) + dst_file = rebase_path(test_abc) + extra_args = [] + extra_args += [ "--module" ] + extra_args += [ "--merge-abc" ] + extra_args += [ "--type-extractor" ] + in_puts = [ test_js ] + out_puts = [ test_abc ] + } +} + host_unittest_action("PGOProfilerTest") { module_out_path = module_output_path @@ -38,6 +65,17 @@ host_unittest_action("PGOProfilerTest") { sdk_libc_secshared_dep, ] + foreach(file, test_js_files) { + deps += [ ":gen_${file}_abc" ] + } + + if (is_ohos && is_standard_system) { + test_abc_dir = "/data/test" + } else { + test_abc_dir = rebase_path(target_out_dir) + } + defines = [ "TARGET_ABC_PATH=\"${test_abc_dir}/\"" ] + # hiviewdfx libraries external_deps = hiviewdfx_ext_deps deps += hiviewdfx_deps diff --git a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp index 73d16fe25..a82d3955b 100644 --- a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp +++ b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp @@ -85,6 +85,26 @@ protected: return pf; } + std::shared_ptr ExecuteAndLoadJSPandaFile(std::string profDir, std::string recordName) + { + RuntimeOption option; + option.SetLogLevel(LOG_LEVEL::INFO); + option.SetEnableProfile(true); + option.SetProfileDir(profDir); + vm_ = JSNApi::CreateJSVM(option); + JSNApi::EnableUserUncaughtErrorHandler(vm_); + + std::string targetAbcPath = TARGET_ABC_PATH + recordName + ".abc"; + auto result = JSNApi::Execute(vm_, targetAbcPath, recordName, false); + EXPECT_TRUE(result); + + std::shared_ptr jsPandaFile = + JSPandaFileManager::GetInstance()->FindJSPandaFile(CString(targetAbcPath)); + + JSNApi::DestroyJSVM(vm_); + return jsPandaFile; + } + EcmaVM *vm_ = nullptr; }; @@ -672,4 +692,180 @@ HWTEST_F_L0(PGOProfilerTest, FailResetProfilerInWorker) ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); rmdir("ark-profiler12/"); } + +#if defined(SUPPORT_ENABLE_ASM_INTERP) +HWTEST_F_L0(PGOProfilerTest, ProfileCallTest) +{ + mkdir("ark-profiler13/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + const char *targetRecordName = "call_test"; + std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler13/", targetRecordName); + ASSERT_NE(jsPandaFile, nullptr); + uint32_t checksum = jsPandaFile->GetChecksum(); + + // Loader + PGOProfilerDecoder decoder("ark-profiler13/modules.ap", 1); + PGOProfilerDecoder decoder1("ark-profiler13/modules.ap", 10); + PGOProfilerDecoder decoder2("ark-profiler13/modules.ap", 11000); + ASSERT_TRUE(decoder.LoadAndVerify(checksum)); + ASSERT_TRUE(decoder1.LoadAndVerify(checksum)); + ASSERT_TRUE(decoder2.LoadAndVerify(checksum)); + auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + for (auto iter : methodLiterals) { + auto methodLiteral = iter.second; + auto methodId = methodLiteral->GetMethodId(); + auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId); + decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId); + decoder1.MatchAndMarkMethod(targetRecordName, methodName, methodId); + decoder2.MatchAndMarkMethod(targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(targetRecordName, methodId)); + if (std::string(methodName) == "foo") { + ASSERT_TRUE(decoder1.Match(targetRecordName, methodId)); + } else { + ASSERT_TRUE(!decoder1.Match(targetRecordName, methodId)); + } + ASSERT_TRUE(!decoder2.Match(targetRecordName, methodId)); + } + unlink("ark-profiler13/modules.ap"); + rmdir("ark-profiler13/"); +} + +HWTEST_F_L0(PGOProfilerTest, UseClassTypeTest) +{ + mkdir("ark-profiler14/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + const char *targetRecordName = "class_test"; + std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler14/", targetRecordName); + ASSERT_NE(jsPandaFile, nullptr); + uint32_t checksum = jsPandaFile->GetChecksum(); + + // Loader + PGOProfilerDecoder decoder("ark-profiler14/modules.ap", 1); + ASSERT_TRUE(decoder.LoadAndVerify(checksum)); + auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + for (auto iter : methodLiterals) { + auto methodLiteral = iter.second; + auto methodId = methodLiteral->GetMethodId(); + auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId); + decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(targetRecordName, methodId)); + auto callback = [methodName, methodId](uint32_t offset, PGOType *type) { + ASSERT_NE(offset, 0); + if (type->IsScalarOpType()) { + } else if (type->IsRwOpType()) { + auto pgoRWOpType = *reinterpret_cast(type); + if (std::string(methodName) == "Foot" || std::string(methodName) == "Arm") { + ASSERT_TRUE(pgoRWOpType.GetCount() == 1); + ASSERT_EQ(pgoRWOpType.GetObjectInfo(0).GetClassType(), ClassType(methodId.GetOffset())); + } else if (std::string(methodName) == "foo" || std::string(methodName) == "Body") { + ASSERT_TRUE(pgoRWOpType.GetCount() == 3); + } + } else { + ASSERT_TRUE(false); + } + }; + decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + } + unlink("ark-profiler14/modules.ap"); + rmdir("ark-profiler14/"); +} + +HWTEST_F_L0(PGOProfilerTest, DefineClassTypeTest) +{ + mkdir("ark-profiler15/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + const char *targetRecordName = "class_test"; + std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler15/", targetRecordName); + ASSERT_NE(jsPandaFile, nullptr); + uint32_t checksum = jsPandaFile->GetChecksum(); + + // Loader + PGOProfilerDecoder decoder("ark-profiler15/modules.ap", 1); + ASSERT_TRUE(decoder.LoadAndVerify(checksum)); + auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + for (auto iter : methodLiterals) { + auto methodLiteral = iter.second; + auto methodId = methodLiteral->GetMethodId(); + auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId); + decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(targetRecordName, methodId)); + auto callback = [methodName, &decoder, jsPandaFile](uint32_t offset, PGOType *type) { + ASSERT_NE(offset, 0); + if (type->IsScalarOpType()) { + auto sampleType = *reinterpret_cast(type); + if (sampleType.IsClassType()) { + ASSERT_EQ(std::string(methodName), "func_main_0"); + PGOHClassLayoutDesc *desc; + ASSERT_TRUE(decoder.GetHClassLayoutDesc(sampleType, &desc)); + ASSERT_EQ(desc->GetCtorLayoutDesc().size(), 3); + ASSERT_EQ(desc->GetPtLayoutDesc().size(), 1); + auto classId = EntityId(sampleType.GetClassType().GetClassType()); + auto className = MethodLiteral::GetMethodName(jsPandaFile.get(), classId); + if (std::string(className) == "Arm") { + auto superClassId = EntityId(desc->GetSuperClassType().GetClassType()); + auto superClassName = MethodLiteral::GetMethodName(jsPandaFile.get(), superClassId); + ASSERT_EQ(std::string(superClassName), "Body"); + ASSERT_EQ(desc->GetLayoutDesc().size(), 3); + ASSERT_EQ(desc->GetLayoutDesc()[0].first, "x"); + ASSERT_EQ(desc->GetLayoutDesc()[1].first, "y"); + ASSERT_EQ(desc->GetLayoutDesc()[2].first, "t"); + } else if (std::string(className) == "Foot") { + auto superClassId = EntityId(desc->GetSuperClassType().GetClassType()); + auto superClassName = MethodLiteral::GetMethodName(jsPandaFile.get(), superClassId); + ASSERT_EQ(std::string(superClassName), "Body"); + ASSERT_EQ(desc->GetLayoutDesc().size(), 4); + ASSERT_EQ(desc->GetLayoutDesc()[0].first, "x"); + ASSERT_EQ(desc->GetLayoutDesc()[1].first, "y"); + ASSERT_EQ(desc->GetLayoutDesc()[2].first, "u"); + ASSERT_EQ(desc->GetLayoutDesc()[3].first, "v"); + } else { + ASSERT_EQ(desc->GetSuperClassType().GetClassType(), 0); + ASSERT_EQ(desc->GetLayoutDesc().size(), 2); + ASSERT_EQ(desc->GetLayoutDesc()[0].first, "x"); + ASSERT_EQ(desc->GetLayoutDesc()[1].first, "y"); + } + } + } + }; + decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + } + unlink("ark-profiler15/modules.ap"); + rmdir("ark-profiler15/"); +} + +HWTEST_F_L0(PGOProfilerTest, OpTypeTest) +{ + mkdir("ark-profiler16/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + const char *targetRecordName = "op_type_test"; + std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler16/", targetRecordName); + ASSERT_NE(jsPandaFile, nullptr); + uint32_t checksum = jsPandaFile->GetChecksum(); + + // Loader + PGOProfilerDecoder decoder("ark-profiler16/modules.ap", 1); + ASSERT_TRUE(decoder.LoadAndVerify(checksum)); + std::string types[17] = { "1", "1", "1", "5", "4", "4", "4", "4", "4", "4", "5", "4", "4", "1", "4", "5", "1" }; + int index = 0; + auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + for (auto iter : methodLiterals) { + auto methodLiteral = iter.second; + auto methodId = methodLiteral->GetMethodId(); + auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId); + decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(targetRecordName, methodId)); + auto callback = [methodName, types, &index](uint32_t offset, PGOType *type) { + ASSERT_NE(offset, 0); + if (type->IsScalarOpType()) { + auto sampleType = *reinterpret_cast(type); + if (sampleType.IsClassType()) { + return; + } + if (std::string(methodName) == "advance") { + ASSERT_EQ(sampleType.GetTypeString(), types[index++]); + } + } + }; + decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + } + unlink("ark-profiler16/modules.ap"); + rmdir("ark-profiler16/"); +} +#endif } // namespace panda::test diff --git a/ecmascript/pgo_profiler/tests/pgo_test_case/call_test.js b/ecmascript/pgo_profiler/tests/pgo_test_case/call_test.js new file mode 100644 index 000000000..4037866f9 --- /dev/null +++ b/ecmascript/pgo_profiler/tests/pgo_test_case/call_test.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +class Test { + x + y + constructor(x, y) { + this.x = x; + this.y = y; + } +} + +function foo(p) +{ + return p.x +} + +let a = new Test(1, 23) +for (let i = 0; i < 1000000; i++) { + foo(a) +} diff --git a/ecmascript/pgo_profiler/tests/pgo_test_case/class_test.js b/ecmascript/pgo_profiler/tests/pgo_test_case/class_test.js new file mode 100644 index 000000000..65d6effc5 --- /dev/null +++ b/ecmascript/pgo_profiler/tests/pgo_test_case/class_test.js @@ -0,0 +1,51 @@ +/* + * 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. + */ + +class Body { + constructor(x, y) { + this.x = x; + this.y = y; + } +} + +class Foot extends Body { + constructor(x, y, u, v) { + super(x, y) + this.u = u + this.v = v + } +} + +class Arm extends Body { + constructor(x, y, t) { + super(x, y) + this.t = t + } +} + +function foo(p) +{ + return p.x +} + +let a = new Body(1, 23) +let b = new Foot(3, 3.2, 2, 32.3) +let c = new Arm(1.3, 23.2, 23) + +for (let i = 0; i < 1000000; i++) { + foo(a) + foo(b) + foo(c) +} diff --git a/ecmascript/pgo_profiler/tests/pgo_test_case/op_type_test.js b/ecmascript/pgo_profiler/tests/pgo_test_case/op_type_test.js new file mode 100644 index 000000000..ffa4cfd1e --- /dev/null +++ b/ecmascript/pgo_profiler/tests/pgo_test_case/op_type_test.js @@ -0,0 +1,69 @@ +/* + * 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. + */ + +class Body { + constructor(x, vx, mass) { + this.x = x; + this.vx = vx; + this.mass = mass; + } +} + +function advance(bodies, dt) { + const sqrt = Math.sqrt; + const size = bodies.length; + + for (let i = 0; i < size; i++) { + const bodyi = bodies[i]; + let vxi = bodyi.vx; + const xi = bodyi.x; + const massi = bodyi.mass; + + for (let j = i + 1; j < size; j++) { + const bodyj = bodies[j]; + const dx = xi - bodyj.x; + + const d2 = dx * dx; + const mag = dt / (d2 * sqrt(d2)); + const massiMag = massi * mag; + + const massj = bodyj.mass; + const massjMag = massj * mag; + vxi -= dx * massjMag; + + bodyj.vx += dx * massiMag; + } + bodyi.vx = vxi; + + bodyi.x += dt * vxi; + } +} + +const PI = Math.PI; +const SOLAR_MASS = 4 * PI * PI; + +function Sun() { + return new Body(0.0, 0.0, SOLAR_MASS); +} + +function Sun1() { + return new Body(1.2, 3.1, PI); +} + +const bodies = [Sun(), Sun1()]; +const n = 100000; +for (let i = 0; i < n; i++) { + advance(bodies, 0.01); +} diff --git a/test/resource/js_runtime/ohos_test.xml b/test/resource/js_runtime/ohos_test.xml index 8d57159ce..86e0d79fc 100755 --- a/test/resource/js_runtime/ohos_test.xml +++ b/test/resource/js_runtime/ohos_test.xml @@ -128,7 +128,7 @@