From a69340ebf8e8bd5820b004002c4ea4761164fcbf Mon Sep 17 00:00:00 2001 From: chenxun Date: Thu, 21 Sep 2023 17:28:45 +0800 Subject: [PATCH 01/50] =?UTF-8?q?typedop=E4=BB=A3=E6=9B=BFop=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: chenxun --- tools/circuit_viewer/src/ir/IrToPicture.js | 8 +++++++- tools/circuit_viewer/src/ir/IrViewer.js | 15 +++++++++------ tools/circuit_viewer/src/ir/LogParser.js | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tools/circuit_viewer/src/ir/IrToPicture.js b/tools/circuit_viewer/src/ir/IrToPicture.js index 175450e099..1a8e742330 100644 --- a/tools/circuit_viewer/src/ir/IrToPicture.js +++ b/tools/circuit_viewer/src/ir/IrToPicture.js @@ -98,10 +98,16 @@ class IrToPicture { if (type == 0) {//仅控制流 if (this.nodeType(ir) != "control") continue; } - let name = ir.id + "," + ir.op; + let name; if (XTools.CONFIG.OpTypeJsBytecode.indexOf(ir.op) >= 0) { name = ir.id + "," + ir.bytecode; } + else if (ir.typedop) { + name = ir.id + "," + ir.typedop; + } + else { + name = ir.id + "," + ir.op; + } nodes[ir.id] = { type: this.nodeType(ir), mask: this.nodeTypeMask(ir), diff --git a/tools/circuit_viewer/src/ir/IrViewer.js b/tools/circuit_viewer/src/ir/IrViewer.js index f1628715dd..0c46872f9f 100644 --- a/tools/circuit_viewer/src/ir/IrViewer.js +++ b/tools/circuit_viewer/src/ir/IrViewer.js @@ -866,15 +866,18 @@ class IrViewer { this.selectPoint_ = []; for (let i in nodes) { let n = nodes[i]; + let searchName; if (XTools.CONFIG.OpTypeJsBytecode.indexOf(n.ir.op) >= 0) { - if (n.ir.id == v || n.ir.bytecode.indexOf(v) >= 0 || (isRegExp(v) && n.ir.bytecode.match(v))) { - this.searchInput.result.push(i); - } + searchName = n.ir.bytecode; + } + else if (n.ir.typedop) { + searchName = n.ir.typedop; } else { - if (n.ir.id == v || n.ir.op.indexOf(v) >= 0 || (isRegExp(v) && n.ir.op.match(v))) { - this.searchInput.result.push(i); - } + searchName = n.ir.op; + } + if (n.ir.id == v || searchName.indexOf(v) >= 0 || (isRegExp(v) && searchName.match(v))) { + this.searchInput.result.push(i); } } if (this.searchInput.result.length > 0) { diff --git a/tools/circuit_viewer/src/ir/LogParser.js b/tools/circuit_viewer/src/ir/LogParser.js index 4fe8828893..04cd658a02 100644 --- a/tools/circuit_viewer/src/ir/LogParser.js +++ b/tools/circuit_viewer/src/ir/LogParser.js @@ -78,9 +78,9 @@ class LogParser { } isStart(l) { //========= After bytecode2circuit lowering [func_main_0@484@arkcompiler/ets_runtime/sd_test/ttabs.abc] ======== - const regexStart = /=+ *After ([a-zA-Z0-9_ ]+) \[([#a-zA-Z0-9_@/.]+)\] *=+/g + const regexStart = /=+ *After ([a-zA-Z0-9_ ]+) \[([#a-zA-Z0-9_@/.-]+)\] *=+/g //========= After inlining [OthreMath@test@arkcompiler/ets_runtime/sd_test/test.abc] Caller method [func_main_0@641@arkcompiler/ets_runtime/sd_test/test.abc]==================== - const regexStart2 = /=+ *After ([a-zA-Z0-9_ ]+) \[([a-zA-Z0-9_@/.]+)\] *Caller method \[([#a-zA-Z0-9_@/.]+)\] *=+/g + const regexStart2 = /=+ *After ([a-zA-Z0-9_ ]+) \[([a-zA-Z0-9_@/.-]+)\] *Caller method \[([#a-zA-Z0-9_@/.]+)\] *=+/g if (l[11] != '=') { return; From 420abd9171c016e1e32025e79853ecba75656511 Mon Sep 17 00:00:00 2001 From: like Date: Sat, 7 Oct 2023 11:06:03 +0800 Subject: [PATCH 02/50] Fix ASSERTION FAILED: ctor->IsJSFunction() issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I85PWS Signed-off-by: like Change-Id: Ia584d906dbda888e53d5c41dfc4253e456b746e7 --- ecmascript/stubs/runtime_stubs-inl.h | 1 + .../defineclasswithbuffer/defineclasswithbuffer.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/ecmascript/stubs/runtime_stubs-inl.h b/ecmascript/stubs/runtime_stubs-inl.h index 21c8ea2a3a..861029bb30 100644 --- a/ecmascript/stubs/runtime_stubs-inl.h +++ b/ecmascript/stubs/runtime_stubs-inl.h @@ -862,6 +862,7 @@ JSTaggedValue RuntimeStubs::RuntimeCreateClassWithBuffer(JSThread *thread, lexenv, ihclass, chclass); } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); RuntimeSetClassInheritanceRelationship(thread, JSHandle(cls), base); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return cls.GetTaggedValue(); diff --git a/test/aottest/defineclasswithbuffer/defineclasswithbuffer.ts b/test/aottest/defineclasswithbuffer/defineclasswithbuffer.ts index 555443da1d..575f051174 100644 --- a/test/aottest/defineclasswithbuffer/defineclasswithbuffer.ts +++ b/test/aottest/defineclasswithbuffer/defineclasswithbuffer.ts @@ -51,3 +51,11 @@ abstract class C { } print(C.prototype.bar()); + +function f26() { + function f29() {} + f29(); + throw f29 +} +const v31 = f26(); +class C33 {} \ No newline at end of file From 59fae0812af5609b9ef2ea4c34f900a45df67725 Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Mon, 9 Oct 2023 13:53:57 +0800 Subject: [PATCH 03/50] Fix compiler fail Fix standalone build fail Issue: https://gitee.com/openharmony/arkcompiler_toolchain/issues/I869QD Signed-off-by: wengchangcheng Change-Id: Ie9349d8d22a7f0b6ccd40ce2ff36cf947580302e --- ecmascript/common.h | 6 +++--- ecmascript/compiler/object_access_helper.cpp | 2 ++ ecmascript/compiler/ts_class_analysis.cpp | 3 +++ ecmascript/compiler/ts_hclass_generator.cpp | 4 +++- .../compiler/type_inference/pgo_type_infer_helper.cpp | 2 ++ ecmascript/debugger/js_debugger_interface.h | 8 ++++++-- ecmascript/jspandafile/accessor/module_data_accessor.cpp | 1 + ecmascript/jspandafile/js_pandafile.h | 1 - ecmascript/mem/heap.cpp | 5 ++++- ecmascript/patch/quick_fix_manager.cpp | 3 +++ 10 files changed, 27 insertions(+), 8 deletions(-) diff --git a/ecmascript/common.h b/ecmascript/common.h index c22714e7c3..7eb60703ea 100644 --- a/ecmascript/common.h +++ b/ecmascript/common.h @@ -156,13 +156,13 @@ using Address = uintptr_t; #ifdef PANDA_TARGET_32 #define STATIC_ASSERT_EQ_ARCH32(a, b) static_assert(a == b) #else -#define STATIC_ASSERT_EQ_ARCH32(a, b) +#define STATIC_ASSERT_EQ_ARCH32(a, b) static_assert(true) #endif #ifdef PANDA_TARGET_64 #define STATIC_ASSERT_EQ_ARCH64(a, b) static_assert(a == b) #else -#define STATIC_ASSERT_EQ_ARCH64(a, b) +#define STATIC_ASSERT_EQ_ARCH64(a, b) static_assert(true) #endif #if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS) || defined(PANDA_TARGET_IOS) @@ -172,7 +172,7 @@ using Address = uintptr_t; #endif #define STATIC_ASSERT_EQ_ARCH(expect, valueArch32, valueArch64) \ - STATIC_ASSERT_EQ_ARCH32(expect, valueArch32) \ + STATIC_ASSERT_EQ_ARCH32(expect, valueArch32); \ STATIC_ASSERT_EQ_ARCH64(expect, valueArch64) } // namespace ecmascript } // namespace panda diff --git a/ecmascript/compiler/object_access_helper.cpp b/ecmascript/compiler/object_access_helper.cpp index c83c3d53ab..36da6aa8f1 100644 --- a/ecmascript/compiler/object_access_helper.cpp +++ b/ecmascript/compiler/object_access_helper.cpp @@ -14,6 +14,8 @@ */ #include "ecmascript/compiler/object_access_helper.h" + +#include "ecmascript/js_hclass-inl.h" #include "ecmascript/ts_types/ts_type.h" namespace panda::ecmascript::kungfu { diff --git a/ecmascript/compiler/ts_class_analysis.cpp b/ecmascript/compiler/ts_class_analysis.cpp index 8b4109d735..fde44da773 100644 --- a/ecmascript/compiler/ts_class_analysis.cpp +++ b/ecmascript/compiler/ts_class_analysis.cpp @@ -14,6 +14,9 @@ */ #include "ecmascript/compiler/ts_class_analysis.h" + +#include "ecmascript/js_hclass-inl.h" +#include "ecmascript/layout_info.h" #include "ecmascript/ts_types/ts_type_accessor.h" namespace panda::ecmascript::kungfu { diff --git a/ecmascript/compiler/ts_hclass_generator.cpp b/ecmascript/compiler/ts_hclass_generator.cpp index 3d292e9371..a8c08a1b2f 100644 --- a/ecmascript/compiler/ts_hclass_generator.cpp +++ b/ecmascript/compiler/ts_hclass_generator.cpp @@ -15,8 +15,10 @@ #include "ecmascript/compiler/ts_hclass_generator.h" #include "ecmascript/global_env_constants-inl.h" -#include "ecmascript/subtyping_operator.h" +#include "ecmascript/layout_info.h" +#include "ecmascript/js_function.h" #include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/subtyping_operator.h" namespace panda::ecmascript::kungfu { using ClassInfoExtractor = panda::ecmascript::ClassInfoExtractor; diff --git a/ecmascript/compiler/type_inference/pgo_type_infer_helper.cpp b/ecmascript/compiler/type_inference/pgo_type_infer_helper.cpp index 356ef156f8..9e1664d2d8 100644 --- a/ecmascript/compiler/type_inference/pgo_type_infer_helper.cpp +++ b/ecmascript/compiler/type_inference/pgo_type_infer_helper.cpp @@ -14,6 +14,8 @@ */ #include "ecmascript/compiler/type_inference/pgo_type_infer_helper.h" + +#include "ecmascript/js_hclass-inl.h" #include "ecmascript/ts_types/ts_type_accessor.h" namespace panda::ecmascript::kungfu { diff --git a/ecmascript/debugger/js_debugger_interface.h b/ecmascript/debugger/js_debugger_interface.h index 386124d5f0..faa8f5b992 100644 --- a/ecmascript/debugger/js_debugger_interface.h +++ b/ecmascript/debugger/js_debugger_interface.h @@ -21,7 +21,10 @@ #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/debugger/js_pt_location.h" -namespace panda::ecmascript::tooling { +namespace panda::ecmascript { +class Method; + +namespace tooling { struct JSPtStepRange { uint32_t startBcOffset {0}; uint32_t endBcOffset {0}; @@ -139,6 +142,7 @@ public: NO_COPY_SEMANTIC(JSDebugInterface); NO_MOVE_SEMANTIC(JSDebugInterface); }; -} // namespace panda::ecmascript::tooling +} // namespace tooling +} // namespace panda::ecmascript #endif // ECMASCRIPT_DEBUGGER_JS_DEBUG_INTERFACE_H diff --git a/ecmascript/jspandafile/accessor/module_data_accessor.cpp b/ecmascript/jspandafile/accessor/module_data_accessor.cpp index da6ec423d4..78994b21a5 100644 --- a/ecmascript/jspandafile/accessor/module_data_accessor.cpp +++ b/ecmascript/jspandafile/accessor/module_data_accessor.cpp @@ -16,6 +16,7 @@ #include "ecmascript/jspandafile/accessor/module_data_accessor.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript { ModuleDataAccessor::ModuleDataAccessor(const JSPandaFile *pandaFile, EntityId moduleDataId) diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index e354fcfbc8..d4314ad305 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -17,7 +17,6 @@ #define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H #include "ecmascript/common.h" -#include "ecmascript/js_function.h" #include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/mem/c_containers.h" diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index 40b7b29a84..4143600b3c 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -15,6 +15,9 @@ #include "ecmascript/mem/heap-inl.h" +#include +#include + #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" #include "ecmascript/js_finalization_registry.h" @@ -1242,7 +1245,7 @@ bool Heap::AsyncClearTask::Run([[maybe_unused]] uint32_t threadIndex) bool Heap::FinishColdStartTask::Run([[maybe_unused]] uint32_t threadIndex) { - usleep(2000000); // 2000000 means 2s + std::this_thread::sleep_for(std::chrono::microseconds(2000000)); // 2000000 means 2s heap_->NotifyFinishColdStart(false); return true; } diff --git a/ecmascript/patch/quick_fix_manager.cpp b/ecmascript/patch/quick_fix_manager.cpp index 52bd6427dd..db8cded76c 100644 --- a/ecmascript/patch/quick_fix_manager.cpp +++ b/ecmascript/patch/quick_fix_manager.cpp @@ -14,10 +14,13 @@ */ #include "ecmascript/patch/quick_fix_manager.h" +#include "ecmascript/mem/barriers-inl.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/object_factory.h" namespace panda::ecmascript { QuickFixManager::~QuickFixManager() From bc618b2b42a9c1fd2db78061fe07b1f3c333b113 Mon Sep 17 00:00:00 2001 From: chenjx-huawei Date: Mon, 9 Oct 2023 13:27:52 +0800 Subject: [PATCH 04/50] Add a fast path for regexp.test Issue: https://gitee.com/open_harmony/dashboard?issue_id=I82ZUW Signed-off-by: chenjx-huawei Change-Id: Ic056e086675f4c9e0124f8c7a46c72ddf5fe5876 --- ecmascript/builtins/builtins.cpp | 4 + ecmascript/builtins/builtins_regexp.cpp | 151 ++++++++++++++++++++++- ecmascript/builtins/builtins_regexp.h | 14 ++- ecmascript/global_env.h | 1 + ecmascript/js_regexp.h | 2 + test/moduletest/regexp/expect_output.txt | 6 + test/moduletest/regexp/regexp.js | 30 +++++ 7 files changed, 201 insertions(+), 7 deletions(-) diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index c50aafc527..1489722d08 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -1865,6 +1865,10 @@ void Builtins::InitializeRegExp(const JSHandle &env) env->SetRegExpFunction(thread_, regexpFunction); env->SetRegExpPrototype(thread_, regPrototype); env->SetRegExpExecFunction(thread_, execFunc); + // Set RegExp.prototype hclass + JSHandle regPrototypeClass(thread_, regPrototype->GetJSHClass()); + env->SetRegExpPrototypeClass(thread_, regPrototypeClass.GetTaggedValue()); + auto globalConst = const_cast(thread_->GlobalConstants()); globalConst->SetConstant(ConstantIndex::JS_REGEXP_CLASS_INDEX, regexpFuncInstanceHClass.GetTaggedValue()); } diff --git a/ecmascript/builtins/builtins_regexp.cpp b/ecmascript/builtins/builtins_regexp.cpp index 17db705206..b0cd6deb72 100644 --- a/ecmascript/builtins/builtins_regexp.cpp +++ b/ecmascript/builtins/builtins_regexp.cpp @@ -185,15 +185,19 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv) // 1. Let R be the this value. JSHandle thisObj = GetThis(argv); JSHandle inputStr = GetCallArg(argv, 0); + // 2. If Type(R) is not Object, throw a TypeError exception. + if (!thisObj->IsECMAObject()) { + // throw a TypeError exception. + THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); + } // 3. Let string be ToString(S). // 4. ReturnIfAbrupt(string). JSHandle stringHandle = JSTaggedValue::ToString(thread, inputStr); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle string = JSHandle::Cast(stringHandle); - // 2. If Type(R) is not Object, throw a TypeError exception. - if (!thisObj->IsECMAObject()) { - // throw a TypeError exception. - THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); + // test fast path + if (IsFastRegExp(thread, thisObj)) { + return RegExpTestFast(thread, thisObj, string, true); } // 5. Let match be RegExpExec(R, string). @@ -204,6 +208,45 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv) return GetTaggedBoolean(!matchResult.IsNull()); } +bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle ®exp) +{ + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHClass *hclass = JSHandle::Cast(regexp)->GetJSHClass(); + JSHClass *originHClass = JSHClass::Cast(globalConst->GetJSRegExpClass().GetTaggedObject()); + // regexp instance hclass + if (hclass != originHClass) { + return false; + } + // RegExp.prototype hclass + JSTaggedValue proto = hclass->GetPrototype(); + JSHClass *regexpHclass = proto.GetTaggedObject()->GetClass(); + JSHandle originRegexpClassValue = env->GetRegExpPrototypeClass(); + JSHClass *originRegexpHclass = JSHClass::Cast(originRegexpClassValue.GetTaggedValue().GetTaggedObject()); + if (regexpHclass != originRegexpHclass) { + return false; + } + // RegExp.prototype.exec + auto execVal = JSObject::Cast(proto)->GetPropertyInlinedProps(JSRegExp::EXEC_INLINE_PROPERTY_INDEX); + if (execVal != env->GetTaggedRegExpExecFunction()) { + return false; + } + return true; +} + +JSTaggedValue BuiltinsRegExp::RegExpTestFast(JSThread *thread, JSHandle ®exp, + const JSHandle &inputStr, bool useCache) +{ + // 1. Assert: Type(S) is String. + ASSERT(inputStr->IsString()); + // 2. If R does not have a [[RegExpMatcher]] internal slot, throw a TypeError exception. + if (!regexp->IsJSRegExp()) { + // throw a TypeError exception. + THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have a [[RegExpMatcher]]", JSTaggedValue::Exception()); + } + return RegExpExecForTestFast(thread, regexp, inputStr, useCache); +} + // 20.2.5.14 JSTaggedValue BuiltinsRegExp::ToString(EcmaRuntimeCallInfo *argv) { @@ -1737,6 +1780,100 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle ®exp, + const JSHandle &inputStr, bool useCache) +{ + JSHandle object = JSHandle::Cast(regexp); + JSTaggedValue lastIndexValue = object->GetPropertyInlinedProps(LAST_INDEX_OFFSET); + // ASSERT GetPropertyInlinedProps(LAST_INDEX_OFFSET) is not hole + ASSERT(!JSTaggedValue::SameValue(lastIndexValue, JSTaggedValue::Hole())); + // 1. load lastIndex as length + int32_t lastIndex = 0; + if (lastIndexValue.IsInt()) { + lastIndex = lastIndexValue.GetInt(); + } else { + JSHandle lastIndexResult(thread, lastIndexValue); + JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + lastIndex = lastIndexNumber.GetNumber(); + } + // 2. Check whether the regexp is global or sticky, which determines whether we update last index later on. + JSHandle regexpObj(regexp); + JSMutableHandle pattern(thread, regexpObj->GetOriginalSource()); + JSMutableHandle flags(thread, regexpObj->GetOriginalFlags()); + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + uint8_t flagsBits = static_cast(flags->GetInt()); + bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0; + bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) != 0; + if (!global && !sticky) { + lastIndex = 0; + } + // 3. Search RegExpExecResult cache + uint32_t lastIndexInput = lastIndex; + if (useCache) { + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputStr, + RegExpExecResultCache::TEST_TYPE, regexp, + JSTaggedValue(lastIndexInput)); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } + } + + uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength(); + if (lastIndex > static_cast(length)) { + object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0)); + return JSTaggedValue::False(); + } + JSHandle inputString = JSHandle::Cast(inputStr); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); + auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced(); + const uint8_t *strBuffer = inputPtr.get(); + size_t stringLength = EcmaStringAccessor(inputString).GetLength(); + RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, stringLength, + lastIndex, isUtf16); + if (!matchResult.isSuccess_) { + if (global || sticky) { + object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0)); + } + return JSTaggedValue::False(); + } + uint32_t endIndex = matchResult.endIndex_; + if (global || sticky) { + object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(endIndex)); + } + uint32_t capturesSize = matchResult.captures_.size(); + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + uint32_t captureIndex = 1; + // For each integer i such that i > 0 and i <= n + for (; captureIndex < capturesSize; captureIndex++) { + // Let capture_i be ith element of r's captures List + JSTaggedValue capturedValue; + if (matchResult.captures_[captureIndex].first) { + capturedValue = JSTaggedValue::Undefined(); + } else { + auto captureI = matchResult.captures_[captureIndex].second; + capturedValue = captureI.capturedValue.GetTaggedValue(); + } + // add to RegExp.$i and i must <= 9 + if (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) { + globalTable->SetCapture(thread, captureIndex, capturedValue); + } + } + JSHandle emptyString = thread->GlobalConstants()->GetHandledEmptyString(); + while (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) { + globalTable->SetCapture(thread, captureIndex, emptyString.GetTaggedValue()); + ++captureIndex; + } + if (useCache) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr, + JSHandle(thread, JSTaggedValue(matchResult.isSuccess_)), + RegExpExecResultCache::TEST_TYPE, + lastIndexInput, endIndex); + } + return GetTaggedBoolean(matchResult.isSuccess_); +} + // 21.2.3.2.1 JSTaggedValue BuiltinsRegExp::RegExpAlloc(JSThread *thread, const JSHandle &newTarget) { @@ -2057,6 +2194,9 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, case INTERMEDIATE_REPLACE_TYPE: result = Get(index + RESULT_INTERMEDIATE_REPLACE_INDEX); break; + case TEST_TYPE: + result = Get(index + RESULT_TEST_INDEX); + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -2193,6 +2333,9 @@ void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTag case INTERMEDIATE_REPLACE_TYPE: Set(thread, index + RESULT_INTERMEDIATE_REPLACE_INDEX, resultArray); break; + case TEST_TYPE: + Set(thread, index + RESULT_TEST_INDEX, resultArray); + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); diff --git a/ecmascript/builtins/builtins_regexp.h b/ecmascript/builtins/builtins_regexp.h index 1801396338..b890251ada 100644 --- a/ecmascript/builtins/builtins_regexp.h +++ b/ecmascript/builtins/builtins_regexp.h @@ -101,6 +101,7 @@ private: static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000; static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu; static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9; + static constexpr uint32_t LAST_INDEX_OFFSET = 0; static RegExpExecutor::MatchResult Matcher(JSThread *thread, const JSHandle ®exp, const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16); @@ -124,6 +125,11 @@ private: const JSHandle &flags); static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle ®exp, JSHandle inputString, uint32_t inputLength); + static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle ®exp, + const JSHandle &inputString, bool useCache); + static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle ®exp, + const JSHandle &inputStr, bool useCache); + static bool IsFastRegExp(JSThread *thread, JSHandle ®exp); // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) static JSHandle MakeMatchIndicesIndexPairArray(JSThread* thread, const std::vector>& indices, @@ -137,7 +143,8 @@ public: SPLIT_TYPE, MATCH_TYPE, EXEC_TYPE, - INTERMEDIATE_REPLACE_TYPE + INTERMEDIATE_REPLACE_TYPE, + TEST_TYPE }; static RegExpExecResultCache *Cast(TaggedObject *object) { @@ -252,9 +259,10 @@ private: static constexpr int RESULT_MATCH_INDEX = 7; static constexpr int RESULT_EXEC_INDEX = 8; static constexpr int RESULT_INTERMEDIATE_REPLACE_INDEX = 9; + static constexpr int RESULT_TEST_INDEX = 10; // Extend index used for saving an additional parameter to judge cached - static constexpr int EXTEND_INDEX = 10; - static constexpr int ENTRY_SIZE = 11; + static constexpr int EXTEND_INDEX = 11; + static constexpr int ENTRY_SIZE = 12; }; class RegExpGlobalResult : public TaggedArray { diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index a2f0a4107a..ea188b8ba2 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -80,6 +80,7 @@ class JSThread; V(JSTaggedValue, RegExpFunction, REGEXP_FUNCTION_INDEX) \ V(JSTaggedValue, RegExpExecFunction, REGEXP_EXEC_FUNCTION_INDEX) \ V(JSTaggedValue, RegExpPrototype, REGEXP_PROTOTYPE_INDEX) \ + V(JSTaggedValue, RegExpPrototypeClass, REGEXP_PROTOTYPE_CLASS_INDEX) \ V(JSTaggedValue, BuiltinsSetFunction, BUILTINS_SET_FUNCTION_INDEX) \ V(JSTaggedValue, SetPrototype, SET_PROTOTYPE_INDEX) \ V(JSTaggedValue, BuiltinsMapFunction, BUILTINS_MAP_FUNCTION_INDEX) \ diff --git a/ecmascript/js_regexp.h b/ecmascript/js_regexp.h index 4045742aa9..498a745970 100644 --- a/ecmascript/js_regexp.h +++ b/ecmascript/js_regexp.h @@ -24,6 +24,8 @@ namespace panda::ecmascript { class JSRegExp : public JSObject { public: + static constexpr int EXEC_INLINE_PROPERTY_INDEX = 1; + CAST_CHECK(JSRegExp, IsJSRegExp); static constexpr size_t REGEXP_BYTE_CODE_OFFSET = JSObject::SIZE; diff --git a/test/moduletest/regexp/expect_output.txt b/test/moduletest/regexp/expect_output.txt index 1df4e01d6a..47e32c323d 100644 --- a/test/moduletest/regexp/expect_output.txt +++ b/test/moduletest/regexp/expect_output.txt @@ -46,3 +46,9 @@ aaaabb_Bbccc_C _xy_B_xy_C aaaabbBbcccC (s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s,(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(,s,(,s,(,s,(,s,(,s,(,s,(,s,(,s +false +true +false +true +false +true diff --git a/test/moduletest/regexp/regexp.js b/test/moduletest/regexp/regexp.js index be835b3a2f..a8492a61fc 100644 --- a/test/moduletest/regexp/regexp.js +++ b/test/moduletest/regexp/regexp.js @@ -311,3 +311,33 @@ let string = '(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s'; const regex1 = new RegExp(mediaReg); let matchArray = string.match(regex1); print(matchArray); + +// Test regexp.test fastpath +var protoExec = RegExp.prototype.exec +RegExp.prototype.exec = function () { + return null +} +var reg = /a/ +print(reg.test("aaaaa")); + +delete RegExp.prototype.exec +print(reg.test("aaaaa")); + +Object.prototype.exec = function () { + return null +} +print(reg.test("aaaaa")); + +delete Object.prototype.exec +RegExp.prototype.exec = protoExec +print(reg.test("aaaaa")); + +var protoTest = RegExp.prototype.test +RegExp.prototype.test = function () { + return false +} +var reg2 = /foo*/ +print(reg2.test("fooooooo")); + +RegExp.prototype.test = protoTest +print(reg2.test("fooooooo")); \ No newline at end of file From 8054787155b007e9b4e79f85915eef0c2f371a18 Mon Sep 17 00:00:00 2001 From: xiaoweidong Date: Sat, 23 Sep 2023 22:49:53 +0800 Subject: [PATCH 05/50] Opt object.assign function Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I845N3 Change-Id: If8ba8f8fd2a5ea7d5e97f780a22e5498dff57a44 Signed-off-by: xiaoweidong --- ecmascript/builtins/builtins_object.cpp | 31 ++ ecmascript/builtins/builtins_object.h | 4 +- .../builtins/builtins_call_signature.h | 1 + .../builtins/builtins_object_stub_builder.cpp | 397 ++++++++++++++++++ .../builtins/builtins_object_stub_builder.h | 11 +- .../compiler/builtins/builtins_stubs.cpp | 2 + ecmascript/compiler/stub_builder-inl.h | 26 +- ecmascript/compiler/stub_builder.cpp | 72 ++++ ecmascript/compiler/stub_builder.h | 4 + ecmascript/stubs/runtime_stubs.cpp | 9 + ecmascript/stubs/runtime_stubs.h | 1 + test/aottest/object/BUILD.gn | 1 + test/aottest/object/object_assign/BUILD.gn | 18 + .../object/object_assign/expect_output.txt | 19 + .../object/object_assign/object_assign.ts | 57 +++ test/perform/object/object.ts | 89 +++- 16 files changed, 729 insertions(+), 13 deletions(-) create mode 100644 test/aottest/object/object_assign/BUILD.gn create mode 100644 test/aottest/object/object_assign/expect_output.txt create mode 100644 test/aottest/object/object_assign/object_assign.ts diff --git a/ecmascript/builtins/builtins_object.cpp b/ecmascript/builtins/builtins_object.cpp index a942d26e13..1d3317ff06 100644 --- a/ecmascript/builtins/builtins_object.cpp +++ b/ecmascript/builtins/builtins_object.cpp @@ -60,6 +60,37 @@ JSTaggedValue BuiltinsObject::ObjectConstructor(EcmaRuntimeCallInfo *argv) return JSTaggedValue::ToObject(thread, value).GetTaggedValue(); } +JSTaggedValue BuiltinsObject::AssignTaggedValue(JSThread *thread, const JSHandle &source, + const JSHandle &toAssign) +{ + JSHandle from = JSTaggedValue::ToObject(thread, source); + JSHandle keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle::Cast(from)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + uint32_t keysLen = keys->GetLength(); + for (uint32_t j = 0; j < keysLen; j++) { + PropertyDescriptor desc(thread); + key.Update(keys->Get(j)); + bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle::Cast(from), key, desc); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + if (success && desc.IsEnumerable()) { + JSTaggedValue value = desc.GetValue().GetTaggedValue(); + if (value.IsUndefined() || JSHandle::Cast(from)->IsJSProxy()) { + value = ObjectFastOperator::FastGetPropertyByValue(thread, from.GetTaggedValue(), + key.GetTaggedValue()); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + ObjectFastOperator::FastSetPropertyByValue(thread, toAssign.GetTaggedValue(), key.GetTaggedValue(), + value); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + } + return JSTaggedValue::Undefined(); +} + // 19.1.2.1 Object.assign ( target, ...sources ) JSTaggedValue BuiltinsObject::Assign(EcmaRuntimeCallInfo *argv) { diff --git a/ecmascript/builtins/builtins_object.h b/ecmascript/builtins/builtins_object.h index 602c23cd3a..16516203e8 100644 --- a/ecmascript/builtins/builtins_object.h +++ b/ecmascript/builtins/builtins_object.h @@ -29,7 +29,7 @@ // - Object.getOwnPropertyDescriptors ( O ) #define BUILTIN_OBJECT_FUNCTIONS(V) \ /* Object.assign ( target, ...sources ) */ \ - V("assign", Assign, 2, INVALID) \ + V("assign", Assign, 2, ObjectAssign) \ /* Object.create ( O, Properties ) */ \ V("create", Create, 2, ObjectCreate) \ /* Object.defineProperties ( O, Properties ) */ \ @@ -175,6 +175,8 @@ public: return Span(OBJECT_PROTOTYPE_FUNCTIONS); } + static JSTaggedValue AssignTaggedValue(JSThread *thread, const JSHandle &source, + const JSHandle &toAssign); private: #define BUILTIN_OBJECT_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsObject::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/compiler/builtins/builtins_call_signature.h b/ecmascript/compiler/builtins/builtins_call_signature.h index f112876955..467f2724fe 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.h +++ b/ecmascript/compiler/builtins/builtins_call_signature.h @@ -39,6 +39,7 @@ namespace panda::ecmascript::kungfu { V(StringFromCharCode) \ V(ObjectToString) \ V(ObjectCreate) \ + V(ObjectAssign) \ V(VectorForEach) \ V(VectorReplaceAllElements) \ V(StackForEach) \ diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp index df54146264..1228e4ad6c 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp @@ -20,6 +20,8 @@ #include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/js_arguments.h" #include "ecmascript/message_string.h" +#include "ecmascript/tagged_dictionary.h" + namespace panda::ecmascript::kungfu { GateRef BuiltinsObjectStubBuilder::CreateListFromArrayLike(GateRef glue, GateRef arrayObj) { @@ -287,4 +289,399 @@ void BuiltinsObjectStubBuilder::Create(Variable *result, Label *exit, Label *slo } } } + +void BuiltinsObjectStubBuilder::AssignEnumElementProperty(Variable *result, Label *funcExit, + GateRef toAssign, GateRef source) +{ + auto env = GetEnvironment(); + Label entryLabel(env); + env->SubCfgEntry(&entryLabel); + Label exit(env); + + GateRef elements = GetElementsArray(source); + Label dictionaryMode(env); + Label notDictionaryMode(env); + Branch(IsDictionaryMode(elements), &dictionaryMode, ¬DictionaryMode); + Bind(¬DictionaryMode); + { + GateRef len = GetLengthOfTaggedArray(elements); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32LessThan(*idx, len), &next, &loopExit); + Bind(&next); + GateRef value = GetValueFromTaggedArray(elements, *idx); + Label notHole(env); + Branch(TaggedIsHole(value), &loopEnd, ¬Hole); + Bind(¬Hole); + { + // key, value + FastSetPropertyByIndex(glue_, toAssign, *idx, value); + Label exception(env); + Branch(HasPendingException(glue_), &exception, &loopEnd); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + } + Bind(&loopEnd); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&exit); + } + Bind(&dictionaryMode); + { + // NumberDictionary::VisitAllEnumProperty + GateRef sizeIndex = Int32(TaggedHashTable::SIZE_INDEX); + GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(elements, sizeIndex)); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32LessThan(*idx, size), &next, &loopExit); + Bind(&next); + GateRef key = GetKeyFromDictionary(elements, *idx); + Label checkEnumerable(env); + Branch(BoolOr(TaggedIsUndefined(key), TaggedIsHole(key)), &loopEnd, &checkEnumerable); + Bind(&checkEnumerable); + { + GateRef attr = GetAttributesFromDictionary(elements, *idx); + Label enumerable(env); + Branch(IsEnumerable(attr), &enumerable, &loopEnd); + Bind(&enumerable); + { + GateRef value = GetValueFromDictionary(elements, *idx); + Label notHole(env); + Branch(TaggedIsHole(value), &loopEnd, ¬Hole); + Bind(¬Hole); + { + // value + FastSetPropertyByIndex(glue_, toAssign, *idx, value); + Label exception(env); + Branch(HasPendingException(glue_), &exception, &loopEnd); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + } + } + } + Bind(&loopEnd); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsObjectStubBuilder::LayoutInfoAssignAllEnumProperty(Variable *result, Label *funcExit, + GateRef toAssign, GateRef source) +{ + auto env = GetEnvironment(); + Label entryLabel(env); + env->SubCfgEntry(&entryLabel); + Label exit(env); + + // LayoutInfo::VisitAllEnumProperty + GateRef cls = LoadHClass(source); + GateRef num = GetNumberOfPropsFromHClass(cls); + GateRef layout = GetLayoutFromHClass(cls); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32LessThan(*idx, num), &next, &loopExit); + Bind(&next); + + GateRef key = GetKeyFromLayoutInfo(layout, *idx); + GateRef attr = TruncInt64ToInt32(GetPropAttrFromLayoutInfo(layout, *idx)); + Label stringKey(env); + Branch(TaggedIsString(key), &stringKey, &loopEnd); + Bind(&stringKey); + { + Label enumerable(env); + Branch(IsEnumerable(attr), &enumerable, &loopEnd); + Bind(&enumerable); + { + DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); + value = JSObjectGetProperty(source, cls, attr); + // exception + Label exception0(env); + Label noexception0(env); + Branch(HasPendingException(glue_), &exception0, &noexception0); + Bind(&exception0); + { + *result = Exception(); + Jump(funcExit); + } + Bind(&noexception0); + Label propertyBox(env); + Label checkAccessor(env); + Label setValue(env); + Branch(TaggedIsPropertyBox(*value), &propertyBox, &checkAccessor); + Bind(&propertyBox); + { + value = GetValueFromPropertyBox(*value); + Jump(&setValue); + } + Bind(&checkAccessor); + Label isAccessor(env); + Branch(IsAccessor(attr), &isAccessor, &setValue); + Bind(&isAccessor); + { + value = CallGetterHelper(glue_, source, source, *value, ProfileOperation()); + Label exception(env); + Branch(HasPendingException(glue_), &exception, &setValue); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + Bind(&setValue); + { + FastSetPropertyByName(glue_, toAssign, key, *value); + Label exception(env); + Branch(HasPendingException(glue_), &exception, &loopEnd); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + } + } + } + Bind(&loopEnd); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&exit); + + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsObjectStubBuilder::NameDictionaryAssignAllEnumProperty(Variable *result, Label *funcExit, + GateRef toAssign, GateRef source, GateRef properties) +{ + // NameDictionary::VisitAllEnumProperty + auto env = GetEnvironment(); + Label entryLabel(env); + env->SubCfgEntry(&entryLabel); + Label exit(env); + + GateRef sizeIndex = Int32(TaggedHashTable::SIZE_INDEX); + GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(properties, sizeIndex)); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32LessThan(*idx, size), &next, &loopExit); + Bind(&next); + GateRef key = GetKeyFromDictionary(properties, *idx); + Label stringKey(env); + Branch(TaggedIsString(key), &stringKey, &loopEnd); + Bind(&stringKey); + { + GateRef attr = GetAttributesFromDictionary(properties, *idx); + Label enumerable(env); + Branch(IsEnumerable(attr), &enumerable, &loopEnd); + Bind(&enumerable); + { + DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); + value = GetValueFromDictionary(properties, *idx); + Label notHole(env); + Branch(TaggedIsHole(*value), &loopEnd, ¬Hole); + Bind(¬Hole); + { + Label isAccessor(env); + Label notAccessor(env); + Branch(IsAccessor(attr), &isAccessor, ¬Accessor); + Bind(&isAccessor); + { + value = CallGetterHelper(glue_, source, source, *value, ProfileOperation()); + // exception + Label exception(env); + Branch(HasPendingException(glue_), &exception, ¬Accessor); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + Bind(¬Accessor); + { + FastSetPropertyByName(glue_, toAssign, key, *value); + Label exception(env); + Branch(HasPendingException(glue_), &exception, &loopEnd); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + } + } + } + } + } + Bind(&loopEnd); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&exit); + + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsObjectStubBuilder::AssignAllEnumProperty(Variable *res, Label *funcExit, + GateRef toAssign, GateRef source) +{ + auto env = GetEnvironment(); + Label entryLabel(env); + env->SubCfgEntry(&entryLabel); + Label exit(env); + + GateRef properties = GetPropertiesArray(source); + Label dictionaryMode(env); + Label notDictionaryMode(env); + Branch(IsDictionaryMode(properties), &dictionaryMode, ¬DictionaryMode); + Bind(¬DictionaryMode); + { + LayoutInfoAssignAllEnumProperty(res, funcExit, toAssign, source); + Jump(&exit); + } + Bind(&dictionaryMode); + { + NameDictionaryAssignAllEnumProperty(res, funcExit, toAssign, source, properties); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsObjectStubBuilder::SlowAssign(Variable *result, Label *funcExit, GateRef toAssign, GateRef source) +{ + auto env = GetEnvironment(); + Label entryLabel(env); + env->SubCfgEntry(&entryLabel); + Label exit(env); + CallRuntime(glue_, RTSTUB_ID(ObjectSlowAssign), { toAssign, source }); + + Label exception(env); + Branch(HasPendingException(glue_), &exception, &exit); + Bind(&exception); + { + *result = Exception(); + Jump(funcExit); + } + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsObjectStubBuilder::FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source) +{ + // visit elements + AssignEnumElementProperty(res, funcExit, toAssign, source); + AssignAllEnumProperty(res, funcExit, toAssign, source); +} + +void BuiltinsObjectStubBuilder::Assign(Variable *res, Label *nextIt, Label *funcExit, + GateRef toAssign, GateRef source) +{ + auto env = GetEnvironment(); + Label checkJsObj(env); + Branch(BoolOr(TaggedIsNull(source), TaggedIsUndefined(source)), nextIt, &checkJsObj); + Bind(&checkJsObj); + { + Label fastAssign(env); + Label slowAssign(env); + Branch(IsJSObjectType(source, JSType::JS_OBJECT), &fastAssign, &slowAssign); + Bind(&fastAssign); + { + FastAssign(res, funcExit, toAssign, source); + Jump(nextIt); + } + Bind(&slowAssign); + { + SlowAssign(res, funcExit, toAssign, source); + Jump(nextIt); + } + } +} + +void BuiltinsObjectStubBuilder::Assign(Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisCollectionObj(env); + + GateRef target = GetCallArg0(numArgs_); + *result = target; + Label jsObject(env); + Branch(IsJSObjectType(target, JSType::JS_OBJECT), &jsObject, slowPath); + Bind(&jsObject); + { + Label twoArg(env); + Label notTwoArg(env); + Branch(Int64Equal(numArgs_, IntPtr(2)), &twoArg, ¬TwoArg); // 2 : two args + Bind(&twoArg); + { + GateRef source = GetCallArg1(numArgs_); + Label next(env); + Assign(result, &next, exit, target, source); + Bind(&next); + Jump(exit); + } + Bind(¬TwoArg); + Label threeArg(env); + Label notThreeArg(env); + Branch(Int64Equal(numArgs_, IntPtr(3)), &threeArg, ¬ThreeArg); // 3 : three args + Bind(&threeArg); + { + Label nextArg(env); + GateRef source = GetCallArg1(numArgs_); + Label next(env); + Assign(result, &next, exit, target, source); + Bind(&next); + Label next1(env); + GateRef source1 = GetCallArg2(numArgs_); + Assign(result, &next1, exit, target, source1); + Bind(&next1); + Jump(exit); + } + Bind(¬ThreeArg); + { + Jump(slowPath); + } + } +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.h b/ecmascript/compiler/builtins/builtins_object_stub_builder.h index c6079eeb1d..48ab77c168 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.h @@ -31,14 +31,23 @@ public: GateRef CreateListFromArrayLike(GateRef glue, GateRef arrayObj); void ToString(Variable *result, Label *exit, Label *slowPath); void Create(Variable *result, Label *exit, Label *slowPath); + void Assign(Variable *result, Label *exit, Label *slowPath); private: GateRef OrdinaryNewJSObjectCreate(GateRef proto); GateRef TransProtoWithoutLayout(GateRef hClass, GateRef proto); + void AssignEnumElementProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source); + void LayoutInfoAssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source); + void NameDictionaryAssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source, + GateRef properties); + void SlowAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source); + void FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source); + void AssignAllEnumProperty(Variable *res, Label *funcExit, GateRef toAssign, GateRef source); + void Assign(Variable *res, Label *nextIt, Label *funcExit, GateRef toAssign, GateRef source); GateRef glue_; GateRef thisValue_; GateRef numArgs_; }; } // namespace panda::ecmascript::kungfu -#endif // ECMASCRIPT_COMPILER_BUILTINS_OBJECT_STUB_BUILDER_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_BUILTINS_OBJECT_STUB_BUILDER_H diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index 466cfe50e8..854a44ecb1 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -546,6 +546,8 @@ DECLARE_BUILTINS(type##method) DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, ToString, VariableType::JS_ANY(), Undefined()); // Object.protetype.Create DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Create, VariableType::JS_ANY(), Undefined()); +// Object.protetype.Assign +DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Assign, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER #define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(type, method, retType, retDefaultValue) \ diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index e677d080e3..d88ecc155b 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1089,8 +1089,21 @@ inline GateRef StubBuilder::TaggedObjectIsEcmaObject(GateRef obj) inline GateRef StubBuilder::IsEcmaObject(GateRef obj) { - auto isHeapObject = TaggedIsHeapObject(obj); - return env_->GetBuilder()->LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj)); + auto env = GetEnvironment(); + Label entryPass(env); + env->SubCfgEntry(&entryPass); + DEFVARIABLE(result, VariableType::BOOL(), False()); + Label heapObj(env); + Label exit(env); + GateRef isHeapObject = TaggedIsHeapObject(obj); + Branch(isHeapObject, &heapObj, &exit); + Bind(&heapObj); + result = env_->GetBuilder()->LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj)); + Jump(&exit); + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; } inline GateRef StubBuilder::IsJSObject(GateRef obj) @@ -1324,6 +1337,15 @@ inline GateRef StubBuilder::IsAccessor(GateRef attr) Int32(0)); } +inline GateRef StubBuilder::IsEnumerable(GateRef attr) +{ + return Int32NotEqual( + Int32And(Int32LSR(attr, + Int32(PropertyAttributes::EnumerableField::START_BIT)), + Int32((1LLU << PropertyAttributes::EnumerableField::SIZE) - 1)), + Int32(0)); +} + inline GateRef StubBuilder::IsInlinedProperty(GateRef attr) { return Int32NotEqual( diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index beaf2fe0d6..77bcc60d56 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -3734,6 +3734,78 @@ GateRef StubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef i return ret; } +void StubBuilder::FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, GateRef value, + ProfileOperation callback) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(keyVar, VariableType::JS_ANY(), key); + DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); + Label exit(env); + Label fastPath(env); + Label slowPath(env); + Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath); + Bind(&fastPath); + { + Label isString(env); + Label getByName(env); + Label isInternalString(env); + Label notIntenalString(env); + Branch(TaggedIsString(*keyVar), &isString, &getByName); + Bind(&isString); + { + Branch(IsInternalString(*keyVar), &isInternalString, ¬IntenalString); + Bind(&isInternalString); + Jump(&getByName); + Bind(¬IntenalString); + { + keyVar = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *keyVar }); + Jump(&getByName); + } + } + Bind(&getByName); + + result = SetPropertyByName(glue, obj, *keyVar, value, false, callback); + Label notHole(env); + Branch(TaggedIsHole(*result), &slowPath, &exit); + } + Bind(&slowPath); + { + result = CallRuntime(glue, RTSTUB_ID(StoreICByValue), { obj, *keyVar, value, Int64ToTaggedPtr(Int32(0)) }); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + +void StubBuilder::FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, GateRef value) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); + Label exit(env); + Label fastPath(env); + Label slowPath(env); + + Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath); + Bind(&fastPath); + { + result = SetPropertyByIndex(glue, obj, index, value, false); + Label notHole(env); + Branch(TaggedIsHole(*result), &slowPath, &exit); + } + Bind(&slowPath); + { + result = CallRuntime(glue, RTSTUB_ID(StObjByIndex), + { obj, IntToTaggedInt(index), value }); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index e353ac05e1..ca939dfd98 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -323,6 +323,7 @@ public: GateRef IsByteArray(GateRef obj); GateRef IsJsCOWArray(GateRef obj); GateRef IsJSObject(GateRef obj); + GateRef IsEnumerable(GateRef attr); GateRef IsWritable(GateRef attr); GateRef IsAccessor(GateRef attr); GateRef IsInlinedProperty(GateRef attr); @@ -555,6 +556,9 @@ public: GateRef FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback); GateRef FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback); GateRef GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback); + void FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, GateRef value, + ProfileOperation callback = ProfileOperation()); + void FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, GateRef value); GateRef SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn); GateRef SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn, ProfileOperation callback = ProfileOperation()); // Crawl prototype chain diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index deea10e788..442c1ac19f 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -57,6 +57,7 @@ #include "ecmascript/tagged_node.h" #include "ecmascript/ts_types/ts_manager.h" #include "ecmascript/linked_hash_table.h" +#include "ecmascript/builtins/builtins_object.h" #include "libpandafile/bytecode_instruction-inl.h" #include "macros.h" #ifdef ARK_SUPPORT_INTL @@ -2654,6 +2655,14 @@ DEF_RUNTIME_STUBS(LinkedHashSetComputeCapacity) return JSTaggedValue(LinkedHashSet::ComputeCapacity(value.GetInt())).GetRawData(); } +DEF_RUNTIME_STUBS(ObjectSlowAssign) +{ + RUNTIME_STUBS_HEADER(ObjectSlowAssign); + JSHandle toAssign = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSHandle source = GetHArg(argv, argc, 1); // 1: means the first parameter + return builtins::BuiltinsObject::AssignTaggedValue(thread, source, toAssign).GetRawData(); +} + void RuntimeStubs::Initialize(JSThread *thread) { #define DEF_RUNTIME_STUB(name) kungfu::RuntimeStubCSigns::ID_##name diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 6e852dae18..fd9a39acc1 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -317,6 +317,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(LocaleCompare) \ V(ArraySort) \ V(FastStringify) \ + V(ObjectSlowAssign) \ V(GetLinkedHash) \ V(LinkedHashMapComputeCapacity) \ V(LinkedHashSetComputeCapacity) \ diff --git a/test/aottest/object/BUILD.gn b/test/aottest/object/BUILD.gn index ba75d3da98..faafe66236 100644 --- a/test/aottest/object/BUILD.gn +++ b/test/aottest/object/BUILD.gn @@ -15,6 +15,7 @@ group("object_test") { testonly = true test_list = [ + "object_assign", "object_hasOwnProperty", "object_toString", ] diff --git a/test/aottest/object/object_assign/BUILD.gn b/test/aottest/object/object_assign/BUILD.gn new file mode 100644 index 0000000000..3c2cd16615 --- /dev/null +++ b/test/aottest/object/object_assign/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright (c) 2022 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_aot_test_action("object_assign") { + deps = [] +} diff --git a/test/aottest/object/object_assign/expect_output.txt b/test/aottest/object/object_assign/expect_output.txt new file mode 100644 index 0000000000..ab78ca9638 --- /dev/null +++ b/test/aottest/object/object_assign/expect_output.txt @@ -0,0 +1,19 @@ +# 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. + +1 +6 +6 +3 +false +a,b,c diff --git a/test/aottest/object/object_assign/object_assign.ts b/test/aottest/object/object_assign/object_assign.ts new file mode 100644 index 0000000000..39cec94a7c --- /dev/null +++ b/test/aottest/object/object_assign/object_assign.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ + +declare function print(arg:any):string; +const obja = { a: 1 }; +const copy = Object.assign({}, obja); +print(copy.a); + +const o1 = { a: 1 }; +const o2 = { b: 2 }; +const o3 = { c: 3 }; + +const obj = Object.assign(o1, o2, o3); +print(obj.a + obj.b + obj.c) +const o4 = { a: 1, b: 1, c: 1 }; +const o5 = { b: 2, c: 2 }; +const o6 = { c: 3 }; + +const obj1 = Object.assign({}, o4, o5, o6, o6); +print(obj1.a + obj1.b + obj1.c); + +const obj2 = Object.create( + { foo: 1 }, + { + bar: { + value: 2, + }, + baz: { + value: 3, + enumerable: true, + }, + }, +); + +const copy1 = Object.assign({}, obj2); +print(copy1.baz); +print(copy1.hasOwnProperty("bar")); + +const v1 = "abc"; +const v2 = true; +const v3 = 10; +const v4 = Symbol("foo"); + +const obj3 = Object.assign({}, v1, null, v2, undefined, v3, v4); +print(Object.values(obj3)) diff --git a/test/perform/object/object.ts b/test/perform/object/object.ts index 18452cde2b..942708a9f7 100644 --- a/test/perform/object/object.ts +++ b/test/perform/object/object.ts @@ -16,21 +16,33 @@ declare interface ArkTools { timeInUs(arg:any):number } -function testToString() { - let theDog = new Dog("Gabby", "Lab"); - let res; +function testDefineProperty() { let start = ArkTools.timeInUs(); - for (let i = 0; i < 1_000_000; i++) { - res = theDog.toString(); + for (let i = 0; i < 100_000; i++) { + const o = {}; + Object.defineProperty(o, "a", { + value: 1, + enumerable: false, + configurable: false, + writable: false, + value: "static", + }); + Object.defineProperty(o, "b", { + value: 2, + writable: true, + enumerable: true, + configurable: true, + }); + Object.defineProperty(o, "c", { + value: 3, + writable: false, + }); } let end = ArkTools.timeInUs(); let time = (end - start) / 1000 - print(res); - print("Object ToString:\t" + String(time) + "\tms"); + print("Object DefineProperty:\t"+String(time)+"\tms"); } -testToString(); - function testHasOwnProperty() { const example = {}; example.prop = "exists"; @@ -43,4 +55,63 @@ function testHasOwnProperty() { print("Object HasOwnProperty:\t"+String(time)+"\tms"); } +function testAssign() { + let o1 = { a: 1 }; + let o2 = { b: 2 }; + let o3 = { c: 3 }; + let res; + let start = ArkTools.timeInUs(); + for (let i = 0; i < 1_000_000; i++) { + res = Object.assign(o1, o2, o3); + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print(res); + print("Object Assign:\t"+String(time)+"\tms"); +} + +function testCreate() { + const person = { + isHuman: false, + printIntroduction: function () { + }, + }; + let res; + let start = ArkTools.timeInUs(); + for (let i = 0; i < 1_000_000; i++) { + res = Object.create(person); + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print(res); + print("Object Create:\t"+String(time)+"\tms"); +} + +class Dog { + constructor(name, breed, color, sex) { + this.name = name; + this.breed = breed; + this.color = color; + this.sex = sex; + } +} + +function testToString() { + let theDog = new Dog("Gabby", "Lab", "chocolate", "female"); + let res; + let start = ArkTools.timeInUs(); + for (let i = 0; i < 1_000_000; i++) { + res = theDog.toString(); + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print(res); + print("Object ToString:\t"+String(time)+"\tms"); +} + +testDefineProperty(); testHasOwnProperty(); +testAssign(); +testCreate(); +testToString(); + From 672e0f7e42686d5e164dae7d8368e47742448e66 Mon Sep 17 00:00:00 2001 From: hzzhouzebin Date: Wed, 27 Sep 2023 14:36:04 +0800 Subject: [PATCH 06/50] Add Switch For external package compiling Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84SCZ Signed-off-by: hzzhouzebin Change-Id: Ib4853662fc4d833ad1a5e35eef48785e8b512a0f --- ecmascript/compiler/aot_compiler.cpp | 62 +++++++++------------------- ecmascript/compiler/aot_compiler.h | 9 ++-- ecmascript/compiler/ohos_pkg_args.h | 49 +++++++++++++++++++--- ecmascript/js_runtime_options.cpp | 10 +++++ ecmascript/js_runtime_options.h | 12 ++++++ 5 files changed, 89 insertions(+), 53 deletions(-) diff --git a/ecmascript/compiler/aot_compiler.cpp b/ecmascript/compiler/aot_compiler.cpp index c3cf261a1d..4289063c14 100644 --- a/ecmascript/compiler/aot_compiler.cpp +++ b/ecmascript/compiler/aot_compiler.cpp @@ -26,6 +26,7 @@ #include "ecmascript/js_runtime_options.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/log.h" +#include "ecmascript/log_wrapper.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/platform/file.h" @@ -42,8 +43,7 @@ std::string GetHelper() return str; } -CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, - OhosPkgArgs &pkgArgs, arg_list_t &pandaFileNames) +CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions) { triple_ = runtimeOptions.GetTargetTriple(); if (runtimeOptions.GetAOTOutputFile().empty()) { @@ -91,22 +91,21 @@ bool CompilationPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOpti bool CompilationPreprocessor::HandleOhosPkgArgs() { ASSERT(runtimeOptions_.IsTargetCompilerMode()); + OhosPkgArgs pkgArgs; if (!runtimeOptions_.GetCompilerPkgJsonInfo().empty()) { - if (pkgArgs_.ParseFromJson(vm_, runtimeOptions_.GetCompilerPkgJsonInfo())) { + if (pkgArgs.ParseFromJson(vm_, runtimeOptions_.GetCompilerPkgJsonInfo())) { LOG_COMPILER(INFO) << "Parse main pkg info success."; - pkgArgs_.Dump(); - pandaFileNames_.emplace_back(pkgArgs_.GetFullName()); + pkgsArgs_[pkgArgs.GetFullName()] = pkgArgs; } else { return false; } } - // for external pkg, dump it first. - if (!runtimeOptions_.GetCompilerExternalPkgJsonInfo().empty()) { - std::list externalList; - OhosPkgArgs::ParseListFromJson(vm_, runtimeOptions_.GetCompilerExternalPkgJsonInfo(), externalList); - for (const auto &externalPkg : externalList) { - externalPkg.Dump(); - } + if (runtimeOptions_.GetCompilerEnableExternalPkg() && !runtimeOptions_.GetCompilerExternalPkgJsonInfo().empty()) { + OhosPkgArgs::ParseListFromJson(vm_, runtimeOptions_.GetCompilerExternalPkgJsonInfo(), pkgsArgs_); + } + for (const auto &pkgInfo : pkgsArgs_) { + pandaFileNames_.emplace_back(pkgInfo.first); + pkgInfo.second.Dump(); } return true; } @@ -125,7 +124,7 @@ void CompilationPreprocessor::HandleTargetModeInfo(CompilationOptions &cOptions) bool CompilationPreprocessor::HandlePandaFileNames(const int argc, const char **argv) { - if (runtimeOptions_.GetCompilerPkgJsonInfo().empty() || !pkgArgs_.Valid()) { + if (runtimeOptions_.GetCompilerPkgJsonInfo().empty() || pkgsArgs_.empty()) { // if no pkgArgs, last param must be abc file std::string files = argv[argc - 1]; if (!base::StringHelper::EndsWith(files, ".abc")) { @@ -182,37 +181,14 @@ std::shared_ptr CompilationPreprocessor::CreateAndVerifyJSPandaFile JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance(); std::shared_ptr jsPandaFile = nullptr; if (runtimeOptions_.IsTargetCompilerMode()) { - std::string hapPath; - uint32_t offset {}; - uint32_t size {}; - if (pkgArgs_.Valid()) { - hapPath = pkgArgs_.GetPath(); - offset = pkgArgs_.GetOffset(); - size = pkgArgs_.GetSize(); - } else { - // for legacy params - hapPath = runtimeOptions_.GetHapPath(); - offset = runtimeOptions_.GetHapAbcOffset(); - size = runtimeOptions_.GetHapAbcSize(); - } - if (size == 0) { - LOG_ECMA(ERROR) << "buffer is empty in target compiler mode!"; + auto pkgArgsIter = pkgsArgs_.find(fileName); + if (pkgArgsIter == pkgsArgs_.end()) { + LOG_COMPILER(ERROR) << "Can not find file in ohos pkgs args. file name: " << fileName; return nullptr; } - std::string realPath; - if (!RealPath(hapPath, realPath, false)) { - LOG_ECMA(ERROR) << "realpath for hap path failed!"; + if (!(pkgArgsIter->second.GetJSPandaFile(runtimeOptions_, jsPandaFile))) { return nullptr; } - MemMap fileMapMem = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ); - if (fileMapMem.GetOriginAddr() == nullptr) { - LOG_ECMA(ERROR) << "File mmap failed"; - return nullptr; - } - uint8_t *buffer = reinterpret_cast(fileMapMem.GetOriginAddr()) + offset; - jsPandaFile = jsPandaFileManager->OpenJSPandaFileFromBuffer(buffer, size, fileName.c_str()); - FileUnMap(fileMapMem); - fileMapMem.Reset(); } else { jsPandaFile = jsPandaFileManager->OpenJSPandaFile(fileName.c_str()); } @@ -342,15 +318,15 @@ int Main(const int argc, const char **argv) { LocalScope scope(vm); arg_list_t pandaFileNames {}; - OhosPkgArgs pkgArgs; - CompilationOptions cOptions(vm, runtimeOptions, pkgArgs, pandaFileNames); + std::map pkgArgsMap; + CompilationOptions cOptions(vm, runtimeOptions); CompilerLog log(cOptions.logOption_); log.SetEnableCompilerLogTime(cOptions.compilerLogTime_); AotMethodLogList logList(cOptions.logMethodsList_); PGOProfilerDecoder profilerDecoder(cOptions.profilerIn_, cOptions.hotnessThreshold_); - CompilationPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgs, profilerDecoder, pandaFileNames); + CompilationPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgsMap, profilerDecoder, pandaFileNames); if (!cPreprocessor.HandleTargetCompilerMode(cOptions) || !cPreprocessor.HandlePandaFileNames(argc, argv)) { return 1; diff --git a/ecmascript/compiler/aot_compiler.h b/ecmascript/compiler/aot_compiler.h index f143030611..168493d958 100644 --- a/ecmascript/compiler/aot_compiler.h +++ b/ecmascript/compiler/aot_compiler.h @@ -33,8 +33,7 @@ struct AbcFileInfo { }; struct CompilationOptions { - explicit CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, - OhosPkgArgs &pkgArgs, arg_list_t &pandaFileNames); + explicit CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions); std::string triple_; std::string outputFileName_; @@ -64,9 +63,9 @@ struct CompilationOptions { class CompilationPreprocessor { public: - CompilationPreprocessor(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, OhosPkgArgs &pkgArgs, + CompilationPreprocessor(EcmaVM *vm, JSRuntimeOptions &runtimeOptions, std::map &pkgsArgs, PGOProfilerDecoder &profilerDecoder, arg_list_t &pandaFileNames) - : vm_(vm), runtimeOptions_(runtimeOptions), pkgArgs_(pkgArgs), + : vm_(vm), runtimeOptions_(runtimeOptions), pkgsArgs_(pkgsArgs), profilerDecoder_(profilerDecoder), pandaFileNames_(pandaFileNames) {}; ~CompilationPreprocessor() = default; @@ -106,7 +105,7 @@ private: EcmaVM *vm_; JSRuntimeOptions &runtimeOptions_; - OhosPkgArgs &pkgArgs_; + std::map &pkgsArgs_; PGOProfilerDecoder &profilerDecoder_; arg_list_t &pandaFileNames_; CVector fileInfos_; diff --git a/ecmascript/compiler/ohos_pkg_args.h b/ecmascript/compiler/ohos_pkg_args.h index aa118c0b7a..38de3265a9 100644 --- a/ecmascript/compiler/ohos_pkg_args.h +++ b/ecmascript/compiler/ohos_pkg_args.h @@ -17,12 +17,14 @@ #define ECMASCRIPT_COMPILER_OHOS_PKG_ARGS_H #include +#include #include "ecmascript/ecma_vm.h" #include "ecmascript/base/json_parser.h" #include "ecmascript/js_array.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_tagged_value.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/platform/file.h" @@ -39,7 +41,44 @@ public: OhosPkgArgs() = default; - static bool ParseListFromJson(EcmaVM *vm, const std::string &jsonInfo, std::list &infoList) + bool GetJSPandaFile(const JSRuntimeOptions &runtimeOptions, std::shared_ptr &pf) const + { + std::string hapPath; + uint32_t offset {}; + uint32_t size {}; + if (Valid()) { + hapPath = GetPath(); + offset = GetOffset(); + size = GetSize(); + } else { + // for legacy params + hapPath = runtimeOptions.GetHapPath(); + offset = runtimeOptions.GetHapAbcOffset(); + size = runtimeOptions.GetHapAbcSize(); + } + if (size == 0) { + LOG_ECMA(ERROR) << "buffer is empty in target compiler mode!"; + return false; + } + std::string realPath; + if (!RealPath(hapPath, realPath, false)) { + LOG_ECMA(ERROR) << "realpath for hap path failed!"; + return false; + } + MemMap fileMapMem = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ); + if (fileMapMem.GetOriginAddr() == nullptr) { + LOG_ECMA(ERROR) << "File mmap failed"; + return false; + } + uint8_t *buffer = reinterpret_cast(fileMapMem.GetOriginAddr()) + offset; + JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance(); + pf = jsPandaFileManager->OpenJSPandaFileFromBuffer(buffer, size, GetFullName().c_str()); + FileUnMap(fileMapMem); + fileMapMem.Reset(); + return true; + } + + static bool ParseListFromJson(EcmaVM *vm, const std::string &jsonInfo, std::map &argsMap) { LocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); @@ -67,7 +106,7 @@ public: LOG_COMPILER(ERROR) << "Pkg list entry info parse failed. jsonData: " << jsonInfo.c_str(); return false; } - infoList.emplace_back(pkgInfo); + argsMap[pkgInfo.GetFullName()] = pkgInfo; } return true; } @@ -140,9 +179,9 @@ public: void Dump() const { - LOG_ECMA(INFO) << "PkgInfo: " << KEY_BUNDLE_NAME << ": " << bundleName_ << ", " << KEY_MODULE_NAME << ": " - << moduleName_ << ", " << KEY_PKG_PATH << ": " << pkgPath_ << ", " << KEY_ABC_OFFSET << ": " - << std::hex << abcOffset_ << ", " << KEY_ABC_SIZE << ": " << abcSize_; + LOG_COMPILER(INFO) << "PkgInfo: " << KEY_BUNDLE_NAME << ": " << bundleName_ << ", " << KEY_MODULE_NAME << ": " + << moduleName_ << ", " << KEY_PKG_PATH << ": " << pkgPath_ << ", " << KEY_ABC_OFFSET << ": " + << std::hex << abcOffset_ << ", " << KEY_ABC_SIZE << ": " << abcSize_; } const std::string &GetBundleName() const diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index d2e0e88d95..cd0103c33c 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -147,6 +147,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = "--compiler-opt-loop-peeling: Enable loop peeling for aot compiler: Default: 'false'\n" "--compiler-pkg-info Specify the package json info for ark aot compiler\n" "--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-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) @@ -230,6 +231,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-opt-array-onheap-check", required_argument, nullptr, OPTION_COMPILER_OPT_ON_HEAP_CHECK}, {"compiler-pkg-info", required_argument, nullptr, OPTION_COMPILER_PKG_INFO}, {"compiler-external-pkg-info", required_argument, nullptr, OPTION_COMPILER_EXTERNAL_PKG_INFO}, + {"compiler-enable-external-pkg", required_argument, nullptr, OPTION_COMPILER_ENABLE_EXTERNAL_PKG}, {nullptr, 0, nullptr, 0}, }; @@ -759,6 +761,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) case OPTION_COMPILER_EXTERNAL_PKG_INFO: SetCompilerExternalPkgJsonInfo(optarg); break; + case OPTION_COMPILER_ENABLE_EXTERNAL_PKG: + ret = ParseBoolParam(&argBool); + if (ret) { + SetCompilerEnableExternalPkg(argBool); + } else { + return false; + } + break; default: LOG_ECMA(ERROR) << "Invalid option\n"; return false; diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 8167b9740e..9df0cec810 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -140,6 +140,7 @@ enum CommandValues { OPTION_COMPILER_OPT_ON_HEAP_CHECK, OPTION_COMPILER_PKG_INFO, OPTION_COMPILER_EXTERNAL_PKG_INFO, + OPTION_COMPILER_ENABLE_EXTERNAL_PKG, OPTION_COMPILER_OPT_ARRAY_BOUNDS_CHECK_ELIMINATION, OPTION_COMPILER_OPT_LOOP_INVARIANT_CODE_MOTION, }; @@ -214,6 +215,16 @@ public: return compilerExternalPkgInfo_; } + void SetCompilerEnableExternalPkg(bool compilerEnableExternalPkg) + { + compilerEnableExternalPkg_ = compilerEnableExternalPkg; + } + + bool GetCompilerEnableExternalPkg() const + { + return compilerEnableExternalPkg_; + } + bool WasStubFileSet() const { return WasOptionSet(OPTION_STUB_FILE); @@ -1246,6 +1257,7 @@ private: std::string stubFile_ {"stub.an"}; std::string compilerPkgInfo_ {}; std::string compilerExternalPkgInfo_ {}; + bool compilerEnableExternalPkg_ {false}; bool enableForceGc_ {true}; bool forceFullGc_ {true}; int arkProperties_ = GetDefaultProperties(); From 2ff432f662b3671a6f801b108ed840fc58d35170 Mon Sep 17 00:00:00 2001 From: xiongluo Date: Tue, 10 Oct 2023 14:39:32 +0800 Subject: [PATCH 07/50] fix mem pool asseret fail Signed-off-by: xiongluo Change-Id: I5849387ceeb9c27c748f42d4b1cdd01108a1fe7f --- ecmascript/mem/mem_map_allocator.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ecmascript/mem/mem_map_allocator.cpp b/ecmascript/mem/mem_map_allocator.cpp index e8751ff58c..bb21b50e5c 100644 --- a/ecmascript/mem/mem_map_allocator.cpp +++ b/ecmascript/mem/mem_map_allocator.cpp @@ -74,8 +74,11 @@ void MemMapAllocator::CacheOrFree(void *mem, size_t size, bool isRegular, size_t int freeNum = memMapPool_.ShouldFreeMore(cachedSize); for (int i = 0; i < freeNum; i++) { void *freeMem = memMapPool_.GetRegularMemFromCommitted(size).GetMem(); - ASSERT(freeMem != nullptr); - Free(freeMem, size, isRegular); + if (freeMem != nullptr) { + Free(freeMem, size, isRegular); + } else { + return; + } } } } From e2301fc36c644167127e37e130781af5c87faa10 Mon Sep 17 00:00:00 2001 From: like Date: Tue, 10 Oct 2023 17:40:09 +0800 Subject: [PATCH 08/50] Fix cannot find record 'func_main_0', please check the request path. Signed-off-by: like Change-Id: Ic898285c74f09985863e12e7e2f359247ed490e5 --- ecmascript/compiler/bytecode_info_collector.h | 7 +++++-- test/aottest/definemethod/definemethod.ts | 21 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ecmascript/compiler/bytecode_info_collector.h b/ecmascript/compiler/bytecode_info_collector.h index 38efd93b8f..2e516547dc 100644 --- a/ecmascript/compiler/bytecode_info_collector.h +++ b/ecmascript/compiler/bytecode_info_collector.h @@ -523,8 +523,11 @@ public: auto &item = cpInfo_.GetCPItem(type); for (auto &iter : item) { ConstantPoolInfo::ItemData &data = iter.second; - data.recordName = &methodOffsetToRecordName_[data.outerMethodOffset]; - cb(data); + auto recordNameIter = methodOffsetToRecordName_.find(data.outerMethodOffset); + if (recordNameIter != methodOffsetToRecordName_.end()) { + data.recordName = &recordNameIter->second; + cb(data); + } } } diff --git a/test/aottest/definemethod/definemethod.ts b/test/aottest/definemethod/definemethod.ts index 12c34c1092..9c95104c65 100644 --- a/test/aottest/definemethod/definemethod.ts +++ b/test/aottest/definemethod/definemethod.ts @@ -13,12 +13,23 @@ * limitations under the License. */ -declare function print(str:any):string; +declare function print(str: any): string; var obj = { - get method():string { - return "define method"; - } -} + get method(): string { + return "define method"; + }, +}; print(obj.method); + +function f45() { + return 0; + class C113 { + [Symbol.iterator]() { + return { + next() {}, + }; + } + } +} From 9430c55952980a272ba55b7a402ee54e49de23b3 Mon Sep 17 00:00:00 2001 From: dov1s Date: Tue, 26 Sep 2023 16:58:53 +0800 Subject: [PATCH 09/50] opt lambda expression issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84JE7 Signed-off-by: dov1s Change-Id: I213604f81b9d324a40317f61abc3a990ed7052df --- ecmascript/mem/parallel_marker-inl.h | 16 +++++-------- ecmascript/mem/parallel_marker.cpp | 36 ++++++++++++++++++---------- ecmascript/mem/parallel_marker.h | 3 ++- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/ecmascript/mem/parallel_marker-inl.h b/ecmascript/mem/parallel_marker-inl.h index 3426742979..d2d590b838 100644 --- a/ecmascript/mem/parallel_marker-inl.h +++ b/ecmascript/mem/parallel_marker-inl.h @@ -28,18 +28,17 @@ namespace panda::ecmascript { constexpr size_t HEAD_SIZE = TaggedObject::TaggedObjectSize(); template -inline bool NonMovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback) +ARK_INLINE bool NonMovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, + bool needBarrier, Callback callback) { auto hclass = root->SynchronizedGetClass(); - if (hclass->IsAllTaggedProp()) { - return false; - } + Region *rootRegion = Region::ObjectAddressToRange(root); int index = 0; for (ObjectSlot slot = start; slot < end; slot++) { auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject()); auto attr = layout->GetAttr(index++); if (attr.IsTaggedRep()) { - callback(slot); + callback(slot, rootRegion, needBarrier); } } return true; @@ -134,12 +133,9 @@ inline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedTyp } template -inline bool MovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback) +ARK_INLINE bool MovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback) { auto hclass = root->GetClass(); - if (hclass->IsAllTaggedProp()) { - return false; - } int index = 0; for (ObjectSlot slot = start; slot < end; slot++) { TaggedObject *dst = hclass->GetLayout().GetTaggedObject(); @@ -150,7 +146,7 @@ inline bool MovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, auto layout = LayoutInfo::Cast(dst); auto attr = layout->GetAttr(index++); if (attr.IsTaggedRep()) { - callback(slot); + callback(slot, root); } } return true; diff --git a/ecmascript/mem/parallel_marker.cpp b/ecmascript/mem/parallel_marker.cpp index 1919d0b56c..536ee715a0 100644 --- a/ecmascript/mem/parallel_marker.cpp +++ b/ecmascript/mem/parallel_marker.cpp @@ -66,13 +66,16 @@ void NonMovableMarker::ProcessMarkStack(uint32_t threadId) { TRACE_GC(GCStats::Scope::ScopeId::ProcessMarkStack, heap_->GetEcmaVM()->GetEcmaGCStats()); bool isFullMark = heap_->IsFullMark(); - auto visitor = [this, threadId, isFullMark](TaggedObject *root, ObjectSlot start, ObjectSlot end, - VisitObjectArea area) { + auto cb = [&](ObjectSlot s, Region *rootRegion,bool needBarrier) { + MarkValue(threadId, s, rootRegion, needBarrier); + }; + auto visitor = [this, threadId, isFullMark, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, + VisitObjectArea area) { Region *rootRegion = Region::ObjectAddressToRange(root); bool needBarrier = isFullMark && !rootRegion->InYoungSpaceOrCSet(); if (area == VisitObjectArea::IN_OBJECT) { - if (VisitBodyInObj(root, start, end, - [&](ObjectSlot slot) { MarkValue(threadId, slot, rootRegion, needBarrier); })) { + auto hclass = root->SynchronizedGetClass(); + if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, needBarrier, cb)) { return; } } @@ -98,14 +101,17 @@ void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t m TRACE_GC(GCStats::Scope::ScopeId::ProcessMarkStack, heap_->GetEcmaVM()->GetEcmaGCStats()); bool isFullMark = heap_->IsFullMark(); uint32_t visitAddrNum = 0; - auto visitor = [this, threadId, isFullMark, &visitAddrNum](TaggedObject *root, ObjectSlot start, ObjectSlot end, - VisitObjectArea area) { + auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) { + MarkValue(threadId, s, rootRegion, needBarrier); + }; + auto visitor = [this, threadId, isFullMark, &visitAddrNum, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, + VisitObjectArea area) { Region *rootRegion = Region::ObjectAddressToRange(root); visitAddrNum += end.SlotAddress() - start.SlotAddress(); bool needBarrier = isFullMark && !rootRegion->InYoungSpaceOrCSet(); if (area == VisitObjectArea::IN_OBJECT) { - if (VisitBodyInObj(root, start, end, - [&](ObjectSlot slot) { MarkValue(threadId, slot, rootRegion, needBarrier); })) { + auto hclass = root->SynchronizedGetClass(); + if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, needBarrier, cb)) { return; } } @@ -146,10 +152,12 @@ void SemiGCMarker::Initialize() void SemiGCMarker::ProcessMarkStack(uint32_t threadId) { TRACE_GC(GCStats::Scope::ScopeId::ProcessMarkStack, heap_->GetEcmaVM()->GetEcmaGCStats()); - auto visitor = [this, threadId](TaggedObject *root, ObjectSlot start, ObjectSlot end, - VisitObjectArea area) { + auto cb = [&](ObjectSlot s, TaggedObject *root) { MarkValue(threadId, root, s); }; + auto visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, + VisitObjectArea area) { if (area == VisitObjectArea::IN_OBJECT) { - if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { MarkValue(threadId, root, slot); })) { + auto hclass = root->SynchronizedGetClass(); + if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, cb)) { return; } } @@ -172,10 +180,12 @@ void SemiGCMarker::ProcessMarkStack(uint32_t threadId) void CompressGCMarker::ProcessMarkStack(uint32_t threadId) { TRACE_GC(GCStats::Scope::ScopeId::ProcessMarkStack, heap_->GetEcmaVM()->GetEcmaGCStats()); - auto visitor = [this, threadId](TaggedObject *root, ObjectSlot start, ObjectSlot end, + auto cb = [&](ObjectSlot s, [[maybe_unused]] TaggedObject *root) { MarkValue(threadId, s); }; + auto visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { if (area == VisitObjectArea::IN_OBJECT) { - if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { MarkValue(threadId, slot); })) { + auto hclass = root->SynchronizedGetClass(); + if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, cb)) { return; } } diff --git a/ecmascript/mem/parallel_marker.h b/ecmascript/mem/parallel_marker.h index f7a4ff9b0b..1f48dd6bf2 100644 --- a/ecmascript/mem/parallel_marker.h +++ b/ecmascript/mem/parallel_marker.h @@ -96,7 +96,8 @@ public: protected: void ProcessMarkStack(uint32_t threadId) override; template - inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback); + inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, + bool needBarrier, Callback callback); inline void MarkValue(uint32_t threadId, ObjectSlot &slot, Region *rootRegion, bool needBarrier); inline void MarkObject(uint32_t threadId, TaggedObject *object) override; inline void HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) override; From 8ec3d6f383aa5b0ad4a017f2939d334b92024b72 Mon Sep 17 00:00:00 2001 From: yaoyuan Date: Wed, 11 Oct 2023 08:58:19 +0800 Subject: [PATCH 10/50] BugFix on LdGlobalVar Js TypeInfer When doing type-inference in js file, we substitute undefined type to any type. Issue: I870WC Signed-off-by: yaoyuan Change-Id: I2bd5b2e70bbdfb99d768cbe970fe860ce461cf81 --- ecmascript/compiler/type_inference/method_type_infer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ecmascript/compiler/type_inference/method_type_infer.cpp b/ecmascript/compiler/type_inference/method_type_infer.cpp index fd6d2bd69c..cf86cdb7d5 100644 --- a/ecmascript/compiler/type_inference/method_type_infer.cpp +++ b/ecmascript/compiler/type_inference/method_type_infer.cpp @@ -692,6 +692,9 @@ bool MethodTypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC) ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); } + if (!hasType_ && inValueType.IsUndefinedType()) { + inValueType = GateType::AnyType(); + } if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) { stringIdToGateType_[stringId] = inValueType; } else { From 2ac74c5acc4ce5d42483e0a0acc5bc50852249df Mon Sep 17 00:00:00 2001 From: K0u1hw Date: Tue, 26 Sep 2023 16:33:02 +0800 Subject: [PATCH 11/50] Optimize CreateObjectWithBuffer Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84U4E Signed-off-by: K0u1hw Change-Id: I7dfe3084fd5a96cc19961de3aaa28c73fc24f9da --- .../builtins/builtins_object_stub_builder.cpp | 63 ++++++++++++++++++ .../builtins/builtins_object_stub_builder.h | 2 + ecmascript/compiler/circuit_builder.cpp | 51 +++++++++++++++ ecmascript/compiler/circuit_builder.h | 4 ++ ecmascript/compiler/interpreter_stub.cpp | 62 +++++++++++++++--- ecmascript/compiler/stub_builder-inl.h | 10 +++ ecmascript/compiler/stub_builder.cpp | 7 ++ ecmascript/compiler/stub_builder.h | 3 + ecmascript/jspandafile/program_object.h | 53 +++++++++++++-- ecmascript/stubs/runtime_stubs.cpp | 10 +++ ecmascript/stubs/runtime_stubs.h | 1 + test/moduletest/BUILD.gn | 3 + .../createobjectwithbuffer/BUILD.gn | 18 ++++++ .../createobjectwithbuffer.js | 64 +++++++++++++++++++ .../createobjectwithbuffer/expect_output.txt | 22 +++++++ 15 files changed, 357 insertions(+), 16 deletions(-) create mode 100644 test/moduletest/createobjectwithbuffer/BUILD.gn create mode 100644 test/moduletest/createobjectwithbuffer/createobjectwithbuffer.js create mode 100644 test/moduletest/createobjectwithbuffer/expect_output.txt diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp index 1228e4ad6c..4fc85cc0c7 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp @@ -684,4 +684,67 @@ void BuiltinsObjectStubBuilder::Assign(Variable *result, Label *exit, Label *slo } } } + +GateRef BuiltinsObjectStubBuilder::CloneObjectLiteral(GateRef glue, GateRef objLiteral) +{ + auto env = GetEnvironment(); + Label entry(env); + Label loopHead(env); + Label loopExit(env); + Label loopBack(env); + env->SubCfgEntry(&entry); + auto klass = LoadHClass(objLiteral); + NewObjectStubBuilder objBuilder(this); + auto newObj = objBuilder.NewJSObject(glue, klass); + + auto elements = GetElementsArray(objLiteral); + auto newElements = CloneProperties(glue, elements); + SetElementsArray(VariableType::JS_ANY(), glue, newObj, newElements); + + auto properties = GetPropertiesArray(objLiteral); + auto newProperties = CloneProperties(glue, properties); + SetPropertiesArray(VariableType::JS_ANY(), glue, newObj, newProperties); + + auto inlinedProperties = GetInlinedPropertiesFromHClass(klass); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + Jump(&loopHead); + LoopBegin(&loopHead); + Branch(Int32UnsignedLessThan(*idx, inlinedProperties), &loopBack, &loopExit); + Bind(&loopBack); + { + auto value = GetPropertyInlinedProps(objLiteral, klass, *idx); + SetPropertyInlinedProps(glue, newObj, klass, value, *idx, VariableType::JS_ANY()); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + } + Bind(&loopExit); + env->SubCfgExit(); + return newObj; +} + +GateRef BuiltinsObjectStubBuilder::CloneProperties(GateRef glue, GateRef old) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(res, VariableType::JS_ANY(), Hole()); + DEFVARIABLE(idx, VariableType::INT32(), Int32(0)); + auto newLength = GetLengthOfTaggedArray(old); + Label exit(env); + Label loopHead(env); + Label loopBack(env); + NewObjectStubBuilder newObjBuilder(GetEnvironment()); + auto newArray = newObjBuilder.NewTaggedArray(glue, newLength); + Jump(&loopHead); + LoopBegin(&loopHead); + Branch(Int32UnsignedLessThan(*idx, newLength), &loopBack, &exit); + Bind(&loopBack); + auto value = GetValueFromTaggedArray(old, *idx); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArray, *idx, value); + idx = Int32Add(*idx, Int32(1)); + LoopEnd(&loopHead); + Bind(&exit); + env->SubCfgExit(); + return newArray; +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.h b/ecmascript/compiler/builtins/builtins_object_stub_builder.h index 48ab77c168..6e6f53371f 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.h @@ -32,6 +32,8 @@ public: void ToString(Variable *result, Label *exit, Label *slowPath); void Create(Variable *result, Label *exit, Label *slowPath); void Assign(Variable *result, Label *exit, Label *slowPath); + GateRef CloneObjectLiteral(GateRef glue, GateRef objLiteral); + GateRef CloneProperties(GateRef glue, GateRef old); private: GateRef OrdinaryNewJSObjectCreate(GateRef proto); diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index ceff99f15d..d094e50fdb 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -580,6 +580,57 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga return ret; } +GateRef CircuitBuilder::GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index, + ConstPoolType type) +{ + GateRef constPool = GetConstPoolFromFunction(jsFunc); + GateRef module = GetModuleFromFunction(jsFunc); + return GetObjectInfoFromConstPool(glue, hirGate, constPool, module, index, type); +} + +GateRef CircuitBuilder::GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, + GateRef index, ConstPoolType type) +{ + Label entry(env_); + SubCfgEntry(&entry); + Label exit(env_); + Label cacheMiss(env_); + Label cache(env_); + + auto cacheValue = GetValueFromTaggedArray(constPool, index); + DEFVAlUE(result, env_, VariableType::JS_ANY(), cacheValue); + Branch(BoolOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache); + Bind(&cacheMiss); + { + if (type == ConstPoolType::OBJECT_LITERAL) { + result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralInfoFromCache), Gate::InvalidGateRef, + { constPool, Int32ToTaggedInt(index), module }, hirGate); + } else { + UNREACHABLE(); + } + Jump(&exit); + } + Bind(&cache); + { + if (type == ConstPoolType::OBJECT_LITERAL) { + Label isAOTLiteralInfo(env_); + Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); + Bind(&isAOTLiteralInfo); + { + result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralInfoFromCache), Gate::InvalidGateRef, + { constPool, Int32ToTaggedInt(index), module }, hirGate); + Jump(&exit); + } + } else { + UNREACHABLE(); + } + } + Bind(&exit); + auto ret = *result; + SubCfgExit(); + return ret; +} + GateRef CircuitBuilder::GetFunctionLexicalEnv(GateRef function) { return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET)); diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 8aa9329a46..c40a07495b 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -220,6 +220,10 @@ public: GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index, ConstPoolType type); GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index, ConstPoolType type); + GateRef GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, + GateRef index, ConstPoolType type); + GateRef GetObjectInfoFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, + GateRef module, GateRef index, ConstPoolType type); GateRef GetFunctionLexicalEnv(GateRef function); GateRef GetGlobalEnv(); GateRef GetGlobalEnvObj(GateRef env, size_t index); diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index fa5cf5e448..5b2f70326e 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -17,6 +17,7 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/access_object_stub_builder.h" #include "ecmascript/compiler/bc_call_signature.h" +#include "ecmascript/compiler/builtins/builtins_object_stub_builder.h" #include "ecmascript/compiler/ic_stub_builder.h" #include "ecmascript/compiler/interpreter_stub-inl.h" #include "ecmascript/compiler/llvm_ir_builder.h" @@ -32,6 +33,7 @@ #include "ecmascript/js_array.h" #include "ecmascript/js_function.h" #include "ecmascript/js_generator_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/message_string.h" #include "ecmascript/tagged_hash_table.h" #include "libpandafile/bytecode_instruction-inl.h" @@ -3940,26 +3942,66 @@ DECLARE_ASM_HANDLER(HandleDeprecatedCreatearraywithbufferPrefImm16) DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm8Id16) { + auto env = GetEnvironment(); GateRef imm = ZExtInt16ToInt32(ReadInst16_1(pc)); GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp)); GateRef module = GetModuleFromFunction(currentFunc); - GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module); - GateRef currentEnv = GetEnvFromFrame(GetFrame(sp)); - GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv }); - callback.ProfileCreateObject(res); - CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16)); + GateRef fixedArray = GetObjectLiteralInfoFromConstPool(glue, constpool, imm, module); + GateRef result = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX)); + GateRef hasMethod = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_HAS_METHOD_INDEX)); + DEFVARIABLE(res, VariableType::JS_ANY(), Hole()); + Label fastpath(env); + Label slowpath(env); + Label dispatch(env); + GateRef flag = BoolOr(IsDictionaryModeByHClass(LoadHClass(result)), TaggedIsTrue(hasMethod)); + Branch(flag, &slowpath, &fastpath); + Bind(&slowpath); + { + GateRef currentEnv = GetEnvFromFrame(GetFrame(sp)); + res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv }); + Jump(&dispatch); + } + Bind(&fastpath); + { + BuiltinsObjectStubBuilder builder(this); + res = builder.CloneObjectLiteral(glue, result); + Jump(&dispatch); + } + Bind(&dispatch); + callback.ProfileCreateObject(*res); + CHECK_EXCEPTION_WITH_ACC(*res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16)); } DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm16Id16) { + auto env = GetEnvironment(); GateRef imm = ZExtInt16ToInt32(ReadInst16_2(pc)); GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp)); GateRef module = GetModuleFromFunction(currentFunc); - GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module); - GateRef currentEnv = GetEnvFromFrame(GetFrame(sp)); - GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv }); - callback.ProfileCreateObject(res); - CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16)); + GateRef fixedArray = GetObjectLiteralInfoFromConstPool(glue, constpool, imm, module); + GateRef result = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX)); + GateRef hasMethod = GetValueFromTaggedArray(fixedArray, Int32(ConstantPool::OBJECT_LITERAL_INFO_HAS_METHOD_INDEX)); + DEFVARIABLE(res, VariableType::JS_ANY(), Hole()); + Label fastpath(env); + Label slowpath(env); + Label dispatch(env); + GateRef flag = BoolOr(IsDictionaryModeByHClass(LoadHClass(result)), TaggedIsTrue(hasMethod)); + Branch(flag, &slowpath, &fastpath); + Bind(&slowpath); + { + GateRef currentEnv = GetEnvFromFrame(GetFrame(sp)); + res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv }); + Jump(&dispatch); + } + Bind(&fastpath); + { + BuiltinsObjectStubBuilder builder(this); + res = builder.CloneObjectLiteral(glue, result); + Jump(&dispatch); + } + Bind(&dispatch); + callback.ProfileCreateObject(*res); + CHECK_EXCEPTION_WITH_ACC(*res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16)); } DECLARE_ASM_HANDLER(HandleDeprecatedCreateobjectwithbufferPrefImm16) diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index d88ecc155b..82c95c75f9 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1004,6 +1004,16 @@ inline GateRef StubBuilder::GetLengthOfTaggedArray(GateRef array) return Load(VariableType::INT32(), array, IntPtr(TaggedArray::LENGTH_OFFSET)); } +inline GateRef StubBuilder::GetExtractLengthOfTaggedArray(GateRef array) +{ + return Load(VariableType::INT32(), array, IntPtr(TaggedArray::EXTRACT_LENGTH_OFFSET)); +} + +inline void StubBuilder::SetExtractLengthOfTaggedArray(GateRef glue, GateRef array, GateRef extraLength) +{ + return Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::EXTRACT_LENGTH_OFFSET), extraLength); +} + inline GateRef StubBuilder::IsJSHClass(GateRef obj) { ASM_ASSERT(GET_MESSAGE_STRING_ID(IsJSHClass), TaggedIsHeapObject(obj)); diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 77bcc60d56..869298ccf7 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -5191,6 +5191,13 @@ GateRef StubBuilder::GetObjectLiteralFromConstPool(GateRef glue, GateRef constpo ConstPoolType::OBJECT_LITERAL); } +GateRef StubBuilder::GetObjectLiteralInfoFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module) +{ + GateRef hirGate = Circuit::NullGate(); + return env_->GetBuilder()->GetObjectInfoFromConstPool(glue, hirGate, constpool, module, index, + ConstPoolType::OBJECT_LITERAL); +} + GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index ca939dfd98..4dfd1b3fe8 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -287,6 +287,8 @@ public: void SetPropertiesArray(VariableType type, GateRef glue, GateRef object, GateRef propsArray); void SetHash(GateRef glue, GateRef object, GateRef hash); GateRef GetLengthOfTaggedArray(GateRef array); + GateRef GetExtractLengthOfTaggedArray(GateRef array); + void SetExtractLengthOfTaggedArray(GateRef glue, GateRef array, GateRef extraLength); // object operation GateRef IsJSHClass(GateRef obj); GateRef LoadHClass(GateRef object); @@ -590,6 +592,7 @@ public: GateRef GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); GateRef GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); GateRef GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); + GateRef GetObjectLiteralInfoFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible); // fast path diff --git a/ecmascript/jspandafile/program_object.h b/ecmascript/jspandafile/program_object.h index 52cf9709f4..5f65901c38 100644 --- a/ecmascript/jspandafile/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -32,7 +32,6 @@ #include "ecmascript/pgo_profiler/pgo_utils.h" #include "libpandafile/class_data_accessor-inl.h" #include "libpandafile/index_accessor.h" - namespace panda { namespace ecmascript { class JSThread; @@ -74,6 +73,10 @@ class ConstantPool : public TaggedArray { public: static constexpr size_t JS_PANDA_FILE_INDEX = 1; // not need gc static constexpr size_t INDEX_HEADER_INDEX = 2; // not need gc + static constexpr size_t OBJECT_LITERAL_INFO_OBJECT_INDEX = 0; + static constexpr size_t OBJECT_LITERAL_INFO_HAS_METHOD_INDEX = 1; + static constexpr size_t KEY_VALUE_PAIR_VALUE_OFFSET = 1; + static constexpr size_t KEY_VALUE_PAIR_SIZE = 2; static constexpr size_t CONSTANT_INDEX_INFO_INDEX = 3; static constexpr size_t RESERVED_POOL_LENGTH = INDEX_HEADER_INDEX; // divide the gc area @@ -268,14 +271,14 @@ public: } template - static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index, CString entry) + static JSTaggedValue GetLiteralInfoFromCache(JSThread *thread, JSTaggedValue constpool, + uint32_t index, CString entry) { static_assert(type == ConstPoolType::OBJECT_LITERAL || type == ConstPoolType::ARRAY_LITERAL); [[maybe_unused]] EcmaHandleScope handleScope(thread); const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); auto val = taggedPool->GetObjectFromCache(index); JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile(); - // For AOT bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); JSHandle entryIndexes(thread, JSTaggedValue::Undefined()); @@ -304,13 +307,28 @@ public: JSHandle obj = JSObject::CreateObjectFromProperties(thread, properties, ihcVal); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); + bool hasMethod = false; + size_t propertiesLen = properties->GetLength(); + for (size_t i = 0; i < propertiesLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { // 2: Each literal buffer has a pair of key-value. + key.Update(properties->Get(i)); + if (key->IsHole()) { + break; + } + valueHandle.Update(properties->Get(i + ConstantPool::KEY_VALUE_PAIR_VALUE_OFFSET)); + if (key->IsJSFunction() || valueHandle->IsJSFunction()) { + hasMethod = true; + } + } size_t elementsLen = elements->GetLength(); - for (size_t i = 0; i < elementsLen; i += 2) { // 2: Each literal buffer has a pair of key-value. + for (size_t i = 0; i < elementsLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { // 2: Each literal buffer has a pair of key-value. key.Update(elements->Get(i)); if (key->IsHole()) { break; } - valueHandle.Update(elements->Get(i + 1)); + valueHandle.Update(elements->Get(i + ConstantPool::KEY_VALUE_PAIR_VALUE_OFFSET)); + if (key->IsJSFunction() || valueHandle->IsJSFunction()) { + hasMethod = true; + } JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle); } if (thread->GetEcmaVM()->IsEnablePGOProfiler()) { @@ -320,7 +338,13 @@ public: thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(obj.GetTaggedType(), abcId, id.GetOffset()); } - val = obj.GetTaggedValue(); + JSHandle fixedArray = + thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2); // 2: object + hasMethod + // new fixed array + fixedArray->Set(thread, ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX, obj); + fixedArray->Set(thread, ConstantPool::OBJECT_LITERAL_INFO_HAS_METHOD_INDEX, + hasMethod ? JSTaggedValue::True() : JSTaggedValue::False()); + val = fixedArray.GetTaggedValue(); break; } case ConstPoolType::ARRAY_LITERAL: { @@ -341,7 +365,16 @@ public: } constpoolHandle->SetObjectToCache(thread, index, val); } + return val; + } + template + static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index, CString entry) + { + auto val = GetLiteralInfoFromCache(thread, constpool, index, entry); + if (type == ConstPoolType::OBJECT_LITERAL) { + return JSHandle(thread, val)->Get(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX); + } return val; } @@ -360,6 +393,14 @@ public: return GetLiteralFromCache(thread, constpool, index, entry); } + template + static JSTaggedValue GetLiteralInfoFromCache(JSThread *thread, JSTaggedValue constpool, + uint32_t index, JSTaggedValue module) + { + CString entry = ModuleManager::GetRecordName(module); + return GetLiteralInfoFromCache(thread, constpool, index, entry); + } + static JSTaggedValue PUBLIC_API GetStringFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index) { const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index ea92711cff..e54af254d4 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -881,6 +881,16 @@ DEF_RUNTIME_STUBS(GetObjectLiteralFromCache) thread, constpool.GetTaggedValue(), index.GetInt(), module.GetTaggedValue()).GetRawData(); } +DEF_RUNTIME_STUBS(GetObjectLiteralInfoFromCache) +{ + RUNTIME_STUBS_HEADER(GetObjectLiteralInfoFromCache); + JSHandle constpool = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSTaggedValue index = GetArg(argv, argc, 1); // 1: means the first parameter + JSHandle module = GetHArg(argv, argc, 2); // 2: means the second parameter + return ConstantPool::GetLiteralInfoFromCache( + thread, constpool.GetTaggedValue(), index.GetInt(), module.GetTaggedValue()).GetRawData(); +} + DEF_RUNTIME_STUBS(GetArrayLiteralFromCache) { RUNTIME_STUBS_HEADER(GetArrayLiteralFromCache); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 8bc1960cad..d12dfe1df9 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -302,6 +302,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(GetMethodFromCache) \ V(GetArrayLiteralFromCache) \ V(GetObjectLiteralFromCache) \ + V(GetObjectLiteralInfoFromCache) \ V(GetStringFromCache) \ V(OptLdSuperByValue) \ V(OptStSuperByValue) \ diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 0caea5a8d0..c6f8043644 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -39,6 +39,7 @@ group("ark_js_moduletest") { "concurrent", "container", "createarray", + "createobjectwithbuffer", "dataproperty", "datecase", "datecompare", @@ -168,6 +169,7 @@ group("ark_asm_test") { "compareobjecthclass", "concurrent", "container", + "createobjectwithbuffer", "dataproperty", "dateparse", "decodeuricomponent", @@ -277,6 +279,7 @@ group("ark_asm_single_step_test") { "compareobjecthclass", "concurrent", "container", + "createobjectwithbuffer", "dataproperty", "dynamicimport", "dyninstruction", diff --git a/test/moduletest/createobjectwithbuffer/BUILD.gn b/test/moduletest/createobjectwithbuffer/BUILD.gn new file mode 100644 index 0000000000..424ee9b87f --- /dev/null +++ b/test/moduletest/createobjectwithbuffer/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("createobjectwithbuffer") { + deps = [] +} diff --git a/test/moduletest/createobjectwithbuffer/createobjectwithbuffer.js b/test/moduletest/createobjectwithbuffer/createobjectwithbuffer.js new file mode 100644 index 0000000000..17842c7fae --- /dev/null +++ b/test/moduletest/createobjectwithbuffer/createobjectwithbuffer.js @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/* + * @tc.name:createobjectwithbuffer + * @tc.desc:test createobjectwithbuffer + * @tc.type: FUNC + * @tc.require: issueI84U4E + */ + +function logit(a) { + print(a.x) + print(a.y) + print(a[0]) + print(a[1]) +} + +function foo() { + for (let i = 0; i < 1; ++i) { + let a = { + x : 1, + y : "tik", + z() { return 666 }, + 0 : 0, + 1 : 1, + } + logit(a) + } +} + +function goo() { + let a = { + x : 1, + y : "yyy", + 0 : 0, + 1 : 1, + } + logit(a) +} + +function hoo() { + for (let i = 0; i < 1; ++i) { + let a = { + 444444444444 : 16, + } + print(a[444444444444]); + } +} + +foo(); +goo(); +hoo(); diff --git a/test/moduletest/createobjectwithbuffer/expect_output.txt b/test/moduletest/createobjectwithbuffer/expect_output.txt new file mode 100644 index 0000000000..1ec0a1e06b --- /dev/null +++ b/test/moduletest/createobjectwithbuffer/expect_output.txt @@ -0,0 +1,22 @@ +# 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. + +1 +tik +0 +1 +1 +yyy +0 +1 +16 From d239af3a68a7fc941281b6aea433e8a2811b2561 Mon Sep 17 00:00:00 2001 From: yaochaonan Date: Wed, 11 Oct 2023 13:43:44 +0800 Subject: [PATCH 12/50] Add MainThread check to avoid unload NativeModule on workerThread Issue: https://gitee.com/openharmony/arkui_napi/issues/I86WKL?from=project-issue Signed-off-by: yaochaonan Change-Id: I5003e63153101ffcbbc1f225d8db5df8dc3439ab --- ecmascript/module/js_module_deregister.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ecmascript/module/js_module_deregister.cpp b/ecmascript/module/js_module_deregister.cpp index 74b4516cdc..ccee7929f8 100644 --- a/ecmascript/module/js_module_deregister.cpp +++ b/ecmascript/module/js_module_deregister.cpp @@ -83,7 +83,8 @@ void ModuleDeregister::RemoveModule(JSThread *thread, JSHandle { JSTaggedValue moduleRecordName = SourceTextModule::GetModuleName(module.GetTaggedValue()); ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); - if (module->GetTypes() == ModuleTypes::APP_MODULE || module->GetTypes() == ModuleTypes::OHOS_MODULE) { + if (!thread->GetEcmaVM()->IsWorkerThread() && + (module->GetTypes() == ModuleTypes::APP_MODULE || module->GetTypes() == ModuleTypes::OHOS_MODULE)) { if (TryToRemoveSO(thread, module)) { LOG_FULL(INFO) << "Remove native module " << ConvertToString(moduleRecordName).c_str() << " successfully."; } else { From 200b100a55f22482a82fc5b1bd104ab251abb4b1 Mon Sep 17 00:00:00 2001 From: liu-zelin Date: Wed, 11 Oct 2023 18:09:45 +0800 Subject: [PATCH 13/50] update build mode argument name to runtime_mode Signed-off-by: liu-zelin Change-Id: Ibe2ce37fd27e17d3abcb14234f542cefb537ed51 --- js_runtime_config.gni | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js_runtime_config.gni b/js_runtime_config.gni index e403fd34ff..ae771a9688 100644 --- a/js_runtime_config.gni +++ b/js_runtime_config.gni @@ -43,8 +43,10 @@ enable_cow_array = true enable_coverage = false enable_asm_assert = false ark_compile_mode = "debug" -if (is_cross_platform_build && !is_debug && !is_profile) { - ark_compile_mode = "release" +if (is_cross_platform_build) { + if (defined(runtime_mode) && runtime_mode == "relase") { + ark_compile_mode = "release" + } } asan_lib_path = "/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux" From 9e52ecdc90c4ec83fef109e49f6bbca100d3ba9e Mon Sep 17 00:00:00 2001 From: Yong Zhou Date: Thu, 21 Sep 2023 21:20:55 +0800 Subject: [PATCH 14/50] GlobalValueNumering implementation Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I83EHP?from=project-issue Change-Id: I471ed10b269c6b810d990acc6389878f7b418a8e Signed-off-by: Yong Zhou --- ecmascript/compiler/gate_accessor.cpp | 8 + ecmascript/compiler/gate_accessor.h | 1 + ecmascript/compiler/hcr_gate_meta_data.h | 14 ++ ecmascript/compiler/mcr_gate_meta_data.h | 37 +++ ecmascript/compiler/pass.h | 6 +- ecmascript/compiler/pass_manager.cpp | 2 + ecmascript/compiler/share_gate_meta_data.h | 49 ++++ ecmascript/compiler/tests/BUILD.gn | 18 ++ .../tests/global_value_numbering_test.cpp | 218 ++++++++++++++++++ .../compiler/tests/meta_data_equal_test.cpp | 213 +++++++++++++++++ ecmascript/compiler/value_numbering.cpp | 176 ++++++++++---- ecmascript/compiler/value_numbering.h | 30 ++- ecmascript/js_runtime_options.cpp | 19 ++ ecmascript/js_runtime_options.h | 24 ++ .../global_value_numbering_ts/BUILD.gn | 18 ++ .../expect_output.txt | 21 ++ .../global_value_numbering_ts.ts | 97 ++++++++ 17 files changed, 900 insertions(+), 51 deletions(-) create mode 100644 ecmascript/compiler/tests/global_value_numbering_test.cpp create mode 100644 ecmascript/compiler/tests/meta_data_equal_test.cpp create mode 100644 test/aottest/global_value_numbering_ts/BUILD.gn create mode 100644 test/aottest/global_value_numbering_ts/expect_output.txt create mode 100644 test/aottest/global_value_numbering_ts/global_value_numbering_ts.ts diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index 6b6e600ce8..a18f93cd34 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -1537,6 +1537,14 @@ bool GateAccessor::MetaDataEqu(GateRef g1, GateRef g2) const return GetMetaData(g1) == GetMetaData(g2); } +bool GateAccessor::MetaDataValueEqu(GateRef g1, GateRef g2) const +{ + const GateMetaData *g1Meta = GetMetaData(g1); + const GateMetaData *g2Meta = GetMetaData(g2); + + return g1Meta->equal(*g2Meta); +} + bool GateAccessor::IsNop(GateRef g) const { return GetMetaData(g)->IsNop(); diff --git a/ecmascript/compiler/gate_accessor.h b/ecmascript/compiler/gate_accessor.h index ec71db587c..545e6aedbf 100644 --- a/ecmascript/compiler/gate_accessor.h +++ b/ecmascript/compiler/gate_accessor.h @@ -521,6 +521,7 @@ public: bool IsProlog(GateRef g) const; bool IsCFGMerge(GateRef g) const; bool MetaDataEqu(GateRef g1, GateRef g2) const; + bool MetaDataValueEqu(GateRef g1, GateRef g2) const; bool IsNop(GateRef g) const; bool IsRoot(GateRef g) const; bool HasOuts(GateRef gate) const; diff --git a/ecmascript/compiler/hcr_gate_meta_data.h b/ecmascript/compiler/hcr_gate_meta_data.h index a9786514e2..5f38dab714 100644 --- a/ecmascript/compiler/hcr_gate_meta_data.h +++ b/ecmascript/compiler/hcr_gate_meta_data.h @@ -40,6 +40,20 @@ public: SetKind(GateMetaData::Kind::JSBYTECODE); } + bool equal(const GateMetaData &other) const override + { + if (!GateMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (opcode_ == cast_other->opcode_ && + pcOffset_ == cast_other->pcOffset_ && type_ == cast_other->type_ && + elementsKinds_ == cast_other->elementsKinds_) { + return true; + } + return false; + } + static const JSBytecodeMetaData* Cast(const GateMetaData* meta) { meta->AssertKind(GateMetaData::Kind::JSBYTECODE); diff --git a/ecmascript/compiler/mcr_gate_meta_data.h b/ecmascript/compiler/mcr_gate_meta_data.h index 99007ee5d5..69d1f21657 100644 --- a/ecmascript/compiler/mcr_gate_meta_data.h +++ b/ecmascript/compiler/mcr_gate_meta_data.h @@ -173,6 +173,18 @@ public: SetKind(GateMetaData::Kind::TYPED_CALL); } + bool equal(const GateMetaData &other) const override + { + if (!OneParameterMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (noGC_ == cast_other->noGC_) { + return true; + } + return false; + } + static const TypedCallMetaData* Cast(const GateMetaData* meta) { meta->AssertKind(GateMetaData::Kind::TYPED_CALL); @@ -196,6 +208,19 @@ public: SetKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP); } + bool equal(const GateMetaData &other) const override + { + if (!OneParameterMetaData::equal(other)) { + return false; + } + auto cast_other = + static_cast(&other); + if (checkOp_ == cast_other->checkOp_) { + return true; + } + return false; + } + static const TypedCallTargetCheckMetaData* Cast(const GateMetaData* meta) { meta->AssertKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP); @@ -219,6 +244,18 @@ public: SetKind(GateMetaData::Kind::TYPED_BINARY_OP); } + bool equal(const GateMetaData &other) const override + { + if (!OneParameterMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (binOp_ == cast_other->binOp_ && type_ == cast_other->type_) { + return true; + } + return false; + } + static const TypedBinaryMetaData* Cast(const GateMetaData* meta) { meta->AssertKind(GateMetaData::Kind::TYPED_BINARY_OP); diff --git a/ecmascript/compiler/pass.h b/ecmascript/compiler/pass.h index 636d7e8752..e9f044432f 100644 --- a/ecmascript/compiler/pass.h +++ b/ecmascript/compiler/pass.h @@ -47,6 +47,7 @@ #include "ecmascript/compiler/type_mcr_lowering.h" #include "ecmascript/compiler/value_numbering.h" #include "ecmascript/compiler/verifier.h" +#include "ecmascript/js_runtime_options.h" namespace panda::ecmascript::kungfu { class PassContext; @@ -580,11 +581,14 @@ public: if (!passOptions->EnableTypeLowering() || !passOptions->EnableValueNumbering()) { return false; } + JSRuntimeOptions runtimeOption = data->GetPassContext()->GetEcmaVM()->GetJSOptions(); TimeScope timescope("ValueNumberingPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog()); Chunk chunk(data->GetNativeAreaAllocator()); bool enableLog = data->GetLog()->EnableMethodCIRLog(); CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); - ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk); + ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk, + runtimeOption.IsEnableNewValueNumbering(), + runtimeOption.GetTraceValueNumbering()); visitor.AddPass(&valueNumbering); visitor.VisitGraph(); visitor.PrintLog("value numbering"); diff --git a/ecmascript/compiler/pass_manager.cpp b/ecmascript/compiler/pass_manager.cpp index daa5ae316b..194cc310ca 100644 --- a/ecmascript/compiler/pass_manager.cpp +++ b/ecmascript/compiler/pass_manager.cpp @@ -134,7 +134,9 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); + pipeline.RunPass(); pipeline.RunPass(); + pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); diff --git a/ecmascript/compiler/share_gate_meta_data.h b/ecmascript/compiler/share_gate_meta_data.h index eadb1fb692..96ec708cde 100644 --- a/ecmascript/compiler/share_gate_meta_data.h +++ b/ecmascript/compiler/share_gate_meta_data.h @@ -107,6 +107,15 @@ public: : opcode_(opcode), flags_(flags), statesIn_(statesIn), dependsIn_(dependsIn), valuesIn_(valuesIn) {} + virtual bool equal(const GateMetaData &other) const + { + if (opcode_ == other.opcode_ && kind_ == other.kind_ && flags_ == other.flags_ && + statesIn_ == other.statesIn_ && dependsIn_ == other.dependsIn_ && valuesIn_ == other.valuesIn_) { + return true; + } + return false; + } + size_t GetStateCount() const { return statesIn_; @@ -282,6 +291,18 @@ public: SetKind(GateMetaData::Kind::IMMUTABLE_BOOL); } + bool equal(const GateMetaData &other) const override + { + if (!GateMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (value_ == cast_other->value_) { + return true; + } + return false; + } + static const BoolMetaData* Cast(const GateMetaData* meta) { meta->AssertKind(GateMetaData::Kind::IMMUTABLE_BOOL); @@ -306,6 +327,18 @@ public: SetKind(GateMetaData::Kind::IMMUTABLE_ONE_PARAMETER); } + bool equal(const GateMetaData &other) const override + { + if (!GateMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (value_ == cast_other->value_) { + return true; + } + return false; + } + static const OneParameterMetaData* Cast(const GateMetaData* meta) { ASSERT(meta->IsOneParameterKind()); @@ -341,6 +374,22 @@ public: } SetKind(GateMetaData::Kind::MUTABLE_STRING); } + bool equal(const GateMetaData &other) const override + { + if (!GateMetaData::equal(other)) { + return false; + } + auto cast_other = static_cast(&other); + if (stringData_.size() != cast_other->GetString().size()) { + return false; + } + + if (strncmp(stringData_.data(), cast_other->GetString().data(), stringData_.size()) != 0) { + return false; + } + + return true; + } const ChunkVector &GetString() const { diff --git a/ecmascript/compiler/tests/BUILD.gn b/ecmascript/compiler/tests/BUILD.gn index 6d3d4f7d56..4510153f1c 100644 --- a/ecmascript/compiler/tests/BUILD.gn +++ b/ecmascript/compiler/tests/BUILD.gn @@ -101,12 +101,30 @@ host_unittest_action("LoopOptimizationTest") { ] } +host_unittest_action("GlobalValueNumberingTest") { + module_out_path = module_output_path + + sources = [ + # test file + "global_value_numbering_test.cpp", + "meta_data_equal_test.cpp", + ] + + deps = [ + "$ark_root/libpandafile:libarkfile_static", + "$js_root:libark_jsruntime_test_set", + "$js_root/ecmascript/compiler:libark_jsoptimizer_set", + sdk_libc_secshared_dep, + ] +} + group("host_unittest") { testonly = true # deps file deps = [ ":AssemblerTestAction", + ":GlobalValueNumberingTestAction", ":LoopOptimizationTestAction", ":TypedArrayLoweringTestAction", ] diff --git a/ecmascript/compiler/tests/global_value_numbering_test.cpp b/ecmascript/compiler/tests/global_value_numbering_test.cpp new file mode 100644 index 0000000000..62f772368f --- /dev/null +++ b/ecmascript/compiler/tests/global_value_numbering_test.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/compiler/pass.h" +#include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/compiler/share_opcodes.h" +#include "ecmascript/compiler/value_numbering.h" +#include "ecmascript/compiler/verifier.h" +#include "ecmascript/compiler/ts_hcr_lowering.h" +#include "ecmascript/compiler/type_mcr_lowering.h" +#include "ecmascript/elements.h" +#include "ecmascript/mem/concurrent_marker.h" +#include "ecmascript/mem/native_area_allocator.h" +#include "ecmascript/tests/test_helper.h" +#include "gtest/gtest.h" +#include +#include + +namespace panda::test { +class GlobalValueNumberingTests : public testing::Test {}; + +using ecmascript::kungfu::Circuit; +using ecmascript::kungfu::CircuitBuilder; +using ecmascript::kungfu::CombinedPassVisitor; +using ecmascript::kungfu::EcmaOpcode; +using ecmascript::kungfu::Environment; +using ecmascript::kungfu::GateAccessor; +using ecmascript::kungfu::GateRef; +using ecmascript::kungfu::PGOSampleType; +using ecmascript::kungfu::ValueNumbering; +using ecmascript::kungfu::Verifier; + + +HWTEST_F_L0(GlobalValueNumberingTests, AllInputsCheckedTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + auto z = builder.Arguments(3); + auto add1 = builder.Int64Add(x, y); + auto add2 = builder.Int64Add(x, y); + auto add3 = builder.Int64Add(x, z); + + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + + EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate()); + EXPECT_EQ(valuenumber.VisitGate(add2), add1); + EXPECT_EQ(valuenumber.VisitGate(add3), Circuit::NullGate()); +} + + +HWTEST_F_L0(GlobalValueNumberingTests, DeadNodesTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + + auto add1 = builder.Int64Add(x, y); + auto add2 = builder.Int64Add(x, y); + + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + + EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate()); + acc.DeleteGate(add1); + EXPECT_EQ(valuenumber.VisitGate(add2), Circuit::NullGate()); +} + +HWTEST_F_L0(GlobalValueNumberingTests, WontReplaceNodeWithItself) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + + auto add1 = builder.Int64Add(x, y); + + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + + EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate()); + EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate()); +} + + +HWTEST_F_L0(GlobalValueNumberingTests, E2ESimpleAddTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + + + auto add1 = builder.Int64Add(x, y); + auto add2 = builder.Int64Add(x, y); + auto add3 = builder.Int64Add(add1, add2); + + builder.Return(add3); + EXPECT_TRUE(Verifier::Run(&circuit)); + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + visitor.AddPass(&valuenumber); + visitor.VisitGraph(); + EXPECT_TRUE(Verifier::Run(&circuit)); + EXPECT_TRUE(acc.GetValueIn(add3, 0) == acc.GetValueIn(add3, 1)); + EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 1); +} + +HWTEST_F_L0(GlobalValueNumberingTests, GrowStressTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + std::vector results; + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + + for (int i = 0; i < 10000; i++) { + auto add1 = builder.Int64Add(x, y); + results.push_back(add1); + } + + GateRef before = results[0]; + for (int i = 1; i < 10000; i++) { + before = builder.Int64Add(before, results[i]); + } + + builder.Return(before); + EXPECT_TRUE(Verifier::Run(&circuit)); + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + visitor.AddPass(&valuenumber); + visitor.VisitGraph(); + EXPECT_TRUE(Verifier::Run(&circuit)); + EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 9999); +} + + +HWTEST_F_L0(GlobalValueNumberingTests, ComplexAddTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + auto x = builder.Arguments(1); + auto y = builder.Arguments(2); + + auto add1 = builder.Int64Add(x, y); + auto add2 = builder.Int64Add(x, y); + auto add3 = builder.Int64Add(add1, add2); + + auto add4 = builder.Int64Add(x, y); + auto add5 = builder.Int64Add(x, y); + auto add6 = builder.Int64Add(add4, add5); + + auto add7 = builder.Int64Add(add3, add6); + builder.Return(add7); + EXPECT_TRUE(Verifier::Run(&circuit)); + CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk); + ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false); + visitor.AddPass(&valuenumber); + visitor.VisitGraph(); + EXPECT_TRUE(Verifier::Run(&circuit)); + EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 4); +} + +} // namespace panda::test \ No newline at end of file diff --git a/ecmascript/compiler/tests/meta_data_equal_test.cpp b/ecmascript/compiler/tests/meta_data_equal_test.cpp new file mode 100644 index 0000000000..eed1b2257e --- /dev/null +++ b/ecmascript/compiler/tests/meta_data_equal_test.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/compiler/share_opcodes.h" +#include "ecmascript/compiler/verifier.h" +#include "ecmascript/compiler/ts_hcr_lowering.h" +#include "ecmascript/compiler/type_mcr_lowering.h" +#include "ecmascript/elements.h" +#include "ecmascript/mem/concurrent_marker.h" +#include "ecmascript/mem/native_area_allocator.h" +#include "ecmascript/tests/test_helper.h" +#include "gtest/gtest.h" +#include + +namespace panda::test { +class MetaDataEqualTests : public testing::Test {}; + +using ecmascript::kungfu::Circuit; +using ecmascript::kungfu::CircuitBuilder; +using ecmascript::kungfu::EcmaOpcode; +using ecmascript::kungfu::ElementsKind; +using ecmascript::kungfu::Environment; +using ecmascript::kungfu::GateAccessor; +using ecmascript::kungfu::GateMetaData; +using ecmascript::kungfu::GateType; +using ecmascript::kungfu::JSBytecodeMetaData; +using ecmascript::kungfu::MachineType; +using ecmascript::kungfu::PGOSampleType; +using ecmascript::kungfu::TypedBinOp; +using ecmascript::kungfu::TypedCallTargetCheckOp; + +HWTEST_F_L0(MetaDataEqualTests, StringMetaDataEqualTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue()); + + + auto stringGate2 = circuit.GetConstantStringGate(MachineType::ARCH, "test2", GateType::NJSValue()); + + EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, stringGate2)); + + auto stringGate3 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue()); + + EXPECT_TRUE(acc.MetaDataValueEqu(stringGate1, stringGate3)); +} + +HWTEST_F_L0(MetaDataEqualTests, ConstantMetaDataEqualTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + + auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + + auto constantValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + + EXPECT_TRUE(acc.MetaDataValueEqu(constantValue1, constantValue2)); + + auto constantValue3 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + + auto constantValue4 = circuit.GetConstantGate(MachineType::I64, 3, GateType::NJSValue()); + + EXPECT_FALSE(acc.MetaDataValueEqu(constantValue3, constantValue4)); + + + // MetaData is equal, but Gate is not equal + auto constantValue5 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + + auto constantValue6 = circuit.GetConstantGate(MachineType::I32, 2, GateType::NJSValue()); + + EXPECT_TRUE(acc.MetaDataValueEqu(constantValue5, constantValue6)); + + // MetaData is equal, but Gate is not equal + auto ConstGateNJSValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + + auto ConstGateUndefined = + circuit.GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType()); + + EXPECT_TRUE(acc.MetaDataValueEqu(ConstGateNJSValue2, ConstGateUndefined)); +} + +HWTEST_F_L0(MetaDataEqualTests, TypeErrorMetaDataEqualTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue()); + auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue()); + EXPECT_FALSE(acc.MetaDataValueEqu(constantValue1, stringGate1)); + EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, constantValue1)); +} + +HWTEST_F_L0(MetaDataEqualTests, HCRMetaDataEqualTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + // JSBytecodeMetaData + auto meta = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false); + auto gate = + circuit.NewGate(meta, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + auto meta2 = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false); + auto gate2 = + circuit.NewGate(meta2, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2)); + + static_cast(const_cast(meta))->SetElementsKind(ElementsKind::NUMBER); + static_cast(const_cast(meta2))->SetElementsKind(ElementsKind::NUMBER); + EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2)); + + static_cast(const_cast(meta))->SetType(PGOSampleType::CreateProfileType(0, 0)); + static_cast(const_cast(meta2))->SetType(PGOSampleType::CreateProfileType(0, 0)); + EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2)); + + + static_cast(const_cast(meta))->SetType(PGOSampleType::CreateProfileType(0, 0)); + static_cast(const_cast(meta2))->SetType(PGOSampleType::CreateProfileType(0, 1)); + EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2)); + + static_cast(const_cast(meta))->SetElementsKind(ElementsKind::NUMBER); + static_cast(const_cast(meta2))->SetElementsKind(ElementsKind::HOLE_NUMBER); + EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2)); +} + +HWTEST_F_L0(MetaDataEqualTests, MCRMetaDataEqualTest) +{ + // construct a circuit + ecmascript::NativeAreaAllocator allocator; + Circuit circuit(&allocator); + ecmascript::Chunk chunk(&allocator); + GateAccessor acc(&circuit); + CircuitBuilder builder(&circuit); + Environment env(0, &builder); + builder.SetEnvironment(&env); + + // TypedCallMetaData + auto callGate = + circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + auto callGate2 = + circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + EXPECT_TRUE(acc.MetaDataValueEqu(callGate, callGate2)); + EXPECT_TRUE(acc.MetaDataValueEqu(callGate2, callGate)); + + // TypedCallTargetCheckMetaData + auto callGate3 = + circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + auto callGate4 = + circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + EXPECT_TRUE(acc.MetaDataValueEqu(callGate3, callGate4)); + EXPECT_TRUE(acc.MetaDataValueEqu(callGate4, callGate3)); + + // TypedBinaryMetaData + auto callGate5 = circuit.NewGate( + circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + // TypedBinaryMetaData + auto callGate6 = circuit.NewGate( + circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + + EXPECT_TRUE(acc.MetaDataValueEqu(callGate5, callGate6)); + EXPECT_TRUE(acc.MetaDataValueEqu(callGate6, callGate5)); +} + + +} // namespace panda::test \ No newline at end of file diff --git a/ecmascript/compiler/value_numbering.cpp b/ecmascript/compiler/value_numbering.cpp index 2eee303cb4..9409ba63b3 100644 --- a/ecmascript/compiler/value_numbering.cpp +++ b/ecmascript/compiler/value_numbering.cpp @@ -13,71 +13,169 @@ * limitations under the License. */ #include "ecmascript/compiler/value_numbering.h" - +#include + namespace panda::ecmascript::kungfu { GateRef ValueNumbering::VisitGate(GateRef gate) { - auto opcode = acc_.GetOpCode(gate); - if (opcode != OpCode::CONVERT) { - return Circuit::NullGate(); - } size_t hash = HashCode(gate); - if (entries_.size() == 0) { - entries_.resize(CACHE_LENGTH, Circuit::NullGate()); - SetEntry(hash, gate); + auto opcode = acc_.GetOpCode(gate); + if (opcode != OpCode::CONVERT && !useNewGVN_) { return Circuit::NullGate(); } - GateRef replacement = GetEntry(hash); - if (replacement != Circuit::NullGate() && - CheckReplacement(gate, replacement)) { - return replacement; + if (entries_ == nullptr) { + InitEntries(entriesLength_); + SetEntry(hash, gate); + entriesSize_++; + return Circuit::NullGate(); + } + ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_); + const size_t mask = entriesLength_ - 1; + size_t dead = entriesLength_; + for (size_t i = hash & mask;; i = (i + 1) & mask) { + GateRef entry = entries_[i]; + if (entry == Circuit::NullGate()) { + if (dead != entriesLength_) { + entries_[dead] = gate; + } else { + // Have to insert a new entry. + entries_[i] = gate; + entriesSize_++; + // Resize to keep load factor below 80% + EnsureCapacity(); + } + ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_); + return Circuit::NullGate(); + } + + if (entry == gate) { + return Circuit::NullGate(); + } + + // Skip dead entries, but remember their indices so we can reuse them. + if (acc_.IsNop(entry)) { + dead = i; + continue; + } + + if (CheckReplacement(gate, entry)) { + optimizedGateCount++; + if (enableLog_) { + LOG_COMPILER(INFO) << "Found a replaceable node, before -> after"; + acc_.Print(gate); + acc_.Print(entry); + } + return entry; + } } - SetEntry(hash, gate); return Circuit::NullGate(); } +void ValueNumbering::EnsureCapacity() +{ + if (entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD >= entriesLength_) { + Grow(); + } +} + +void ValueNumbering::Grow() +{ + GateRef *const oldEntries = entries_; + size_t const oldSize = entriesLength_; + entriesLength_ *= 2; + InitEntries(entriesLength_); + size_t const mask = entriesLength_ - 1; + + for (size_t i = 0; i < oldSize; i++) { + GateRef oldEnrty = oldEntries[i]; + if (oldEnrty == Circuit::NullGate() || acc_.IsNop(oldEnrty)) { + continue; + } + for (size_t j = HashCode(oldEnrty) & mask;; j = (j + 1) & mask) { + GateRef entry = entries_[j]; + if (entry == oldEnrty) { + break; + } + if (entry == Circuit::NullGate()) { + entries_[j] = oldEnrty; + entriesSize_++; + break; + } + } + } + chunk_->Free(oldEntries); + if (enableLog_) { + LOG_COMPILER(INFO) << "Grow happend"; + } +} + +void ValueNumbering::InitEntries(size_t initSize) +{ + entries_ = chunk_->NewArray(initSize); + for (size_t i = 0; i < initSize; i++) { + entries_[i] = Circuit::NullGate(); + } + entriesSize_ = 0; +} + + +size_t HashCombine(size_t seed, size_t value) +{ + // In the meantime, we're not considering 32-bit systems + assert(sizeof(void *) == 8); + const uint64_t m = uint64_t{0xC6A4A7935BD1E995}; + const uint32_t r = 47; + + value *= m; + value ^= value >> r; + value *= m; + + seed ^= value; + seed *= m; + return seed; +} + size_t ValueNumbering::HashCode(GateRef gate) { - size_t hash = static_cast(acc_.GetOpCode(gate)); - hash ^= acc_.TryGetValue(gate); size_t valueCount = acc_.GetNumValueIn(gate); + size_t hash = HashCombine(static_cast(acc_.GetOpCode(gate)), valueCount); for (size_t i = 0; i < valueCount; i++) { - GateRef input = acc_.GetValueIn(gate); + GateRef input = acc_.GetValueIn(gate, i); auto id = acc_.GetId(input); - hash ^= id; + hash = HashCombine(hash, id); } - return hash % CACHE_LENGTH; + return hash; } +// Gates are considered replaceable only when their values are identical bool ValueNumbering::CheckReplacement(GateRef lhs, GateRef rhs) { - if (!acc_.MetaDataEqu(lhs, rhs)) { - if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) { + if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) + return false; + + size_t valueCount1 = acc_.GetNumIns(lhs); + size_t valueCount2 = acc_.GetNumIns(rhs); + if (valueCount1 != valueCount2) + return false; + for (size_t i = 0; i < valueCount1; i++) { + if (acc_.GetIn(lhs, i) != acc_.GetIn(rhs, i)) { return false; } } - size_t valueCount = acc_.GetNumValueIn(lhs); - for (size_t i = 0; i < valueCount; i++) { - if (acc_.GetValueIn(lhs, i) != acc_.GetValueIn(rhs, i)) { - return false; - } + + if (acc_.GetGateType(lhs) != acc_.GetGateType(rhs)) { + return false; } - if (acc_.HasFrameState(lhs)) { - ASSERT(acc_.HasFrameState(rhs)); - if (acc_.GetFrameState(lhs) != acc_.GetFrameState(rhs)) { - return false; - } + + if (acc_.GetMachineType(lhs) != acc_.GetMachineType(rhs)) { + return false; } - auto opcode = acc_.GetOpCode(lhs); - if (opcode == OpCode::CONVERT) { - if (acc_.GetSrcType(lhs) != acc_.GetSrcType(rhs)) { - return false; - } - if (acc_.GetDstType(lhs) != acc_.GetDstType(rhs)) { - return false; - } + + if (!acc_.MetaDataValueEqu(lhs, rhs)) { + return false; } + return true; } -} // namespace panda::ecmascript::kungfu \ No newline at end of file +} // namespace panda::ecmascript::kungfu \ No newline at end of file diff --git a/ecmascript/compiler/value_numbering.h b/ecmascript/compiler/value_numbering.h index 949ab1c127..c3e9d1add5 100644 --- a/ecmascript/compiler/value_numbering.h +++ b/ecmascript/compiler/value_numbering.h @@ -24,29 +24,37 @@ namespace panda::ecmascript::kungfu { class ValueNumbering : public PassVisitor { public: - ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk) - : PassVisitor(circuit, chunk, visitor), entries_(chunk) {} + ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk, bool useNewGVN, bool enableLog) + : PassVisitor(circuit, chunk, visitor), entries_(nullptr), useNewGVN_(useNewGVN), + enableLog_(enableLog) {} ~ValueNumbering() = default; GateRef VisitGate(GateRef gate) override; bool CheckReplacement(GateRef lhs, GateRef rhs); -private: - size_t HashCode(GateRef gate); - GateRef GetEntry(size_t hash) + int GetoptimizedGateCount() { - ASSERT(hash < entries_.size()); - return entries_[hash]; + return optimizedGateCount; } + +private: + void Grow(); + void EnsureCapacity(); + void InitEntries(size_t initSize); + size_t HashCode(GateRef gate); void SetEntry(size_t hash, GateRef gate) { - ASSERT(hash < entries_.size()); - entries_[hash] = gate; + entries_[hash & (entriesLength_ - 1)] = gate; } static const uint32_t CACHE_LENGTH_BIT = 8; static const uint32_t CACHE_LENGTH = (1U << CACHE_LENGTH_BIT); - - ChunkVector entries_; + const uint8_t LOAD_FACTOR_THRESHOLD = 4; + uint32_t entriesLength_ = (1U << CACHE_LENGTH_BIT); + uint32_t entriesSize_ = 0; + GateRef* entries_; + bool useNewGVN_; + int optimizedGateCount = 0; + bool enableLog_ = false; }; } // panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_VALUE_NUMBERING_H \ No newline at end of file diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 7f09c22a4e..633f33bf4a 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -69,6 +69,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = "--compiler-trace-bc: Enable tracing bytecode for aot runtime. Default: 'false'\n" "--compiler-trace-deopt: Enable tracing deopt for aot runtime. Default: 'false'\n" "--compiler-trace-inline: Enable tracing inline function for aot runtime. Default: 'false'\n" + "--compiler-trace-value-numbering: Enable tracing value numbering for aot runtime. Default: 'false'\n" "--compiler-max-inline-bytecodes Set max bytecodes count which aot function can be inlined. Default: '25'\n" "--compiler-deopt-threshold: Set max count which aot function can occur deoptimization. Default: '10'\n" "--compiler-stress-deopt: Enable stress deopt for aot compiler. Default: 'false'\n" @@ -172,6 +173,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-trace-bc", required_argument, nullptr, OPTION_COMPILER_TRACE_BC}, {"compiler-trace-deopt", required_argument, nullptr, OPTION_COMPILER_TRACE_DEOPT}, {"compiler-trace-inline", required_argument, nullptr, OPTION_COMPILER_TRACE_INLINE}, + {"compiler-trace-value-numbering", required_argument, nullptr, OPTION_COMPILER_TRACE_VALUE_NUMBERING}, {"compiler-max-inline-bytecodes", required_argument, nullptr, OPTION_COMPILER_MAX_INLINE_BYTECODES}, {"compiler-deopt-threshold", required_argument, nullptr, OPTION_COMPILER_DEOPT_THRESHOLD}, {"compiler-stress-deopt", required_argument, nullptr, OPTION_COMPILER_STRESS_DEOPT}, @@ -185,6 +187,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-opt-early-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_EARLY_ELIMINATION}, {"compiler-opt-later-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_LATER_ELIMINATION}, {"compiler-opt-value-numbering", required_argument, nullptr, OPTION_COMPILER_OPT_VALUE_NUMBERING}, + {"compiler-opt-new-value-numbering", required_argument, nullptr, OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING}, {"compiler-opt-inlining", required_argument, nullptr, OPTION_COMPILER_OPT_INLINING}, {"compiler-opt-pgotype", required_argument, nullptr, OPTION_COMPILER_OPT_PGOTYPE}, {"compiler-opt-track-field", required_argument, nullptr, OPTION_COMPILER_OPT_TRACK_FIELD}, @@ -371,6 +374,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_COMPILER_TRACE_VALUE_NUMBERING: + ret = ParseBoolParam(&argBool); + if (ret) { + SetTraceValueNumbering(argBool); + } else { + return false; + } + break; case OPTION_COMPILER_MAX_INLINE_BYTECODES: ret = ParseUint32Param("max-inline-bytecodes", &argUint32); if (ret) { @@ -668,6 +679,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING: + ret = ParseBoolParam(&argBool); + if (ret) { + SetEnableNewValueNumbering(argBool); + } else { + return false; + } + break; case OPTION_COMPILER_OPT_INLINING: ret = ParseBoolParam(&argBool); if (ret) { diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 33f4b09399..0961ec196c 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -98,6 +98,7 @@ enum CommandValues { OPTION_COMPILER_TRACE_BC, OPTION_COMPILER_TRACE_DEOPT, OPTION_COMPILER_TRACE_INLINE, + OPTION_COMPILER_TRACE_VALUE_NUMBERING, OPTION_COMPILER_MAX_INLINE_BYTECODES, OPTION_COMPILER_DEOPT_THRESHOLD, OPTION_COMPILER_STRESS_DEOPT, @@ -117,6 +118,7 @@ enum CommandValues { OPTION_COMPILER_OPT_EARLY_ELIMINATION, OPTION_COMPILER_OPT_LATER_ELIMINATION, OPTION_COMPILER_OPT_VALUE_NUMBERING, + OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING, OPTION_COMPILER_OPT_INLINING, OPTION_COMPILER_OPT_PGOTYPE, OPTION_COMPILER_OPT_TRACK_FIELD, @@ -981,6 +983,16 @@ public: return enableValueNumbering_; } + void SetEnableNewValueNumbering(bool value) + { + enableNewValueNumbering_ = value; + } + + bool IsEnableNewValueNumbering() const + { + return enableNewValueNumbering_; + } + void SetEnableOptInlining(bool value) { enableOptInlining_ = value; @@ -1116,6 +1128,16 @@ public: return traceInline_; } + void SetTraceValueNumbering(bool value) + { + traceValueNumbering_ = value; + } + + bool GetTraceValueNumbering() const + { + return traceValueNumbering_; + } + void SetMaxInlineBytecodes(size_t value) { maxInlineBytecodes_ = value; @@ -1304,6 +1326,7 @@ private: bool enableEarlyElimination_ {true}; bool enableLaterElimination_ {true}; bool enableValueNumbering_ {true}; + bool enableNewValueNumbering_ {true}; bool enableOptInlining_ {true}; bool enableOptPGOType_ {true}; bool enableGlobalTypeInfer_ {false}; @@ -1325,6 +1348,7 @@ private: std::string compilerSelectMethods_ {""}; std::string compilerSkipMethods_ {""}; bool traceInline_ {false}; + bool traceValueNumbering_{false}; size_t maxInlineBytecodes_ {45}; std::string targetCompilerMode_ {""}; std::string hapPath_ {""}; diff --git a/test/aottest/global_value_numbering_ts/BUILD.gn b/test/aottest/global_value_numbering_ts/BUILD.gn new file mode 100644 index 0000000000..a272690ae0 --- /dev/null +++ b/test/aottest/global_value_numbering_ts/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_aot_test_action("global_value_numbering_ts") { + deps = [] +} diff --git a/test/aottest/global_value_numbering_ts/expect_output.txt b/test/aottest/global_value_numbering_ts/expect_output.txt new file mode 100644 index 0000000000..9108220aca --- /dev/null +++ b/test/aottest/global_value_numbering_ts/expect_output.txt @@ -0,0 +1,21 @@ +# 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. + +Hello +Hello +Hello +Hello +1 +4 +-2 +6 diff --git a/test/aottest/global_value_numbering_ts/global_value_numbering_ts.ts b/test/aottest/global_value_numbering_ts/global_value_numbering_ts.ts new file mode 100644 index 0000000000..c326920d51 --- /dev/null +++ b/test/aottest/global_value_numbering_ts/global_value_numbering_ts.ts @@ -0,0 +1,97 @@ +/* + * 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. + */ + +declare function print(n:string):string; +declare function print(n:number):string; + +// CMP +//[compiler] Found a replaceable node, before -> after +//[compiler] {"id":212, "op":"ICMP", "MType":"I1, bitfield=0xa, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=2, ","in":[[], [], [55, 205], [], []], "out":[213]}, +//[compiler] {"id":209, "op":"ICMP", "MType":"I1, bitfield=0xa, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=3, ","in":[[], [], [55, 205], [], []], "out":[210]}, + +//[compiler] {"id":55, "op":"VALUE_SELECTOR", "MType":"I32, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=9, mark=3, ","in":[[16], [], [227, 217], [], []], "out":[215, 212, 209, 206, 102, 88, 94, 97, 99, 85, 83, 80, 71]}, +//[compiler] {"id":205, "op":"CONSTANT", "MType":"I32, bitfield=0x1, type=NJS_VALUE-GT(M=0, L=0), stamp=9, mark=3, ","in":[[], [], [], [], []], "out":[227, 224, 221, 215, 212, 209]}, + +for (var i:number = 0; i < 10; i++) { + if (i <= 1) { + print("Hello"); + } + if (i <= 1) { + print("Hello"); + } +} + +// TypedOperator + +//[compiler] Found a replaceable node, before -> after +//[compiler] {"id":669, "op":"FDIV", "MType":"F64, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=2, ","in":[[], [], [608, 610], [], []], "out":[670]}, +//[compiler] {"id":664, "op":"FDIV", "MType":"F64, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=3, ","in":[[], [], [608, 610], [], []], "out":[665]}, +function div(a: number, b: number): number { + let sum = 0; + if (a > 0) { + let k = a / b; + sum += k; + } + if (b > 0) { + let k = a / b; + sum += k; + } + return sum; +} +print(div(1,2)); + +function mul(a: number, b: number): number { + let sum = 0; + if (a > 0) { + let k = a * b; + sum += k; + } + if (b > 0) { + let k = a * b; + sum += k; + } + return sum; +} +print(mul(1,2)); + +function sub(a: number, b: number): number { + let sum = 0; + if (a > 0) { + let k = a - b; + sum += k; + } + if (b > 0) { + let k = a - b; + sum += k; + } + return sum; +} +print(sub(1,2)); + + +function add(a: number, b: number): number { + let sum = 0; + if (a > 0) { + let k = a + b; + sum += k; + } + if (b > 0) { + let k = a + b; + sum += k; + } + return sum; +} +print(add(1,2)); + From df45bf8b4419fc171c6b795e66b90568f519063f Mon Sep 17 00:00:00 2001 From: wupengyong Date: Wed, 11 Oct 2023 10:55:33 +0800 Subject: [PATCH 15/50] Reason:optimize string split and fix slicedString bug Description:optimize string split and fix slicedString bug Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84LJG?from=project-issue Signed-off-by: wupengyong Change-Id: I6ff124fb81f6e72384e6df0fe1cbb89836e73c4a --- ecmascript/builtins/builtins_string.cpp | 163 ++++++++++++------ ecmascript/builtins/builtins_string.h | 9 + .../builtins/builtins_string_stub_builder.cpp | 86 ++++++--- .../builtins/builtins_string_stub_builder.h | 1 + ecmascript/ecma_string.cpp | 27 ++- ecmascript/ecma_string.h | 6 +- test/moduletest/string/expect_output.txt | 18 ++ test/moduletest/string/string.js | 63 ++++++- 8 files changed, 290 insertions(+), 83 deletions(-) diff --git a/ecmascript/builtins/builtins_string.cpp b/ecmascript/builtins/builtins_string.cpp index 91fd3272c0..0dc3459e66 100644 --- a/ecmascript/builtins/builtins_string.cpp +++ b/ecmascript/builtins/builtins_string.cpp @@ -1352,10 +1352,31 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) // Let O be RequireObjectCoercible(this value). JSHandle thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle thisObj(thisTag); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle seperatorTag = BuiltinsString::GetCallArg(argv, 0); JSHandle limitTag = BuiltinsString::GetCallArg(argv, 1); + if (thisTag->IsString() && seperatorTag->IsString()) { + JSHandle thisString(thisTag); + JSHandle seperatorString(seperatorTag); + auto thisLength = EcmaStringAccessor(thisString).GetLength(); + auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength(); + if (limitTag->IsUndefined() && thisLength != 0 && seperatorLength != 0) { + return CreateArrayThisStringAndSeperatorStringAreNotEmpty( + thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength); + } + uint32_t lim = UINT32_MAX - 1; + if (!limitTag->IsUndefined()) { + lim = JSTaggedValue::ToInteger(thread, limitTag).ToUint32(); + } + // ReturnIfAbrupt(lim). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (lim == 0) { + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return resultArray.GetTaggedValue(); + } + return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); + } + // If separator is neither undefined nor null, then if (seperatorTag->IsECMAObject()) { JSHandle splitKey = env->GetSplitSymbol(); @@ -1376,85 +1397,116 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) // Let S be ToString(O). JSHandle thisString = JSTaggedValue::ToString(thread, thisTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // Let A be ArrayCreate(0). - JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - uint32_t arrayLength = 0; + // If limit is undefined, let lim = 2^53–1; else let lim = ToLength(limit). - uint32_t lim = 0; - if (limitTag->IsUndefined()) { - lim = UINT32_MAX - 1; - } else { + uint32_t lim = UINT32_MAX - 1; + if (!limitTag->IsUndefined()) { lim = JSTaggedValue::ToInteger(thread, limitTag).ToUint32(); } // ReturnIfAbrupt(lim). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // If lim = 0, return A. - if (lim == 0) { - return resultArray.GetTaggedValue(); - } // Let s be the number of elements in S. - int32_t thisLength = static_cast(EcmaStringAccessor(thisString).GetLength()); + auto thisLength = EcmaStringAccessor(thisString).GetLength(); JSHandle seperatorString = JSTaggedValue::ToString(thread, seperatorTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // If lim = 0, return A. + if (lim == 0) { + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return resultArray.GetTaggedValue(); + } + auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength(); + // If S is undefined or (this.length = 0 and S.length != 0), return array of size is 1 containing this string if (seperatorTag->IsUndefined()) { - // Perform CreateDataProperty(A, "0", S). + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle(thisString)); ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception"); return resultArray.GetTaggedValue(); } - // If S.length = 0, then - if (thisLength == 0) { - if (EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString) != -1) { + return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); +} + +JSTaggedValue BuiltinsString::CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm, + const JSHandle &thisString, uint32_t thisLength, uint32_t lim) +{ + uint32_t actualLength = std::min(thisLength, lim); + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(actualLength))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + for (uint32_t i = 0; i < actualLength; ++i) { + EcmaString *elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, i, 1); + JSHandle elementTag(thread, elementString); + // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path + JSObject::CreateDataProperty(thread, resultArray, i, elementTag); + ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); + } + return resultArray.GetTaggedValue(); +} + +JSTaggedValue BuiltinsString::CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm, + const JSHandle &thisString, const JSHandle &seperatorString, + uint32_t thisLength, uint32_t seperatorLength, uint32_t lim) +{ + if (thisLength != 0) { + if (seperatorLength != 0) { + return CreateArrayThisStringAndSeperatorStringAreNotEmpty( + thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); + } + return CreateArrayFromString(thread, ecmaVm, thisString, thisLength, lim); + } else { + if (seperatorLength != 0) { + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path + JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle(thisString)); + ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception"); return resultArray.GetTaggedValue(); } - JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle(thisString)); - ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception"); + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return resultArray.GetTaggedValue(); } +} - int32_t seperatorLength = static_cast(EcmaStringAccessor(seperatorString).GetLength()); - if (seperatorLength == 0) { - for (int32_t i = 0; i < thisLength; ++i) { - EcmaString *elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, i, 1); - JSHandle elementTag(thread, elementString); - JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag); - ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); - ++arrayLength; - if (arrayLength == lim) { - return resultArray.GetTaggedValue(); - } - } - return resultArray.GetTaggedValue(); - } +JSTaggedValue BuiltinsString::CreateArrayThisStringAndSeperatorStringAreNotEmpty(JSThread *thread, + EcmaVM *ecmaVm, const JSHandle &thisString, const JSHandle &seperatorString, + uint32_t thisLength, uint32_t seperatorLength, uint32_t lim) +{ + uint32_t arrayLength = 0; + std::vector posArray; int32_t index = 0; int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString); while (pos != -1) { - EcmaString *elementString; - if (static_cast(pos - index) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) { - elementString = EcmaStringAccessor::GetSlicedString(ecmaVm, thisString, index, pos - index); - } else { - elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, index, pos - index); - } - JSHandle elementTag(thread, elementString); - JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag); - ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); + posArray.emplace_back(pos); ++arrayLength; if (arrayLength == lim) { - return resultArray.GetTaggedValue(); + break; } index = pos + seperatorLength; pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString, index); } - EcmaString *elementString; - if (static_cast(thisLength - index) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) { - elementString = EcmaStringAccessor::GetSlicedString(ecmaVm, thisString, index, thisLength - index); - } else { - elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, index, thisLength - index); + uint32_t posArrLength = posArray.size(); + arrayLength = lim > posArrLength ? posArrLength + 1 : posArrLength; + JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(arrayLength))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + index = 0; + for (uint32_t i = 0; i < posArrLength; i++) { + pos = posArray[i]; + EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, pos - index); + JSHandle elementTag(thread, elementString); + // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path + JSObject::CreateDataProperty(thread, resultArray, i, elementTag); + ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); + index = pos + seperatorLength; + } + if (lim > posArrLength) { + EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, thisLength - index); + JSHandle elementTag(thread, elementString); + // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path + JSObject::CreateDataProperty(thread, resultArray, posArrLength, elementTag); + ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); } - JSHandle elementTag(thread, elementString); - JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag); - ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); return resultArray.GetTaggedValue(); } @@ -1533,10 +1585,7 @@ JSTaggedValue BuiltinsString::Substring(EcmaRuntimeCallInfo *argv) int32_t from = std::min(start, end); int32_t to = std::max(start, end); int32_t len = to - from; - if (static_cast(len) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) { - return JSTaggedValue(EcmaStringAccessor::GetSlicedString(thread->GetEcmaVM(), thisHandle, from, len)); - } - return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisHandle, from, len)); + return JSTaggedValue(EcmaStringAccessor::GetSubString(thread->GetEcmaVM(), thisHandle, from, len)); } // 21.1.3.20 diff --git a/ecmascript/builtins/builtins_string.h b/ecmascript/builtins/builtins_string.h index c2d05ec184..917d54b7e8 100644 --- a/ecmascript/builtins/builtins_string.h +++ b/ecmascript/builtins/builtins_string.h @@ -248,6 +248,15 @@ private: static JSTaggedValue Pad(EcmaRuntimeCallInfo *argv, bool isStart); static int32_t ConvertDoubleToInt(double d); + static JSTaggedValue CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm, + const JSHandle &thisString, uint32_t thisLength, uint32_t lim); + static JSTaggedValue CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm, + const JSHandle &thisString, const JSHandle &seperatorString, + uint32_t thisLength, uint32_t seperatorLength, uint32_t lim); + static JSTaggedValue CreateArrayThisStringAndSeperatorStringAreNotEmpty( + JSThread *thread, EcmaVM *ecmaVm, + const JSHandle &thisString, const JSHandle &seperatorString, + uint32_t thisLength, uint32_t seperatorLength, uint32_t lim = UINT32_MAX - 1); // 21.1.3.17.1 }; } // namespace panda::ecmascript::builtins diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp index 0788485415..609fa62080 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp @@ -359,9 +359,6 @@ void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateR Label startGreatEnd(env); Label startNotGreatEnd(env); Label thisIsHeapobject(env); - Label flattenFastPath(env); - Label sliceString(env); - Label fastSubstring(env); Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull); Bind(&objNotUndefinedAndNull); @@ -465,28 +462,77 @@ void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateR Bind(&countRes); { GateRef len = Int32Sub(*to, *from); - FlatStringStubBuilder thisFlat(this); - thisFlat.FlattenString(glue, thisValue, &flattenFastPath); - Bind(&flattenFastPath); - { - Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)), - &sliceString, &fastSubstring); - Bind(&sliceString); - { - NewObjectStubBuilder newBuilder(this); - newBuilder.SetParameters(glue, 0); - newBuilder.AllocSlicedStringObject(res, exit, *from, len, &thisFlat); - } - Bind(&fastSubstring); - StringInfoGateRef stringInfoGate(&thisFlat); - res->WriteVariable(FastSubString(glue, thisValue, *from, len, stringInfoGate)); - Jump(exit); - } + res->WriteVariable(GetSubString(glue, thisValue, *from, len)); + Jump(exit); } } } } +GateRef BuiltinsStringStubBuilder::GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined()); + + Label exit(env); + Label flattenFastPath(env); + Label sliceString(env); + Label mayGetSliceString(env); + Label fastSubstring(env); + Label isUtf16(env); + Label isUtf8(env); + Label afterNew(env); + FlatStringStubBuilder thisFlat(this); + thisFlat.FlattenString(glue, thisValue, &flattenFastPath); + Bind(&flattenFastPath); + { + Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)), + &mayGetSliceString, &fastSubstring); + Bind(&mayGetSliceString); + { + Branch(IsUtf16String(thisValue), &isUtf16, &sliceString); + Bind(&isUtf16); + { + StringInfoGateRef stringInfoGate(&thisFlat); + GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t))); + GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset); + GateRef canBeCompressed = CanBeCompressed(source, len, true); + Branch(canBeCompressed, &isUtf8, &sliceString); + Bind(&isUtf8); + { + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + newBuilder.AllocLineStringObject(&result, &afterNew, len, true); + Bind(&afterNew); + { + GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset); + GateRef dst = + ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET))); + CopyUtf16AsUtf8(glue, dst, source1, len); + Jump(&exit); + } + } + } + Bind(&sliceString); + { + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + newBuilder.AllocSlicedStringObject(&result, &exit, from, len, &thisFlat); + } + } + Bind(&fastSubstring); + StringInfoGateRef stringInfoGate(&thisFlat); + result = FastSubString(glue, thisValue, from, len, stringInfoGate); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + GateRef BuiltinsStringStubBuilder::StringAt(const StringInfoGateRef &stringInfoGate, GateRef index) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.h b/ecmascript/compiler/builtins/builtins_string_stub_builder.h index 972e458d76..1d7bd91027 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.h @@ -67,6 +67,7 @@ private: GateRef GetSingleCharCodeFromConstantString(GateRef str, GateRef index); GateRef GetSingleCharCodeFromLineString(GateRef str, GateRef index); GateRef GetSingleCharCodeFromSlicedString(GateRef str, GateRef index); + GateRef GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len); }; class FlatStringStubBuilder : public StubBuilder { diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index 66f190bfae..55a38c86f8 100644 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -144,9 +144,6 @@ EcmaString *EcmaString::GetSlicedString(const EcmaVM *vm, const JSHandle &src, uint32_t start, uint32_t length) { ASSERT((start + length) <= src->GetLength()); - if (start == 0 && length == src->GetLength()) { - return *src; - } JSHandle slicedString(vm->GetJSThread(), CreateSlicedString(vm)); FlatStringInfo srcFlat = FlattenAllString(vm, src); slicedString->SetLength(length, srcFlat.GetString()->IsUtf8()); @@ -155,6 +152,30 @@ EcmaString *EcmaString::GetSlicedString(const EcmaVM *vm, return *slicedString; } +/* static */ +EcmaString *EcmaString::GetSubString(const EcmaVM *vm, + const JSHandle &src, uint32_t start, uint32_t length) +{ + ASSERT((start + length) <= src->GetLength()); + if (static_cast(length) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) { + if (start == 0 && length == src->GetLength()) { + return *src; + } + if (src->IsUtf16()) { + FlatStringInfo srcFlat = FlattenAllString(vm, src); + bool canBeCompressed = CanBeCompressed(srcFlat.GetDataUtf16() + start, length); + if (canBeCompressed) { + JSHandle string(vm->GetJSThread(), CreateLineString(vm, length, canBeCompressed)); + srcFlat = FlattenAllString(vm, src); + CopyChars(string->GetDataUtf8Writable(), srcFlat.GetDataUtf16() + start, length); + return *string; + } + } + return GetSlicedString(vm, src, start, length); + } + return FastSubString(vm, src, start, length); +} + void EcmaString::WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length) { ASSERT(IsLineString() && !IsConstantString()); diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index c0ead4b947..6df20f158d 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -110,6 +110,8 @@ private: const JSHandle &src, uint32_t start, uint32_t length); static EcmaString *GetSlicedString(const EcmaVM *vm, const JSHandle &src, uint32_t start, uint32_t length); + static EcmaString *GetSubString(const EcmaVM *vm, + const JSHandle &src, uint32_t start, uint32_t length); // require src is LineString // not change src data structure static inline EcmaString *FastSubUtf8String(const EcmaVM *vm, @@ -919,10 +921,10 @@ public: } // get - static EcmaString *GetSlicedString(const EcmaVM *vm, + static EcmaString *GetSubString(const EcmaVM *vm, const JSHandle &src, uint32_t start, uint32_t length) { - return EcmaString::GetSlicedString(vm, src, start, length); + return EcmaString::GetSubString(vm, src, start, length); } bool IsUtf8() const diff --git a/test/moduletest/string/expect_output.txt b/test/moduletest/string/expect_output.txt index b43d081864..4e2ac6d9b1 100644 --- a/test/moduletest/string/expect_output.txt +++ b/test/moduletest/string/expect_output.txt @@ -33,3 +33,21 @@ AB testfiles就发(2) testfileswodet true +0 +1 +123_352_42342_483297538927943872943_12i2 +1,2,3,_,3,5,2,_,4,2,3,4,2,_,4,8,3,2,9,7,5,3,8,9,2,7,9,4,3,8,7,2,9,4,3,_,1,2,i,2 +123_352_42342_483297538927943872943_12i2 +123,352,42342,483297538927943872943,12i2 +123,352 +12哈哈3,352,42好呀342_4832975389279你们43872943 +2哈哈3,352,42好呀342_4832975389279你们43872943,12i2 +0 +2哈哈3尼352尼,2好呀3,2_,832975389279你们,38729 +Cannot convert a illegal value to a String +4 +123,wode2222222222222222,fast,哈哈哈 +123,wode2222222222222222,fast,hhh +abc +1111,2222 +4 diff --git a/test/moduletest/string/string.js b/test/moduletest/string/string.js index a2bbe04b96..5bbfda558e 100644 --- a/test/moduletest/string/string.js +++ b/test/moduletest/string/string.js @@ -90,9 +90,70 @@ let filename2 = name2.substring(0, 14); let kk2 = filename2.toLowerCase(); print(kk2); - var strA = name2 + name1; for (let i = 0; i < 100; i++) { strA.toLocaleString(); } print("true"); + +var a = ""; +var b = a.split(""); +var c = a.split("1"); +print(b.length); +print(c.length); +var a1 = "123_352_42342_483297538927943872943_12i2"; +var a2 = "12哈哈3尼352尼42好呀342_4832975389279你们43872943尼12i2"; +var a3 = a2.substring(1); +var b1 = a1.split(); +var c1 = a1.split(""); +var d1 = a1.split(" "); +var e1 = a1.split("_"); +var f1 = a1.split("_", 2); +var g1 = a2.split("尼", 3); +var r1 = a3.split("尼", 44); +var k1 = a3.split("尼", 0); +var k2 = a3.split("4", 5); +print(b1); +print(c1); +print(d1); +print(e1); +print(f1); +print(g1); +print(r1); +print(k1.length); +print(k2); +try { + var sym = Symbol(); + a2.split(sym, 0); +} catch (e) { + print(e.message); +} + +var test1 = "fun123ctionManualChapter123Tip1_352_42342_483297538927943872943_12i2哈哈哈"; +var test2 = test1.split("_"); +var test3 = test2[0]; +var test4 = "1111fun123ctionManualChapter123Tip1" +let pos = test4.indexOf(test3); +print(pos); + +Object.defineProperty(Array.prototype, "1", { + value:37, + writable:false, +}); +var test5 = "123_wode2222222222222222_fast_哈哈哈"; +var test6 = "123_wode2222222222222222_fast_hhh"; +var test7 = test5.split("_"); +var test8 = test6.split("_"); +print(test7); +print(test8); + +var test9 = "abc" +var test10 = new Number(4); +test10[Symbol.split] = RegExp.prototype[Symbol.split]; +print(test9.split(test10)); +var test11 = test1.substring(0, 31); +var test12 = "1111fun123ctionManualChapter123Tip12222" +var test13 = test12.split(test11); +var test14 = test12.lastIndexOf(test11); +print(test13); +print(test14); \ No newline at end of file From eef37db2c3936660f746e74b35bf43fd48b47b26 Mon Sep 17 00:00:00 2001 From: zhangyukun8 Date: Thu, 28 Sep 2023 17:02:15 +0800 Subject: [PATCH 16/50] Optimize for-in loop 1. Add EnumCache for simple properties and no-elements properties 2. Add fastpath for non-special objects 3. Avoid duplicated copy for slowpath 4. Transition hclass when detele prop in TS Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84DMO?from=project-issue Signed-off-by: zhangyukun8 Change-Id: I81648b44cc83a907c50ec90c9e8de3bbb104cef8 --- BUILD.gn | 1 + ecmascript/base/fast_json_stringifier.cpp | 4 +- ecmascript/base/json_stringifier.cpp | 2 +- ecmascript/compiler/call_signature.cpp | 30 ++ ecmascript/compiler/call_signature.h | 2 + ecmascript/compiler/circuit_builder-inl.h | 2 +- ecmascript/compiler/circuit_builder.h | 3 +- ecmascript/compiler/common_stubs.cpp | 17 + ecmascript/compiler/common_stubs.h | 2 + ecmascript/compiler/interpreter_stub.cpp | 5 +- ecmascript/compiler/mcr_circuit_builder.h | 20 + .../compiler/new_object_stub_builder.cpp | 74 +++ ecmascript/compiler/new_object_stub_builder.h | 2 + ecmascript/compiler/slowpath_lowering.cpp | 27 +- ecmascript/compiler/stub_builder-inl.h | 130 ++++- ecmascript/compiler/stub_builder.cpp | 505 +++++++++++++++++- ecmascript/compiler/stub_builder.h | 38 +- ecmascript/compiler/type_mcr_lowering.cpp | 2 +- ecmascript/dump.cpp | 18 +- ecmascript/ecma_string.cpp | 3 + ecmascript/global_dictionary-inl.h | 19 + ecmascript/global_dictionary.h | 2 + ecmascript/js_for_in_iterator.cpp | 211 ++++---- ecmascript/js_for_in_iterator.h | 30 +- ecmascript/js_hclass.h | 29 + ecmascript/js_object-inl.h | 68 ++- ecmascript/js_object.cpp | 265 +++++++-- ecmascript/js_object.h | 37 +- ecmascript/js_tagged_value-inl.h | 10 + ecmascript/js_tagged_value.h | 2 + ecmascript/layout_info.cpp | 74 ++- ecmascript/layout_info.h | 9 +- ecmascript/object_factory.cpp | 31 +- ecmascript/object_factory.h | 5 +- ecmascript/property_accessor.cpp | 313 +++++++++++ ecmascript/property_accessor.h | 63 +++ ecmascript/runtime_call_id.h | 3 + ecmascript/stubs/runtime_stubs-inl.h | 5 +- ecmascript/stubs/runtime_stubs.cpp | 25 + ecmascript/stubs/runtime_stubs.h | 3 + ecmascript/tagged_dictionary.cpp | 79 ++- ecmascript/tagged_dictionary.h | 14 +- ecmascript/tests/dump_test.cpp | 4 +- ecmascript/tests/js_forin_iterator_test.cpp | 22 +- ecmascript/tests/layout_info_test.cpp | 2 +- .../delete_property/expect_output.txt | 2 +- test/moduletest/BUILD.gn | 18 + .../moduletest/forin_delete_property/BUILD.gn | 18 + .../forin_delete_property/expect_output.txt | 23 + .../forin_delete_property.js | 52 ++ .../moduletest/forin_dictionary_mode/BUILD.gn | 18 + .../forin_dictionary_mode/expect_output.txt | 21 + .../forin_dictionary_mode.js | 45 ++ .../moduletest/forin_empty_prototype/BUILD.gn | 18 + .../forin_empty_prototype/expect_output.txt | 23 + .../forin_empty_prototype.js | 47 ++ test/moduletest/forin_enum_cache/BUILD.gn | 18 + .../forin_enum_cache/expect_output.txt | 34 ++ .../forin_enum_cache/forin_enum_cache.js | 69 +++ .../forin_non_empty_prototype/BUILD.gn | 18 + .../expect_output.txt | 19 + .../forin_non_empty_prototype.js | 47 ++ test/moduletest/forin_special_object/BUILD.gn | 18 + .../forin_special_object/expect_output.txt | 39 ++ .../forin_special_object.js | 56 ++ test/moduletest/stubbuilder/stubbuilder.js | 2 +- 66 files changed, 2543 insertions(+), 274 deletions(-) create mode 100644 ecmascript/property_accessor.cpp create mode 100644 ecmascript/property_accessor.h create mode 100644 test/moduletest/forin_delete_property/BUILD.gn create mode 100644 test/moduletest/forin_delete_property/expect_output.txt create mode 100644 test/moduletest/forin_delete_property/forin_delete_property.js create mode 100644 test/moduletest/forin_dictionary_mode/BUILD.gn create mode 100644 test/moduletest/forin_dictionary_mode/expect_output.txt create mode 100644 test/moduletest/forin_dictionary_mode/forin_dictionary_mode.js create mode 100644 test/moduletest/forin_empty_prototype/BUILD.gn create mode 100644 test/moduletest/forin_empty_prototype/expect_output.txt create mode 100644 test/moduletest/forin_empty_prototype/forin_empty_prototype.js create mode 100644 test/moduletest/forin_enum_cache/BUILD.gn create mode 100644 test/moduletest/forin_enum_cache/expect_output.txt create mode 100644 test/moduletest/forin_enum_cache/forin_enum_cache.js create mode 100644 test/moduletest/forin_non_empty_prototype/BUILD.gn create mode 100644 test/moduletest/forin_non_empty_prototype/expect_output.txt create mode 100644 test/moduletest/forin_non_empty_prototype/forin_non_empty_prototype.js create mode 100644 test/moduletest/forin_special_object/BUILD.gn create mode 100644 test/moduletest/forin_special_object/expect_output.txt create mode 100644 test/moduletest/forin_special_object/forin_special_object.js diff --git a/BUILD.gn b/BUILD.gn index cf3d38d741..266ce693b8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -752,6 +752,7 @@ ecma_source = [ "ecmascript/pgo_profiler/pgo_utils.cpp", "ecmascript/pgo_profiler/ap_file/pgo_method_type_set.cpp", "ecmascript/pgo_profiler/types/pgo_profile_type.cpp", + "ecmascript/property_accessor.cpp", "ecmascript/stackmap/ark_stackmap_builder.cpp", "ecmascript/stackmap/ark_stackmap_parser.cpp", "ecmascript/stackmap/llvm_stackmap_parser.cpp", diff --git a/ecmascript/base/fast_json_stringifier.cpp b/ecmascript/base/fast_json_stringifier.cpp index 32562748ce..6a7cd60754 100644 --- a/ecmascript/base/fast_json_stringifier.cpp +++ b/ecmascript/base/fast_json_stringifier.cpp @@ -488,7 +488,7 @@ bool FastJsonStringifier::TryCacheSerializeKeys(const JSHandle &obj, b if (!propertiesArr->IsDictionaryMode()) { JSHandle jsHclass(thread_, obj->GetJSHClass()); JSTaggedValue enumCache = jsHclass->GetEnumCache(); - if (!enumCache.IsNull()) { + if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) { JSHandle cache(thread_, enumCache); uint32_t length = cache->GetLength(); for (uint32_t i = 0; i < length; i++) { @@ -765,7 +765,7 @@ bool FastJsonStringifier::DefaultSerializeKeys(const JSHandle &obj, bo if (!propertiesArr->IsDictionaryMode()) { JSHandle jsHclass(thread_, obj->GetJSHClass()); JSTaggedValue enumCache = jsHclass->GetEnumCache(); - if (!enumCache.IsNull()) { + if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) { JSHandle cache(thread_, enumCache); uint32_t length = cache->GetLength(); for (uint32_t i = 0; i < length; i++) { diff --git a/ecmascript/base/json_stringifier.cpp b/ecmascript/base/json_stringifier.cpp index 8c190efe05..351e582023 100644 --- a/ecmascript/base/json_stringifier.cpp +++ b/ecmascript/base/json_stringifier.cpp @@ -616,7 +616,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl bool hasChangedToDictionaryMode = false; JSHandle jsHclass(thread_, obj->GetJSHClass()); JSTaggedValue enumCache = jsHclass->GetEnumCache(); - if (!enumCache.IsNull()) { + if (JSObject::GetEnumCacheKind(thread_, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) { JSHandle cache(thread_, enumCache); uint32_t length = cache->GetLength(); for (uint32_t i = 0; i < length; i++) { diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index 478854dd60..be57ca6888 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -2049,6 +2049,36 @@ DEF_CALL_SIGNATURE(CreateStringBySingleCharCode) callSign->SetCallConv(CallSignature::CallConv::CCallConv); } +DEF_CALL_SIGNATURE(Getpropiterator) +{ + // 2 : 2 input parameters + CallSignature signature("Getpropiterator", 0, 2, + ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); + *callSign = signature; + // 2 : 2 input parameters + std::array params = { + VariableType::NATIVE_POINTER(), // glue + VariableType::JS_ANY(), // object + }; + callSign->SetParameters(params.data()); + callSign->SetCallConv(CallSignature::CallConv::CCallConv); +} + +DEF_CALL_SIGNATURE(Getnextpropname) +{ + // 2 : 2 input parameters + CallSignature signature("Getnextpropname", 0, 2, + ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); + *callSign = signature; + // 2 : 2 input parameters + std::array params = { + VariableType::NATIVE_POINTER(), // glue + VariableType::JS_ANY(), // iter + }; + callSign->SetParameters(params.data()); + callSign->SetCallConv(CallSignature::CallConv::CCallConv); +} + DEF_CALL_SIGNATURE(FastStringEqual) { // 3 : 3 input parameters diff --git a/ecmascript/compiler/call_signature.h b/ecmascript/compiler/call_signature.h index a287982be1..88cc47e796 100644 --- a/ecmascript/compiler/call_signature.h +++ b/ecmascript/compiler/call_signature.h @@ -464,6 +464,8 @@ private: V(GetSingleCharCodeByIndex) \ V(CreateStringBySingleCharCode) \ V(FastStringEqual) \ + V(Getpropiterator) \ + V(Getnextpropname) \ V(JSHClassFindProtoTransitions) #define DECL_CALL_SIGNATURE(name) \ diff --git a/ecmascript/compiler/circuit_builder-inl.h b/ecmascript/compiler/circuit_builder-inl.h index 9370e80d77..70b898e77a 100644 --- a/ecmascript/compiler/circuit_builder-inl.h +++ b/ecmascript/compiler/circuit_builder-inl.h @@ -56,7 +56,7 @@ GateRef CircuitBuilder::DoubleIsINF(GateRef x) // Js World // cast operation -GateRef CircuitBuilder::GetGlobalConstantString(ConstantIndex index) +GateRef CircuitBuilder::GetGlobalConstantOffset(ConstantIndex index) { return PtrMul(IntPtr(sizeof(JSTaggedValue)), IntPtr(static_cast(index))); } diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index c40a07495b..ea3fe14635 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -235,7 +235,7 @@ public: GateRef GetModuleFromFunction(GateRef function); GateRef GetHomeObjectFromFunction(GateRef function); inline GateRef GetExpectedNumOfArgs(GateRef method); - inline GateRef GetGlobalConstantString(ConstantIndex index); // shareir + inline GateRef GetGlobalConstantOffset(ConstantIndex index); // shareir // Set void SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value); @@ -531,6 +531,7 @@ public: inline GateRef TaggedIsString(GateRef obj); inline GateRef TaggedIsStringOrSymbol(GateRef obj); inline GateRef TaggedIsSymbol(GateRef obj); + inline GateRef TaggedIsProtoChangeMarker(GateRef obj); inline GateRef TaggedGetInt(GateRef x); inline GateRef TaggedObjectIsString(GateRef obj); inline GateRef TaggedObjectBothAreString(GateRef x, GateRef y); diff --git a/ecmascript/compiler/common_stubs.cpp b/ecmascript/compiler/common_stubs.cpp index 5f99b9dc96..c5b090bd9d 100644 --- a/ecmascript/compiler/common_stubs.cpp +++ b/ecmascript/compiler/common_stubs.cpp @@ -919,6 +919,23 @@ void FastStringEqualStubBuilder::GenerateCircuit() Return(result); } +void GetpropiteratorStubBuilder::GenerateCircuit() +{ + GateRef glue = PtrArgument(0); + GateRef object = TaggedArgument(1); + NewObjectStubBuilder newBuilder(this); + GateRef result = newBuilder.EnumerateObjectProperties(glue, object); + Return(result); +} + +void GetnextpropnameStubBuilder::GenerateCircuit() +{ + GateRef glue = PtrArgument(0); + GateRef iter = TaggedArgument(1); + GateRef result = NextInternal(glue, iter); + Return(result); +} + CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS]; void CommonStubCSigns::Initialize() diff --git a/ecmascript/compiler/common_stubs.h b/ecmascript/compiler/common_stubs.h index e48899c82c..98165e71ea 100644 --- a/ecmascript/compiler/common_stubs.h +++ b/ecmascript/compiler/common_stubs.h @@ -78,6 +78,8 @@ namespace panda::ecmascript::kungfu { V(JsBoundCallInternal) \ V(JsProxyCallInternal) \ V(CreateStringBySingleCharCode) \ + V(Getpropiterator) \ + V(Getnextpropname) \ V(GetSingleCharCodeByIndex) \ V(FastStringEqual) diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index 5b2f70326e..34ba2b0b06 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -443,7 +443,8 @@ DECLARE_ASM_HANDLER(HandleDefinegettersetterbyvalueV8V8V8V8) DECLARE_ASM_HANDLER(HandleGetpropiterator) { DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc); - GateRef res = CallRuntime(glue, RTSTUB_ID(GetPropIterator), { *varAcc }); + NewObjectStubBuilder newBuilder(this); + GateRef res = newBuilder.EnumerateObjectProperties(glue, *varAcc); CHECK_EXCEPTION_WITH_VARACC(res, INT_PTR(GETPROPITERATOR)); } @@ -1147,7 +1148,7 @@ DECLARE_ASM_HANDLER(HandleGetnextpropnameV8) { GateRef v0 = ReadInst8_0(pc); GateRef iter = GetVregValue(sp, ZExtInt8ToPtr(v0)); - GateRef result = CallRuntime(glue, RTSTUB_ID(GetNextPropName), { iter }); + GateRef result = NextInternal(glue, iter); CHECK_EXCEPTION_WITH_ACC(result, INT_PTR(GETNEXTPROPNAME_V8)); } diff --git a/ecmascript/compiler/mcr_circuit_builder.h b/ecmascript/compiler/mcr_circuit_builder.h index dad53b2aed..6106f59366 100644 --- a/ecmascript/compiler/mcr_circuit_builder.h +++ b/ecmascript/compiler/mcr_circuit_builder.h @@ -164,6 +164,26 @@ GateRef CircuitBuilder::TaggedIsStringOrSymbol(GateRef obj) return ret; } +GateRef CircuitBuilder::TaggedIsProtoChangeMarker(GateRef obj) +{ + Label entry(env_); + SubCfgEntry(&entry); + Label exit(env_); + DEFVAlUE(result, env_, VariableType::BOOL(), False()); + Label isHeapObject(env_); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + GateRef objType = GetObjectType(LoadHClass(obj)); + result = Equal(objType, Int32(static_cast(JSType::PROTO_CHANGE_MARKER))); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + SubCfgExit(); + return ret; +} + inline GateRef CircuitBuilder::IsOptimizedAndNotFastCall(GateRef obj) { GateRef hClass = LoadHClass(obj); diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index f8f131616f..a6ba12ecc7 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -207,6 +207,80 @@ GateRef NewObjectStubBuilder::NewTaggedArray(GateRef glue, GateRef len) return ret; } +GateRef NewObjectStubBuilder::NewJSForinIterator(GateRef glue, GateRef receiver, GateRef keys, GateRef cachedHclass) +{ + auto env = GetEnvironment(); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + GateRef hclass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::FOR_IN_ITERATOR_CLASS_INDEX); + GateRef iter = NewJSObject(glue, hclass); + // init JSForinIterator + SetObjectOfForInIterator(glue, iter, receiver); + SetCachedHclassOFForInIterator(glue, iter, cachedHclass); + SetKeysOfForInIterator(glue, iter, keys); + SetIndexOfForInIterator(glue, iter, Int32(EnumCache::ENUM_CACHE_HEADER_SIZE)); + GateRef length = GetLengthOfTaggedArray(keys); + SetLengthOfForInIterator(glue, iter, length); + return iter; +} + +GateRef NewObjectStubBuilder::EnumerateObjectProperties(GateRef glue, GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(object, VariableType::JS_ANY(), Undefined()); + + Label isString(env); + Label isNotString(env); + Label afterObjectTransform(env); + Label slowpath(env); + Label empty(env); + Label tryGetEnumCache(env); + Label cacheHit(env); + + Branch(TaggedIsString(obj), &isString, &isNotString); + Bind(&isString); + { + object = CallRuntime(glue, RTSTUB_ID(PrimitiveStringCreate), { obj });; + Jump(&afterObjectTransform); + } + Bind(&isNotString); + { + object = ToPrototypeOrObj(glue, obj); + Jump(&afterObjectTransform); + } + Bind(&afterObjectTransform); + Branch(TaggedIsUndefinedOrNull(*object), &empty, &tryGetEnumCache); + Bind(&tryGetEnumCache); + GateRef enumCache = TryGetEnumCache(glue, *object); + Branch(TaggedIsUndefined(enumCache), &slowpath, &cacheHit); + Bind(&cacheHit); + { + GateRef hclass = LoadHClass(obj); + result = NewJSForinIterator(glue, *object, enumCache, hclass); + Jump(&exit); + } + Bind(&empty); + { + GateRef emptyArray = GetEmptyArray(glue); + result = NewJSForinIterator(glue, Undefined(), emptyArray, Undefined()); + Jump(&exit); + } + + Bind(&slowpath); + { + result = CallRuntime(glue, RTSTUB_ID(GetPropIteratorSlowpath), { *object }); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + void NewObjectStubBuilder::NewArgumentsList(Variable *result, Label *exit, GateRef sp, GateRef startIdx, GateRef numArgs) { diff --git a/ecmascript/compiler/new_object_stub_builder.h b/ecmascript/compiler/new_object_stub_builder.h index a6c4ffc22f..d6f105805b 100644 --- a/ecmascript/compiler/new_object_stub_builder.h +++ b/ecmascript/compiler/new_object_stub_builder.h @@ -49,6 +49,8 @@ public: GateRef NewJSArray(GateRef glue, GateRef hclass); GateRef NewTaggedArray(GateRef glue, GateRef len); GateRef NewJSArrayWithSize(GateRef hclass, GateRef size); + GateRef NewJSForinIterator(GateRef glue, GateRef receiver, GateRef keys, GateRef cachedHclass); + GateRef EnumerateObjectProperties(GateRef glue, GateRef obj); void NewArgumentsList(Variable *result, Label *exit, GateRef sp, GateRef startIdx, GateRef numArgs); void NewArgumentsObj(Variable *result, Label *exit, GateRef argumentsList, GateRef numArgs); void AllocLineStringObject(Variable *result, Label *exit, GateRef length, bool compressed); diff --git a/ecmascript/compiler/slowpath_lowering.cpp b/ecmascript/compiler/slowpath_lowering.cpp index 5f8faea301..cf963ba51e 100644 --- a/ecmascript/compiler/slowpath_lowering.cpp +++ b/ecmascript/compiler/slowpath_lowering.cpp @@ -1269,10 +1269,10 @@ void SlowPathLowering::LowerGreaterEq(GateRef gate) void SlowPathLowering::LowerGetPropIterator(GateRef gate) { - const int id = RTSTUB_ID(GetPropIterator); // 1: number of value inputs ASSERT(acc_.GetNumValueIn(gate) == 1); - GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)}); + GateRef object = {acc_.GetValueIn(gate, 0)}; + GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getpropiterator, {glue_, object}); ReplaceHirWithValue(gate, newGate); } @@ -1793,11 +1793,10 @@ void SlowPathLowering::LowerConditionJump(GateRef gate, bool isEqualJump) void SlowPathLowering::LowerGetNextPropName(GateRef gate) { - const int id = RTSTUB_ID(GetNextPropName); // 1: number of value inputs ASSERT(acc_.GetNumValueIn(gate) == 1); GateRef iter = acc_.GetValueIn(gate, 0); - GateRef newGate = LowerCallRuntime(gate, id, { iter }); + GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getnextpropname, {glue_, iter}); ReplaceHirWithValue(gate, newGate); } @@ -2498,14 +2497,14 @@ void SlowPathLowering::LowerTypeof(GateRef gate) GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_, builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit()))); - GateRef undefinedIndex = builder_.GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX); + GateRef undefinedIndex = builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX); GateRef gConstUndefinedStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex); DEFVAlUE(result, (&builder_), VariableType::JS_POINTER(), gConstUndefinedStr); Label objIsTrue(&builder_); Label objNotTrue(&builder_); Label defaultLabel(&builder_); GateRef gConstBooleanStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::BOOLEAN_STRING_INDEX)); builder_.Branch(builder_.TaggedIsTrue(obj), &objIsTrue, &objNotTrue); builder_.Bind(&objIsTrue); { @@ -2530,7 +2529,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsNull); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotNull); @@ -2541,7 +2540,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsUndefined); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotUndefined); @@ -2562,7 +2561,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsString); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::STRING_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotString); @@ -2573,7 +2572,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsSymbol); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::SYMBOL_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotSymbol); @@ -2584,7 +2583,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsCallable); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::FUNCTION_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotCallable); @@ -2595,13 +2594,13 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsBigInt); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::BIGINT_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotBigInt); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX)); builder_.Jump(&exit); } } @@ -2616,7 +2615,7 @@ void SlowPathLowering::LowerTypeof(GateRef gate) builder_.Bind(&objIsNum); { result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, - builder_.GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX)); + builder_.GetGlobalConstantOffset(ConstantIndex::NUMBER_STRING_INDEX)); builder_.Jump(&exit); } builder_.Bind(&objNotNum); diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 82c95c75f9..9f6d2907d2 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -30,6 +30,7 @@ #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/js_array.h" #include "ecmascript/js_function.h" +#include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_object.h" #include "ecmascript/js_tagged_value.h" @@ -1205,6 +1206,32 @@ inline GateRef StubBuilder::IsJsProxy(GateRef obj) return Int32Equal(objectType, Int32(static_cast(JSType::JS_PROXY))); } +inline GateRef StubBuilder::IsJSGlobalObject(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_GLOBAL_OBJECT))); +} + +inline GateRef StubBuilder::IsModuleNamespace(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_MODULE_NAMESPACE))); +} + +inline GateRef StubBuilder::ObjIsSpecialContainer(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return BoolAnd( + Int32GreaterThanOrEqual(objectType, Int32(static_cast(JSType::JS_API_ARRAY_LIST))), + Int32LessThanOrEqual(objectType, Int32(static_cast(JSType::JS_API_QUEUE)))); +} + +inline GateRef StubBuilder::IsJSPrimitiveRef(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_PRIMITIVE_REF))); +} + inline GateRef StubBuilder::IsJsArray(GateRef obj) { GateRef objectType = GetObjectType(LoadHClass(obj)); @@ -1421,6 +1448,86 @@ inline GateRef StubBuilder::HclassIsPropertyBox(GateRef hClass) Int32(static_cast(JSType::PROPERTY_BOX))); } +inline GateRef StubBuilder::TaggedIsProtoChangeMarker(GateRef obj) +{ + return env_->GetBuilder()->TaggedIsProtoChangeMarker(obj); +} + +inline GateRef StubBuilder::GetEmptyArray(GateRef glue) +{ + GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, + IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit()))); + GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); + return Load(VariableType::JS_ANY(), gConstAddr, offset); +} + +inline GateRef StubBuilder::GetLengthFromForInIterator(GateRef iter) +{ + GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); + return Load(VariableType::INT32(), iter, offset); +} + +inline GateRef StubBuilder::GetIndexFromForInIterator(GateRef iter) +{ + GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); + return Load(VariableType::INT32(), iter, offset); +} + +inline GateRef StubBuilder::GetKeysFromForInIterator(GateRef iter) +{ + GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); + return Load(VariableType::JS_ANY(), iter, offset); +} + +inline GateRef StubBuilder::GetObjectFromForInIterator(GateRef iter) +{ + GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); + return Load(VariableType::JS_ANY(), iter, offset); +} + +inline GateRef StubBuilder::GetCachedHclassFromForInIterator(GateRef iter) +{ + GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); + return Load(VariableType::JS_ANY(), iter, offset); +} + +inline void StubBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length) +{ + GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, iter, offset, length); +} + +inline void StubBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index) +{ + GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); + Store(VariableType::INT32(), glue, iter, offset, index); +} + +inline void StubBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys) +{ + GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); + Store(VariableType::JS_ANY(), glue, iter, offset, keys); +} + +inline void StubBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object) +{ + GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); + Store(VariableType::JS_ANY(), glue, iter, offset, object); +} + +inline void StubBuilder::SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass) +{ + GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); + Store(VariableType::JS_ANY(), glue, iter, offset, hclass); +} + +inline void StubBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index) +{ + GateRef newIndex = Int32Add(index, Int32(1)); + GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); + Store(VariableType::INT32(), glue, iter, offset, newIndex); +} + inline GateRef StubBuilder::IsField(GateRef attr) { return Int32Equal( @@ -1590,6 +1697,18 @@ inline GateRef StubBuilder::GetPrototypeFromHClass(GateRef hClass) return Load(VariableType::JS_ANY(), hClass, protoOffset); } +inline GateRef StubBuilder::GetEnumCacheFromHClass(GateRef hClass) +{ + GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET); + return Load(VariableType::JS_ANY(), hClass, offset); +} + +inline GateRef StubBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass) +{ + GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET); + return Load(VariableType::JS_ANY(), hClass, offset); +} + inline GateRef StubBuilder::GetLayoutFromHClass(GateRef hClass) { GateRef attrOffset = IntPtr(JSHClass::LAYOUT_OFFSET); @@ -1747,6 +1866,15 @@ inline GateRef StubBuilder::GetNumberOfPropsFromHClass(GateRef hClass) Int32((1LLU << JSHClass::NumberOfPropsBits::SIZE) - 1)); } +inline GateRef StubBuilder::HasDeleteProperty(GateRef hClass) +{ + GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET)); + return Int32NotEqual( + Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)), + Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)), + Int32(0)); +} + inline GateRef StubBuilder::IsTSHClass(GateRef hClass) { GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); @@ -2099,7 +2227,7 @@ inline GateRef StubBuilder::GetGlobalConstantAddr(GateRef index) return Int64Mul(Int64(sizeof(JSTaggedValue)), index); } -inline GateRef StubBuilder::GetGlobalConstantString(ConstantIndex index) +inline GateRef StubBuilder::GetGlobalConstantOffset(ConstantIndex index) { if (env_->Is32Bit()) { return Int32Mul(Int32(sizeof(JSTaggedValue)), Int32(static_cast(index))); diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 869298ccf7..4c073e7324 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -28,6 +28,7 @@ #include "ecmascript/js_api/js_api_arraylist.h" #include "ecmascript/js_api/js_api_vector.h" #include "ecmascript/js_object.h" +#include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_arguments.h" #include "ecmascript/mem/remembered_set.h" #include "ecmascript/message_string.h" @@ -3390,14 +3391,14 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit()))); - GateRef undefinedIndex = GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX); + GateRef undefinedIndex = GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX); GateRef gConstUndefinedStr = Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex); DEFVARIABLE(result, VariableType::JS_POINTER(), gConstUndefinedStr); Label objIsTrue(env); Label objNotTrue(env); Label defaultLabel(env); GateRef gConstBooleanStr = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::BOOLEAN_STRING_INDEX)); Branch(TaggedIsTrue(obj), &objIsTrue, &objNotTrue); Bind(&objIsTrue); { @@ -3422,7 +3423,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsNull); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX)); Jump(&exit); } Bind(&objNotNull); @@ -3433,7 +3434,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsUndefined); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX)); Jump(&exit); } Bind(&objNotUndefined); @@ -3454,7 +3455,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsString); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::STRING_STRING_INDEX)); Jump(&exit); } Bind(&objNotString); @@ -3465,7 +3466,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsSymbol); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::SYMBOL_STRING_INDEX)); Jump(&exit); } Bind(&objNotSymbol); @@ -3476,7 +3477,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsCallable); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::FUNCTION_STRING_INDEX)); Jump(&exit); } Bind(&objNotCallable); @@ -3487,13 +3488,13 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsBigInt); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::BIGINT_STRING_INDEX)); Jump(&exit); } Bind(&objNotBigInt); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX)); Jump(&exit); } } @@ -3508,7 +3509,7 @@ GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj) Bind(&objIsNum); { result = Load(VariableType::JS_POINTER(), gConstAddr, - GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX)); + GetGlobalConstantOffset(ConstantIndex::NUMBER_STRING_INDEX)); Jump(&exit); } Bind(&objNotNum); @@ -5232,6 +5233,490 @@ GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef i return ret; } +GateRef StubBuilder::GetEnumCacheKind(GateRef glue, GateRef enumCache) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::INT32(), Int32(static_cast(EnumCacheKind::NONE))); + + Label enumCacheIsArray(env); + Label isEmptyArray(env); + Label notEmptyArray(env); + + Branch(TaggedIsUndefinedOrNull(enumCache), &exit, &enumCacheIsArray); + Bind(&enumCacheIsArray); + GateRef emptyArray = GetEmptyArray(glue); + Branch(Int64Equal(enumCache, emptyArray), &isEmptyArray, ¬EmptyArray); + Bind(&isEmptyArray); + { + result = Int32(static_cast(EnumCacheKind::SIMPLE)); + Jump(&exit); + } + Bind(¬EmptyArray); + { + GateRef taggedKind = GetValueFromTaggedArray(enumCache, Int32(EnumCache::ENUM_CACHE_KIND_OFFSET)); + result = TaggedGetInt(taggedKind); + Jump(&exit); + } + + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::BOOL(), False()); + + Label isSameHclass(env); + Label isSimpleEnumCache(env); + Label notSimpleEnumCache(env); + Label prototypeIsEcmaObj(env); + Label isProtoChangeMarker(env); + Label protoNotChanged(env); + + GateRef hclass = LoadHClass(receiver); + Branch(Int64Equal(hclass, cachedHclass), &isSameHclass, &exit); + Bind(&isSameHclass); + Branch(Int32Equal(kind, Int32(static_cast(EnumCacheKind::SIMPLE))), + &isSimpleEnumCache, ¬SimpleEnumCache); + Bind(&isSimpleEnumCache); + { + result = True(); + Jump(&exit); + } + Bind(¬SimpleEnumCache); + GateRef prototype = GetPrototypeFromHClass(hclass); + Branch(IsEcmaObject(prototype), &prototypeIsEcmaObj, &exit); + Bind(&prototypeIsEcmaObj); + GateRef protoChangeMarker = GetProtoChangeMarkerFromHClass(hclass); + Branch(TaggedIsProtoChangeMarker(protoChangeMarker), &isProtoChangeMarker, &exit); + Bind(&isProtoChangeMarker); + Branch(GetHasChanged(protoChangeMarker), &exit, &protoNotChanged); + Bind(&protoNotChanged); + { + result = True(); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::NeedCheckProperty(GateRef receiver) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Label isJSObject(env); + Label hasNoDeleteProperty(env); + + DEFVARIABLE(result, VariableType::BOOL(), True()); + DEFVARIABLE(current, VariableType::JS_ANY(), receiver); + + Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop); + LoopBegin(&loopHead); + { + Branch(IsJSObject(*current), &isJSObject, &exit); + Bind(&isJSObject); + GateRef hclass = LoadHClass(*current); + Branch(HasDeleteProperty(hclass), &exit, &hasNoDeleteProperty); + Bind(&hasNoDeleteProperty); + current = GetPrototypeFromHClass(hclass); + Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop); + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + result = False(); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::NextInternal(GateRef glue, GateRef iter) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + + Label notFinish(env); + Label notEnumCacheValid(env); + Label fastGetKey(env); + Label slowpath(env); + + GateRef index = GetIndexFromForInIterator(iter); + GateRef length = GetLengthFromForInIterator(iter); + Branch(Int32GreaterThanOrEqual(index, length), &exit, ¬Finish); + Bind(¬Finish); + GateRef keys = GetKeysFromForInIterator(iter); + GateRef receiver = GetObjectFromForInIterator(iter); + GateRef cachedHclass = GetCachedHclassFromForInIterator(iter); + GateRef kind = GetEnumCacheKind(glue, keys); + Branch(IsEnumCacheValid(receiver, cachedHclass, kind), &fastGetKey, ¬EnumCacheValid); + Bind(¬EnumCacheValid); + Branch(NeedCheckProperty(receiver), &slowpath, &fastGetKey); + Bind(&fastGetKey); + { + result = GetValueFromTaggedArray(keys, index); + IncreaseInteratorIndex(glue, iter, index); + Jump(&exit); + } + Bind(&slowpath); + { + result = CallRuntime(glue, RTSTUB_ID(GetNextPropNameSlowpath), { iter }); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::GetFunctionPrototype(GateRef glue, size_t index) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + + Label isHeapObject(env); + Label isJSHclass(env); + + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env_->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + GateRef func = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, index); + GateRef protoOrHclass = Load(VariableType::JS_ANY(), func, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + result = protoOrHclass; + Branch(TaggedIsHeapObject(protoOrHclass), &isHeapObject, &exit); + Bind(&isHeapObject); + Branch(IsJSHClass(protoOrHclass), &isJSHclass, &exit); + Bind(&isJSHclass); + { + result = GetPrototypeFromHClass(protoOrHclass); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::ToPrototypeOrObj(GateRef glue, GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::JS_ANY(), obj); + + Label isNumber(env); + Label notNumber(env); + Label isBoolean(env); + Label notBoolean(env); + Label isString(env); + Label notString(env); + Label isSymbol(env); + Label notSymbol(env); + Label isBigInt(env); + Branch(TaggedIsNumber(obj), &isNumber, ¬Number); + Bind(&isNumber); + { + result = GetFunctionPrototype(glue, GlobalEnv::NUMBER_FUNCTION_INDEX); + Jump(&exit); + } + Bind(¬Number); + Branch(TaggedIsBoolean(obj), &isBoolean, ¬Boolean); + Bind(&isBoolean); + { + result = GetFunctionPrototype(glue, GlobalEnv::BOOLEAN_FUNCTION_INDEX); + Jump(&exit); + } + Bind(¬Boolean); + Branch(TaggedIsString(obj), &isString, ¬String); + Bind(&isString); + { + result = GetFunctionPrototype(glue, GlobalEnv::STRING_FUNCTION_INDEX); + Jump(&exit); + } + Bind(¬String); + Branch(TaggedIsSymbol(obj), &isSymbol, ¬Symbol); + Bind(&isSymbol); + { + result = GetFunctionPrototype(glue, GlobalEnv::SYMBOL_FUNCTION_INDEX); + Jump(&exit); + } + Bind(¬Symbol); + Branch(TaggedIsBigInt(obj), &isBigInt, &exit); + Bind(&isBigInt); + { + result = GetFunctionPrototype(glue, GlobalEnv::BIGINT_FUNCTION_INDEX); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::IsSpecialKeysObject(GateRef obj) +{ + return BoolOr(BoolOr(IsTypedArray(obj), IsModuleNamespace(obj)), ObjIsSpecialContainer(obj)); +} + +GateRef StubBuilder::IsSlowKeysObject(GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::BOOL(), False()); + + Label isHeapObject(env); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + result = BoolOr(BoolOr(IsJSGlobalObject(obj), IsJsProxy(obj)), IsSpecialKeysObject(obj)); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::GetNumberOfElements(GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(numOfElements, VariableType::INT32(), Int32(0)); + DEFVARIABLE(i, VariableType::INT32(), Int32(0)); + + Label isJSPrimitiveRef(env); + Label isPrimitiveString(env); + Label notPrimitiveString(env); + Label isDictMode(env); + Label notDictMode(env); + + Branch(IsJSPrimitiveRef(obj), &isJSPrimitiveRef, ¬PrimitiveString); + Bind(&isJSPrimitiveRef); + GateRef value = Load(VariableType::JS_ANY(), obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET)); + Branch(TaggedIsString(value), &isPrimitiveString, ¬PrimitiveString); + Bind(&isPrimitiveString); + { + numOfElements = GetLengthFromString(value); + Jump(¬PrimitiveString); + } + Bind(¬PrimitiveString); + GateRef elements = GetElementsArray(obj); + Branch(IsDictionaryMode(elements), &isDictMode, ¬DictMode); + Bind(¬DictMode); + { + Label loopHead(env); + Label loopEnd(env); + Label iLessLength(env); + Label notHole(env); + GateRef elementsLen = GetLengthOfTaggedArray(elements); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32UnsignedLessThan(*i, elementsLen), &iLessLength, &exit); + Bind(&iLessLength); + { + GateRef element = GetValueFromTaggedArray(elements, *i); + Branch(TaggedIsHole(element), &loopEnd, ¬Hole); + Bind(¬Hole); + numOfElements = Int32Add(*numOfElements, Int32(1)); + Jump(&loopEnd); + } + Bind(&loopEnd); + i = Int32Add(*i, Int32(1)); + LoopEnd(&loopHead); + } + } + Bind(&isDictMode); + { + GateRef entryCount = TaggedGetInt( + GetValueFromTaggedArray(elements, Int32(TaggedHashTable::NUMBER_OF_ENTRIES_INDEX))); + numOfElements = Int32Add(*numOfElements, entryCount); + Jump(&exit); + } + Bind(&exit); + auto ret = *numOfElements; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::IsSimpleEnumCacheValid(GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::BOOL(), False()); + DEFVARIABLE(current, VariableType::JS_ANY(), Undefined()); + + Label receiverHasNoElements(env); + + GateRef numOfElements = GetNumberOfElements(obj); + Branch(Int32GreaterThan(numOfElements, Int32(0)), &exit, &receiverHasNoElements); + Bind(&receiverHasNoElements); + { + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Label currentHasNoElements(env); + Label enumCacheIsUndefined(env); + current = GetPrototypeFromHClass(LoadHClass(obj)); + Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop); + LoopBegin(&loopHead); + { + GateRef numOfCurrentElements = GetNumberOfElements(*current); + Branch(Int32GreaterThan(numOfCurrentElements, Int32(0)), &exit, ¤tHasNoElements); + Bind(¤tHasNoElements); + GateRef hclass = LoadHClass(*current); + GateRef protoEnumCache = GetEnumCacheFromHClass(hclass); + Branch(TaggedIsUndefined(protoEnumCache), &enumCacheIsUndefined, &exit); + Bind(&enumCacheIsUndefined); + current = GetPrototypeFromHClass(hclass); + Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop); + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + result = True(); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::IsEnumCacheWithProtoChainInfoValid(GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::BOOL(), False()); + DEFVARIABLE(current, VariableType::JS_ANY(), Undefined()); + + Label receiverHasNoElements(env); + Label prototypeIsEcmaObj(env); + Label isProtoChangeMarker(env); + Label protoNotChanged(env); + + GateRef numOfElements = GetNumberOfElements(obj); + Branch(Int32GreaterThan(numOfElements, Int32(0)), &exit, &receiverHasNoElements); + Bind(&receiverHasNoElements); + GateRef prototype = GetPrototypeFromHClass(LoadHClass(obj)); + Branch(IsEcmaObject(prototype), &prototypeIsEcmaObj, &exit); + Bind(&prototypeIsEcmaObj); + GateRef protoChangeMarker = GetProtoChangeMarkerFromHClass(LoadHClass(prototype)); + Branch(TaggedIsProtoChangeMarker(protoChangeMarker), &isProtoChangeMarker, &exit); + Bind(&isProtoChangeMarker); + Branch(GetHasChanged(protoChangeMarker), &exit, &protoNotChanged); + Bind(&protoNotChanged); + { + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Label currentHasNoElements(env); + current = prototype; + Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop); + LoopBegin(&loopHead); + { + GateRef numOfCurrentElements = GetNumberOfElements(*current); + Branch(Int32GreaterThan(numOfCurrentElements, Int32(0)), &exit, ¤tHasNoElements); + Bind(¤tHasNoElements); + current = GetPrototypeFromHClass(LoadHClass(*current)); + Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop); + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + result = True(); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::TryGetEnumCache(GateRef glue, GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + + Label notSlowKeys(env); + Label notDictionaryMode(env); + Label checkSimpleEnumCache(env); + Label notSimpleEnumCache(env); + Label checkEnumCacheWithProtoChainInfo(env); + Label enumCacheValid(env); + + Branch(IsSlowKeysObject(obj), &exit, ¬SlowKeys); + Bind(¬SlowKeys); + GateRef hclass = LoadHClass(obj); + Branch(IsDictionaryModeByHClass(hclass), &exit, ¬DictionaryMode); + Bind(¬DictionaryMode); + GateRef enumCache = GetEnumCacheFromHClass(hclass); + GateRef kind = GetEnumCacheKind(glue, enumCache); + Branch(Int32Equal(kind, Int32(static_cast(EnumCacheKind::SIMPLE))), + &checkSimpleEnumCache, ¬SimpleEnumCache); + Bind(&checkSimpleEnumCache); + { + Branch(IsSimpleEnumCacheValid(obj), &enumCacheValid, &exit); + } + Bind(¬SimpleEnumCache); + Branch(Int32Equal(kind, Int32(static_cast(EnumCacheKind::PROTOCHAIN))), + &checkEnumCacheWithProtoChainInfo, &exit); + Bind(&checkEnumCacheWithProtoChainInfo); + { + Branch(IsEnumCacheWithProtoChainInfoValid(obj), &enumCacheValid, &exit); + } + Bind(&enumCacheValid); + { + result = enumCache; + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + GateRef StubBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 4dfd1b3fe8..664cd304fd 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -222,6 +222,7 @@ public: GateRef BothAreString(GateRef x, GateRef y); GateRef TaggedIsStringOrSymbol(GateRef obj); GateRef TaggedIsSymbol(GateRef obj); + GateRef TaggedIsProtoChangeMarker(GateRef obj); GateRef GetNextPositionForHash(GateRef last, GateRef count, GateRef size); GateRef DoubleIsNAN(GateRef x); GateRef DoubleIsINF(GateRef x); @@ -318,6 +319,10 @@ public: GateRef TaggedIsPropertyBox(GateRef obj); GateRef TaggedObjectIsBigInt(GateRef obj); GateRef IsJsProxy(GateRef obj); + GateRef IsJSGlobalObject(GateRef obj); + GateRef IsModuleNamespace(GateRef obj); + GateRef ObjIsSpecialContainer(GateRef obj); + GateRef IsJSPrimitiveRef(GateRef obj); GateRef IsJSFunctionBase(GateRef obj); GateRef IsConstructor(GateRef object); GateRef IsBase(GateRef func); @@ -392,6 +397,8 @@ public: // SetDictionaryOrder func in property_attribute.h GateRef SetDictionaryOrderFieldInPropAttr(GateRef attr, GateRef value); GateRef GetPrototypeFromHClass(GateRef hClass); + GateRef GetEnumCacheFromHClass(GateRef hClass); + GateRef GetProtoChangeMarkerFromHClass(GateRef hClass); GateRef GetLayoutFromHClass(GateRef hClass); GateRef GetBitFieldFromHClass(GateRef hClass); GateRef GetLengthFromString(GateRef value); @@ -420,6 +427,7 @@ public: void IncNumberOfProps(GateRef glue, GateRef hClass); GateRef GetNumberOfPropsFromHClass(GateRef hClass); + GateRef HasDeleteProperty(GateRef hClass); GateRef IsTSHClass(GateRef hClass); void SetNumberOfPropsToHClass(GateRef glue, GateRef hClass, GateRef value); void SetElementsKindToTrackInfo(GateRef glue, GateRef trackInfo, GateRef elementsKind); @@ -534,7 +542,7 @@ public: GateRef TruncInt64ToInt1(GateRef x); GateRef TruncInt32ToInt1(GateRef x); GateRef GetGlobalConstantAddr(GateRef index); - GateRef GetGlobalConstantString(ConstantIndex index); + GateRef GetGlobalConstantOffset(ConstantIndex index); GateRef IsCallableFromBitField(GateRef bitfield); GateRef IsCallable(GateRef obj); GateRef GetOffsetFieldInPropAttr(GateRef attr); @@ -611,6 +619,34 @@ public: GateRef GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType); GateRef JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index); + // for-in + GateRef NextInternal(GateRef glue, GateRef iter); + GateRef GetLengthFromForInIterator(GateRef iter); + GateRef GetIndexFromForInIterator(GateRef iter); + GateRef GetKeysFromForInIterator(GateRef iter); + GateRef GetObjectFromForInIterator(GateRef iter); + GateRef GetCachedHclassFromForInIterator(GateRef iter); + void SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length); + void SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index); + void SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys); + void SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object); + void SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass); + void IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index); + GateRef GetEnumCacheKind(GateRef glue, GateRef enumCache); + GateRef GetEmptyArray(GateRef glue); + GateRef IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind); + GateRef NeedCheckProperty(GateRef receiver); + + GateRef EnumerateObjectProperties(GateRef glue, GateRef obj); + GateRef GetFunctionPrototype(GateRef glue, size_t index); + GateRef ToPrototypeOrObj(GateRef glue, GateRef obj); + GateRef IsSpecialKeysObject(GateRef obj); + GateRef IsSlowKeysObject(GateRef obj); + GateRef TryGetEnumCache(GateRef glue, GateRef obj); + GateRef GetNumberOfElements(GateRef obj); + GateRef IsSimpleEnumCacheValid(GateRef obj); + GateRef IsEnumCacheWithProtoChainInfoValid(GateRef obj); + // Exception handle GateRef HasPendingException(GateRef glue); void ReturnExceptionIfAbruptCompletion(GateRef glue); diff --git a/ecmascript/compiler/type_mcr_lowering.cpp b/ecmascript/compiler/type_mcr_lowering.cpp index e5314007a8..cdc9982038 100644 --- a/ecmascript/compiler/type_mcr_lowering.cpp +++ b/ecmascript/compiler/type_mcr_lowering.cpp @@ -1641,7 +1641,7 @@ void TypeMCRLowering::LowerTypeOf(GateRef gate, GateRef glue) UNREACHABLE(); } - GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, builder_.GetGlobalConstantString(index)); + GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, builder_.GetGlobalConstantOffset(index)); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 52f3730e93..c7edb38d08 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -1871,14 +1871,15 @@ void JSForInIterator::Dump(std::ostream &os) const { os << " - Object : "; GetObject().DumpTaggedValue(os); + os << " - CachedHclass : "; + GetCachedHclass().DumpTaggedValue(os); os << "\n"; - os << " - WasVisited : " << GetWasVisited(); + os << " - Keys : "; + GetKeys().DumpTaggedValue(os); os << "\n"; - os << " - VisitedObjs : "; - GetVisitedObjs().DumpTaggedValue(os); + os << " - Index : " << GetIndex(); os << "\n"; - os << " - RemainingKeys : "; - GetRemainingKeys().DumpTaggedValue(os); + os << " - Length : " << GetLength(); os << "\n"; JSObject::Dump(os); } @@ -4557,9 +4558,10 @@ void JSMap::DumpForSnapshot(std::vector &vec) const void JSForInIterator::DumpForSnapshot(std::vector &vec) const { vec.emplace_back(CString("Object"), GetObject()); - vec.emplace_back(CString("WasVisited"), JSTaggedValue(GetWasVisited())); - vec.emplace_back(CString("VisitedObjs"), GetVisitedObjs()); - vec.emplace_back(CString("RemainingKeys"), GetRemainingKeys()); + vec.emplace_back(CString("CachedHclass"), GetCachedHclass()); + vec.emplace_back(CString("Keys"), GetKeys()); + vec.emplace_back(CString("Index"), JSTaggedValue(GetIndex())); + vec.emplace_back(CString("Length"), JSTaggedValue(GetLength())); JSObject::DumpForSnapshot(vec); } diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index 66f190bfae..3348682259 100644 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -552,6 +552,9 @@ bool EcmaString::StringsAreEqual(const EcmaVM *vm, const JSHandle &s if (str1 == str2) { return true; } + if (str1->IsInternString() && str2->IsInternString()) { + return false; + } uint32_t str1Len = str1->GetLength(); if (str1Len != str2->GetLength()) { return false; diff --git a/ecmascript/global_dictionary-inl.h b/ecmascript/global_dictionary-inl.h index ee910a3a4c..ba1f35a715 100644 --- a/ecmascript/global_dictionary-inl.h +++ b/ecmascript/global_dictionary-inl.h @@ -155,6 +155,25 @@ void GlobalDictionary::GetAllKeysByFilter(const JSThread *thread, } } +std::pair GlobalDictionary::GetNumOfEnumKeys() const +{ + uint32_t enumKeys = 0; + uint32_t shadowKeys = 0; + int size = Size(); + for (int hashIndex = 0; hashIndex < size; hashIndex++) { + JSTaggedValue key = GetKey(hashIndex); + if (key.IsString()) { + PropertyAttributes attr = GetAttributes(hashIndex); + if (attr.IsEnumerable()) { + enumKeys++; + } else { + shadowKeys++; + } + } + } + return std::make_pair(enumKeys, shadowKeys); +} + void GlobalDictionary::GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray, uint32_t *keys) const { diff --git a/ecmascript/global_dictionary.h b/ecmascript/global_dictionary.h index ccfb0fc925..d93a4f8317 100644 --- a/ecmascript/global_dictionary.h +++ b/ecmascript/global_dictionary.h @@ -81,6 +81,8 @@ public: inline void GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray, uint32_t *keys) const; + inline std::pair GetNumOfEnumKeys() const; + static bool inline CompKey(const std::pair &a, const std::pair &b); diff --git a/ecmascript/js_for_in_iterator.cpp b/ecmascript/js_for_in_iterator.cpp index cbb3477de8..c7f4ac9843 100644 --- a/ecmascript/js_for_in_iterator.cpp +++ b/ecmascript/js_for_in_iterator.cpp @@ -16,138 +16,123 @@ #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/base/builtins_base.h" -#include "ecmascript/global_dictionary-inl.h" -#include "ecmascript/global_env.h" +#include "ecmascript/ic/proto_change_details.h" #include "ecmascript/js_object-inl.h" -#include "ecmascript/js_primitive_ref.h" -#include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" -#include "ecmascript/tagged_dictionary.h" -#include "ecmascript/tagged_queue.h" -#include "ecmascript/tagged_queue.h" namespace panda::ecmascript { using BuiltinsBase = base::BuiltinsBase; - -bool JSForInIterator::CheckObjProto(const JSThread *thread, const JSHandle &it) +bool JSForInIterator::IsEnumCacheValid(JSTaggedValue receiver, JSTaggedValue cachedHclass, EnumCacheKind kind) { - JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); - JSHandle object(thread, it->GetObject()); - if (!object->IsJSObject()) { + DISALLOW_GARBAGE_COLLECTION; + JSHClass *hclass = receiver.GetTaggedObject()->GetClass(); + if (JSTaggedValue(hclass) != cachedHclass) { return false; } - auto *hclass = object->GetTaggedObject()->GetClass(); - JSType jsType = hclass->GetObjectType(); - if (jsType != JSType::JS_OBJECT) { - return false; + if (kind == EnumCacheKind::SIMPLE) { + return true; } + ASSERT(kind == EnumCacheKind::PROTOCHAIN); JSTaggedValue proto = hclass->GetPrototype(); - if (!proto.IsJSObject()) { + if (!proto.IsECMAObject()) { return false; } - return hclass->GetPrototype().GetTaggedObject()->GetClass() == - env->GetObjectFunctionPrototypeClass().GetTaggedValue().GetTaggedObject()->GetClass(); + JSTaggedValue protoChangeMarker = proto.GetTaggedObject()->GetClass()->GetProtoChangeMarker(); + if (protoChangeMarker.IsProtoChangeMarker()) { + if (!ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject())->GetHasChanged()) { + return true; + } + } + return false; } -void JSForInIterator::GetAllEnumKeys(JSThread *thread, const JSHandle &it, - const JSHandle &object) +bool JSForInIterator::NeedCheckProperty(JSTaggedValue receiver) { - ASSERT(object->IsHeapObject()); - JSMutableHandle value(thread, JSTaggedValue::Undefined()); - JSMutableHandle remaining(thread, thread->GlobalConstants()->GetEmptyTaggedQueue()); - if (object->IsJSProxy()) { - JSHandle proxyArr = JSProxy::OwnPropertyKeys(thread, JSHandle(object)); - RETURN_IF_ABRUPT_COMPLETION(thread); - uint32_t length = proxyArr->GetLength(); - for (uint32_t i = 0; i < length; i++) { - value.Update(proxyArr->Get(i)); - PropertyDescriptor desc(thread); - JSProxy::GetOwnProperty(thread, JSHandle(object), value, desc); - RETURN_IF_ABRUPT_COMPLETION(thread); - if (desc.IsEnumerable()) { - TaggedQueue *newQueue = TaggedQueue::Push(thread, remaining, value); - remaining.Update(JSTaggedValue(newQueue)); - } - } - } else { - JSHandle arr = JSTaggedValue::GetOwnEnumPropertyKeys(thread, object); - uint32_t len = arr->GetLength(); - for (uint32_t i = 0; i < len; i++) { - value.Update(arr->Get(i)); - if (value->IsString()) { - TaggedQueue *newQueue = TaggedQueue::Push(thread, remaining, value); - remaining.Update(JSTaggedValue(newQueue)); - } + DISALLOW_GARBAGE_COLLECTION; + JSTaggedValue current = receiver; + while (current.IsHeapObject()) { + if (!current.IsJSObject() || current.GetTaggedObject()->GetClass()->HasDeleteProperty()) { + return true; } + current = JSObject::GetPrototype(current); } - if (it->GetHasVisitObjs()) { - JSMutableHandle remained(thread, thread->GlobalConstants()->GetEmptyTaggedQueue()); - JSMutableHandle visited(thread, it->GetVisitedObjs()); - uint32_t size = visited->Size(); - while (!remaining->Empty()) { - JSHandle key(thread, remaining->Pop(thread)); - bool has = false; - for (uint32_t i = 0; i < size; i++) { - value.Update(visited->Get(i)); - PropertyDescriptor desc(thread); - has = JSTaggedValue::GetOwnProperty(thread, value, key, desc); - RETURN_IF_ABRUPT_COMPLETION(thread); - if (has) { - break; - } - } - if (!has) { - TaggedQueue *newQueue = TaggedQueue::Push(thread, remained, key); - remained.Update(JSTaggedValue(newQueue)); - } - } - it->SetRemainingKeys(thread, remained); - } else { - it->SetRemainingKeys(thread, remaining); - } - it->SetWasVisited(true); - object->GetTaggedObject()->GetClass()->SetHasDeleteProperty(false); + return false; } -std::pair JSForInIterator::NextInternal(JSThread *thread, const JSHandle &it) +bool JSForInIterator::HasProperty(JSThread *thread, JSHandle receiver, JSHandle key) { - while (true) { - JSHandle object(thread, it->GetObject()); - if (object->IsNull() || object->IsUndefined()) { - return std::make_pair(JSTaggedValue::Undefined(), true); + JSMutableHandle current(thread, receiver.GetTaggedValue()); + while (current->IsHeapObject()) { + PropertyDescriptor desc(thread); + bool has = JSTaggedValue::GetOwnProperty(thread, current, key, desc); + if (has && desc.IsEnumerable()) { + return true; } - if (!it->GetWasVisited()) { - GetAllEnumKeys(thread, it, object); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, std::make_pair(JSTaggedValue::Exception(), false)); - } - - JSHandle remaining(thread, it->GetRemainingKeys()); - while (!remaining->Empty()) { - ASSERT(object->IsHeapObject()); - JSTaggedValue r = remaining->Pop(thread); - bool hasDelete = object->GetTaggedObject()->GetClass()->HasDeleteProperty(); - if (object->IsJSObject() && !hasDelete) { - return std::make_pair(r, false); - } - JSHandle key(thread, r); - PropertyDescriptor desc(thread); - bool has = JSTaggedValue::GetOwnProperty(thread, object, key, desc); - if (has) { - if (desc.IsEnumerable()) { - return std::make_pair(key.GetTaggedValue(), false); - } - } - } - JSMutableHandle visited(thread, it->GetVisitedObjs()); - TaggedQueue *newQueue = TaggedQueue::Push(thread, visited, object); - visited.Update(JSTaggedValue(newQueue)); - it->SetVisitedObjs(thread, visited); - JSTaggedValue proto = JSTaggedValue::GetPrototype(thread, object); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, std::make_pair(JSTaggedValue::Exception(), false)); - it->SetObject(thread, proto); - it->SetWasVisited(false); - it->SetHasVisitObjs(true); + current.Update(JSTaggedValue::GetPrototype(thread, current)); } + return false; +} + +JSTaggedValue JSForInIterator::NextInternal(JSThread *thread, const JSHandle &it) +{ + uint32_t length = it->GetLength(); + uint32_t index = it->GetIndex(); + if (index >= length) { + return JSTaggedValue::Undefined(); + } + JSTaggedValue taggedKeys = it->GetKeys(); + JSTaggedValue receiver = it->GetObject(); + EnumCacheKind kind = JSObject::GetEnumCacheKind(thread, taggedKeys); + TaggedArray *keys = TaggedArray::Cast(taggedKeys.GetTaggedObject()); + if (IsEnumCacheValid(receiver, it->GetCachedHclass(), kind)) { + JSTaggedValue key = keys->Get(index); + index++; + it->SetIndex(index); + return key; + } + + if (!NeedCheckProperty(receiver)) { + JSTaggedValue key = keys->Get(index); + index++; + it->SetIndex(index); + return key; + } + // slow path + return NextInternalSlowpath(thread, it); +} + +JSTaggedValue JSForInIterator::NextInternalSlowpath(JSThread *thread, const JSHandle &it) +{ + uint32_t length = it->GetLength(); + uint32_t index = it->GetIndex(); + if (index >= length) { + return JSTaggedValue::Undefined(); + } + JSHandle keysHandle(thread, it->GetKeys()); + JSHandle receiverHandle(thread, it->GetObject()); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + bool has = false; + while (index < length) { + keyHandle.Update(keysHandle->Get(index)); + if (keyHandle->IsUndefined()) { + has = false; + break; + } + has = HasProperty(thread, receiverHandle, keyHandle); + if (has) { + break; + } + index++; + } + if (!has) { + it->SetIndex(index); + return JSTaggedValue::Undefined(); + } + + JSTaggedValue key = keysHandle->Get(index); + index++; + it->SetIndex(index); + return key; } // 13.7.5.16.2.1 %ForInIteratorPrototype%.next ( ) @@ -158,8 +143,8 @@ JSTaggedValue JSForInIterator::Next(EcmaRuntimeCallInfo *msg) [[maybe_unused]] EcmaHandleScope handleScope(thread); // 1. Let O be the this value. JSHandle it(BuiltinsBase::GetThis(msg)); - ASSERT(it->IsForinIterator()); - std::pair res = NextInternal(thread, it); - return res.first; + ASSERT(JSHandle(it)->IsForinIterator()); + JSTaggedValue res = NextInternal(thread, it); + return res; } } // namespace panda::ecmascript diff --git a/ecmascript/js_for_in_iterator.h b/ecmascript/js_for_in_iterator.h index 08a0b16ab1..06d563c93a 100644 --- a/ecmascript/js_for_in_iterator.h +++ b/ecmascript/js_for_in_iterator.h @@ -27,29 +27,27 @@ class JSForInIterator : public JSObject { public: CAST_CHECK(JSForInIterator, IsForinIterator); - static std::pair NextInternal(JSThread *thread, const JSHandle &it); + static JSTaggedValue NextInternal(JSThread *thread, const JSHandle &it); + static JSTaggedValue NextInternalSlowpath(JSThread *thread, const JSHandle &it); static JSTaggedValue Next(EcmaRuntimeCallInfo *msg); - static bool CheckObjProto(const JSThread *thread, const JSHandle &it); - - static void GetAllEnumKeys(JSThread *thread, const JSHandle &it, - const JSHandle &object); - static constexpr size_t OBJECT_OFFSET = JSObject::SIZE; - ACCESSORS(Object, OBJECT_OFFSET, VISITED_KEYS_OFFSET) - ACCESSORS(VisitedObjs, VISITED_KEYS_OFFSET, REMAINING_KEYS_OFFSET) - ACCESSORS(RemainingKeys, REMAINING_KEYS_OFFSET, BIT_FIELD_OFFSET) - ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) + ACCESSORS(Object, OBJECT_OFFSET, CACHED_HCLASS_OFFSET) + ACCESSORS(CachedHclass, CACHED_HCLASS_OFFSET, KEYS_OFFSET) + ACCESSORS(Keys, KEYS_OFFSET, INDEX_OFFSET) + ACCESSORS_PRIMITIVE_FIELD(Index, uint32_t, INDEX_OFFSET, LENGTH_OFFSET) + ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, LAST_OFFSET) DEFINE_ALIGN_SIZE(LAST_OFFSET); - // define BitField - static constexpr size_t WAS_VISITED_BITS = 3; - FIRST_BIT_FIELD(BitField, WasVisited, bool, WAS_VISITED_BITS) - NEXT_BIT_FIELD(BitField, HasVisitObjs, bool, 1, WasVisited) - - DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, OBJECT_OFFSET, BIT_FIELD_OFFSET) + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, OBJECT_OFFSET, INDEX_OFFSET) DECL_DUMP() + +private: + static bool IsEnumCacheValid(JSTaggedValue receiver, JSTaggedValue cachedHclass, EnumCacheKind kind); + static bool NeedCheckProperty(JSTaggedValue receiver); + static bool HasProperty(JSThread *thread, JSHandle receiver, JSHandle key); + }; } // namespace panda::ecmascript diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 5127519fe8..78dc56038d 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -298,6 +298,35 @@ enum class JSType : uint8_t { JSTYPE_DECL, }; +// EnumCache: +// +-----------------+----------------------+ +// | value | status | +// +-----------------+----------------------+ +// | null | uninitialized | +// ------------------------------------------ +// | undefined | a fast path to check | +// | | simple enum cache | +// ------------------------------------------ +// | empty array | enum keys is empty | +// ------------------------------------------ +// | non-empty array | non-empty enum keys | +// +----------------------------------------+ +// structure of non-empty array of EnumCache: +// 0: an int value indicating enum cache kind +// 1-n: enum keys +namespace EnumCache { +static constexpr uint32_t ENUM_CACHE_HEADER_SIZE = 1; +static constexpr uint32_t ENUM_CACHE_KIND_OFFSET = 0; +enum class EnumCacheKind : uint8_t { + NONE = 0, + SIMPLE, // simple enum cache(used in for-in) + // make sure EnumCache is empty array only for SIMPLE + PROTOCHAIN, // enum cache with prototype chain info(used in for-in) + ONLY_OWN_KEYS // enum cache with only own enum keys(used in Json.stringify and Object.keys) +}; + +} // namespace EnumCache + class JSHClass : public TaggedObject { public: static constexpr int TYPE_BITFIELD_NUM = 8; diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index d63ba411b7..376355a7f0 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -23,6 +23,7 @@ #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/tagged_array-inl.h" +#include "ecmascript/tagged_queue.h" namespace panda::ecmascript { inline void ECMAObject::SetCallable(bool flag) @@ -452,16 +453,77 @@ inline uint32_t JSObject::SetValuesOrEntries(JSThread *thread, const JSHandleSet(thread, EnumCache::ENUM_CACHE_KIND_OFFSET, JSTaggedValue(static_cast(kind))); +} + +inline EnumCacheKind JSObject::GetEnumCacheKind(JSThread *thread, TaggedArray *array) +{ + return static_cast(array->Get(thread, EnumCache::ENUM_CACHE_KIND_OFFSET).GetInt()); +} + +inline EnumCacheKind JSObject::GetEnumCacheKind(JSThread *thread, JSTaggedValue enumCache) +{ + if (enumCache.IsUndefinedOrNull()) { + return EnumCacheKind::NONE; + } + JSTaggedValue emptyArray = thread->GlobalConstants()->GetEmptyArray(); + if (enumCache == emptyArray) { + return EnumCacheKind::SIMPLE; + } + TaggedArray *array = TaggedArray::Cast(enumCache.GetTaggedObject()); + return JSObject::GetEnumCacheKind(thread, array); +} + +inline JSTaggedValue JSObject::GetPrototype(JSTaggedValue obj) +{ + JSHClass *hclass = obj.GetTaggedObject()->GetClass(); + return hclass->GetPrototype(); +} + +inline bool JSObject::IsDepulicateKeys(JSThread *thread, JSHandle keys, int32_t lastLength, + JSHandle shadowQueue, JSHandle key) +{ + if (lastLength < 0) { + return false; + } + JSMutableHandle value(thread, JSTaggedValue::Undefined()); + for (int32_t i = EnumCache::ENUM_CACHE_HEADER_SIZE; i < lastLength; i++) { + value.Update(keys->Get(i)); + bool has = JSTaggedValue::Equal(thread, value, key); + if (has) { + return true; + } + } + + uint32_t shadowSize = shadowQueue->Size(); + for (uint32_t i = 0; i < shadowSize; i++) { + value.Update(shadowQueue->Get(i)); + bool has = JSTaggedValue::Equal(thread, value, key); + if (has) { + return true; + } + } + return false; +} + +inline void JSObject::ClearHasDeleteProperty(JSHandle object) +{ + object->GetTaggedObject()->GetClass()->SetHasDeleteProperty(false); +} + inline std::pair, JSHandle> JSObject::GetOwnEnumerableNamesInFastMode( JSThread *thread, const JSHandle &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - uint32_t numOfKeys = obj->GetNumberOfKeys(); + std::pair numOfKeys = obj->GetNumberOfEnumKeys(); + uint32_t numOfEnumKeys = numOfKeys.first; uint32_t numOfElements = obj->GetNumberOfElements(); JSHandle elementArray = numOfElements > 0 ? JSObject::GetEnumElementKeys( thread, obj, 0, numOfElements, copyLengthOfElements) : factory->EmptyArray(); - JSHandle keyArray = numOfKeys > 0 ? JSObject::GetAllEnumKeys( - thread, obj, 0, numOfKeys, copyLengthOfKeys) : factory->EmptyArray(); + JSHandle keyArray = numOfEnumKeys > 0 ? JSObject::GetAllEnumKeys( + thread, obj, numOfEnumKeys, copyLengthOfKeys) : factory->EmptyArray(); return std::make_pair(keyArray, elementArray); } diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index f5ce1617a2..8efd6bd4ff 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -21,6 +21,7 @@ #include "ecmascript/filter_helper.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" +#include "ecmascript/ic/proto_change_details.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_iterator.h" @@ -29,6 +30,7 @@ #include "ecmascript/object_factory-inl.h" #include "ecmascript/object_fast_operator-inl.h" #include "ecmascript/pgo_profiler/pgo_profiler.h" +#include "ecmascript/property_accessor.h" #include "ecmascript/property_attributes.h" #include "ecmascript/tagged_array-inl.h" @@ -300,12 +302,6 @@ void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle } if (!array->IsDictionaryMode()) { - JSHClass *hclass = obj->GetJSHClass(); - // To maintain TS inherit info, not change hclass, just set hole. - if (hclass->HasTSSubtyping() && !hclass->IsPrototype()) { - obj->SetPropertyInlinedProps(thread, index, JSTaggedValue::Hole()); - return; - } JSHandle dictHandle(TransitionToDictionary(thread, obj)); int entry = dictHandle->FindEntry(key.GetTaggedValue()); ASSERT(entry != -1); @@ -384,14 +380,14 @@ void JSObject::GetAllKeysForSerialization(const JSHandle &obj, std::ve } } -JSHandle JSObject::GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, +JSHandle JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle &obj, uint32_t numOfKeys, uint32_t *keys) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); if (obj->IsJSGlobalObject()) { JSHandle keyArray = factory->NewTaggedArray(numOfKeys); GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject()); - dict->GetEnumAllKeys(thread, offset, *keyArray, keys); + dict->GetEnumAllKeys(thread, 0, *keyArray, keys); return keyArray; } @@ -399,34 +395,34 @@ JSHandle JSObject::GetAllEnumKeys(const JSThread *thread, const JSH if (!array->IsDictionaryMode()) { JSHClass *jsHclass = obj->GetJSHClass(); JSTaggedValue enumCache = jsHclass->GetEnumCache(); - if (!enumCache.IsNull()) { + if (JSObject::GetEnumCacheKind(thread, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) { JSHandle cacheArray = JSHandle(thread, enumCache); - *keys = cacheArray->GetLength(); - JSHandle keyArray = factory->CopyArray(cacheArray, *keys, *keys); + JSHandle keyArray = factory->CopyFromEnumCache(cacheArray); + *keys = keyArray->GetLength(); return keyArray; } - JSHandle keyArray = factory->NewTaggedArray(numOfKeys); - int end = static_cast(jsHclass->NumberOfProps()); - if (end > 0) { + + if (numOfKeys > 0) { + int end = static_cast(jsHclass->NumberOfProps()); + JSHandle keyArray = factory->NewTaggedArray(numOfKeys + EnumCache::ENUM_CACHE_HEADER_SIZE); LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject()) - ->GetAllEnumKeys(thread, end, offset, *keyArray, keys, obj); - if (*keys == keyArray->GetLength()) { - jsHclass->SetEnumCache(thread, keyArray.GetTaggedValue()); - JSHandle newkeyArray = factory->CopyArray(keyArray, *keys, *keys); - return newkeyArray; - } + ->GetAllEnumKeys(thread, end, EnumCache::ENUM_CACHE_HEADER_SIZE, keyArray, keys, obj); + JSObject::SetEnumCacheKind(thread, *keyArray, EnumCacheKind::ONLY_OWN_KEYS); + jsHclass->SetEnumCache(thread, keyArray.GetTaggedValue()); + JSHandle newkeyArray = factory->CopyFromEnumCache(keyArray); + return newkeyArray; } - return keyArray; + return factory->EmptyArray(); } JSHandle keyArray = factory->NewTaggedArray(numOfKeys); NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject()); - dict->GetAllEnumKeys(thread, offset, *keyArray, keys); + dict->GetAllEnumKeys(thread, 0, keyArray, keys); return keyArray; } -void JSObject::GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, - const JSHandle &keyArray) +uint32_t JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle &obj, int offset, + const JSHandle &keyArray) { TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject()); uint32_t keys = 0; @@ -435,18 +431,19 @@ void JSObject::GetAllEnumKeys(const JSThread *thread, const JSHandle & int end = static_cast(jsHclass->NumberOfProps()); if (end > 0) { LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject()) - ->GetAllEnumKeys(thread, end, offset, *keyArray, &keys, obj); + ->GetAllEnumKeys(thread, end, offset, keyArray, &keys, obj); } - return; + return keys; } if (obj->IsJSGlobalObject()) { GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject()); dict->GetEnumAllKeys(thread, offset, *keyArray, &keys); - return; + return keys; } NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject()); - dict->GetAllEnumKeys(thread, offset, *keyArray, &keys); + dict->GetAllEnumKeys(thread, offset, keyArray, &keys); + return keys; } void JSObject::GetAllElementKeys(JSThread *thread, const JSHandle &obj, int offset, @@ -537,34 +534,49 @@ JSHandle JSObject::GetEnumElementKeys(JSThread *thread, const JSHan { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle elementArray = factory->NewTaggedArray(numOfElements); - uint32_t elementIndex = 0; + CollectEnumElementsAlongProtoChain(thread, obj, offset, elementArray, keys); + return elementArray; +} + +void JSObject::CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle &obj, int offset, + JSHandle elementArray, uint32_t *keys, + int32_t lastLength) +{ + uint32_t elementIndex = static_cast(offset); JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) { - elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength(); - *keys += elementIndex; - elementIndex += static_cast(offset); - for (uint32_t i = static_cast(offset); i < elementIndex; ++i) { + uint32_t strLen = JSPrimitiveRef::Cast(*obj)->GetStringLength(); + for (uint32_t i = 0; i < strLen; ++i) { keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i)); - elementArray->Set(thread, i, keyHandle); + elementArray->Set(thread, elementIndex, keyHandle); + elementIndex++; } + *keys += strLen; } JSHandle arr(thread, obj->GetElements()); if (!arr->IsDictionaryMode()) { + JSHandle emptyQueue = thread->GetEcmaVM()->GetFactory()->GetEmptyTaggedQueue(); uint32_t elementsLen = arr->GetLength(); uint32_t preElementIndex = elementIndex; for (uint32_t i = 0; i < elementsLen; ++i) { - if (!arr->Get(i).IsHole()) { - keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i)); - elementArray->Set(thread, elementIndex++, keyHandle); + if (arr->Get(i).IsHole()) { + continue; } + keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i)); + bool isDuplicated = IsDepulicateKeys(thread, elementArray, lastLength, emptyQueue, keyHandle); + if (isDuplicated) { + continue; + } + elementArray->Set(thread, elementIndex, keyHandle); + elementIndex++; } *keys += (elementIndex - preElementIndex); } else { - NumberDictionary::GetAllEnumKeys(thread, JSHandle(arr), elementIndex, elementArray, keys); + NumberDictionary::GetAllEnumKeys( + thread, JSHandle(arr), elementIndex, elementArray, keys, lastLength); } - return elementArray; } void JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle &obj, int offset, @@ -594,6 +606,27 @@ void JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle &ob } } +std::pair JSObject::GetNumberOfEnumKeys() const +{ + DISALLOW_GARBAGE_COLLECTION; + TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject()); + if (!array->IsDictionaryMode()) { + int end = static_cast(GetJSHClass()->NumberOfProps()); + if (end > 0) { + LayoutInfo *layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject()); + return layout->GetNumOfEnumKeys(end, this); + } + return std::make_pair(0, 0); + } + if (IsJSGlobalObject()) { + GlobalDictionary *dict = GlobalDictionary::Cast(array); + return dict->GetNumOfEnumKeys(); + } + + NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject()); + return dict->GetNumOfEnumKeys(); +} + uint32_t JSObject::GetNumberOfKeys() { DISALLOW_GARBAGE_COLLECTION; @@ -1337,6 +1370,38 @@ JSHandle JSObject::GetAllPropertyKeys(JSThread *thread, const JSHan return retArray; } +void JSObject::CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle &obj, + JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue, int32_t lastLength) +{ + ASSERT(!obj->IsJSGlobalObject()); + + TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject()); + if (!array->IsDictionaryMode()) { + JSHClass *jsHclass = obj->GetJSHClass(); + int end = static_cast(jsHclass->NumberOfProps()); + if (end > 0) { + LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject()) + ->GetAllEnumKeys(thread, end, *keys, keyArray, keys, shadowQueue, obj, lastLength); + } + return; + } + NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject()); + dict->GetAllEnumKeys(thread, *keys, keyArray, keys, shadowQueue, lastLength); +} + +void JSObject::AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle &obj, + JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue) +{ + int32_t lastLength = *keys; + uint32_t numOfElements = obj->GetNumberOfElements(); + if (numOfElements > 0) { + CollectEnumElementsAlongProtoChain(thread, obj, *keys, keyArray, keys, lastLength); + } + CollectEnumKeysAlongProtoChain(thread, obj, keyArray, keys, shadowQueue, lastLength); +} + JSHandle JSObject::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle &obj) { uint32_t numOfElements = obj->GetNumberOfElements(); @@ -2059,13 +2124,95 @@ void PropertyDescriptor::CompletePropertyDescriptor(const JSThread *thread, Prop } } +// static +// When receiver has no elements and there is no enum cache and elements on receiver's prototype chain, +// the enum cache is a simple enum cache. +// When receiver and receiver's prototype chain have no elements, and the prototype is not modified, +// the enum cache is a enum cache with protochain +bool JSObject::IsSimpleEnumCacheValid(JSTaggedValue receiver) +{ + DISALLOW_GARBAGE_COLLECTION; + uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements(); + if (numOfElements > 0) { + return false; + } + + JSTaggedValue current = JSObject::GetPrototype(receiver); + while (current.IsHeapObject()) { + JSObject *currentObj = JSObject::Cast(current.GetTaggedObject()); + uint32_t numOfCurrentElements = currentObj->GetNumberOfElements(); + if (numOfCurrentElements > 0) { + return false; + } + JSHClass *hclass = currentObj->GetJSHClass(); + JSTaggedValue protoEnumCache = hclass->GetEnumCache(); + if (!protoEnumCache.IsUndefined()) { + return false; + } + current = JSObject::GetPrototype(current); + } + return true; +} + +bool JSObject::IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver) +{ + DISALLOW_GARBAGE_COLLECTION; + // check elements of receiver + uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements(); + if (numOfElements > 0) { + return false; + } + // check protochain keys + JSTaggedValue proto = JSObject::GetPrototype(receiver); + if (!proto.IsECMAObject()) { + return false; + } + JSTaggedValue protoChangeMarker = proto.GetTaggedObject()->GetClass()->GetProtoChangeMarker(); + if (!protoChangeMarker.IsProtoChangeMarker()) { + return false; + } + if (ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject())->GetHasChanged()) { + return false; + } + // check protochain elements + JSTaggedValue current = proto; + while (current.IsHeapObject()) { + JSObject *currentObj = JSObject::Cast(current.GetTaggedObject()); + uint32_t numOfCurrentElements = currentObj->GetNumberOfElements(); + if (numOfCurrentElements > 0) { + return false; + } + current = JSObject::GetPrototype(current); + } + return true; +} + +JSTaggedValue JSObject::TryGetEnumCache(JSThread *thread, JSTaggedValue obj) +{ + if (obj.IsSlowKeysObject() || obj.GetTaggedObject()->GetClass()->IsDictionaryMode()) { + return JSTaggedValue::Undefined(); + } + JSTaggedValue enumCache = obj.GetTaggedObject()->GetClass()->GetEnumCache(); + EnumCacheKind kind = JSObject::GetEnumCacheKind(thread, enumCache); + bool isEnumCacheValid = false; + switch (kind) { + case EnumCacheKind::SIMPLE: + isEnumCacheValid = IsSimpleEnumCacheValid(obj); + break; + case EnumCacheKind::PROTOCHAIN: + isEnumCacheValid = IsEnumCacheWithProtoChainInfoValid(obj); + default: + break; + } + if (!isEnumCacheValid) { + return JSTaggedValue::Undefined(); + } + return enumCache; +} + // 13.7.5.15 EnumerateObjectProperties ( O ) JSHandle JSObject::EnumerateObjectProperties(JSThread *thread, const JSHandle &obj) { - // 1. Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of - // enumerable properties of O. The Iterator object must inherit from %IteratorPrototype% (25.1.2). The - // mechanics and order of enumerating the properties is not specified but must conform to the rules specified - // below. JSHandle object; if (obj->IsString()) { JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); @@ -2074,7 +2221,37 @@ JSHandle JSObject::EnumerateObjectProperties(JSThread *thread, object = JSTaggedValue::ToPrototypeOrObj(thread, obj); } - return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object); + JSMutableHandle keys(thread, JSTaggedValue::Undefined()); + JSMutableHandle cachedHclass(thread, JSTaggedValue::Undefined()); + if (object->IsNull() || object->IsUndefined()) { + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + keys.Update(factory->EmptyArray()); + return factory->NewJSForinIterator(undefined, keys, cachedHclass); + } + keys.Update(TryGetEnumCache(thread, object.GetTaggedValue())); + if (!keys->IsUndefined()) { + cachedHclass.Update(JSTaggedValue(JSHandle::Cast(object)->GetJSHClass())); + return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass); + } + return LoadEnumerateProperties(thread, object); +} + +JSHandle JSObject::LoadEnumerateProperties(JSThread *thread, const JSHandle &object) +{ + PropertyAccessor accessor(thread, object); + JSHandle fastKeys = accessor.GetKeysFast(); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread); + JSMutableHandle keys(thread, JSTaggedValue::Undefined()); + JSMutableHandle cachedHclass(thread, JSTaggedValue::Undefined()); + if (fastKeys->IsUndefined()) { + keys.Update(accessor.GetKeysSlow()); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread); + } else { + keys.Update(fastKeys); + cachedHclass.Update(accessor.GetCachedHclass()); + } + return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass); } void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle &obj, diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index bd8c15bfbd..e5ac739148 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -40,6 +40,9 @@ class JSArray; class JSForInIterator; class LexicalEnv; class GlobalEnv; +class TaggedQueue; + +using EnumCacheKind = EnumCache::EnumCacheKind; // Integrity level for objects enum IntegrityLevel { SEALED, FROZEN }; @@ -424,6 +427,8 @@ public: // [[GetPrototypeOf]] static JSTaggedValue GetPrototype(const JSHandle &obj); + static JSTaggedValue GetPrototype(JSTaggedValue obj); + // [[SetPrototypeOf]] static bool SetPrototype(JSThread *thread, const JSHandle &obj, const JSHandle &proto); @@ -503,6 +508,14 @@ public: static JSHandle GetAllPropertyKeys(JSThread *thread, const JSHandle &obj, uint32_t filter); + static void CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle &obj, + JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue, int32_t lastLength = -1); + + static void AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle &obj, + JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue); + static JSHandle GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle &obj); // 9.1.13 ObjectCreate @@ -512,8 +525,11 @@ public: static bool InstanceOf(JSThread *thread, const JSHandle &object, const JSHandle &target); + static JSTaggedValue TryGetEnumCache(JSThread *thread, JSTaggedValue obj); + // 13.7.5.15 EnumerateObjectProperties ( O ); same as [[Enumerate]] static JSHandle EnumerateObjectProperties(JSThread *thread, const JSHandle &obj); + static JSHandle LoadEnumerateProperties(JSThread *thread, const JSHandle &object); static bool IsRegExp(JSThread *thread, const JSHandle &argument); @@ -588,17 +604,21 @@ public: static void GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle &obj, std::vector &keyVector); + std::pair GetNumberOfEnumKeys() const; uint32_t GetNumberOfKeys(); uint32_t GetNumberOfElements(); static JSHandle GetEnumElementKeys(JSThread *thread, const JSHandle &obj, int offset, uint32_t numOfElements, uint32_t *keys); + static void CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle &obj, int offset, + JSHandle elementArray, uint32_t *keys, + int32_t lastLength = -1); static void GetEnumElementKeys(JSThread *thread, const JSHandle &obj, int offset, const JSHandle &keyArray); - static JSHandle GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, + static JSHandle GetAllEnumKeys(JSThread *thread, const JSHandle &obj, uint32_t numOfKeys, uint32_t *keys); - static void GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, - const JSHandle &keyArray); + static uint32_t GetAllEnumKeys(JSThread *thread, const JSHandle &obj, int offset, + const JSHandle &keyArray); static void AddAccessor(JSThread *thread, const JSHandle &obj, const JSHandle &key, const JSHandle &value, PropertyAttributes attr); @@ -637,6 +657,15 @@ public: static JSHandle GrowElementsCapacity(const JSThread *thread, const JSHandle &obj, uint32_t capacity, bool highGrowth = false, bool isNew = false); + static bool IsDepulicateKeys(JSThread *thread, JSHandle keys, int32_t lastLength, + JSHandle shadowQueue, JSHandle key); + + static void SetEnumCacheKind(JSThread *thread, TaggedArray *array, EnumCacheKind kind); + static EnumCacheKind GetEnumCacheKind(JSThread *thread, TaggedArray *array); + static EnumCacheKind GetEnumCacheKind(JSThread *thread, JSTaggedValue enumCache); + + static void ClearHasDeleteProperty(JSHandle object); + static JSHandle IterableToList(JSThread *thread, const JSHandle &items, JSTaggedValue method = JSTaggedValue::Undefined()); @@ -674,6 +703,8 @@ private: static uint32_t SetValuesOrEntries(JSThread *thread, const JSHandle &prop, uint32_t index, const JSHandle &key, const JSHandle &value, PropertyKind kind); + static bool IsSimpleEnumCacheValid(JSTaggedValue receiver); + static bool IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver); }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index b0321816fe..c7b392acb8 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -1294,6 +1294,16 @@ inline bool JSTaggedValue::IsJSGlobalObject() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSGlobalObject(); } +inline bool JSTaggedValue::IsSpecialKeysObject() const +{ + return IsTypedArray() || IsModuleNamespace() || IsSpecialContainer(); +} + +inline bool JSTaggedValue::IsSlowKeysObject() const +{ + return IsJSGlobalObject() || IsJSProxy() || IsSpecialKeysObject(); +} + inline bool JSTaggedValue::IsMachineCodeObject() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsMachineCodeObject(); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index 62668ddd5e..b6551d4602 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -676,6 +676,8 @@ public: bool IsProtoChangeDetails() const; bool IsMarkerCell() const; bool IsTrackInfoObject() const; + bool IsSpecialKeysObject() const; + bool IsSlowKeysObject() const; bool IsMachineCodeObject() const; bool IsClassInfoExtractor() const; bool IsTSType() const; diff --git a/ecmascript/layout_info.cpp b/ecmascript/layout_info.cpp index 6d4664ac28..ebcab486db 100644 --- a/ecmascript/layout_info.cpp +++ b/ecmascript/layout_info.cpp @@ -69,7 +69,7 @@ void LayoutInfo::GetAllKeys(const JSThread *thread, int end, int offset, TaggedA for (int i = 0; i < end; i++) { JSTaggedValue key = GetKey(i); if (key.IsString()) { - if (IsUninitializedProperty(object, i)) { + if (IsUninitializedProperty(*object, i)) { continue; } keyArray->Set(thread, enumKeys + offset, key); @@ -99,7 +99,7 @@ void LayoutInfo::GetAllKeysByFilter(const JSThread *thread, uint32_t numberOfPro for (uint32_t i = 0; i < numberOfProps; i++) { JSTaggedValue key = GetKey(static_cast(i)); if (key.IsString() && !(filter & NATIVE_KEY_SKIP_STRINGS)) { - if (IsUninitializedProperty(object, i)) { + if (IsUninitializedProperty(*object, i)) { continue; } PropertyAttributes attr = GetAttr(static_cast(i)); @@ -140,29 +140,81 @@ void LayoutInfo::GetAllKeysForSerialization(int end, std::vector } } -void LayoutInfo::GetAllEnumKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray, +std::pair LayoutInfo::GetNumOfEnumKeys(int end, const JSObject *object) const +{ + ASSERT(end <= NumberOfElements()); + uint32_t enumKeys = 0; + uint32_t shadowKeys = 0; + for (int i = 0; i < end; i++) { + JSTaggedValue key = GetKey(i); + if (!key.IsString()) { + continue; + } + if (IsUninitializedProperty(object, i)) { + continue; + } + if (GetAttr(i).IsEnumerable()) { + enumKeys++; + } else { + shadowKeys++; + } + } + return std::make_pair(enumKeys, shadowKeys); +} + +void LayoutInfo::GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle keyArray, + uint32_t *keys, JSHandle shadowQueue, const JSHandle object, + int32_t lastLength) +{ + ASSERT(end <= NumberOfElements()); + ASSERT_PRINT(offset <= static_cast(keyArray->GetLength()), + "keyArray capacity is not enough for dictionary"); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + int enumKeys = 0; + for (int i = 0; i < end; i++) { + keyHandle.Update(GetKey(i)); + if (!keyHandle->IsString()) { + continue; + } + if (IsUninitializedProperty(*object, i)) { + continue; + } + if (GetAttr(i).IsEnumerable()) { + bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, shadowQueue, keyHandle); + if (isDuplicated) { + continue; + } + keyArray->Set(thread, enumKeys + offset, keyHandle); + enumKeys++; + } else { + TaggedQueue::PushFixedQueue(thread, shadowQueue, keyHandle); + } + } + *keys += enumKeys; +} + +void LayoutInfo::GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle keyArray, uint32_t *keys, const JSHandle object) { ASSERT(end <= NumberOfElements()); - ASSERT_PRINT(offset + end <= static_cast(keyArray->GetLength()), + ASSERT_PRINT(offset <= static_cast(keyArray->GetLength()), "keyArray capacity is not enough for dictionary"); - - DISALLOW_GARBAGE_COLLECTION; + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); int enumKeys = 0; for (int i = 0; i < end; i++) { - JSTaggedValue key = GetKey(i); - if (key.IsString() && GetAttr(i).IsEnumerable()) { - if (IsUninitializedProperty(object, i)) { + keyHandle.Update(GetKey(i)); + if (keyHandle->IsString() && GetAttr(i).IsEnumerable()) { + if (IsUninitializedProperty(*object, i)) { continue; } - keyArray->Set(thread, enumKeys + offset, key); + keyArray->Set(thread, enumKeys + offset, keyHandle); enumKeys++; } } *keys += enumKeys; } -bool LayoutInfo::IsUninitializedProperty(const JSHandle object, uint32_t index) +bool LayoutInfo::IsUninitializedProperty(const JSObject *object, uint32_t index) const { PropertyAttributes attr = GetAttr(index); if (!attr.IsInlinedProps()) { diff --git a/ecmascript/layout_info.h b/ecmascript/layout_info.h index 880ec19ff0..f43523f7d0 100644 --- a/ecmascript/layout_info.h +++ b/ecmascript/layout_info.h @@ -84,14 +84,17 @@ public: void GetAllKeysForSerialization(int end, std::vector &keyVector); void GetAllKeysByFilter(const JSThread *thread, uint32_t numberOfProps, uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, const JSHandle object, uint32_t filter); - void GetAllEnumKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray, uint32_t *keys, + std::pair GetNumOfEnumKeys(int end, const JSObject *object) const; + void GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue, const JSHandle object, + int32_t lastLength); + void GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle keyArray, uint32_t *keys, const JSHandle object); - void DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjKind kind); DECL_DUMP() private: - bool IsUninitializedProperty(const JSHandle object, uint32_t index); + bool IsUninitializedProperty(const JSObject *object, uint32_t index) const; }; } // namespace panda::ecmascript diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 6f3909aeba..692db8a001 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -655,16 +655,20 @@ JSHandle ObjectFactory::NewJSArray() return JSHandle(NewJSObjectByConstructor(function)); } -JSHandle ObjectFactory::NewJSForinIterator(const JSHandle &obj) +JSHandle ObjectFactory::NewJSForinIterator(const JSHandle &obj, + const JSHandle keys, + const JSHandle cachedHclass) { JSHandle env = vm_->GetGlobalEnv(); JSHandle hclass(env->GetForinIteratorClass()); JSHandle it = JSHandle::Cast(NewJSObject(hclass)); it->SetObject(thread_, obj); - it->SetVisitedObjs(thread_, thread_->GlobalConstants()->GetEmptyTaggedQueue()); - it->SetRemainingKeys(thread_, thread_->GlobalConstants()->GetEmptyTaggedQueue()); - it->ClearBitField(); + it->SetCachedHclass(thread_, cachedHclass); + it->SetKeys(thread_, keys); + it->SetIndex(EnumCache::ENUM_CACHE_HEADER_SIZE); + uint32_t enumLength = JSHandle::Cast(keys)->GetLength(); + it->SetLength(enumLength); return it; } @@ -2439,6 +2443,25 @@ JSHandle ObjectFactory::CopyArray(const JSHandle &old, return newArray; } +JSHandle ObjectFactory::CopyFromEnumCache(const JSHandle &old) +{ + NewObjectHook(); + uint32_t oldLength = old->GetLength(); + uint32_t newLength = oldLength - EnumCache::ENUM_CACHE_HEADER_SIZE; + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); + JSHandle newArray(thread_, header); + newArray->SetLength(newLength); + newArray->SetExtraLength(old->GetExtraLength()); + + for (uint32_t i = 0; i < newLength; i++) { + JSTaggedValue value = old->Get(i + EnumCache::ENUM_CACHE_HEADER_SIZE); + newArray->Set(thread_, i, value); + } + return newArray; +} + JSHandle ObjectFactory::CreateLayoutInfo(int properties, MemSpaceType type, GrowMode mode) { int growLength = diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 39e63adff9..c5e225bf7f 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -350,7 +350,9 @@ public: // Copy on write array is allocated in nonmovable space by default. JSHandle NewCOWTaggedArray(uint32_t length, JSTaggedValue initVal = JSTaggedValue::Hole()); JSHandle NewDictionaryArray(uint32_t length); - JSHandle NewJSForinIterator(const JSHandle &obj); + JSHandle NewJSForinIterator(const JSHandle &obj, + const JSHandle keys, + const JSHandle cachedHclass); JSHandle NewByteArray(uint32_t length, uint32_t size); @@ -370,6 +372,7 @@ public: JSHandle CopyArray(const JSHandle &old, uint32_t oldLength, uint32_t newLength, JSTaggedValue initVal = JSTaggedValue::Hole(), MemSpaceType type = MemSpaceType::SEMI_SPACE); + JSHandle CopyFromEnumCache(const JSHandle &old); JSHandle CloneProperties(const JSHandle &old); JSHandle CloneProperties(const JSHandle &old, const JSHandle &env, const JSHandle &obj); diff --git a/ecmascript/property_accessor.cpp b/ecmascript/property_accessor.cpp new file mode 100644 index 0000000000..6dca1f1fda --- /dev/null +++ b/ecmascript/property_accessor.cpp @@ -0,0 +1,313 @@ +/* + * 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/property_accessor.h" + +#include "ecmascript/js_object-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tagged_array-inl.h" + +namespace panda::ecmascript { +PropertyAccessor::PropertyAccessor(JSThread *thread, JSHandle object) + : thread_(thread), + receiver_(thread, object.GetTaggedValue()), + fastKeysArray_(thread, JSTaggedValue::Undefined()), + cachedHclass_(thread, JSTaggedValue::Undefined()), + keyLength_(0), + shadowKeyLength_(0), + onlyHasSimpleProperties_(true), + canUseEnumCache_(true), + hasSlowProperties_(false), + slowKeysArray_(thread, JSTaggedValue::Undefined()), + acutalKeyLength_(0) +{ + PreLoad(); +} + +void PropertyAccessor::PreLoad() +{ + if (receiver_->IsSlowKeysObject()) { + hasSlowProperties_ = true; + return; + } + JSHandle receiverObj(receiver_); + JSHClass *jshclass = receiverObj->GetJSHClass(); + if (jshclass->IsDictionaryMode()) { + onlyHasSimpleProperties_ = false; + canUseEnumCache_ = false; + } + uint32_t numOfElements = receiverObj->GetNumberOfElements(); + if (numOfElements > 0) { + AccumulateKeyLength(numOfElements); + onlyHasSimpleProperties_ = false; + canUseEnumCache_ = false; + } + std::pair numOfKeys = receiverObj->GetNumberOfEnumKeys(); + uint32_t numOfEnumKeys = numOfKeys.first; + if (numOfEnumKeys > 0) { + AccumulateKeyLength(numOfEnumKeys); + } + uint32_t numOfShadowKeys = numOfKeys.second; + if (numOfShadowKeys > 0) { + AccumulateShadowKeyLength(numOfShadowKeys); + } + + CollectPrototypeInfo(); + if (hasSlowProperties_ || !onlyHasSimpleProperties_) { + return; + } + ASSERT(canUseEnumCache_); + // fast path + InitSimplePropertiesEnumCache(); +} + +void PropertyAccessor::CollectPrototypeInfo() +{ + DISALLOW_GARBAGE_COLLECTION; + JSTaggedValue current = JSTaggedValue::GetPrototype(thread_, receiver_); + while (current.IsHeapObject()) { + if (current.IsSlowKeysObject()) { + hasSlowProperties_ = true; + break; + } + JSObject *currentObj = JSObject::Cast(current.GetTaggedObject()); + uint32_t numOfCurrentElements = currentObj->GetNumberOfElements(); + if (numOfCurrentElements > 0) { + AccumulateKeyLength(numOfCurrentElements); + onlyHasSimpleProperties_ = false; + canUseEnumCache_ = false; + } + std::pair numOfKeys = currentObj->GetNumberOfEnumKeys(); + uint32_t numOfEnumKeys = numOfKeys.first; + if (numOfEnumKeys > 0) { + AccumulateKeyLength(numOfEnumKeys); + onlyHasSimpleProperties_ = false; + } + uint32_t numOfShadowKeys = numOfKeys.second; + if (numOfShadowKeys > 0) { + AccumulateShadowKeyLength(numOfShadowKeys); + } + JSHClass *jshclass = currentObj->GetJSHClass(); + if (jshclass->IsDictionaryMode()) { + onlyHasSimpleProperties_ = false; + canUseEnumCache_ = false; + } + if (onlyHasSimpleProperties_) { + // a fast path to check simple enum cache + jshclass->SetEnumCache(thread_, JSTaggedValue::Undefined()); + } + current = JSObject::GetPrototype(current); + } +} + +void PropertyAccessor::InitSimplePropertiesEnumCache() +{ + ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory(); + JSHandle receiverObj(receiver_); + ASSERT(receiverObj->GetNumberOfElements() == 0); + + JSMutableHandle keyArray(thread_, JSTaggedValue::Undefined()); + if (keyLength_ == 0) { + keyArray.Update(factory->EmptyArray()); + SetActualKeyLength(0); + } else { + uint32_t arraySize = keyLength_ + EnumCache::ENUM_CACHE_HEADER_SIZE; + JSHandle newArray = thread_->GetEcmaVM()->GetFactory()->NewTaggedArray(arraySize); + uint32_t length = JSObject::GetAllEnumKeys(thread_, receiverObj, EnumCache::ENUM_CACHE_HEADER_SIZE, newArray); + SetActualKeyLength(length); + JSObject::SetEnumCacheKind(thread_, *newArray, EnumCacheKind::SIMPLE); + keyArray.Update(newArray); + } + JSObject::ClearHasDeleteProperty(receiver_); + JSHClass *jsHclass = receiverObj->GetJSHClass(); + jsHclass->SetEnumCache(thread_, keyArray.GetTaggedValue()); + fastKeysArray_.Update(keyArray.GetTaggedValue()); + cachedHclass_.Update(JSTaggedValue(jsHclass)); +} + +inline void PropertyAccessor::AccumulateKeyLength(uint32_t length) +{ + keyLength_ += length; +} + +inline void PropertyAccessor::AccumulateShadowKeyLength(uint32_t length) +{ + shadowKeyLength_ += length; +} + +JSHandle PropertyAccessor::GetCachedHclass() +{ + return cachedHclass_; +} + +uint32_t PropertyAccessor::GetActualKeyLength() const +{ + return acutalKeyLength_; +} + +inline void PropertyAccessor::SetActualKeyLength(uint32_t length) +{ + acutalKeyLength_ = length; +} + +void PropertyAccessor::AddKeysEndIfNeeded(JSHandle keys) +{ + // when has duplicated keys + if (acutalKeyLength_ < keyLength_) { + keys->Set(thread_, acutalKeyLength_ + EnumCache::ENUM_CACHE_HEADER_SIZE, JSTaggedValue::Undefined()); + } +} + +void PropertyAccessor::TryInitEnumCacheWithProtoChainInfo() +{ +#if ECMASCRIPT_ENABLE_IC + if (!canUseEnumCache_) { + JSObject::SetEnumCacheKind(thread_, TaggedArray::Cast(fastKeysArray_->GetTaggedObject()), EnumCacheKind::NONE); + return; + } + ASSERT(!onlyHasSimpleProperties_); + JSHandle receiverObj(receiver_); + JSHandle jsHclass(thread_, receiverObj->GetJSHClass()); + jsHclass->SetEnumCache(thread_, fastKeysArray_.GetTaggedValue()); + JSObject::SetEnumCacheKind( + thread_, TaggedArray::Cast(fastKeysArray_->GetTaggedObject()), EnumCacheKind::PROTOCHAIN); + cachedHclass_.Update(jsHclass); + JSHClass::EnableProtoChangeMarker(thread_, jsHclass); +#endif +} + +JSHandle PropertyAccessor::GetKeysFast() +{ + if (!fastKeysArray_->IsUndefined()) { + AddKeysEndIfNeeded(JSHandle(thread_, fastKeysArray_.GetTaggedValue())); + return fastKeysArray_; + } + if (hasSlowProperties_) { + return JSHandle(thread_, JSTaggedValue::Undefined()); + } + ASSERT(keyLength_ != 0); + ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory(); + uint32_t arraySize = keyLength_ + EnumCache::ENUM_CACHE_HEADER_SIZE; + JSHandle keyArray = factory->NewTaggedArray(arraySize); + JSHandle shadowQueue = factory->NewTaggedQueue(shadowKeyLength_); + uint32_t keysNum = EnumCache::ENUM_CACHE_HEADER_SIZE; + JSMutableHandle current(thread_, receiver_); + while (current->IsHeapObject()) { + JSObject::AppendOwnEnumPropertyKeys(thread_, JSHandle(current), keyArray, &keysNum, shadowQueue); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_); + JSObject::ClearHasDeleteProperty(current); + current.Update(JSObject::GetPrototype(current.GetTaggedValue())); + } + SetActualKeyLength(keysNum - EnumCache::ENUM_CACHE_HEADER_SIZE); + AddKeysEndIfNeeded(keyArray); + fastKeysArray_.Update(keyArray.GetTaggedValue()); + TryInitEnumCacheWithProtoChainInfo(); + return fastKeysArray_; +} + +JSHandle PropertyAccessor::GetKeysSlow() +{ + std::vector> remainings; + std::vector> visited; + JSMutableHandle current(thread_, receiver_); + while (current->IsHeapObject()) { + PushRemainingKeys(JSHandle(current), remainings); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_); + JSObject::ClearHasDeleteProperty(current); + visited.emplace_back(thread_, current.GetTaggedValue()); + current.Update(JSTaggedValue::GetPrototype(thread_, current)); + } + MergeRemainings(remainings, visited); + return JSHandle(thread_, slowKeysArray_.GetTaggedValue()); +} + +void PropertyAccessor::PushRemainingKeys(JSHandle object, std::vector> &remainings) +{ + JSMutableHandle value(thread_, JSTaggedValue::Undefined()); + uint32_t remainingIndex = 0; + if (object->IsJSProxy()) { + JSHandle proxyArr = JSProxy::OwnPropertyKeys(thread_, JSHandle(object)); + RETURN_IF_ABRUPT_COMPLETION(thread_); + uint32_t length = proxyArr->GetLength(); + for (uint32_t i = 0; i < length; i++) { + value.Update(proxyArr->Get(i)); + PropertyDescriptor desc(thread_); + JSProxy::GetOwnProperty(thread_, JSHandle(object), value, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + if (!desc.IsEnumerable()) { + proxyArr->Set(thread_, i, JSTaggedValue::Hole()); + } else { + remainingIndex++; + } + } + remainings.push_back(proxyArr); + AccumulateKeyLength(remainingIndex); + } else { + JSHandle array = JSTaggedValue::GetOwnEnumPropertyKeys(thread_, JSHandle(object)); + uint32_t length = array->GetLength(); + for (uint32_t i = 0; i < length; i++) { + value.Update(array->Get(i)); + if (!value->IsString()) { + array->Set(thread_, i, JSTaggedValue::Hole()); + } else { + remainingIndex++; + } + } + remainings.push_back(array); + AccumulateKeyLength(remainingIndex); + } +} + +void PropertyAccessor::MergeRemainings(const std::vector> &remainings, + const std::vector> &visited) +{ + uint32_t arraySize = keyLength_ + EnumCache::ENUM_CACHE_HEADER_SIZE; + JSHandle keyArray = thread_->GetEcmaVM()->GetFactory()->NewTaggedArray(arraySize); + + JSMutableHandle remaining(thread_, JSTaggedValue::Undefined()); + JSMutableHandle keyHandle(thread_, JSTaggedValue::Undefined()); + JSMutableHandle objHandle(thread_, JSTaggedValue::Undefined()); + uint32_t index = EnumCache::ENUM_CACHE_HEADER_SIZE; + uint32_t numberOfRemaining = remainings.size(); + for (uint32_t i = 0; i < numberOfRemaining; i++) { + remaining.Update(remainings[i]); + uint32_t remainingSize = remaining->GetLength(); + for (uint32_t j = 0; j < remainingSize; j++) { + keyHandle.Update(remaining->Get(thread_, j)); + if (keyHandle->IsHole()) { + continue; + } + bool has = false; + for (uint32_t k = 0; k < i; k++) { + objHandle.Update(visited[k]); + PropertyDescriptor desc(thread_); + has = JSTaggedValue::GetOwnProperty(thread_, objHandle, keyHandle, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + if (has) { + break; + } + } + if (!has) { + keyArray->Set(thread_, index, keyHandle); + index++; + } + } + } + SetActualKeyLength(index - EnumCache::ENUM_CACHE_HEADER_SIZE); + AddKeysEndIfNeeded(keyArray); + slowKeysArray_.Update(keyArray.GetTaggedValue()); + JSObject::SetEnumCacheKind(thread_, *keyArray, EnumCacheKind::NONE); +} +} // namespace panda::ecmascript diff --git a/ecmascript/property_accessor.h b/ecmascript/property_accessor.h new file mode 100644 index 0000000000..da118ea2fb --- /dev/null +++ b/ecmascript/property_accessor.h @@ -0,0 +1,63 @@ +/* + * 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_PROPERTY_ACCESSOR_H +#define ECMASCRIPT_PROPERTY_ACCESSOR_H + +#include "ecmascript/js_handle.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/js_thread.h" + +namespace panda::ecmascript { +class JSObject; +class TaggedArray; +class PropertyAccessor { +public: + PropertyAccessor(JSThread *thread, JSHandle object); + + JSHandle GetKeysFast(); + JSHandle GetKeysSlow(); + + JSHandle GetCachedHclass(); + uint32_t GetActualKeyLength() const; + +private: + void PreLoad(); + void CollectPrototypeInfo(); + void InitSimplePropertiesEnumCache(); + void AccumulateKeyLength(uint32_t length); + void AccumulateShadowKeyLength(uint32_t length); + void PushRemainingKeys(JSHandle object, std::vector> &remainings); + void MergeRemainings(const std::vector> &remainings, + const std::vector> &visited); + void SetActualKeyLength(uint32_t length); + void AddKeysEndIfNeeded(JSHandle keys); + void TryInitEnumCacheWithProtoChainInfo(); + + JSThread *thread_{nullptr}; + JSMutableHandle receiver_; + JSMutableHandle fastKeysArray_; + JSMutableHandle cachedHclass_; + uint32_t keyLength_ {0}; + uint32_t shadowKeyLength_ {0}; + // receiver has no elements, and is not dictionary mode and has empty prototype + bool onlyHasSimpleProperties_ {true}; + bool canUseEnumCache_ {true}; + bool hasSlowProperties_ {false}; + JSMutableHandle slowKeysArray_; + uint32_t acutalKeyLength_ {0}; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_PROPERTY_ACCESSOR_H diff --git a/ecmascript/runtime_call_id.h b/ecmascript/runtime_call_id.h index 8210a8fc93..0d7aa00a63 100644 --- a/ecmascript/runtime_call_id.h +++ b/ecmascript/runtime_call_id.h @@ -99,6 +99,8 @@ namespace panda::ecmascript { V(Ldlexvar) \ V(Ldlexenv) \ V(GetPropIterator) \ + V(GetPropIteratorSlowpath) \ + V(PrimitiveStringCreate) \ V(CreateIterResultObj) \ V(SuspendGenerator) \ V(ResumeGenerator) \ @@ -179,6 +181,7 @@ namespace panda::ecmascript { V(CreateRegExpWithLiteral) \ V(CreateArrayWithBuffer) \ V(GetNextPropName) \ + V(GetNextPropNameSlowpath) \ V(CopyDataProperties) \ V(GetUnmapedArgs) \ V(TryStGlobalByName) \ diff --git a/ecmascript/stubs/runtime_stubs-inl.h b/ecmascript/stubs/runtime_stubs-inl.h index 63ab45b931..89124d0b4b 100644 --- a/ecmascript/stubs/runtime_stubs-inl.h +++ b/ecmascript/stubs/runtime_stubs-inl.h @@ -203,10 +203,9 @@ JSTaggedValue RuntimeStubs::RuntimeGetTemplateObject(JSThread *thread, const JSH JSTaggedValue RuntimeStubs::RuntimeGetNextPropName(JSThread *thread, const JSHandle &iter) { ASSERT(iter->IsForinIterator()); - std::pair res = - JSForInIterator::NextInternal(thread, JSHandle::Cast(iter)); + JSTaggedValue res = JSForInIterator::NextInternal(thread, JSHandle::Cast(iter)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - return res.first; + return res; } JSTaggedValue RuntimeStubs::RuntimeIterNext(JSThread *thread, const JSHandle &iter) diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index e54af254d4..2f7ea0552e 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -42,6 +42,7 @@ #include "ecmascript/js_date.h" #include "ecmascript/js_function.h" #include "ecmascript/js_object.h" +#include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_proxy.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" @@ -633,6 +634,15 @@ DEF_RUNTIME_STUBS(GetNextPropName) return RuntimeGetNextPropName(thread, iter).GetRawData(); } +DEF_RUNTIME_STUBS(GetNextPropNameSlowpath) +{ + RUNTIME_STUBS_HEADER(GetNextPropNameSlowpath); + JSHandle iter = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + ASSERT(iter->IsForinIterator()); + JSTaggedValue res = JSForInIterator::NextInternalSlowpath(thread, JSHandle::Cast(iter)); + return res.GetRawData(); +} + DEF_RUNTIME_STUBS(IterNext) { RUNTIME_STUBS_HEADER(IterNext); @@ -1335,6 +1345,21 @@ DEF_RUNTIME_STUBS(GetPropIterator) return RuntimeGetPropIterator(thread, value).GetRawData(); } +DEF_RUNTIME_STUBS(GetPropIteratorSlowpath) +{ + RUNTIME_STUBS_HEADER(GetPropIteratorSlowpath); + JSHandle value = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + return JSObject::LoadEnumerateProperties(thread, value).GetTaggedValue().GetRawData(); +} + +DEF_RUNTIME_STUBS(PrimitiveStringCreate) +{ + RUNTIME_STUBS_HEADER(PrimitiveStringCreate); + JSHandle str = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSHandle newTarget = thread->GlobalConstants()->GetHandledUndefined(); + return JSPrimitiveRef::StringCreate(thread, str, newTarget).GetTaggedValue().GetRawData(); +} + DEF_RUNTIME_STUBS(AsyncFunctionEnter) { RUNTIME_STUBS_HEADER(AsyncFunctionEnter); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index d12dfe1df9..7d7b75db91 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -176,6 +176,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(ThrowConstAssignment) \ V(GetTemplateObject) \ V(GetNextPropName) \ + V(GetNextPropNameSlowpath) \ V(ThrowIfNotObject) \ V(IterNext) \ V(CloseIterator) \ @@ -221,6 +222,8 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(LdModuleVar) \ V(Throw) \ V(GetPropIterator) \ + V(GetPropIteratorSlowpath) \ + V(PrimitiveStringCreate) \ V(AsyncFunctionEnter) \ V(GetIterator) \ V(GetAsyncIterator) \ diff --git a/ecmascript/tagged_dictionary.cpp b/ecmascript/tagged_dictionary.cpp index 192dbd70c3..8fa00568a6 100644 --- a/ecmascript/tagged_dictionary.cpp +++ b/ecmascript/tagged_dictionary.cpp @@ -16,6 +16,7 @@ #include "ecmascript/tagged_dictionary.h" #include "ecmascript/ecma_string-inl.h" #include "ecmascript/filter_helper.h" +#include "ecmascript/js_object-inl.h" #include "ecmascript/tagged_hash_table.h" namespace panda::ecmascript { @@ -112,22 +113,71 @@ void NameDictionary::GetAllKeysByFilter(const JSThread *thread, uint32_t &keyArr } } -void NameDictionary::GetAllEnumKeys(const JSThread *thread, int offset, TaggedArray *keyArray, uint32_t *keys) const +std::pair NameDictionary::GetNumOfEnumKeys() const { - uint32_t arrayIndex = 0; - CVector> sortArr; + uint32_t enumKeys = 0; + uint32_t shadowKeys = 0; int size = Size(); for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key = GetKey(hashIndex); if (key.IsString()) { PropertyAttributes attr = GetAttributes(hashIndex); if (attr.IsEnumerable()) { - std::pair pair(key, attr); + enumKeys++; + } else { + shadowKeys++; + } + } + } + return std::make_pair(enumKeys, shadowKeys); +} + +void NameDictionary::GetAllEnumKeys(JSThread *thread, int offset, JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue, int32_t lastLength) const +{ + uint32_t arrayIndex = 0; + CVector, PropertyAttributes>> sortArr; + int size = Size(); + for (int hashIndex = 0; hashIndex < size; hashIndex++) { + JSHandle keyHandle(thread, GetKey(hashIndex)); + if (keyHandle->IsString()) { + PropertyAttributes attr = GetAttributes(hashIndex); + if (attr.IsEnumerable()) { + std::pair, PropertyAttributes> pair(keyHandle, attr); + bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, shadowQueue, keyHandle); + if (isDuplicated) { + continue; + } + sortArr.push_back(pair); + } else { + TaggedQueue::PushFixedQueue(thread, shadowQueue, keyHandle); + } + } + } + std::sort(sortArr.begin(), sortArr.end(), CompHandleKey); + for (auto entry : sortArr) { + keyArray->Set(thread, arrayIndex + static_cast(offset), entry.first); + arrayIndex++; + } + *keys += arrayIndex; +} + +void NameDictionary::GetAllEnumKeys(JSThread *thread, int offset, JSHandle keyArray, uint32_t *keys) const +{ + uint32_t arrayIndex = 0; + CVector, PropertyAttributes>> sortArr; + int size = Size(); + for (int hashIndex = 0; hashIndex < size; hashIndex++) { + JSHandle keyHandle(thread, GetKey(hashIndex)); + if (keyHandle->IsString()) { + PropertyAttributes attr = GetAttributes(hashIndex); + if (attr.IsEnumerable()) { + std::pair, PropertyAttributes> pair(keyHandle, attr); sortArr.push_back(pair); } } } - std::sort(sortArr.begin(), sortArr.end(), CompKey); + std::sort(sortArr.begin(), sortArr.end(), CompHandleKey); for (auto entry : sortArr) { keyArray->Set(thread, arrayIndex + static_cast(offset), entry.first); arrayIndex++; @@ -268,16 +318,15 @@ void NumberDictionary::GetAllKeysByFilter(const JSThread *thread, const JSHandle } } std::sort(sortArr.begin(), sortArr.end(), CompKey); + ASSERT_NO_ABRUPT_COMPLETION(thread); for (auto entry : sortArr) { - JSHandle keyHandle(thread, entry); - ASSERT_NO_ABRUPT_COMPLETION(thread); - keyArray->Set(thread, keyArrayEffectivelength, keyHandle.GetTaggedValue()); + keyArray->Set(thread, keyArrayEffectivelength, entry); keyArrayEffectivelength++; } } -void NumberDictionary::GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, - const JSHandle &keyArray, uint32_t *keys) +void NumberDictionary::GetAllEnumKeys(JSThread *thread, const JSHandle &obj, int offset, + const JSHandle &keyArray, uint32_t *keys, int32_t lastLength) { ASSERT_PRINT(offset + obj->EntriesCount() <= static_cast(keyArray->GetLength()), "keyArray capacity is not enough for dictionary"); @@ -294,10 +343,18 @@ void NumberDictionary::GetAllEnumKeys(const JSThread *thread, const JSHandleGetEcmaVM()->GetFactory(); + JSHandle emptyQueue = factory->GetEmptyTaggedQueue(); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); for (auto entry : sortArr) { - JSHandle keyHandle(thread, entry); + keyHandle.Update(entry); JSHandle str = JSTaggedValue::ToString(const_cast(thread), keyHandle); ASSERT_NO_ABRUPT_COMPLETION(thread); + bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, emptyQueue, + JSHandle(str)); + if (isDuplicated) { + continue; + } keyArray->Set(thread, arrayIndex + static_cast(offset), str.GetTaggedValue()); arrayIndex++; } diff --git a/ecmascript/tagged_dictionary.h b/ecmascript/tagged_dictionary.h index 3a00d1ed52..820151ef32 100644 --- a/ecmascript/tagged_dictionary.h +++ b/ecmascript/tagged_dictionary.h @@ -62,7 +62,15 @@ public: void GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const; void GetAllKeysByFilter(const JSThread *thread, uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, uint32_t filter) const; - void GetAllEnumKeys(const JSThread *thread, int offset, TaggedArray *keyArray, uint32_t *keys) const; + std::pair GetNumOfEnumKeys() const; + void GetAllEnumKeys(JSThread *thread, int offset, JSHandle keyArray, uint32_t *keys, + JSHandle shadowQueue, int32_t lastLength) const; + void GetAllEnumKeys(JSThread *thread, int offset, JSHandle keyArray, uint32_t *keys) const; + static inline bool CompHandleKey(const std::pair, PropertyAttributes> &a, + const std::pair, PropertyAttributes> &b) + { + return a.second.GetDictionaryOrder() < b.second.GetDictionaryOrder(); + } static inline bool CompKey(const std::pair &a, const std::pair &b) { @@ -114,8 +122,8 @@ public: const JSHandle &keyArray); static void GetAllKeysByFilter(const JSThread *thread, const JSHandle &obj, uint32_t &keyArrayEffectivelength, const JSHandle &keyArray, uint32_t filter); - static void GetAllEnumKeys(const JSThread *thread, const JSHandle &obj, int offset, - const JSHandle &keyArray, uint32_t *keys); + static void GetAllEnumKeys(JSThread *thread, const JSHandle &obj, int offset, + const JSHandle &keyArray, uint32_t *keys, int32_t lastLength = -1); static inline bool CompKey(const JSTaggedValue &a, const JSTaggedValue &b) { ASSERT(a.IsNumber() && b.IsNumber()); diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index 749dd815d1..7a26c45eea 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -629,7 +629,9 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) case JSType::JS_FORIN_ITERATOR: { CHECK_DUMP_FIELDS(JSObject::SIZE, JSForInIterator::SIZE, 4U); JSHandle array(thread, factory->NewJSArray().GetTaggedValue()); - JSHandle forInIter = factory->NewJSForinIterator(array); + JSHandle keys(thread, factory->EmptyArray().GetTaggedValue()); + JSHandle hclass(thread, JSTaggedValue::Undefined()); + JSHandle forInIter = factory->NewJSForinIterator(array, keys, hclass); DUMP_FOR_HANDLE(forInIter); break; } diff --git a/ecmascript/tests/js_forin_iterator_test.cpp b/ecmascript/tests/js_forin_iterator_test.cpp index 4ce9ac7721..59786f58ea 100644 --- a/ecmascript/tests/js_forin_iterator_test.cpp +++ b/ecmascript/tests/js_forin_iterator_test.cpp @@ -73,21 +73,17 @@ HWTEST_F_L0(JSForinIteratorTest, Create) JSObject::SetProperty(thread, JSHandle(son), key2, key1Value); JSObject::SetProperty(thread, JSHandle(son), key3, key1Value); - JSHandle it = thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(JSHandle(son)); - std::pair n1 = JSForInIterator::NextInternal(thread, it); - EXPECT_EQ(n1.first, key1.GetTaggedValue()); - EXPECT_FALSE(n1.second); + JSHandle it = JSObject::EnumerateObjectProperties(thread, JSHandle(son)); + JSTaggedValue n1 = JSForInIterator::NextInternal(thread, it); + EXPECT_EQ(n1, key1.GetTaggedValue()); - std::pair n2 = JSForInIterator::NextInternal(thread, it); - EXPECT_EQ(n2.first, key2.GetTaggedValue()); - EXPECT_FALSE(n2.second); + JSTaggedValue n2 = JSForInIterator::NextInternal(thread, it); + EXPECT_EQ(n2, key2.GetTaggedValue()); - std::pair n3 = JSForInIterator::NextInternal(thread, it); - EXPECT_EQ(n3.first, key3.GetTaggedValue()); - EXPECT_FALSE(n3.second); + JSTaggedValue n3 = JSForInIterator::NextInternal(thread, it); + EXPECT_EQ(n3, key3.GetTaggedValue()); - std::pair n4 = JSForInIterator::NextInternal(thread, it); - EXPECT_EQ(n4.first, JSTaggedValue::Undefined()); - EXPECT_TRUE(n4.second); + JSTaggedValue n4 = JSForInIterator::NextInternal(thread, it); + EXPECT_EQ(n4, JSTaggedValue::Undefined()); } } // namespace panda::test diff --git a/ecmascript/tests/layout_info_test.cpp b/ecmascript/tests/layout_info_test.cpp index d00436cbac..c1ee2e5754 100644 --- a/ecmascript/tests/layout_info_test.cpp +++ b/ecmascript/tests/layout_info_test.cpp @@ -189,7 +189,7 @@ HWTEST_F_L0(LayoutInfoTest, GetAllEnumKeys) layoutInfoHandle->AddKey(thread, i, elementsKey.GetTaggedValue(), defaultAttr); } uint32_t keys = 0; - layoutInfoHandle->GetAllEnumKeys(thread, infoLength, 0, *keyArray, &keys, objectHandle); // 0: offset + layoutInfoHandle->GetAllEnumKeys(thread, infoLength, 0, keyArray, &keys, objectHandle); // 0: offset EXPECT_EQ(keyArray->Get(0), key3.GetTaggedValue()); EXPECT_EQ(keys, 1U); } diff --git a/test/aottest/vtable/maintain_inherit_info/delete_property/expect_output.txt b/test/aottest/vtable/maintain_inherit_info/delete_property/expect_output.txt index bbe2accbe6..083d03c70c 100644 --- a/test/aottest/vtable/maintain_inherit_info/delete_property/expect_output.txt +++ b/test/aottest/vtable/maintain_inherit_info/delete_property/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -true +false 1 undefined undefined diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index c6f8043644..45e93bbb0f 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -54,6 +54,12 @@ group("ark_js_moduletest") { "flatten", "forawaitof", "forin", + "forin_delete_property", + "forin_dictionary_mode", + "forin_empty_prototype", + "forin_enum_cache", + "forin_non_empty_prototype", + "forin_special_object", "fortest", "funcprotochangeobjectandnew", "functionapply", @@ -180,6 +186,12 @@ group("ark_asm_test") { "errorcause", "flatten", "forin", + "forin_delete_property", + "forin_dictionary_mode", + "forin_empty_prototype", + "forin_enum_cache", + "forin_non_empty_prototype", + "forin_special_object", "fortest", "funcprotochangeobjectandnew", "functionapply", @@ -286,6 +298,12 @@ group("ark_asm_single_step_test") { "ecmastringtable", "errorcause", "forin", + "forin_delete_property", + "forin_dictionary_mode", + "forin_empty_prototype", + "forin_enum_cache", + "forin_non_empty_prototype", + "forin_special_object", "fortest", "funcprotochangeobjectandnew", "functionapply", diff --git a/test/moduletest/forin_delete_property/BUILD.gn b/test/moduletest/forin_delete_property/BUILD.gn new file mode 100644 index 0000000000..b672fef073 --- /dev/null +++ b/test/moduletest/forin_delete_property/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_delete_property") { + deps = [] +} diff --git a/test/moduletest/forin_delete_property/expect_output.txt b/test/moduletest/forin_delete_property/expect_output.txt new file mode 100644 index 0000000000..240c0a701b --- /dev/null +++ b/test/moduletest/forin_delete_property/expect_output.txt @@ -0,0 +1,23 @@ +# 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. + +a +b +=============== +a +b +1 +=============== +b +1 +a diff --git a/test/moduletest/forin_delete_property/forin_delete_property.js b/test/moduletest/forin_delete_property/forin_delete_property.js new file mode 100644 index 0000000000..90c4a803bf --- /dev/null +++ b/test/moduletest/forin_delete_property/forin_delete_property.js @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/* + * @tc.name:forin_delete_property + * @tc.desc:test forin_delete_property + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +// fast path +let fast = {"a":1} +fast.b = "a" +for (let i in fast) { + print(i) + delete fast.a +} +print("===============") +// slow path +let parent = { + "c": undefined, + "a": 1, + "b": undefined, + 1: 2 +} +let own = { + "a": 1, + "b": 1, +} +own.__proto__ = parent + +for (let i in own) { + delete own.a + print(i) + delete parent.c +} +print("===============") +for (let i in own) { + print(i) +} \ No newline at end of file diff --git a/test/moduletest/forin_dictionary_mode/BUILD.gn b/test/moduletest/forin_dictionary_mode/BUILD.gn new file mode 100644 index 0000000000..c43db27f1f --- /dev/null +++ b/test/moduletest/forin_dictionary_mode/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_dictionary_mode") { + deps = [] +} diff --git a/test/moduletest/forin_dictionary_mode/expect_output.txt b/test/moduletest/forin_dictionary_mode/expect_output.txt new file mode 100644 index 0000000000..f764a70be9 --- /dev/null +++ b/test/moduletest/forin_dictionary_mode/expect_output.txt @@ -0,0 +1,21 @@ +# 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. + +1 +c +b +============= +1 +a +c +b diff --git a/test/moduletest/forin_dictionary_mode/forin_dictionary_mode.js b/test/moduletest/forin_dictionary_mode/forin_dictionary_mode.js new file mode 100644 index 0000000000..feee993fcf --- /dev/null +++ b/test/moduletest/forin_dictionary_mode/forin_dictionary_mode.js @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* + * @tc.name:forin_dictionary_mode + * @tc.desc:test forin_dictionary_mode + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +let parent = { + "c": undefined, + "a": 1, + "b": undefined, + 1: 2 +} +delete parent.a + +let own = { + "a": 1, + "b": 1, + 1: 2, +} +delete own.b +own.__proto__ = parent + +for (let i in parent) { + print(i) +} +print("=============") +for (let i in own) { + print(i) +} diff --git a/test/moduletest/forin_empty_prototype/BUILD.gn b/test/moduletest/forin_empty_prototype/BUILD.gn new file mode 100644 index 0000000000..32843bf0ba --- /dev/null +++ b/test/moduletest/forin_empty_prototype/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_empty_prototype") { + deps = [] +} diff --git a/test/moduletest/forin_empty_prototype/expect_output.txt b/test/moduletest/forin_empty_prototype/expect_output.txt new file mode 100644 index 0000000000..a6a6595d34 --- /dev/null +++ b/test/moduletest/forin_empty_prototype/expect_output.txt @@ -0,0 +1,23 @@ +# 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. + +a +b +a +b +a +b +c +2 +4 +s diff --git a/test/moduletest/forin_empty_prototype/forin_empty_prototype.js b/test/moduletest/forin_empty_prototype/forin_empty_prototype.js new file mode 100644 index 0000000000..32d66def40 --- /dev/null +++ b/test/moduletest/forin_empty_prototype/forin_empty_prototype.js @@ -0,0 +1,47 @@ +/* + * 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. + */ + +/* + * @tc.name:forin_empty_prototype + * @tc.desc:test forin_empty_prototype + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +// no elements +let fast = {"a":1} +fast.b = "a" +for (let i in fast) { + print(i) +} + +// use enum cache +for (let i in fast) { + print(i) +} + +fast.c = 1 +// invalidate enum cache +for (let i in fast) { + print(i) +} + +// has elements +let slow = {"s":222} +slow[2] = "aa" +slow[4] = 1 +for (let i in slow) { + print(i) +} \ No newline at end of file diff --git a/test/moduletest/forin_enum_cache/BUILD.gn b/test/moduletest/forin_enum_cache/BUILD.gn new file mode 100644 index 0000000000..26356448e5 --- /dev/null +++ b/test/moduletest/forin_enum_cache/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_enum_cache") { + deps = [] +} diff --git a/test/moduletest/forin_enum_cache/expect_output.txt b/test/moduletest/forin_enum_cache/expect_output.txt new file mode 100644 index 0000000000..0e106d3a7f --- /dev/null +++ b/test/moduletest/forin_enum_cache/expect_output.txt @@ -0,0 +1,34 @@ +# 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. + +===generate enum cache=== +a +b +c +===use enum cache=== +a +b +c +===re-generate enum cache=== +a +b +c +e +===change attribute=== +a +b +c +===delete property=== +a +b +c diff --git a/test/moduletest/forin_enum_cache/forin_enum_cache.js b/test/moduletest/forin_enum_cache/forin_enum_cache.js new file mode 100644 index 0000000000..97c6383e01 --- /dev/null +++ b/test/moduletest/forin_enum_cache/forin_enum_cache.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. + */ + +/* + * @tc.name:forin_enum_cache + * @tc.desc:test forin_enum_cache + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +let grandparent = {} +let parent = { + "c": undefined, + "a": 1, + "b": undefined, +} +let own = { + "a": 1, + "b": 1, +} +own.__proto__ = parent +parent.__proto__ = grandparent + +// generate enum cache +print("===generate enum cache===") +for (let i in own) { + print(i) +} +// use enum cache +print("===use enum cache===") +for (let i in own) { + print(i) +} +// invalid enum cache and re-generate enum cache +print("===re-generate enum cache===") +grandparent['e'] = 1 +for (let i in own) { + print(i) +} +// change attribute +print("===change attribute===") +Object.defineProperty(grandparent, "e", { + configurable:true, + enumerable:false, + value:"ggg", + writable:true +}) +for (let i in own) { + print(i) +} +// delete property +print("===delete property===") +grandparent['f'] = 1 +for (let i in own) { + print(i) + delete grandparent['f'] +} \ No newline at end of file diff --git a/test/moduletest/forin_non_empty_prototype/BUILD.gn b/test/moduletest/forin_non_empty_prototype/BUILD.gn new file mode 100644 index 0000000000..7aa056e526 --- /dev/null +++ b/test/moduletest/forin_non_empty_prototype/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_non_empty_prototype") { + deps = [] +} diff --git a/test/moduletest/forin_non_empty_prototype/expect_output.txt b/test/moduletest/forin_non_empty_prototype/expect_output.txt new file mode 100644 index 0000000000..b9809497c3 --- /dev/null +++ b/test/moduletest/forin_non_empty_prototype/expect_output.txt @@ -0,0 +1,19 @@ +# 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. + +1 +a +b +c +2 +d diff --git a/test/moduletest/forin_non_empty_prototype/forin_non_empty_prototype.js b/test/moduletest/forin_non_empty_prototype/forin_non_empty_prototype.js new file mode 100644 index 0000000000..ea89637b99 --- /dev/null +++ b/test/moduletest/forin_non_empty_prototype/forin_non_empty_prototype.js @@ -0,0 +1,47 @@ +/* + * 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. + */ + +/* + * @tc.name:forin_non_empty_prototype + * @tc.desc:test forin_non_empty_prototype + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +let grandparent = { + "a": 1, + "d": undefined, + 1: 2, + 2: 3 +} + +let parent = { + "c": undefined, + "a": 1, + "b": undefined, + 1: 2 +} + +let own = { + "a": 1, + "b": 1, + 1: 2, +} +own.__proto__ = parent +parent.__proto__ = grandparent + +for (let i in own) { + print(i) +} diff --git a/test/moduletest/forin_special_object/BUILD.gn b/test/moduletest/forin_special_object/BUILD.gn new file mode 100644 index 0000000000..fd6ffc26a6 --- /dev/null +++ b/test/moduletest/forin_special_object/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("forin_special_object") { + deps = [] +} diff --git a/test/moduletest/forin_special_object/expect_output.txt b/test/moduletest/forin_special_object/expect_output.txt new file mode 100644 index 0000000000..fa54db0186 --- /dev/null +++ b/test/moduletest/forin_special_object/expect_output.txt @@ -0,0 +1,39 @@ +# 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. + +2 +8 +a +0 +1 +3 +4 +5 +6 +7 +9 +=============== +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +=============== +_secret +test +eyeCount diff --git a/test/moduletest/forin_special_object/forin_special_object.js b/test/moduletest/forin_special_object/forin_special_object.js new file mode 100644 index 0000000000..daaa57151f --- /dev/null +++ b/test/moduletest/forin_special_object/forin_special_object.js @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/* + * @tc.name:forin_specail_object + * @tc.desc:test forin_specail_object + * @tc.type: FUNC + * @tc.require: issueI84DMO + */ + +var arr = new Array(10) +for (let i = 0; i < 5; i++) { + arr[i] = i; +} +let parent = new Int8Array(arr); +let self = { + 2: "b", + "a": {}, + 8: [] +} +self.__proto__ = parent +for (let i in self) { + print(i) +} +print("===============") +for (let i in parent) { + print(i) +} +print("===============") +const targetObj = { + _secret: 'easily scared', + test: "ss", + eyeCount: 4 +}; + +const proxy_has = new Proxy(targetObj, { + has: (target, key) => { + return key in target; + } +}) + +for (const key in proxy_has) { + print(key); +} \ No newline at end of file diff --git a/test/moduletest/stubbuilder/stubbuilder.js b/test/moduletest/stubbuilder/stubbuilder.js index 0405a7b369..12e01acc94 100644 --- a/test/moduletest/stubbuilder/stubbuilder.js +++ b/test/moduletest/stubbuilder/stubbuilder.js @@ -293,7 +293,7 @@ } /* -* FastTypeOf(); GetGlobalConstantString(); TaggedIsTrue(); TaggedIsFalse(); TaggedIsNull(); IsString(); IsSymbol(); IsCallable(); +* FastTypeOf(); GetGlobalConstantOffset(); TaggedIsTrue(); TaggedIsFalse(); TaggedIsNull(); IsString(); IsSymbol(); IsCallable(); * TaggedObjectIsBigInt(); Int32Mul(); Int64Mul(); */ /**************HandleTypeofImm8****************/ From a1929cf2bc981784d324d73f9e1c409df68ba9be Mon Sep 17 00:00:00 2001 From: hzzhouzebin Date: Wed, 11 Oct 2023 08:14:10 +0800 Subject: [PATCH 17/50] Add white list for aot Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I86B1E Signed-off-by: hzzhouzebin Change-Id: I31f4ba80f8409412d0f310aa315a757e49bf224c --- BUILD.gn | 9 ++ bundle.json | 1 + ecmascript/compiler/aot_compiler.h | 2 +- ecmascript/ecma_vm.cpp | 9 -- ecmascript/ecma_vm.h | 10 --- ecmascript/napi/jsnapi.cpp | 8 +- ecmascript/napi/test/jsnapi_tests.cpp | 4 +- ecmascript/ohos/app_aot_white_list.conf | 2 + ecmascript/{compiler => ohos}/ohos_pkg_args.h | 4 +- ecmascript/ohos/white_list_helper.h | 87 +++++++++++++++++++ .../pgo_profiler/pgo_profiler_encoder.cpp | 22 ++++- .../pgo_profiler/pgo_profiler_encoder.h | 7 ++ .../pgo_profiler/pgo_profiler_manager.h | 22 +++++ 13 files changed, 159 insertions(+), 28 deletions(-) create mode 100644 ecmascript/ohos/app_aot_white_list.conf rename ecmascript/{compiler => ohos}/ohos_pkg_args.h (98%) create mode 100644 ecmascript/ohos/white_list_helper.h diff --git a/BUILD.gn b/BUILD.gn index cf3d38d741..e4919c41b0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1219,3 +1219,12 @@ ohos_shared_library("libark_jsruntime_test") { } subsystem_name = "test" } + +ohos_prebuilt_etc("app_aot_white_list") { + relative_install_dir = "ark" + source = "$js_root/ecmascript/ohos/app_aot_white_list.conf" + + # Set the subsystem name + part_name = "ets_runtime" + subsystem_name = "arkcompiler" +} diff --git a/bundle.json b/bundle.json index 135711abeb..c2ebe0ec29 100644 --- a/bundle.json +++ b/bundle.json @@ -38,6 +38,7 @@ }, "build": { "sub_component": [ + "//arkcompiler/ets_runtime:app_aot_white_list", "//arkcompiler/ets_runtime:ark_js_packages" ], "inner_kits": [ diff --git a/ecmascript/compiler/aot_compiler.h b/ecmascript/compiler/aot_compiler.h index f143030611..aade3e0fdb 100644 --- a/ecmascript/compiler/aot_compiler.h +++ b/ecmascript/compiler/aot_compiler.h @@ -15,7 +15,7 @@ #ifndef ECMASCRIPT_COMPILER_AOT_COMPILER_H #define ECMASCRIPT_COMPILER_AOT_COMPILER_H -#include "ecmascript/compiler/ohos_pkg_args.h" +#include "ecmascript/ohos/ohos_pkg_args.h" #include "ecmascript/compiler/pass_manager.h" #include "ecmascript/ecma_vm.h" diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 35eca1f39b..e49b921548 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -699,13 +699,4 @@ void EcmaVM::ResumeWorkerVm(uint32_t tid) } } } - -bool EcmaVM::RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode) const -{ - if (requestAotCallback_ == nullptr) { - LOG_ECMA(ERROR) << "Trigger aot failed. callback is null."; - return false; - } - return (requestAotCallback_(bundleName, moduleName, static_cast(triggerMode)) == 0); -} } // namespace panda::ecmascript diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index fd3e8cd3a5..52d7b4e2ac 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -272,13 +272,6 @@ public: return resolveBufferCallback_; } - bool RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode) const; - - void SetRequestAotCallback(const RequestAotCallback &cb) - { - requestAotCallback_ = cb; - } - void SetUnloadNativeModuleCallback(const UnloadNativeModuleCallback &cb) { unloadNativeModuleCallback_ = cb; @@ -530,9 +523,6 @@ private: // delete the native module and dlclose so from NativeModuleManager UnloadNativeModuleCallback unloadNativeModuleCallback_ {nullptr}; - // trigger local aot - RequestAotCallback requestAotCallback_ {nullptr}; - // Concurrent taskpool callback and data ConcurrentCallback concurrentCallback_ {nullptr}; void *concurrentData_ {nullptr}; diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 2fec514759..92f6d789de 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -654,6 +654,7 @@ void JSNApi::PostFork(EcmaVM *vm, const RuntimeOption &option) << ", aot: " << jsOption.GetEnableAOT() << ", bundle name: " << option.GetBundleName(); jsOption.SetEnablePGOProfiler(option.GetEnableProfile()); + ecmascript::pgo::PGOProfilerManager::GetInstance()->SetBundleName(option.GetBundleName()); vm->ResetPGOProfiler(); JSRuntimeOptions runtimeOptions; runtimeOptions.SetLogLevel(Log::LevelToString(Log::ConvertFromRuntime(option.GetLogLevel()))); @@ -855,11 +856,10 @@ void JSNApi::SetHostResolveBufferTracker(EcmaVM *vm, vm->SetResolveBufferCallback(cb); } -void JSNApi::SetRequestAotCallback(EcmaVM *vm, const std::function &cb) +void JSNApi::SetRequestAotCallback([[maybe_unused]] EcmaVM *vm, const std::function &cb) { - vm->SetRequestAotCallback(cb); + ecmascript::pgo::PGOProfilerManager::GetInstance()->SetRequestAotCallback(cb); } void JSNApi::SetUnloadNativeModuleCallback(EcmaVM *vm, const std::function &cb) diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index 8ab4f9a3ee..f3a4704b38 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -26,6 +26,7 @@ #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/napi/jsnapi_helper.h" #include "ecmascript/object_factory.h" +#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tests/test_helper.h" #include "ecmascript/js_generator_object.h" @@ -1531,7 +1532,8 @@ HWTEST_F_L0(JSNApiTests, AotTrigger) trigger = triggerMode; return 100; }); - ASSERT_FALSE(vm_->RequestAot("com.test.test", "requestAot", RequestAotMode::RE_COMPILE_ON_IDLE)); + ASSERT_FALSE(ecmascript::pgo::PGOProfilerManager::GetInstance()->RequestAot("com.test.test", "requestAot", + RequestAotMode::RE_COMPILE_ON_IDLE)); ASSERT_EQ(bundle, "com.test.test"); ASSERT_EQ(module, "requestAot"); ASSERT_EQ(trigger, 0); diff --git a/ecmascript/ohos/app_aot_white_list.conf b/ecmascript/ohos/app_aot_white_list.conf new file mode 100644 index 0000000000..67d8ffa717 --- /dev/null +++ b/ecmascript/ohos/app_aot_white_list.conf @@ -0,0 +1,2 @@ +# Apps in this configuration file can be compiled by aot compiler, white list can be written as below: +# {bundleName}:{moduleName} \ No newline at end of file diff --git a/ecmascript/compiler/ohos_pkg_args.h b/ecmascript/ohos/ohos_pkg_args.h similarity index 98% rename from ecmascript/compiler/ohos_pkg_args.h rename to ecmascript/ohos/ohos_pkg_args.h index aa118c0b7a..bae553a26e 100644 --- a/ecmascript/compiler/ohos_pkg_args.h +++ b/ecmascript/ohos/ohos_pkg_args.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_COMPILER_OHOS_PKG_ARGS_H -#define ECMASCRIPT_COMPILER_OHOS_PKG_ARGS_H +#ifndef ECMASCRIPT_OHOS_OHOS_PKG_ARGS_H +#define ECMASCRIPT_OHOS_OHOS_PKG_ARGS_H #include diff --git a/ecmascript/ohos/white_list_helper.h b/ecmascript/ohos/white_list_helper.h new file mode 100644 index 0000000000..17776cbeda --- /dev/null +++ b/ecmascript/ohos/white_list_helper.h @@ -0,0 +1,87 @@ +/* + * 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_OHOS_WHITE_LIST_HELPER_H +#define ECMASCRIPT_OHOS_WHITE_LIST_HELPER_H + +#include +#include +#include +#include + +#include "ecmascript/log_wrapper.h" +#include "macros.h" + +class WhiteListHelper { +public: + static std::shared_ptr GetInstance() + { + static auto helper = std::make_shared(); + return helper; + } + + WhiteListHelper() + { + ReadWhiteList(); + } + + ~WhiteListHelper() = default; + + bool IsEnable(const std::string &bundleName, const std::string &moduleName) + { + return whiteList_.find(bundleName + ":" + moduleName) != whiteList_.end(); + } + +private: + NO_COPY_SEMANTIC(WhiteListHelper); + NO_MOVE_SEMANTIC(WhiteListHelper); + static void Trim(std::string &data) + { + if (data.empty()) { + return; + } + data.erase(0, data.find_first_not_of(' ')); + data.erase(data.find_last_not_of(' ') + 1); + } + + void ReadWhiteList() + { + static const std::string WHITE_LIST_NAME = "/etc/ark/app_aot_white_list.conf"; + std::ifstream inputFile(WHITE_LIST_NAME); + + if (!inputFile.is_open()) { + LOG_ECMA(ERROR) << "bundle white list not exist!"; + return; + } + + std::string line; + while (getline(inputFile, line)) { + auto appName = line; + Trim(appName); + // skip empty line + if (appName.empty()) { + continue; + } + // skip comment line + if (appName.find_first_of('#') == 0) { + continue; + } + whiteList_.insert(appName); + } + } + std::set whiteList_; +}; + +#endif \ No newline at end of file diff --git a/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp b/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp index 59104289b0..40569f0a2f 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp @@ -20,10 +20,11 @@ #include #include "ecmascript/log_wrapper.h" +#include "ecmascript/ohos/white_list_helper.h" #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h" - +#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/pgo_profiler/pgo_utils.h" #include "ecmascript/platform/file.h" #include "os/mutex.h" @@ -172,9 +173,28 @@ bool PGOProfilerEncoder::SaveAndRename(const SaveTask *task) LOG_ECMA(ERROR) << "Rename " << tmpOutPath << " --> " << realOutPath_ << " failure!, errno: " << errno; return false; } + RequestAot(); return true; } +void PGOProfilerEncoder::RequestAot() +{ + if (bundleName_.empty() || moduleName_.empty()) { + return; + } + + if (!WhiteListHelper::GetInstance()->IsEnable(bundleName_, moduleName_)) { + LOG_ECMA(INFO) << "Request local aot failed. App Not in whitelist, bundle: " << bundleName_ + << ", module: " << moduleName_; + return; + } + + LOG_ECMA(INFO) << "Request local aot, bundle: " << bundleName_ << ", module: " << moduleName_; + if (!PGOProfilerManager::GetInstance()->RequestAot(bundleName_, moduleName_, RequestAotMode::RE_COMPILE_ON_IDLE)) { + LOG_ECMA(ERROR) << "Request aot failed, bundle: " << bundleName_ << ", module: " << moduleName_; + } +} + bool PGOProfilerEncoder::InternalSave(const SaveTask *task) { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfilerEncoder::InternalSave"); diff --git a/ecmascript/pgo_profiler/pgo_profiler_encoder.h b/ecmascript/pgo_profiler/pgo_profiler_encoder.h index b8b376c549..9a191913ae 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_encoder.h +++ b/ecmascript/pgo_profiler/pgo_profiler_encoder.h @@ -39,6 +39,11 @@ public: void PUBLIC_API Destroy(); + void SetBundleName(const std::string &bundleName) + { + bundleName_ = bundleName; + } + bool IsInitialized() const { return isInitialized_; @@ -68,6 +73,7 @@ private: void StartSaveTask(const SaveTask *task); bool InternalSave(const SaveTask *task = nullptr); bool SaveAndRename(const SaveTask *task = nullptr); + void RequestAot(); bool ResetOutPath(const std::string& profileFileName); bool isInitialized_ {false}; @@ -81,6 +87,7 @@ private: Mutex mutex_; RWLock rwLock_; std::string moduleName_; + std::string bundleName_; ApGenMode mode_ {OVERWRITE}; friend SaveTask; }; diff --git a/ecmascript/pgo_profiler/pgo_profiler_manager.h b/ecmascript/pgo_profiler/pgo_profiler_manager.h index 55845a0682..1b0a5679aa 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_manager.h +++ b/ecmascript/pgo_profiler/pgo_profiler_manager.h @@ -48,6 +48,27 @@ public: encoder_ = std::make_unique(outDir, hotnessThreshold, ApGenMode::OVERWRITE); } + void SetBundleName(const std::string &bundleName) + { + if (encoder_) { + encoder_->SetBundleName(bundleName); + } + } + + void SetRequestAotCallback(const RequestAotCallback &cb) + { + requestAotCallback_ = cb; + } + + bool RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode) const + { + if (requestAotCallback_ == nullptr) { + LOG_ECMA(ERROR) << "Trigger aot failed. callback is null."; + return false; + } + return (requestAotCallback_(bundleName, moduleName, static_cast(triggerMode)) == 0); + } + void Destroy() { if (encoder_) { @@ -188,6 +209,7 @@ private: } std::unique_ptr encoder_; + RequestAotCallback requestAotCallback_; std::atomic_bool enableSignalSaving_ { false }; }; } // namespace panda::ecmascript::pgo From 5fff3c13e74c9e66cbbb7eb1e5ee1f674031b6c3 Mon Sep 17 00:00:00 2001 From: Onlynagesha Date: Thu, 12 Oct 2023 09:21:54 +0800 Subject: [PATCH 18/50] Optimizes AOT ldobjbyname for Builtin.prototype in TypeScript Signed-off-by: Onlynagesha Change-Id: I4cc373e0569c646858f2a409bc3e47fd01dab91e --- ecmascript/base/builtins_base.h | 8 +- ecmascript/builtins/builtins.cpp | 83 +++++-- ecmascript/builtins/builtins.h | 12 +- ecmascript/builtins/builtins_array.h | 10 + ecmascript/builtins/builtins_dataview.h | 11 + ecmascript/builtins/builtins_date.h | 8 + .../builtins/builtins_lazy_callback.cpp | 25 +- ecmascript/builtins/builtins_map.h | 10 + ecmascript/builtins/builtins_set.h | 11 + ecmascript/builtins/builtins_string.h | 9 + ecmascript/builtins/builtins_typedarray.h | 11 + ecmascript/compiler/circuit_builder.h | 4 + ecmascript/compiler/early_elimination.cpp | 1 + ecmascript/compiler/gate_accessor.cpp | 7 + ecmascript/compiler/gate_accessor.h | 1 + ecmascript/compiler/hcr_circuit_builder.h | 17 ++ ecmascript/compiler/mcr_circuit_builder.cpp | 14 ++ ecmascript/compiler/mcr_opcodes.h | 33 +-- ecmascript/compiler/share_gate_meta_data.h | 88 ++++--- ecmascript/compiler/ts_hcr_lowering.cpp | 97 +++++--- ecmascript/compiler/ts_hcr_lowering.h | 3 +- ecmascript/compiler/type_mcr_lowering.cpp | 36 +++ ecmascript/compiler/type_mcr_lowering.h | 1 + ecmascript/enum_conversion.h | 54 +++++ ecmascript/global_env.h | 211 +---------------- ecmascript/global_env_fields.h | 218 ++++++++++++++++++ ecmascript/js_thread.cpp | 34 +++ ecmascript/js_thread.h | 163 +++---------- ecmascript/js_thread_hclass_entries.h | 84 +++++++ ecmascript/js_thread_stub_entries.h | 148 ++++++++++++ ecmascript/object_factory.cpp | 14 +- ecmascript/object_factory.h | 6 +- ecmascript/ts_types/builtin_type_id.h | 132 +++++++++++ ecmascript/ts_types/ts_manager.cpp | 4 +- ecmascript/ts_types/ts_manager.h | 85 +------ test/aottest/BUILD.gn | 1 + test/aottest/ldobjbyname_typed_path/BUILD.gn | 18 ++ .../ldobjbyname_typed_path/expect_output.txt | 60 +++++ .../ldobjbyname_typed_path.ts | 149 ++++++++++++ 39 files changed, 1350 insertions(+), 531 deletions(-) create mode 100644 ecmascript/enum_conversion.h create mode 100644 ecmascript/global_env_fields.h create mode 100644 ecmascript/js_thread_hclass_entries.h create mode 100644 ecmascript/js_thread_stub_entries.h create mode 100644 ecmascript/ts_types/builtin_type_id.h create mode 100644 test/aottest/ldobjbyname_typed_path/BUILD.gn create mode 100644 test/aottest/ldobjbyname_typed_path/expect_output.txt create mode 100644 test/aottest/ldobjbyname_typed_path/ldobjbyname_typed_path.ts diff --git a/ecmascript/base/builtins_base.h b/ecmascript/base/builtins_base.h index 46ec5305f0..baf84b1858 100644 --- a/ecmascript/base/builtins_base.h +++ b/ecmascript/base/builtins_base.h @@ -32,8 +32,8 @@ class JSArray; namespace base { class BuiltinConstantEntry { public: - constexpr BuiltinConstantEntry(std::string_view name, JSTaggedValue value) : - name_(name), rawTaggedValue_(value.GetRawData()) {} + constexpr BuiltinConstantEntry(std::string_view name, JSTaggedValue value) + : name_(name), rawTaggedValue_(value.GetRawData()) {} static constexpr BuiltinConstantEntry Create(std::string_view name, JSTaggedValue value) { @@ -116,8 +116,8 @@ private: EcmaEntrypoint entrypoint_; uint64_t bitfield_; - constexpr BuiltinFunctionEntry(std::string_view name, EcmaEntrypoint entrypoint, uint64_t bitfield) : - name_(name), entrypoint_(entrypoint), bitfield_(bitfield) {} + constexpr BuiltinFunctionEntry(std::string_view name, EcmaEntrypoint entrypoint, uint64_t bitfield) + : name_(name), entrypoint_(entrypoint), bitfield_(bitfield) {} }; class BuiltinsBase { diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index 99e8447fde..1c9013cb4e 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -292,23 +292,23 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool LazyInitializeDataView(env); LazyInitializeSharedArrayBuffer(env); } else { - InitializeDate(env, objFuncClass); - InitializeSet(env, objFuncClass); - InitializeMap(env, objFuncClass); + InitializeDate(env, objFuncPrototypeVal); + InitializeSet(env, objFuncPrototypeVal); + InitializeMap(env, objFuncPrototypeVal); InitializeWeakMap(env, objFuncClass); InitializeWeakSet(env, objFuncClass); InitializeWeakRef(env, objFuncClass); InitializeFinalizationRegistry(env, objFuncClass); - InitializeTypedArray(env, objFuncClass); + InitializeTypedArray(env, objFuncPrototypeVal); InitializeArrayBuffer(env, objFuncClass); - InitializeDataView(env, objFuncClass); + InitializeDataView(env, objFuncPrototypeVal); InitializeSharedArrayBuffer(env, objFuncClass); } InitializeNumber(env, globalObject, primRefObjHClass); InitializeObject(env, objFuncPrototype, objectFunction); InitializeBoolean(env, primRefObjHClass); InitializeRegExp(env); - InitializeString(env, primRefObjHClass); + InitializeString(env, objFuncPrototypeVal); JSHandle argumentsClass = factory_->CreateJSArguments(env); env->SetArgumentsClass(thread_, argumentsClass); @@ -837,11 +837,13 @@ void Builtins::InitializeBigInt(const JSHandle &env, const JSHandleSetBigIntFunction(thread_, bigIntFunction); } -void Builtins::InitializeDate(const JSHandle &env, const JSHandle &objFuncClass) const +void Builtins::InitializeDate(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); // Date.prototype - JSHandle dateFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass); + JSHandle dateFuncPrototypeHClass = factory_->NewEcmaHClass( + JSObject::SIZE, Date::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle dateFuncPrototype = factory_->NewJSObjectWithInit(dateFuncPrototypeHClass); JSHandle dateFuncPrototypeValue(dateFuncPrototype); // Date.prototype_or_hclass @@ -871,6 +873,10 @@ void Builtins::InitializeDate(const JSHandle &env, const JSHandleSetDateFunction(thread_, dateFunction); + env->SetDatePrototype(thread_, dateFuncPrototype); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::DATE, + dateFunction->GetJSHClass(), + dateFuncPrototype->GetJSHClass()); } void Builtins::LazyInitializeDate(const JSHandle &env) const @@ -1200,12 +1206,14 @@ void Builtins::InitializeCtor(const JSHandle &env, const JSHandle &env, const JSHandle &objFuncClass) const +void Builtins::InitializeSet(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); // Set.prototype - JSHandle setFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass); + JSHandle setFuncPrototypeHClass = factory_->NewEcmaHClass( + JSObject::SIZE, BuiltinsSet::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle setFuncPrototype = factory_->NewJSObjectWithInit(setFuncPrototypeHClass); JSHandle setFuncPrototypeValue(setFuncPrototype); // Set.prototype_or_hclass JSHandle setFuncInstanceHClass = @@ -1252,6 +1260,10 @@ void Builtins::InitializeSet(const JSHandle &env, const JSHandleSetBuiltinsSetFunction(thread_, setFunction); + env->SetSetPrototype(thread_, setFuncPrototype); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::SET, + setFunction->GetTaggedObject()->GetClass(), + setFuncPrototype->GetJSHClass()); } void Builtins::LazyInitializeSet(const JSHandle &env) @@ -1264,12 +1276,14 @@ void Builtins::LazyInitializeSet(const JSHandle &env) env->SetBuiltinsSetFunction(thread_, accessor); } -void Builtins::InitializeMap(const JSHandle &env, const JSHandle &objFuncClass) const +void Builtins::InitializeMap(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); // Map.prototype - JSHandle mapFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass); + JSHandle mapFuncPrototypeHClass = factory_->NewEcmaHClass( + JSObject::SIZE, BuiltinsMap::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle mapFuncPrototype = factory_->NewJSObjectWithInit(mapFuncPrototypeHClass); JSHandle mapFuncPrototypeValue(mapFuncPrototype); // Map.prototype_or_hclass JSHandle mapFuncInstanceHClass = @@ -1315,6 +1329,9 @@ void Builtins::InitializeMap(const JSHandle &env, const JSHandleSetBuiltinsMapFunction(thread_, mapFunction); env->SetMapPrototype(thread_, mapFuncPrototype); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::MAP, + mapFunction->GetTaggedObject()->GetClass(), + mapFuncPrototype->GetJSHClass()); } void Builtins::LazyInitializeMap(const JSHandle &env) const @@ -1564,11 +1581,14 @@ void Builtins::InitializeJson(const JSHandle &env, const JSHandleSetJsonFunction(thread_, jsonObject); } -void Builtins::InitializeString(const JSHandle &env, const JSHandle &primRefObjHClass) const +void Builtins::InitializeString(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); // String.prototype JSHandle toObject(factory_->GetEmptyString()); + JSHandle primRefObjHClass = + factory_->NewEcmaHClass(JSPrimitiveRef::SIZE, BuiltinsSet::GetNumPrototypeInlinedProperties(), + JSType::JS_PRIMITIVE_REF, objFuncPrototypeVal); JSHandle stringFuncPrototype = JSHandle::Cast(factory_->NewJSPrimitiveRef(primRefObjHClass, toObject)); JSHandle stringFuncPrototypeValue(stringFuncPrototype); @@ -1603,6 +1623,9 @@ void Builtins::InitializeString(const JSHandle &env, const JSHandleSetStringFunction(thread_, stringFunction); env->SetStringPrototype(thread_, stringFuncPrototype); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::STRING, + stringFunction->GetJSHClass(), + stringFuncPrototype->GetJSHClass()); } void Builtins::InitializeStringIterator(const JSHandle &env, @@ -1888,7 +1911,8 @@ void Builtins::InitializeArray(const JSHandle &env, const JSHandle arrBaseFuncInstanceHClass = factory_->CreateJSArrayInstanceClass(objFuncPrototypeVal); + JSHandle arrBaseFuncInstanceHClass = factory_->CreateJSArrayInstanceClass( + objFuncPrototypeVal, BuiltinsArray::GetNumPrototypeInlinedProperties()); // Array.prototype JSHandle arrFuncPrototype = factory_->NewJSObjectWithInit(arrBaseFuncInstanceHClass); @@ -1961,18 +1985,25 @@ void Builtins::InitializeArray(const JSHandle &env, const JSHandleSetArrayProtoValuesFunction(thread_, desc.GetValue()); env->SetArrayFunction(thread_, arrayFunction); env->SetArrayPrototype(thread_, arrFuncPrototype); + + thread_->SetInitialBuiltinHClass(BuiltinTypeId::ARRAY, + arrayFunction->GetJSHClass(), + arrFuncPrototype->GetJSHClass()); } -void Builtins::InitializeTypedArray(const JSHandle &env, const JSHandle &objFuncClass) const +void Builtins::InitializeTypedArray(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); // TypedArray.prototype - JSHandle typedArrFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass); + JSHandle typedArrFuncPrototypeHClass = factory_->NewEcmaHClass( + JSObject::SIZE, BuiltinsTypedArray::GetNumPrototypeInlinedProperties(), + JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle typedArrFuncPrototype = factory_->NewJSObjectWithInit(typedArrFuncPrototypeHClass); JSHandle typedArrFuncPrototypeValue(typedArrFuncPrototype); // TypedArray.prototype_or_hclass JSHandle typedArrFuncInstanceHClass = factory_->NewEcmaHClass( - panda::ecmascript::JSTypedArray::SIZE, JSType::JS_TYPED_ARRAY, typedArrFuncPrototypeValue); + JSTypedArray::SIZE, JSType::JS_TYPED_ARRAY, typedArrFuncPrototypeValue); // TypedArray = new Function() JSHandle typedArrayFunction(NewBuiltinConstructor( @@ -2032,6 +2063,9 @@ void Builtins::InitializeTypedArray(const JSHandle &env, const JSHand env->SetTypedArrayFunction(thread_, typedArrayFunction.GetTaggedValue()); env->SetTypedArrayPrototype(thread_, typedArrFuncPrototype); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPED_ARRAY, + typedArrayFunction->GetJSHClass(), + typedArrFuncPrototype->GetJSHClass()); JSHandle specificTypedArrayFuncClass = factory_->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, env->GetTypedArrayFunction()); @@ -2081,6 +2115,10 @@ void Builtins::Initialize##Type(const JSHandle &env, const JSHandle(arrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \ env->Set##Type##Function(thread_, arrayFunction); \ + /* Initializes HClass record of %TypedArray% */ \ + thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPE, \ + arrayFunction->GetJSHClass(), \ + arrFuncPrototype->GetJSHClass()); \ } BUILTIN_TYPED_ARRAY_TYPES(BUILTIN_TYPED_ARRAY_DEFINE_INITIALIZE) @@ -2336,11 +2374,13 @@ void Builtins::InitializePromiseJob(const JSHandle &env) env->SetDynamicImportJob(thread_, func); } -void Builtins::InitializeDataView(const JSHandle &env, const JSHandle &objFuncClass) const +void Builtins::InitializeDataView(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); // ArrayBuffer.prototype - JSHandle dataViewFuncPrototype = factory_->NewJSObjectWithInit(objFuncClass); + JSHandle dataViewFuncPrototypeHClass = factory_->NewEcmaHClass( + JSObject::SIZE, DataView::GetNumPrototypeInlinedProperties(), JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle dataViewFuncPrototype = factory_->NewJSObjectWithInit(dataViewFuncPrototypeHClass); JSHandle dataViewFuncPrototypeValue(dataViewFuncPrototype); // ArrayBuffer.prototype_or_hclass @@ -2376,7 +2416,12 @@ void Builtins::InitializeDataView(const JSHandle &env, const JSHandle // 24.2.4.21 DataView.prototype[ @@toStringTag ] SetStringTagSymbol(env, dataViewFuncPrototype, "DataView"); + env->SetDataViewFunction(thread_, dataViewFunction.GetTaggedValue()); + env->SetDataViewPrototype(thread_, dataViewFuncPrototype.GetTaggedValue()); + thread_->SetInitialBuiltinHClass(BuiltinTypeId::DATA_VIEW, + dataViewFunction->GetJSHClass(), + dataViewFuncPrototype->GetJSHClass()); } void Builtins::LazyInitializeDataView(const JSHandle &env) const diff --git a/ecmascript/builtins/builtins.h b/ecmascript/builtins/builtins.h index 9363139f1b..7bd6a286e8 100644 --- a/ecmascript/builtins/builtins.h +++ b/ecmascript/builtins/builtins.h @@ -89,7 +89,7 @@ private: void InitializeBigIntWithRealm(const JSHandle &realm) const; - void InitializeDate(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeDate(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeDate(const JSHandle &env) const; void InitializeBoolean(const JSHandle &env, const JSHandle &primRefObjClass) const; @@ -100,7 +100,7 @@ private: void InitializeArray(const JSHandle &env, const JSHandle &objFuncPrototypeVal) const; - void InitializeTypedArray(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeTypedArray(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeTypedArray(const JSHandle &env) const; void InitializeInt8Array(const JSHandle &env, const JSHandle &objFuncClass) const; @@ -174,10 +174,10 @@ private: void GeneralUpdateError(ErrorParameter *error, EcmaEntrypoint constructor, EcmaEntrypoint method, std::string_view name, JSType type) const; - void InitializeSet(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSet(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeSet(const JSHandle &env); - void InitializeMap(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeMap(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeMap(const JSHandle &env) const; void InitializeWeakMap(const JSHandle &env, const JSHandle &objFuncClass) const; @@ -199,7 +199,7 @@ private: void InitializeJson(const JSHandle &env, const JSHandle &objFuncPrototypeVal) const; - void InitializeString(const JSHandle &env, const JSHandle &primRefObjHClass) const; + void InitializeString(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void InitializeIterator(const JSHandle &env, const JSHandle &objFuncClass) const; @@ -224,7 +224,7 @@ private: void InitializeSharedArrayBuffer(const JSHandle &env, const JSHandle &objFuncClass) const; void LazyInitializeSharedArrayBuffer(const JSHandle &env) const; - void InitializeDataView(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeDataView(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeDataView(const JSHandle &env) const; void InitializeForPromiseFuncClass(const JSHandle &env); diff --git a/ecmascript/builtins/builtins_array.h b/ecmascript/builtins/builtins_array.h index 08a0a8c927..82fba75e48 100644 --- a/ecmascript/builtins/builtins_array.h +++ b/ecmascript/builtins/builtins_array.h @@ -221,6 +221,16 @@ public: return Span(ARRAY_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 More inlined entries in Array.prototype for the following functions/accessors: + // (1) 'length' accessor + // (2) Array.prototype.constructor, i.e. Array() + // (3) Array.prototype[@@iterator]() + // (4) Array.prototype[@@unscopables]() + return GetArrayPrototypeFunctions().Size() + 4; + } + private: #define BUILTIN_ARRAY_FUNCTION_ENTRY(name, method, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsArray::method, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/builtins/builtins_dataview.h b/ecmascript/builtins/builtins_dataview.h index e2eadc6563..f57d8609c2 100644 --- a/ecmascript/builtins/builtins_dataview.h +++ b/ecmascript/builtins/builtins_dataview.h @@ -112,6 +112,17 @@ public: return Span(DATA_VIEW_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 5 : 5 more inline properties in DataView.prototype: + // (1) DataView.prototype.constructor + // (2) DataView.prototype [ @@toStringTag ] + // (3) get buffer + // (4) get byteLength + // (5) get byteOffset + return GetDataViewPrototypeFunctions().Size() + 5; + } + private: #define BUILTIN_DATA_VIEW_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsDataView::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/builtins/builtins_date.h b/ecmascript/builtins/builtins_date.h index 8ff19aa112..4a2da82e40 100644 --- a/ecmascript/builtins/builtins_date.h +++ b/ecmascript/builtins/builtins_date.h @@ -282,6 +282,14 @@ public: return Span(DATE_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 2 : 2 more inline properties in Date.prototype: + // (1) Date.prototype.constructor + // (2) Date.prototype [ @@toPrimitive ] + return GetDatePrototypeFunctions().Size() + 2; + } + private: #define BUILTIN_DATE_FUNCTION_ENTRY(name, func, length, builtinId) \ base::BuiltinFunctionEntry::Create(name, BuiltinsDate::func, length, kungfu::BuiltinsStubCSigns::builtinId), diff --git a/ecmascript/builtins/builtins_lazy_callback.cpp b/ecmascript/builtins/builtins_lazy_callback.cpp index e6a543b628..3b89bcb8f3 100644 --- a/ecmascript/builtins/builtins_lazy_callback.cpp +++ b/ecmascript/builtins/builtins_lazy_callback.cpp @@ -29,9 +29,10 @@ JSTaggedValue BuiltinsLazyCallback::Date(JSThread *thread, const JSHandleGetFactory(); auto env = vm->GetGlobalEnv(); ResetLazyInternalAttr(thread, obj, "Date"); - JSHandle objFuncClass(env->GetObjectFunctionClass()); + + JSHandle objFuncPrototypeVal = env->GetObjectFunctionPrototype(); Builtins builtin(thread, factory, vm); - builtin.InitializeDate(env, objFuncClass); + builtin.InitializeDate(env, objFuncPrototypeVal); return env->GetDateFunction().GetTaggedValue(); } @@ -43,9 +44,10 @@ JSTaggedValue BuiltinsLazyCallback::Set(JSThread *thread, const JSHandleGetFactory(); auto env = vm->GetGlobalEnv(); ResetLazyInternalAttr(thread, obj, "Set"); + Builtins builtin(thread, factory, vm); - JSHandle objFuncClass(env->GetObjectFunctionClass()); - builtin.InitializeSet(env, objFuncClass); + JSHandle objFuncPrototypeVal = env->GetObjectFunctionPrototype(); + builtin.InitializeSet(env, objFuncPrototypeVal); return env->GetBuiltinsSetFunction().GetTaggedValue(); } @@ -57,9 +59,10 @@ JSTaggedValue BuiltinsLazyCallback::Map(JSThread *thread, const JSHandleGetFactory(); auto env = vm->GetGlobalEnv(); ResetLazyInternalAttr(thread, obj, "Map"); + Builtins builtin(thread, factory, vm); - JSHandle objFuncClass(env->GetObjectFunctionClass()); - builtin.InitializeMap(env, objFuncClass); + JSHandle objFuncPrototypeVal = env->GetObjectFunctionPrototype(); + builtin.InitializeMap(env, objFuncPrototypeVal); return env->GetBuiltinsMapFunction().GetTaggedValue(); } @@ -133,9 +136,10 @@ JSTaggedValue BuiltinsLazyCallback::TypedArray(JSThread *thread, const JSHandle< ITERATE_TYPED_ARRAY(RESET_TYPED_ARRAY_INTERNAL_ATTR) #undef RESET_TYPED_ARRAY_INTERNAL_ATTR + Builtins builtin(thread, factory, vm); - JSHandle objFuncClass(env->GetObjectFunctionClass()); - builtin.InitializeTypedArray(env, objFuncClass); + JSHandle objFuncPrototypeVal = env->GetObjectFunctionPrototype(); + builtin.InitializeTypedArray(env, objFuncPrototypeVal); return env->GetTypedArrayFunction().GetTaggedValue(); } @@ -175,9 +179,10 @@ JSTaggedValue BuiltinsLazyCallback::DataView(JSThread *thread, const JSHandleGetFactory(); auto env = vm->GetGlobalEnv(); ResetLazyInternalAttr(thread, obj, "DataView"); + Builtins builtin(thread, factory, vm); - JSHandle objFuncClass(env->GetObjectFunctionClass()); - builtin.InitializeDataView(env, objFuncClass); + JSHandle objFuncPrototypeVal = env->GetObjectFunctionPrototype(); + builtin.InitializeDataView(env, objFuncPrototypeVal); return env->GetDataViewFunction().GetTaggedValue(); } diff --git a/ecmascript/builtins/builtins_map.h b/ecmascript/builtins/builtins_map.h index 19ed6e823f..86bfcb8b94 100644 --- a/ecmascript/builtins/builtins_map.h +++ b/ecmascript/builtins/builtins_map.h @@ -82,6 +82,16 @@ public: return Span(MAP_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 more inline properties in Map.prototype + // (1) Map.prototype.constructor + // (2) Map.prototype [ @@toStringTag ] + // (3) Map.prototype [ @@iterator ] ( ) + // (4) get Map.prototype.size + return GetMapPrototypeFunctions().Size() + 4; + } + private: #define BUILTIN_MAP_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsMap::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/builtins/builtins_set.h b/ecmascript/builtins/builtins_set.h index 262116ac05..f3b0985dc5 100644 --- a/ecmascript/builtins/builtins_set.h +++ b/ecmascript/builtins/builtins_set.h @@ -71,6 +71,17 @@ public: return Span(SET_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 5 : 5 more inline properties in Set.prototype + // (1) Set.prototype.constructor + // (2) Set.prototype [ @@toStringTag ] + // (3) Set.prototype [ @@iterator ] + // (4) get Set.prototype.size + // (5) Set.prototype.keys, which is not included in BuiltinsSet::GetSetPrototypeFunctions() + return GetSetPrototypeFunctions().Size() + 5; + } + private: #define BUILTIN_SET_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsSet::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/builtins/builtins_string.h b/ecmascript/builtins/builtins_string.h index c2d05ec184..ac306f7af3 100644 --- a/ecmascript/builtins/builtins_string.h +++ b/ecmascript/builtins/builtins_string.h @@ -234,6 +234,15 @@ public: return Span(STRING_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 3 : 3 more inline properties in String.prototype: + // (1) String.prototype.constructor + // (2) String.prototype [ @@iterator ] + // (3) get length + return GetStringPrototypeFunctions().Size() + 3; + } + private: #define BUILTIN_STRING_FUNCTION_ENTRY(name, method, length, builtinId) \ base::BuiltinFunctionEntry::Create(name, BuiltinsString::method, length, kungfu::BuiltinsStubCSigns::builtinId), diff --git a/ecmascript/builtins/builtins_typedarray.h b/ecmascript/builtins/builtins_typedarray.h index ff92912c1c..a46c0a57d7 100644 --- a/ecmascript/builtins/builtins_typedarray.h +++ b/ecmascript/builtins/builtins_typedarray.h @@ -240,6 +240,17 @@ public: return Span(TYPED_ARRAY_PROTOTYPE_FUNCTIONS); } + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 more inline properties in %TypedArray%.prototype for the following functions/accessors: + // (1) %TypedArray%.prototype.constructor + // (2) %TypedArray%.prototype.toString, which is strictly equal to Array.prototype.toString + // (3) %TypedArray%.prototype[@@iterator] + // (4) %TypedArray%.prototype[@@toStringTag] + return GetTypedArrayPrototypeFunctions().Size() + + GetTypedArrayPrototypeAccessors().Size() + 4; + } + private: #define BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsTypedArray::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index c40a07495b..3e9e10e24f 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -379,6 +379,9 @@ public: inline GateRef HasConstructorByHClass(GateRef hClass); inline GateRef IsDictionaryModeByHClass(GateRef hClass); inline GateRef LoadHClass(GateRef object); + inline GateRef LoadHClassByConstOffset(GateRef object); + inline GateRef LoadPrototype(GateRef hclass); + inline GateRef LoadPrototypeHClass(GateRef object); void SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass, GateRef value, GateRef attrOffset, VariableType type); @@ -394,6 +397,7 @@ public: GateRef TypedArrayCheck(GateType type, GateRef gate); GateRef LoadTypedArrayLength(GateType type, GateRef gate); GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right); + GateRef BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type); GateRef IndexCheck(GateType type, GateRef gate, GateRef index); GateRef ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex); GateRef ObjectTypeCompare(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex); diff --git a/ecmascript/compiler/early_elimination.cpp b/ecmascript/compiler/early_elimination.cpp index 9b18058fff..bf10582abd 100644 --- a/ecmascript/compiler/early_elimination.cpp +++ b/ecmascript/compiler/early_elimination.cpp @@ -84,6 +84,7 @@ GateRef EarlyElimination::VisitGate(GateRef gate) case OpCode::LOAD_GETTER: case OpCode::LOAD_SETTER: case OpCode::ECMA_STRING_CHECK: + case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK: case OpCode::TYPE_OF_CHECK: return TryEliminateGate(gate); case OpCode::STATE_SPLIT: diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index 6b6e600ce8..ab3b90cb32 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -197,6 +197,13 @@ ObjectTypeAccessor GateAccessor::GetObjectTypeAccessor(GateRef gate) const return ObjectTypeAccessor(gatePtr->GetOneParameterMetaData()->GetValue()); } +BuiltinPrototypeHClassAccessor GateAccessor::GetBuiltinHClassAccessor(GateRef gate) const +{ + ASSERT(GetOpCode(gate) == OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK); + Gate *gatePtr = circuit_->LoadGatePtr(gate); + return BuiltinPrototypeHClassAccessor(gatePtr->GetOneParameterMetaData()->GetValue()); +} + bool GateAccessor::TypedOpIsTypedArray(GateRef gate, TypedOpKind kind) const { switch (kind) { diff --git a/ecmascript/compiler/gate_accessor.h b/ecmascript/compiler/gate_accessor.h index ec71db587c..3ab8f36ef4 100644 --- a/ecmascript/compiler/gate_accessor.h +++ b/ecmascript/compiler/gate_accessor.h @@ -405,6 +405,7 @@ public: TypedJumpAccessor GetTypedJumpAccessor(GateRef gate) const; ArrayMetaDataAccessor GetArrayMetaDataAccessor(GateRef gate) const; ObjectTypeAccessor GetObjectTypeAccessor(GateRef gate) const; + BuiltinPrototypeHClassAccessor GetBuiltinHClassAccessor(GateRef gate) const; uint64_t GetConstantValue(GateRef gate) const; const ChunkVector& GetConstantString(GateRef gate) const; bool IsVtable(GateRef gate) const; diff --git a/ecmascript/compiler/hcr_circuit_builder.h b/ecmascript/compiler/hcr_circuit_builder.h index ad7f275016..565afb9061 100644 --- a/ecmascript/compiler/hcr_circuit_builder.h +++ b/ecmascript/compiler/hcr_circuit_builder.h @@ -125,6 +125,23 @@ GateRef CircuitBuilder::LoadHClass(GateRef object) return Load(VariableType::JS_POINTER(), object, offset); } +GateRef CircuitBuilder::LoadHClassByConstOffset(GateRef object) +{ + return LoadConstOffset(VariableType::JS_POINTER(), object, TaggedObject::HCLASS_OFFSET); +} + +GateRef CircuitBuilder::LoadPrototype(GateRef hclass) +{ + return LoadConstOffset(VariableType::JS_POINTER(), hclass, JSHClass::PROTOTYPE_OFFSET); +} + +GateRef CircuitBuilder::LoadPrototypeHClass(GateRef object) +{ + GateRef objectHClass = LoadHClassByConstOffset(object); + GateRef objectPrototype = LoadPrototype(objectHClass); + return LoadHClass(objectPrototype); +} + GateRef CircuitBuilder::GetObjectSizeFromHClass(GateRef hClass) { // NOTE: check for special case of string and TAGGED_ARRAY diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 761442ebd6..468613540d 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -187,6 +187,20 @@ GateRef CircuitBuilder::RangeGuard(GateRef gate, uint32_t left, uint32_t right) return ret; } +GateRef CircuitBuilder::BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + auto frameState = acc_.FindNearestFrameState(currentDepend); + BuiltinPrototypeHClassAccessor accessor(type); + GateRef ret = GetCircuit()->NewGate(circuit_->BuiltinPrototypeHClassCheck(accessor.ToValue()), + MachineType::I1, {currentControl, currentDepend, gate, frameState}, GateType::NJSValue()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + GateRef CircuitBuilder::IndexCheck(GateType type, GateRef gate, GateRef index) { auto currentLabel = env_->GetCurrentLabel(); diff --git a/ecmascript/compiler/mcr_opcodes.h b/ecmascript/compiler/mcr_opcodes.h index a91013e58a..09ee3e9249 100644 --- a/ecmascript/compiler/mcr_opcodes.h +++ b/ecmascript/compiler/mcr_opcodes.h @@ -55,22 +55,23 @@ namespace panda::ecmascript::kungfu { V(TypedCall, TYPEDCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value) \ V(TypedFastCall, TYPEDFASTCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value) -#define MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \ - V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \ - V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 1, 1, 2) \ - V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \ - V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \ - V(StoreMemory, STORE_MEMORY, GateFlags::NONE_FLAG, 1, 1, 3) \ - V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \ - V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \ - V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ - V(RangeGuard, RANGE_GUARD, GateFlags::NO_WRITE, 1, 1, 1) \ - V(GetGlobalEnvObj, GET_GLOBAL_ENV_OBJ, GateFlags::NO_WRITE, 0, 1, 1) \ - V(GetGlobalEnvObjHClass, GET_GLOBAL_ENV_OBJ_HCLASS, GateFlags::NO_WRITE, 0, 1, 1) \ - V(GetGlobalConstantValue, GET_GLOBAL_CONSTANT_VALUE, GateFlags::NO_WRITE, 0, 1, 0) \ - V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ - V(HeapAlloc, HEAP_ALLOC, GateFlags::NONE_FLAG, 1, 1, 1) \ - V(RangeCheckPredicate, RANGE_CHECK_PREDICATE, GateFlags::CHECKABLE, 1, 1, 2) +#define MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \ + V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \ + V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 1, 1, 2) \ + V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \ + V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \ + V(StoreMemory, STORE_MEMORY, GateFlags::NONE_FLAG, 1, 1, 3) \ + V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \ + V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \ + V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ + V(RangeGuard, RANGE_GUARD, GateFlags::NO_WRITE, 1, 1, 1) \ + V(GetGlobalEnvObj, GET_GLOBAL_ENV_OBJ, GateFlags::NO_WRITE, 0, 1, 1) \ + V(GetGlobalEnvObjHClass, GET_GLOBAL_ENV_OBJ_HCLASS, GateFlags::NO_WRITE, 0, 1, 1) \ + V(GetGlobalConstantValue, GET_GLOBAL_CONSTANT_VALUE, GateFlags::NO_WRITE, 0, 1, 0) \ + V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ + V(HeapAlloc, HEAP_ALLOC, GateFlags::NONE_FLAG, 1, 1, 1) \ + V(RangeCheckPredicate, RANGE_CHECK_PREDICATE, GateFlags::CHECKABLE, 1, 1, 2) \ + V(BuiltinPrototypeHClassCheck, BUILTIN_PROTOTYPE_HCLASS_CHECK, GateFlags::CHECKABLE, 1, 1, 1) #define MCR_GATE_META_DATA_LIST_WITH_BOOL(V) \ V(LoadProperty, LOAD_PROPERTY, GateFlags::NO_WRITE, 1, 1, 2) diff --git a/ecmascript/compiler/share_gate_meta_data.h b/ecmascript/compiler/share_gate_meta_data.h index eadb1fb692..70cb61923b 100644 --- a/ecmascript/compiler/share_gate_meta_data.h +++ b/ecmascript/compiler/share_gate_meta_data.h @@ -19,16 +19,15 @@ #include #include "ecmascript/compiler/bytecodes.h" +#include "ecmascript/compiler/share_opcodes.h" #include "ecmascript/compiler/type.h" +#include "ecmascript/elements.h" +#include "ecmascript/js_thread_hclass_entries.h" #include "ecmascript/mem/chunk.h" #include "ecmascript/mem/chunk_containers.h" - -#include "ecmascript/elements.h" #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h" #include "libpandabase/macros.h" -#include "ecmascript/compiler/share_opcodes.h" - namespace panda::ecmascript::kungfu { using GateRef = int32_t; using PGOSampleType = pgo::PGOSampleType; @@ -40,33 +39,34 @@ enum class TypedLoadOp : uint8_t; enum class TypedStoreOp : uint8_t; enum class TypedCallTargetCheckOp : uint8_t; -#define GATE_META_DATA_DEOPT_REASON(V) \ - V(NotInt, NOTINT) \ - V(NotDouble, NOTDOUBLE) \ - V(NotNumber, NOTNUMBER) \ - V(NotBool, NOTBOOL) \ - V(NotHeapObject, NOTHEAPOBJECT) \ - V(NotStableArray, NOTSARRAY) \ - V(NotArray, NOTARRAY) \ - V(NotOnHeap, NOTONHEAP) \ - V(InconsistentHClass, INCONSISTENTHCLASS) \ - V(NotNewObj, NOTNEWOBJ) \ - V(NotLegalIndex, NOTLEGALIDX) \ - V(NotIncOverflow, NOTINCOV) \ - V(NotDecOverflow, NOTDECOV) \ - V(NotNegativeOverflow, NOTNEGOV) \ - V(NotCallTarget, NOTCALLTGT) \ - V(NotJSCallTarget, NOTJSCALLTGT) \ - V(CowArray, COWARRAY) \ - V(DivideZero, DIVZERO) \ - V(InlineFail, INLINEFAIL) \ - V(NotJSFastCallTarget, NOTJSFASTCALLTGT) \ - V(LexVarIsHole, LEXVARISHOLE) \ - V(ModZero, MODZERO) \ - V(Int32Overflow, INT32OVERFLOW) \ - V(NotString, NOTSTRING) \ - V(InconsistentType, INCONSISTENTTYPE) \ - V(NotNull, NOTNULL) +#define GATE_META_DATA_DEOPT_REASON(V) \ + V(NotInt, NOTINT) \ + V(NotDouble, NOTDOUBLE) \ + V(NotNumber, NOTNUMBER) \ + V(NotBool, NOTBOOL) \ + V(NotHeapObject, NOTHEAPOBJECT) \ + V(NotStableArray, NOTSARRAY) \ + V(NotArray, NOTARRAY) \ + V(NotOnHeap, NOTONHEAP) \ + V(InconsistentHClass, INCONSISTENTHCLASS) \ + V(NotNewObj, NOTNEWOBJ) \ + V(NotLegalIndex, NOTLEGALIDX) \ + V(NotIncOverflow, NOTINCOV) \ + V(NotDecOverflow, NOTDECOV) \ + V(NotNegativeOverflow, NOTNEGOV) \ + V(NotCallTarget, NOTCALLTGT) \ + V(NotJSCallTarget, NOTJSCALLTGT) \ + V(CowArray, COWARRAY) \ + V(DivideZero, DIVZERO) \ + V(InlineFail, INLINEFAIL) \ + V(NotJSFastCallTarget, NOTJSFASTCALLTGT) \ + V(LexVarIsHole, LEXVARISHOLE) \ + V(ModZero, MODZERO) \ + V(Int32Overflow, INT32OVERFLOW) \ + V(NotString, NOTSTRING) \ + V(InconsistentType, INCONSISTENTTYPE) \ + V(NotNull, NOTNULL) \ + V(BuiltinPrototypeHClassMismatch, BUILTINPROTOHCLASSMISMATCH) enum class DeoptType : uint8_t { NOTCHECK = 0, @@ -471,7 +471,8 @@ public: CREATE = 0, LOAD_ELEMENT, STORE_ELEMENT, - LOAD_LENGTH + LOAD_LENGTH, + CALL_BUILTIN_METHOD }; static constexpr int BITS_SIZE = 8; @@ -552,6 +553,29 @@ private: uint64_t bitField_; }; + +class BuiltinPrototypeHClassAccessor { +public: + explicit BuiltinPrototypeHClassAccessor(uint64_t value): type_(value) {} + // Only valid indices accepted + explicit BuiltinPrototypeHClassAccessor(BuiltinTypeId type): type_(static_cast(type)) + { + ASSERT(BuiltinHClassEntries::GetEntryIndex(type) < BuiltinHClassEntries::N_ENTRIES); + } + + BuiltinTypeId GetBuiltinTypeId() const + { + return static_cast(type_); + } + + uint64_t ToValue() const + { + return type_; + } + +private: + uint64_t type_; +}; } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_SHARE_GATE_META_DATA_H diff --git a/ecmascript/compiler/ts_hcr_lowering.cpp b/ecmascript/compiler/ts_hcr_lowering.cpp index 0afd013cfb..017b30b877 100644 --- a/ecmascript/compiler/ts_hcr_lowering.cpp +++ b/ecmascript/compiler/ts_hcr_lowering.cpp @@ -17,9 +17,9 @@ #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/builtins_lowering.h" #include "ecmascript/compiler/circuit.h" +#include "ecmascript/enum_conversion.h" #include "ecmascript/dfx/vmstat/opt_code_profiler.h" #include "ecmascript/stackmap/llvm_stackmap_parser.h" -#include "ecmascript/ts_types/ts_type.h" namespace panda::ecmascript::kungfu { bool TSHCRLowering::RunTSHCRLowering() @@ -694,22 +694,55 @@ void TSHCRLowering::BuildNamedPropertyAccessVerifier(GateRef gate, GateRef recei } bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate, GateType receiverType, JSTaggedValue key) +{ + // String: primitive string type only + // e.g. let s1 = "ABC"; // OK + // let s2 = new String("DEF"); // Not included, whose type is JSType::JS_PRIMITIVE_REF + if (receiverType.IsStringType()) { + return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::STRING); + } + // Array: created via either array literal or new Array(...) + // e.g. let a1 = [1, 2, 3]; // OK + // let a2 = new Array(1, 2, 3); // OK + if (tsManager_->IsArrayTypeKind(receiverType) || + tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, receiverType)) { + return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::ARRAY); + } + // Other valid types: let x = new X(...); + const auto hclassEntries = thread_->GetBuiltinHClassEntries(); + for (BuiltinTypeId type: BuiltinHClassEntries::BUILTIN_TYPES) { + if (type == BuiltinTypeId::ARRAY || type == BuiltinTypeId::STRING || !hclassEntries.EntryIsValid(type)) { + continue; // Checked before or invalid + } + if (!tsManager_->IsBuiltinInstanceType(type, receiverType)) { + continue; // Type mismatch + } + return TryLowerTypedLdObjByNameForBuiltin(gate, key, type); + } + return false; // No lowering performed +} + +bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate, JSTaggedValue key, BuiltinTypeId type) { EcmaString *propString = EcmaString::Cast(key.GetTaggedObject()); + // (1) get length EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject()); if (propString == lengthString) { - if (tsManager_->IsArrayTypeKind(receiverType)) { + if (type == BuiltinTypeId::ARRAY) { LowerTypedLdArrayLength(gate); return true; - } else if (tsManager_->IsValidTypedArrayType(receiverType)) { - LowerTypedLdTypedArrayLength(gate); - return true; - } else if (receiverType.IsStringType()) { + } + if (type == BuiltinTypeId::STRING) { LowerTypedLdStringLength(gate); return true; } + if (IsTypedArrayType(type)) { + LowerTypedLdTypedArrayLength(gate); + return true; + } } - return TryLowerTypedLdObjByNameForBuiltinMethod(gate, receiverType, key); + // (2) other functions + return TryLowerTypedLdObjByNameForBuiltinMethod(gate, key, type); } bool TSHCRLowering::IsCreateArray(GateRef gate) @@ -770,28 +803,38 @@ void TSHCRLowering::LowerTypedLdStringLength(GateRef gate) acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); } -bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, GateType receiverType, JSTaggedValue key) +bool TSHCRLowering::TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, JSTaggedValue key, BuiltinTypeId type) { - JSHandle globalEnv = thread_->GetEcmaVM()->GetGlobalEnv(); - if (receiverType.IsStringType()) { - JSHClass *stringPhc = globalEnv->GetStringPrototype()->GetTaggedObject()->GetClass(); - PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, stringPhc, key); - // Unable to handle accessor at the moment - if (!plr.IsFound() || plr.IsAccessor()) { - return false; - } - AddProfiling(gate); - GateRef str = acc_.GetValueIn(gate, 2); - if (!Uncheck()) { - builder_.EcmaStringCheck(str); - } - GateRef plrGate = builder_.Int32(plr.GetData()); - GateRef strPrototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), GlobalEnv::STRING_PROTOTYPE_INDEX); - GateRef result = builder_.LoadProperty(strPrototype, plrGate, plr.IsFunction()); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); - return true; + std::optional protoField = ToGlobelEnvPrototypeField(type); + if (!protoField.has_value()) { + return false; } - return false; + size_t protoFieldIndex = static_cast(*protoField); + JSHandle globalEnv = thread_->GetEcmaVM()->GetGlobalEnv(); + JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass(); + PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, prototypeHClass, key); + // Unable to handle accessor at the moment + if (!plr.IsFound() || plr.IsAccessor()) { + return false; + } + GateRef receiver = acc_.GetValueIn(gate, 2); + if (!Uncheck()) { + // For Array type only: array stability shall be ensured. + if (type == BuiltinTypeId::ARRAY) { + builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD); + } + // This check is not required by String, since string is a primitive type. + if (type != BuiltinTypeId::STRING) { + builder_.BuiltinPrototypeHClassCheck(receiver, type); + } + } + // Successfully goes to typed path + AddProfiling(gate); + GateRef plrGate = builder_.Int32(plr.GetData()); + GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast(*protoField)); + GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction()); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + return true; } void TSHCRLowering::LowerTypedLdObjByIndex(GateRef gate) diff --git a/ecmascript/compiler/ts_hcr_lowering.h b/ecmascript/compiler/ts_hcr_lowering.h index d0775e82de..ae2601363c 100644 --- a/ecmascript/compiler/ts_hcr_lowering.h +++ b/ecmascript/compiler/ts_hcr_lowering.h @@ -98,7 +98,8 @@ private: GateRef BuildNamedPropertyAccess(GateRef hir, ObjectAccessHelper accessHelper, PropertyLookupResult plr); void BuildNamedPropertyAccessVerifier(GateRef gate, GateRef receiver, AccessMode mode, GateRef value); bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate, GateType receiverType, JSTaggedValue key); - bool TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, GateType receiverType, JSTaggedValue key); + bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate, JSTaggedValue key, BuiltinTypeId type); + bool TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate, JSTaggedValue key, BuiltinTypeId type); void LowerTypedLdArrayLength(GateRef gate); void LowerTypedLdTypedArrayLength(GateRef gate); void LowerTypedLdStringLength(GateRef gate); diff --git a/ecmascript/compiler/type_mcr_lowering.cpp b/ecmascript/compiler/type_mcr_lowering.cpp index e5314007a8..74cdc1f14e 100644 --- a/ecmascript/compiler/type_mcr_lowering.cpp +++ b/ecmascript/compiler/type_mcr_lowering.cpp @@ -33,6 +33,9 @@ GateRef TypeMCRLowering::VisitGate(GateRef gate) case OpCode::PRIMITIVE_TYPE_CHECK: LowerPrimitiveTypeCheck(gate); break; + case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK: + LowerBuiltinPrototypeHClassCheck(gate); + break; case OpCode::STABLE_ARRAY_CHECK: LowerStableArrayCheck(gate); break; @@ -284,6 +287,12 @@ void TypeMCRLowering::SetDeoptTypeInfo(BuiltinTypeId id, DeoptType &type, size_t case BuiltinTypeId::FLOAT64_ARRAY: funcIndex = GlobalEnv::FLOAT64_ARRAY_FUNCTION_INDEX; break; + case BuiltinTypeId::BIGINT64_ARRAY: + funcIndex = GlobalEnv::BIGINT64_ARRAY_FUNCTION_INDEX; + break; + case BuiltinTypeId::BIGUINT64_ARRAY: + funcIndex = GlobalEnv::BIGUINT64_ARRAY_FUNCTION_INDEX; + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -539,6 +548,33 @@ void TypeMCRLowering::LowerRangeCheckPredicate(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } +void TypeMCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + BuiltinPrototypeHClassAccessor accessor = acc_.GetBuiltinHClassAccessor(gate); + BuiltinTypeId type = accessor.GetBuiltinTypeId(); + GateRef frameState = GetFrameState(gate); + GateRef glue = acc_.GetGlueFromArgList(); + + GateRef receiver = acc_.GetValueIn(gate, 0); + builder_.HeapObjectCheck(receiver, frameState); + + JSThread *thread = tsManager_->GetThread(); + // Only HClasses recorded in the JSThread during builtin initialization are available + [[maybe_unused]] JSHClass *initialPrototypeHClass = thread->GetBuiltinPrototypeHClass(type); + ASSERT(initialPrototypeHClass != nullptr); + + // Phc = PrototypeHClass + size_t phcOffset = JSThread::GlueData::GetBuiltinPrototypeHClassOffset(type, env.IsArch32Bit()); + GateRef receiverPhcAddress = builder_.LoadPrototypeHClass(receiver); + GateRef initialPhcAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, phcOffset); + GateRef phcMatches = builder_.Equal(receiverPhcAddress, initialPhcAddress); + // De-opt if HClass of X.prototype changed where X is the current builtin object. + builder_.DeoptCheck(phcMatches, frameState, DeoptType::BUILTINPROTOHCLASSMISMATCH); + + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); +} + void TypeMCRLowering::LowerIndexCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); diff --git a/ecmascript/compiler/type_mcr_lowering.h b/ecmascript/compiler/type_mcr_lowering.h index c2567ea6dc..0c74987c91 100644 --- a/ecmascript/compiler/type_mcr_lowering.h +++ b/ecmascript/compiler/type_mcr_lowering.h @@ -147,6 +147,7 @@ private: void LowerLoadFromTaggedArray(GateRef gate); void LowerStoreToTaggedArray(GateRef gate, GateRef glue); void LowerRangeCheckPredicate(GateRef gate); + void LowerBuiltinPrototypeHClassCheck(GateRef gate); enum class ArrayState : uint8_t { PACKED = 0, diff --git a/ecmascript/enum_conversion.h b/ecmascript/enum_conversion.h new file mode 100644 index 0000000000..7634c2fb96 --- /dev/null +++ b/ecmascript/enum_conversion.h @@ -0,0 +1,54 @@ +/* + * 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_ENUM_CONVERSION_H +#define ECMASCRIPT_ENUM_CONVERSION_H + +#include +#include "ecmascript/global_env_fields.h" +#include "ecmascript/ts_types/builtin_type_id.h" + +namespace panda::ecmascript { +inline constexpr std::optional ToGlobelEnvPrototypeField(BuiltinTypeId type) +{ + // case BuiltinTypeId::INT8_ARRAY ... + if (IsTypedArrayType(type)) { + return GlobalEnvField::TYPED_ARRAY_PROTOTYPE_INDEX; + } + switch (type) { + case BuiltinTypeId::ARRAY: + return GlobalEnvField::ARRAY_PROTOTYPE_INDEX; + case BuiltinTypeId::DATA_VIEW: + return GlobalEnvField::DATA_VIEW_PROTOTYPE_INDEX; + case BuiltinTypeId::DATE: + return GlobalEnvField::DATE_PROTOTYPE_INDEX; + case BuiltinTypeId::FUNCTION: + return GlobalEnvField::FUNCTION_PROTOTYPE_INDEX; + case BuiltinTypeId::GENERATOR_FUNCTION: + return GlobalEnvField::GENERATOR_FUNCTION_PROTOTYPE_OFFSET; + case BuiltinTypeId::MAP: + return GlobalEnvField::MAP_PROTOTYPE_INDEX; + case BuiltinTypeId::OBJECT: + return GlobalEnvField::OBJECT_FUNCTION_PROTOTYPE_INDEX; + case BuiltinTypeId::SET: + return GlobalEnvField::SET_PROTOTYPE_INDEX; + case BuiltinTypeId::STRING: + return GlobalEnvField::STRING_PROTOTYPE_INDEX; + default: // No corresponding entry in either BuiltinTypeId or GlobalEnvField + return std::nullopt; + } +} +} // namespace panda::ecmascript +#endif // ECMASCRIPT_ENUM_CONVERSION_H diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index ea188b8ba2..57a0ccdff7 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -21,199 +21,23 @@ #include "ecmascript/lexical_env.h" #include "ecmascript/js_handle.h" #include "ecmascript/global_env_constants-inl.h" -#include "ecmascript/property_detector.h" +#include "ecmascript/global_env_fields.h" namespace panda::ecmascript { class JSThread; - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GLOBAL_ENV_COMMON_FIELDS(V) \ - /* Function */ \ - V(JSTaggedValue, ObjectFunction, OBJECT_FUNCTION_INDEX) \ - V(JSTaggedValue, ObjectFunctionClass, OBJECT_FUNCTION_CLASS_INDEX) \ - V(JSTaggedValue, ObjectFunctionPrototype, OBJECT_FUNCTION_PROTOTYPE_INDEX) \ - V(JSTaggedValue, ObjectFunctionPrototypeClass, OBJECT_FUNCTION_PROTOTYPE_CLASS_INDEX) \ - V(JSTaggedValue, FunctionFunction, FUNCTION_FUNCTION_INDEX) \ - V(JSTaggedValue, FunctionPrototype, FUNCTION_PROTOTYPE_INDEX) \ - V(JSTaggedValue, NumberFunction, NUMBER_FUNCTION_INDEX) \ - V(JSTaggedValue, BigIntFunction, BIGINT_FUNCTION_INDEX) \ - V(JSTaggedValue, DateFunction, DATE_FUNCTION_INDEX) \ - V(JSTaggedValue, BooleanFunction, BOOLEAN_FUNCTION_INDEX) \ - V(JSTaggedValue, ErrorFunction, ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, ArrayFunction, ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, ArrayPrototype, ARRAY_PROTOTYPE_INDEX) \ - V(JSTaggedValue, TypedArrayFunction, TYPED_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, TypedArrayPrototype, TYPED_ARRAY_PROTOTYPE_INDEX) \ - V(JSTaggedValue, Int8ArrayFunction, INT8_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Uint8ArrayFunction, UINT8_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Uint8ClampedArrayFunction, UINT8_CLAMPED_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Int16ArrayFunction, INT16_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Uint16ArrayFunction, UINT16_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Int32ArrayFunction, INT32_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Uint32ArrayFunction, UINT32_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Float32ArrayFunction, FLOAT32_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, Float64ArrayFunction, FLOAT64_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, BigInt64ArrayFunction, BIGINT64_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, BigUint64ArrayFunction, BIGUINT64_ARRAY_FUNCTION_INDEX) \ - V(JSTaggedValue, ArrayBufferFunction, ARRAY_BUFFER_FUNCTION_INDEX) \ - V(JSTaggedValue, SharedArrayBufferFunction, SHAREDARRAY_BUFFER_FUNCTION_INDEX) \ - V(JSTaggedValue, ArrayProtoValuesFunction, ARRAY_PROTO_VALUES_FUNCTION_INDEX) \ - V(JSTaggedValue, DataViewFunction, DATA_VIEW_FUNCTION_INDEX) \ - V(JSTaggedValue, SymbolFunction, SYMBOL_FUNCTION_INDEX) \ - V(JSTaggedValue, RangeErrorFunction, RANGE_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, ReferenceErrorFunction, REFERENCE_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, TypeErrorFunction, TYPE_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, AggregateErrorFunction, AGGREGATE_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, URIErrorFunction, URI_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, SyntaxErrorFunction, SYNTAX_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, EvalErrorFunction, EVAL_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, OOMErrorFunction, OOM_ERROR_FUNCTION_INDEX) \ - V(JSTaggedValue, IntlFunction, INTL_FUNCTION_INDEX) \ - V(JSTaggedValue, LocaleFunction, LOCALE_FUNCTION_INDEX) \ - V(JSTaggedValue, DateTimeFormatFunction, DATE_TIME_FORMAT_FUNCTION_INDEX) \ - V(JSTaggedValue, RelativeTimeFormatFunction, RELATIVE_TIME_FORMAT_FUNCTION_INDEX) \ - V(JSTaggedValue, NumberFormatFunction, NUMBER_FORMAT_FUNCTION_INDEX) \ - V(JSTaggedValue, CollatorFunction, COLLATOR_FUNCTION_INDEX) \ - V(JSTaggedValue, PluralRulesFunction, PLURAL_RULES_FUNCTION_INDEX) \ - V(JSTaggedValue, DisplayNamesFunction, DISPLAY_NAMES_FUNCTION_INDEX) \ - V(JSTaggedValue, ListFormatFunction, LIST_FORMAT_FUNCTION_INDEX) \ - V(JSTaggedValue, RegExpFunction, REGEXP_FUNCTION_INDEX) \ - V(JSTaggedValue, RegExpExecFunction, REGEXP_EXEC_FUNCTION_INDEX) \ - V(JSTaggedValue, RegExpPrototype, REGEXP_PROTOTYPE_INDEX) \ - V(JSTaggedValue, RegExpPrototypeClass, REGEXP_PROTOTYPE_CLASS_INDEX) \ - V(JSTaggedValue, BuiltinsSetFunction, BUILTINS_SET_FUNCTION_INDEX) \ - V(JSTaggedValue, SetPrototype, SET_PROTOTYPE_INDEX) \ - V(JSTaggedValue, BuiltinsMapFunction, BUILTINS_MAP_FUNCTION_INDEX) \ - V(JSTaggedValue, BuiltinsWeakMapFunction, BUILTINS_WEAK_MAP_FUNCTION_INDEX) \ - V(JSTaggedValue, BuiltinsWeakSetFunction, BUILTINS_WEAK_SET_FUNCTION_INDEX) \ - V(JSTaggedValue, BuiltinsWeakRefFunction, BUILTINS_WEAK_REF_FUNCTION_INDEX) \ - V(JSTaggedValue, BuiltinsFinalizationRegistryFunction, \ - BUILTINS_FINALIZATION_REGISTRY_FUNCTION_INDEX) \ - V(JSTaggedValue, MapPrototype, MAP_PROTOTYPE_INDEX) \ - V(JSTaggedValue, MathFunction, MATH_FUNCTION_INDEX) \ - V(JSTaggedValue, AtomicsFunction, ATOMICS_FUNCTION_INDEX) \ - V(JSTaggedValue, JsonFunction, JSON_FUNCTION_INDEX) \ - V(JSTaggedValue, StringFunction, STRING_FUNCTION_INDEX) \ - V(JSTaggedValue, StringPrototype, STRING_PROTOTYPE_INDEX) \ - V(JSTaggedValue, ProxyFunction, PROXY_FUNCTION_INDEX) \ - V(JSTaggedValue, GeneratorFunctionFunction, GENERATOR_FUNCTION_OFFSET) \ - V(JSTaggedValue, GeneratorFunctionPrototype, GENERATOR_FUNCTION_PROTOTYPE_OFFSET) \ - V(JSTaggedValue, AsyncGeneratorFunctionFunction, ASYNC_GENERATOR_FUNCTION_OFFSET) \ - V(JSTaggedValue, AsyncGeneratorFunctionPrototype, ASYNC_GENERATOR_FUNCTION_PROTOTYPE_OFFSET) \ - V(JSTaggedValue, InitialGenerator, INITIAL_GENERATOR_OFFSET) \ - V(JSTaggedValue, InitialAsyncGenerator, INITIAL_ASYNC_GENERATOR_OFFSET) \ - V(JSTaggedValue, GeneratorPrototype, GENERATOR_PROTOTYPE_OFFSET) \ - V(JSTaggedValue, AsyncGeneratorPrototype, ASYNC_GENERATOR_PROTOTYPE_OFFSET) \ - V(JSTaggedValue, ReflectFunction, REFLECT_FUNCTION_INDEX) \ - V(JSTaggedValue, AsyncFunction, ASYNC_FUNCTION_INDEX) \ - V(JSTaggedValue, AsyncFunctionPrototype, ASYNC_FUNCTION_PROTOTYPE_INDEX) \ - V(JSTaggedValue, JSGlobalObject, JS_GLOBAL_OBJECT_INDEX) \ - V(JSTaggedValue, HasInstanceSymbol, HASINSTANCE_SYMBOL_INDEX) \ - V(JSTaggedValue, HasInstanceFunction, HASINSTANCE_FUNCTION_INDEX) \ - V(JSTaggedValue, IsConcatSpreadableSymbol, ISCONCAT_SYMBOL_INDEX) \ - V(JSTaggedValue, ToStringTagSymbol, TOSTRINGTAG_SYMBOL_INDEX) \ - V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX) \ - V(JSTaggedValue, AsyncIteratorSymbol, ASYNC_ITERATOR_SYMBOL_INDEX) \ - V(JSTaggedValue, MatchSymbol, MATCH_SYMBOL_INDEX) \ - V(JSTaggedValue, MatchAllSymbol, MATCH_All_SYMBOL_INDEX) \ - V(JSTaggedValue, SearchSymbol, SEARCH_SYMBOL_INDEX) \ - V(JSTaggedValue, SpeciesSymbol, SPECIES_SYMBOL_INDEX) \ - V(JSTaggedValue, ToPrimitiveSymbol, TOPRIMITIVE_SYMBOL_INDEX) \ - V(JSTaggedValue, UnscopablesSymbol, UNSCOPABLES_SYMBOL_INDEX) \ - V(JSTaggedValue, HoleySymbol, HOLEY_SYMBOL_OFFSET) \ - V(JSTaggedValue, ElementICSymbol, ELEMENT_IC_SYMBOL_OFFSET) \ - V(JSTaggedValue, IteratorPrototype, ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, AsyncIteratorPrototype, ASYNC_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, ForinIteratorPrototype, FORIN_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, ForinIteratorClass, FOR_IN_ITERATOR_CLASS_INDEX) \ - V(JSTaggedValue, StringIterator, STRING_ITERATOR_INDEX) \ - V(JSTaggedValue, AsyncFromSyncIterator, ASYNC_FROM_SYNC_ITERATOR_INDEX) \ - V(JSTaggedValue, MapIteratorPrototype, MAP_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, SetIteratorPrototype, SET_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, RegExpIteratorPrototype, REGEXP_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, ArrayIteratorPrototype, ARRAY_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, StringIteratorPrototype, STRING_ITERATOR_PROTOTYPE_INDEX) \ - V(JSTaggedValue, AsyncFromSyncIteratorPrototype, ASYNC_FROM_SYNC_ITERATOR_PROTOTYPE_INDEX) \ - /* SymbolTable *RegisterSymbols */ \ - V(JSTaggedValue, RegisterSymbols, SYMBOLS_INDEX) \ - V(JSTaggedValue, ThrowTypeError, THROW_TYPE_ERROR_INDEX) \ - V(JSTaggedValue, PromiseFunction, PROMISE_FUNCTION_INDEX) \ - V(JSTaggedValue, PromiseReactionJob, PROMISE_REACTION_JOB_INDEX) \ - V(JSTaggedValue, PromiseResolveThenableJob, PROMISE_REACTION_THENABLE_JOB_INDEX) \ - V(JSTaggedValue, DynamicImportJob, DYNAMIC_IMPORT_JOB_INDEX) \ - V(JSTaggedValue, TemplateMap, TEMPLATE_MAP_INDEX) \ - V(JSTaggedValue, FunctionClassWithProto, FUNCTION_CLASS_WITH_PROTO) \ - V(JSTaggedValue, FunctionClassWithProtoOptimized, FUNCTION_CLASS_WITH_PROTO_OPTIMIZED) \ - V(JSTaggedValue, FunctionClassWithProtoOptimizedWithFastCall, \ - FUNCTION_CLASS_WITH_PROTO_OPTIMIZED_WITH_FAST_CALL) \ - V(JSTaggedValue, FunctionClassWithoutProto, FUNCTION_CLASS_WITHOUT_PROTO) \ - V(JSTaggedValue, FunctionClassWithoutProtoOptimized, FUNCTION_CLASS_WITHOUT_PROTO_OPTIMIZED) \ - V(JSTaggedValue, FunctionClassWithoutProtoOptimizedWithFastCall, \ - FUNCTION_CLASS_WITHOUT_PROTO_OPTIMIZED_WITH_FAST_CALL) \ - V(JSTaggedValue, FunctionClassWithoutName, FUNCTION_CLASS_WITHOUT_NAME) \ - V(JSTaggedValue, ArgumentsClass, ARGUMENTS_CLASS) \ - V(JSTaggedValue, ArgumentsCallerAccessor, ARGUMENTS_CALLER_ACCESSOR) \ - V(JSTaggedValue, ArgumentsCalleeAccessor, ARGUMENTS_CALLEE_ACCESSOR) \ - V(JSTaggedValue, AsyncFunctionClass, ASYNC_FUNCTION_CLASS) \ - V(JSTaggedValue, AsyncFunctionClassOptimized, ASYNC_FUNCTION_CLASS_OPTIMIZED) \ - V(JSTaggedValue, AsyncFunctionClassOptimizedWithFastCall, \ - ASYNC_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ - V(JSTaggedValue, AsyncAwaitStatusFunctionClass, ASYNC_AWAIT_STATUS_FUNCTION_CLASS) \ - V(JSTaggedValue, PromiseReactionFunctionClass, PROMISE_REACTION_FUNCTION_CLASS) \ - V(JSTaggedValue, PromiseExecutorFunctionClass, PROMISE_EXECUTOR_FUNCTION_CLASS) \ - V(JSTaggedValue, GeneratorFunctionClass, GENERATOR_FUNCTION_CLASS) \ - V(JSTaggedValue, GeneratorFunctionClassOptimized, GENERATOR_FUNCTION_CLASS_OPTIMIZED) \ - V(JSTaggedValue, GeneratorFunctionClassOptimizedWithFastCall, \ - GENERATOR_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ - V(JSTaggedValue, AsyncGeneratorFunctionClass, ASYNC_GENERATOR_FUNCTION_CLASS) \ - V(JSTaggedValue, AsyncGeneratorFunctionClassOptimized, \ - ASYNC_GENERATOR_FUNCTION_CLASS_OPTIMIZED) \ - V(JSTaggedValue, AsyncGeneratorFunctionClassOptimizedWithFastCall, \ - ASYNC_GENERATOR_FUNCTION_CLASS_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ - V(JSTaggedValue, PromiseAllResolveElementFunctionClass, PROMISE_ALL_RESOLVE_ELEMENT_FUNC_CLASS) \ - V(JSTaggedValue, PromiseAnyRejectElementFunctionClass, PROMISE_ANY_REJECT_ELEMENT_FUNC_CLASS) \ - V(JSTaggedValue, PromiseAllSettledElementFunctionClass, PROMISE_ALL_SETTLED_ELEMENT_FUNC_CLASS) \ - V(JSTaggedValue, PromiseFinallyFunctionClass, PROMISE_FINALLY_FUNC_CLASS) \ - V(JSTaggedValue, PromiseValueThunkOrThrowerFunctionClass, \ - PROMISE_VALUE_THUNK_OR_THROWER_FUNCTION_CLASS) \ - V(JSTaggedValue, AsyncGeneratorResNextRetProRstFtnClass, \ - ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN_CLASS) \ - V(JSTaggedValue, AsyncFromSyncIterUnwarpClass, ASYNC_FROM_SYNC_ITER_UNWARP_CLASS) \ - V(JSTaggedValue, ProxyRevocFunctionClass, PROXY_REVOC_FUNCTION_CLASS) \ - V(JSTaggedValue, NativeErrorFunctionClass, NATIVE_ERROR_FUNCTION_CLASS) \ - V(JSTaggedValue, SpecificTypedArrayFunctionClass, SPERCIFIC_TYPED_ARRAY_FUNCTION_CLASS) \ - V(JSTaggedValue, ConstructorFunctionClass, CONSTRUCTOR_FUNCTION_CLASS) \ - V(JSTaggedValue, NormalFunctionClass, NORMAL_FUNCTION_CLASS) \ - V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ - V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, ListFormatLocales, LIST_FORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) \ - V(JSTaggedValue, ModuleNamespaceClass, MODULENAMESPACE_CLASS) \ - V(JSTaggedValue, ObjectLiteralHClassCache, OBJECT_LITERAL_HCLASS_CACHE) \ - V(JSTaggedValue, WeakRefKeepObjects, WEAK_REF_KEEP_OBJECTS) \ - V(JSTaggedValue, FinRegLists, FIN_REG_LISTS) \ - V(JSTaggedValue, AttachSymbol, ATTACH_SYMBOL_INDEX) \ - V(JSTaggedValue, DetachSymbol, DETACH_SYMBOL_INDEX) \ - V(JSTaggedValue, CjsModuleFunction, CJS_MODULE_FUNCTION_INDEX) \ - V(JSTaggedValue, CjsExportsFunction, CJS_EXPORTS_FUNCTION_INDEX) \ - V(JSTaggedValue, CjsRequireFunction, CJS_REQUIRE_FUNCTION_INDEX) \ - V(JSTaggedValue, GlobalPatch, GLOBAL_PATCH) \ - V(JSTaggedValue, ExportOfScript, DEFAULT_EXPORT_OF_SCRIPT) \ - V(JSTaggedValue, JsonObjectHclassCache, JSON_OBJECT_HCLASS_CACHE) - -// Maintain the same order with DETECTOR_SYMBOL_LIST -#define GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \ - V(JSTaggedValue, ReplaceSymbol, REPLACE_SYMBOL_INDEX) \ - V(JSTaggedValue, SplitSymbol, SPLIT_SYMBOL_INDEX) \ - -#define GLOBAL_ENV_FIELDS(V) \ - GLOBAL_ENV_COMMON_FIELDS(V) \ - GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \ - GLOBAL_ENV_DETECTOR_FIELDS(V) \ - class GlobalEnv : public TaggedObject { public: + using Field = GlobalEnvField; + +#define GLOBAL_ENV_SLOT(type, name, index) \ + static constexpr uint8_t index = static_cast(GlobalEnvField::index); + + GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT) + static constexpr uint8_t FIRST_DETECTOR_SYMBOL_INDEX = static_cast(Field::REPLACE_SYMBOL_INDEX); + static constexpr uint8_t LAST_DETECTOR_SYMBOL_INDEX = static_cast(Field::SPLIT_SYMBOL_INDEX); + static constexpr uint8_t FINAL_INDEX = static_cast(GlobalEnvField::FINAL_INDEX); +#undef GLOBAL_ENV_SLOT + JSTaggedValue GetGlobalObject() const { return GetJSGlobalObject().GetTaggedValue(); @@ -249,17 +73,6 @@ public: JSHandle GetStringFunctionByName(JSThread *thread, const char *name); JSHandle GetStringPrototypeFunctionByName(JSThread *thread, const char *name); - enum Field { -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GLOBAL_ENV_SLOT(type, name, index) index, - GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT) -#undef GLOBAL_ENV_SLOT - FINAL_INDEX - }; - - static constexpr uint8_t FIRST_DETECTOR_SYMBOL_INDEX = Field::REPLACE_SYMBOL_INDEX; - static constexpr uint8_t LAST_DETECTOR_SYMBOL_INDEX = Field::SPLIT_SYMBOL_INDEX; - static inline uintptr_t GetFirstDetectorSymbolAddr(const GlobalEnv *env) { constexpr size_t offset = HEADER_SIZE + FIRST_DETECTOR_SYMBOL_INDEX * JSTaggedValue::TaggedTypeSize(); diff --git a/ecmascript/global_env_fields.h b/ecmascript/global_env_fields.h new file mode 100644 index 0000000000..d5dbf2a9c3 --- /dev/null +++ b/ecmascript/global_env_fields.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_GLOBAL_ENV_FIELDS_H +#define ECMASCRIPT_GLOBAL_ENV_FIELDS_H + +#include +#include "ecmascript/property_detector.h" + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define GLOBAL_ENV_COMMON_FIELDS(V) \ + /* Function */ \ + V(JSTaggedValue, ObjectFunction, OBJECT_FUNCTION_INDEX) \ + V(JSTaggedValue, ObjectFunctionClass, OBJECT_FUNCTION_CLASS_INDEX) \ + V(JSTaggedValue, ObjectFunctionPrototype, OBJECT_FUNCTION_PROTOTYPE_INDEX) \ + V(JSTaggedValue, ObjectFunctionPrototypeClass, OBJECT_FUNCTION_PROTOTYPE_CLASS_INDEX) \ + V(JSTaggedValue, FunctionFunction, FUNCTION_FUNCTION_INDEX) \ + V(JSTaggedValue, FunctionPrototype, FUNCTION_PROTOTYPE_INDEX) \ + V(JSTaggedValue, NumberFunction, NUMBER_FUNCTION_INDEX) \ + V(JSTaggedValue, BigIntFunction, BIGINT_FUNCTION_INDEX) \ + V(JSTaggedValue, DateFunction, DATE_FUNCTION_INDEX) \ + V(JSTaggedValue, DatePrototype, DATE_PROTOTYPE_INDEX) \ + V(JSTaggedValue, BooleanFunction, BOOLEAN_FUNCTION_INDEX) \ + V(JSTaggedValue, ErrorFunction, ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, ArrayFunction, ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, ArrayPrototype, ARRAY_PROTOTYPE_INDEX) \ + V(JSTaggedValue, TypedArrayFunction, TYPED_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, TypedArrayPrototype, TYPED_ARRAY_PROTOTYPE_INDEX) \ + V(JSTaggedValue, Int8ArrayFunction, INT8_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Uint8ArrayFunction, UINT8_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Uint8ClampedArrayFunction, UINT8_CLAMPED_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Int16ArrayFunction, INT16_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Uint16ArrayFunction, UINT16_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Int32ArrayFunction, INT32_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Uint32ArrayFunction, UINT32_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Float32ArrayFunction, FLOAT32_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, Float64ArrayFunction, FLOAT64_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, BigInt64ArrayFunction, BIGINT64_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, BigUint64ArrayFunction, BIGUINT64_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, ArrayBufferFunction, ARRAY_BUFFER_FUNCTION_INDEX) \ + V(JSTaggedValue, SharedArrayBufferFunction, SHAREDARRAY_BUFFER_FUNCTION_INDEX) \ + V(JSTaggedValue, ArrayProtoValuesFunction, ARRAY_PROTO_VALUES_FUNCTION_INDEX) \ + V(JSTaggedValue, DataViewFunction, DATA_VIEW_FUNCTION_INDEX) \ + V(JSTaggedValue, DataViewPrototype, DATA_VIEW_PROTOTYPE_INDEX) \ + V(JSTaggedValue, SymbolFunction, SYMBOL_FUNCTION_INDEX) \ + V(JSTaggedValue, RangeErrorFunction, RANGE_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, ReferenceErrorFunction, REFERENCE_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, TypeErrorFunction, TYPE_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, AggregateErrorFunction, AGGREGATE_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, URIErrorFunction, URI_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, SyntaxErrorFunction, SYNTAX_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, EvalErrorFunction, EVAL_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, OOMErrorFunction, OOM_ERROR_FUNCTION_INDEX) \ + V(JSTaggedValue, IntlFunction, INTL_FUNCTION_INDEX) \ + V(JSTaggedValue, LocaleFunction, LOCALE_FUNCTION_INDEX) \ + V(JSTaggedValue, DateTimeFormatFunction, DATE_TIME_FORMAT_FUNCTION_INDEX) \ + V(JSTaggedValue, RelativeTimeFormatFunction, RELATIVE_TIME_FORMAT_FUNCTION_INDEX) \ + V(JSTaggedValue, NumberFormatFunction, NUMBER_FORMAT_FUNCTION_INDEX) \ + V(JSTaggedValue, CollatorFunction, COLLATOR_FUNCTION_INDEX) \ + V(JSTaggedValue, PluralRulesFunction, PLURAL_RULES_FUNCTION_INDEX) \ + V(JSTaggedValue, DisplayNamesFunction, DISPLAY_NAMES_FUNCTION_INDEX) \ + V(JSTaggedValue, ListFormatFunction, LIST_FORMAT_FUNCTION_INDEX) \ + V(JSTaggedValue, RegExpFunction, REGEXP_FUNCTION_INDEX) \ + V(JSTaggedValue, RegExpExecFunction, REGEXP_EXEC_FUNCTION_INDEX) \ + V(JSTaggedValue, RegExpPrototype, REGEXP_PROTOTYPE_INDEX) \ + V(JSTaggedValue, RegExpPrototypeClass, REGEXP_PROTOTYPE_CLASS_INDEX) \ + V(JSTaggedValue, BuiltinsSetFunction, BUILTINS_SET_FUNCTION_INDEX) \ + V(JSTaggedValue, SetPrototype, SET_PROTOTYPE_INDEX) \ + V(JSTaggedValue, BuiltinsMapFunction, BUILTINS_MAP_FUNCTION_INDEX) \ + V(JSTaggedValue, BuiltinsWeakMapFunction, BUILTINS_WEAK_MAP_FUNCTION_INDEX) \ + V(JSTaggedValue, BuiltinsWeakSetFunction, BUILTINS_WEAK_SET_FUNCTION_INDEX) \ + V(JSTaggedValue, BuiltinsWeakRefFunction, BUILTINS_WEAK_REF_FUNCTION_INDEX) \ + V(JSTaggedValue, BuiltinsFinalizationRegistryFunction, \ + BUILTINS_FINALIZATION_REGISTRY_FUNCTION_INDEX) \ + V(JSTaggedValue, MapPrototype, MAP_PROTOTYPE_INDEX) \ + V(JSTaggedValue, MathFunction, MATH_FUNCTION_INDEX) \ + V(JSTaggedValue, AtomicsFunction, ATOMICS_FUNCTION_INDEX) \ + V(JSTaggedValue, JsonFunction, JSON_FUNCTION_INDEX) \ + V(JSTaggedValue, StringFunction, STRING_FUNCTION_INDEX) \ + V(JSTaggedValue, StringPrototype, STRING_PROTOTYPE_INDEX) \ + V(JSTaggedValue, ProxyFunction, PROXY_FUNCTION_INDEX) \ + V(JSTaggedValue, GeneratorFunctionFunction, GENERATOR_FUNCTION_OFFSET) \ + V(JSTaggedValue, GeneratorFunctionPrototype, GENERATOR_FUNCTION_PROTOTYPE_OFFSET) \ + V(JSTaggedValue, AsyncGeneratorFunctionFunction, ASYNC_GENERATOR_FUNCTION_OFFSET) \ + V(JSTaggedValue, AsyncGeneratorFunctionPrototype, ASYNC_GENERATOR_FUNCTION_PROTOTYPE_OFFSET) \ + V(JSTaggedValue, InitialGenerator, INITIAL_GENERATOR_OFFSET) \ + V(JSTaggedValue, InitialAsyncGenerator, INITIAL_ASYNC_GENERATOR_OFFSET) \ + V(JSTaggedValue, GeneratorPrototype, GENERATOR_PROTOTYPE_OFFSET) \ + V(JSTaggedValue, AsyncGeneratorPrototype, ASYNC_GENERATOR_PROTOTYPE_OFFSET) \ + V(JSTaggedValue, ReflectFunction, REFLECT_FUNCTION_INDEX) \ + V(JSTaggedValue, AsyncFunction, ASYNC_FUNCTION_INDEX) \ + V(JSTaggedValue, AsyncFunctionPrototype, ASYNC_FUNCTION_PROTOTYPE_INDEX) \ + V(JSTaggedValue, JSGlobalObject, JS_GLOBAL_OBJECT_INDEX) \ + V(JSTaggedValue, HasInstanceSymbol, HASINSTANCE_SYMBOL_INDEX) \ + V(JSTaggedValue, HasInstanceFunction, HASINSTANCE_FUNCTION_INDEX) \ + V(JSTaggedValue, IsConcatSpreadableSymbol, ISCONCAT_SYMBOL_INDEX) \ + V(JSTaggedValue, ToStringTagSymbol, TOSTRINGTAG_SYMBOL_INDEX) \ + V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX) \ + V(JSTaggedValue, AsyncIteratorSymbol, ASYNC_ITERATOR_SYMBOL_INDEX) \ + V(JSTaggedValue, MatchSymbol, MATCH_SYMBOL_INDEX) \ + V(JSTaggedValue, MatchAllSymbol, MATCH_All_SYMBOL_INDEX) \ + V(JSTaggedValue, SearchSymbol, SEARCH_SYMBOL_INDEX) \ + V(JSTaggedValue, SpeciesSymbol, SPECIES_SYMBOL_INDEX) \ + V(JSTaggedValue, ToPrimitiveSymbol, TOPRIMITIVE_SYMBOL_INDEX) \ + V(JSTaggedValue, UnscopablesSymbol, UNSCOPABLES_SYMBOL_INDEX) \ + V(JSTaggedValue, HoleySymbol, HOLEY_SYMBOL_OFFSET) \ + V(JSTaggedValue, ElementICSymbol, ELEMENT_IC_SYMBOL_OFFSET) \ + V(JSTaggedValue, IteratorPrototype, ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, AsyncIteratorPrototype, ASYNC_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, ForinIteratorPrototype, FORIN_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, ForinIteratorClass, FOR_IN_ITERATOR_CLASS_INDEX) \ + V(JSTaggedValue, StringIterator, STRING_ITERATOR_INDEX) \ + V(JSTaggedValue, AsyncFromSyncIterator, ASYNC_FROM_SYNC_ITERATOR_INDEX) \ + V(JSTaggedValue, MapIteratorPrototype, MAP_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, SetIteratorPrototype, SET_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, RegExpIteratorPrototype, REGEXP_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, ArrayIteratorPrototype, ARRAY_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, StringIteratorPrototype, STRING_ITERATOR_PROTOTYPE_INDEX) \ + V(JSTaggedValue, AsyncFromSyncIteratorPrototype, ASYNC_FROM_SYNC_ITERATOR_PROTOTYPE_INDEX) \ + /* SymbolTable *RegisterSymbols */ \ + V(JSTaggedValue, RegisterSymbols, SYMBOLS_INDEX) \ + V(JSTaggedValue, ThrowTypeError, THROW_TYPE_ERROR_INDEX) \ + V(JSTaggedValue, PromiseFunction, PROMISE_FUNCTION_INDEX) \ + V(JSTaggedValue, PromiseReactionJob, PROMISE_REACTION_JOB_INDEX) \ + V(JSTaggedValue, PromiseResolveThenableJob, PROMISE_REACTION_THENABLE_JOB_INDEX) \ + V(JSTaggedValue, DynamicImportJob, DYNAMIC_IMPORT_JOB_INDEX) \ + V(JSTaggedValue, TemplateMap, TEMPLATE_MAP_INDEX) \ + V(JSTaggedValue, FunctionClassWithProto, FUNCTION_CLASS_WITH_PROTO) \ + V(JSTaggedValue, FunctionClassWithProtoOptimized, FUNCTION_CLASS_WITH_PROTO_OPTIMIZED) \ + V(JSTaggedValue, FunctionClassWithProtoOptimizedWithFastCall, \ + FUNCTION_CLASS_WITH_PROTO_OPTIMIZED_WITH_FAST_CALL) \ + V(JSTaggedValue, FunctionClassWithoutProto, FUNCTION_CLASS_WITHOUT_PROTO) \ + V(JSTaggedValue, FunctionClassWithoutProtoOptimized, FUNCTION_CLASS_WITHOUT_PROTO_OPTIMIZED) \ + V(JSTaggedValue, FunctionClassWithoutProtoOptimizedWithFastCall, \ + FUNCTION_CLASS_WITHOUT_PROTO_OPTIMIZED_WITH_FAST_CALL) \ + V(JSTaggedValue, FunctionClassWithoutName, FUNCTION_CLASS_WITHOUT_NAME) \ + V(JSTaggedValue, ArgumentsClass, ARGUMENTS_CLASS) \ + V(JSTaggedValue, ArgumentsCallerAccessor, ARGUMENTS_CALLER_ACCESSOR) \ + V(JSTaggedValue, ArgumentsCalleeAccessor, ARGUMENTS_CALLEE_ACCESSOR) \ + V(JSTaggedValue, AsyncFunctionClass, ASYNC_FUNCTION_CLASS) \ + V(JSTaggedValue, AsyncFunctionClassOptimized, ASYNC_FUNCTION_CLASS_OPTIMIZED) \ + V(JSTaggedValue, AsyncFunctionClassOptimizedWithFastCall, \ + ASYNC_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ + V(JSTaggedValue, AsyncAwaitStatusFunctionClass, ASYNC_AWAIT_STATUS_FUNCTION_CLASS) \ + V(JSTaggedValue, PromiseReactionFunctionClass, PROMISE_REACTION_FUNCTION_CLASS) \ + V(JSTaggedValue, PromiseExecutorFunctionClass, PROMISE_EXECUTOR_FUNCTION_CLASS) \ + V(JSTaggedValue, GeneratorFunctionClass, GENERATOR_FUNCTION_CLASS) \ + V(JSTaggedValue, GeneratorFunctionClassOptimized, GENERATOR_FUNCTION_CLASS_OPTIMIZED) \ + V(JSTaggedValue, GeneratorFunctionClassOptimizedWithFastCall, \ + GENERATOR_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ + V(JSTaggedValue, AsyncGeneratorFunctionClass, ASYNC_GENERATOR_FUNCTION_CLASS) \ + V(JSTaggedValue, AsyncGeneratorFunctionClassOptimized, \ + ASYNC_GENERATOR_FUNCTION_CLASS_OPTIMIZED) \ + V(JSTaggedValue, AsyncGeneratorFunctionClassOptimizedWithFastCall, \ + ASYNC_GENERATOR_FUNCTION_CLASS_FUNCTION_CLASS_OPTIMIZED_WITH_FAST_CALL) \ + V(JSTaggedValue, PromiseAllResolveElementFunctionClass, PROMISE_ALL_RESOLVE_ELEMENT_FUNC_CLASS) \ + V(JSTaggedValue, PromiseAnyRejectElementFunctionClass, PROMISE_ANY_REJECT_ELEMENT_FUNC_CLASS) \ + V(JSTaggedValue, PromiseAllSettledElementFunctionClass, PROMISE_ALL_SETTLED_ELEMENT_FUNC_CLASS) \ + V(JSTaggedValue, PromiseFinallyFunctionClass, PROMISE_FINALLY_FUNC_CLASS) \ + V(JSTaggedValue, PromiseValueThunkOrThrowerFunctionClass, \ + PROMISE_VALUE_THUNK_OR_THROWER_FUNCTION_CLASS) \ + V(JSTaggedValue, AsyncGeneratorResNextRetProRstFtnClass, \ + ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN_CLASS) \ + V(JSTaggedValue, AsyncFromSyncIterUnwarpClass, ASYNC_FROM_SYNC_ITER_UNWARP_CLASS) \ + V(JSTaggedValue, ProxyRevocFunctionClass, PROXY_REVOC_FUNCTION_CLASS) \ + V(JSTaggedValue, NativeErrorFunctionClass, NATIVE_ERROR_FUNCTION_CLASS) \ + V(JSTaggedValue, SpecificTypedArrayFunctionClass, SPERCIFIC_TYPED_ARRAY_FUNCTION_CLASS) \ + V(JSTaggedValue, ConstructorFunctionClass, CONSTRUCTOR_FUNCTION_CLASS) \ + V(JSTaggedValue, NormalFunctionClass, NORMAL_FUNCTION_CLASS) \ + V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ + V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ + V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ + V(JSTaggedValue, ListFormatLocales, LIST_FORMAT_LOCALES_INDEX) \ + V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) \ + V(JSTaggedValue, ModuleNamespaceClass, MODULENAMESPACE_CLASS) \ + V(JSTaggedValue, ObjectLiteralHClassCache, OBJECT_LITERAL_HCLASS_CACHE) \ + V(JSTaggedValue, WeakRefKeepObjects, WEAK_REF_KEEP_OBJECTS) \ + V(JSTaggedValue, FinRegLists, FIN_REG_LISTS) \ + V(JSTaggedValue, AttachSymbol, ATTACH_SYMBOL_INDEX) \ + V(JSTaggedValue, DetachSymbol, DETACH_SYMBOL_INDEX) \ + V(JSTaggedValue, CjsModuleFunction, CJS_MODULE_FUNCTION_INDEX) \ + V(JSTaggedValue, CjsExportsFunction, CJS_EXPORTS_FUNCTION_INDEX) \ + V(JSTaggedValue, CjsRequireFunction, CJS_REQUIRE_FUNCTION_INDEX) \ + V(JSTaggedValue, GlobalPatch, GLOBAL_PATCH) \ + V(JSTaggedValue, ExportOfScript, DEFAULT_EXPORT_OF_SCRIPT) \ + V(JSTaggedValue, JsonObjectHclassCache, JSON_OBJECT_HCLASS_CACHE) + +// Maintain the same order with DETECTOR_SYMBOL_LIST +#define GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \ + V(JSTaggedValue, ReplaceSymbol, REPLACE_SYMBOL_INDEX) \ + V(JSTaggedValue, SplitSymbol, SPLIT_SYMBOL_INDEX) \ + +#define GLOBAL_ENV_FIELDS(V) \ + GLOBAL_ENV_COMMON_FIELDS(V) \ + GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \ + GLOBAL_ENV_DETECTOR_FIELDS(V) + +namespace panda::ecmascript { +#define GLOBAL_ENV_FIELD_ENUM_ITEM(Type, Name, INDEX) INDEX, + enum class GlobalEnvField: uint8_t { + GLOBAL_ENV_FIELDS(GLOBAL_ENV_FIELD_ENUM_ITEM) + FINAL_INDEX + }; +#undef GLOBAL_ENV_FIELD_ENUM_ITEM +} // namespace panda::ecmascript +#endif // ECMASCRIPT_GLOBAL_ENV_FIELDS_H diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index f89960511c..6f7fe7a722 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -388,6 +388,40 @@ void JSThread::ResetGuardians() glueData_.stableArrayElementsGuardians_ = true; } +void JSThread::SetInitialBuiltinHClass(BuiltinTypeId type, JSHClass *builtinHClass, JSHClass *prototypeHClass) +{ + size_t index = BuiltinHClassEntries::GetEntryIndex(type); + auto &entry = glueData_.builtinHClassEntries_.entries[index]; + LOG_ECMA(DEBUG) << "JSThread::SetInitialBuiltinHClass: " + << "Builtin = " << ToString(type) + << ", builtinHClass = " << builtinHClass + << ", prototypeHClass = " << prototypeHClass; + entry.builtinHClass = builtinHClass; + entry.prototypeHClass = prototypeHClass; +} + +JSHClass *JSThread::GetBuiltinHClass(BuiltinTypeId type) const +{ + size_t index = BuiltinHClassEntries::GetEntryIndex(type); + return glueData_.builtinHClassEntries_.entries[index].builtinHClass; +} + +JSHClass *JSThread::GetBuiltinPrototypeHClass(BuiltinTypeId type) const +{ + size_t index = BuiltinHClassEntries::GetEntryIndex(type); + return glueData_.builtinHClassEntries_.entries[index].prototypeHClass; +} + +size_t JSThread::GetBuiltinHClassOffset(BuiltinTypeId type, bool isArch32) +{ + return GetGlueDataOffset() + GlueData::GetBuiltinHClassOffset(type, isArch32); +} + +size_t JSThread::GetBuiltinPrototypeHClassOffset(BuiltinTypeId type, bool isArch32) +{ + return GetGlueDataOffset() + GlueData::GetBuiltinPrototypeHClassOffset(type, isArch32); +} + void JSThread::CheckSwitchDebuggerBCStub() { auto isDebug = GetEcmaVM()->GetJsDebuggerManager()->IsDebugMode(); diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 719a7a6e0b..90a863af22 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -20,13 +20,11 @@ #include #include "ecmascript/base/aligned_struct.h" -#include "ecmascript/compiler/builtins/builtins_call_signature.h" -#include "ecmascript/compiler/common_stubs.h" -#include "ecmascript/compiler/interpreter_stub.h" -#include "ecmascript/compiler/rt_call_signature.h" #include "ecmascript/elements.h" #include "ecmascript/frames.h" #include "ecmascript/global_env_constants.h" +#include "ecmascript/js_thread_hclass_entries.h" +#include "ecmascript/js_thread_stub_entries.h" #include "ecmascript/mem/visitor.h" namespace panda::ecmascript { @@ -60,130 +58,6 @@ enum class BCStubStatus: uint8_t { enum class StableArrayChangeKind { PROTO, NOT_PROTO }; -struct BCStubEntries { - static constexpr size_t EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT = - kungfu::BytecodeStubCSigns::NUM_OF_ALL_NORMAL_STUBS; - // The number of bytecodes. - static constexpr size_t BC_HANDLER_COUNT = kungfu::BytecodeStubCSigns::LAST_VALID_OPCODE + 1; - static constexpr size_t COUNT = kungfu::BytecodeStubCSigns::NUM_OF_STUBS; - static_assert(EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT <= COUNT); - Address stubEntries_[COUNT] = {0}; - - static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; - static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; - - void Set(size_t index, Address addr) - { - ASSERT(index < COUNT); - stubEntries_[index] = addr; - } - - Address* GetAddr() - { - return reinterpret_cast(stubEntries_); - } - - Address Get(size_t index) const - { - ASSERT(index < COUNT); - return stubEntries_[index]; - } -}; -STATIC_ASSERT_EQ_ARCH(sizeof(BCStubEntries), BCStubEntries::SizeArch32, BCStubEntries::SizeArch64); - -struct RTStubEntries { - static constexpr size_t COUNT = kungfu::RuntimeStubCSigns::NUM_OF_STUBS; - Address stubEntries_[COUNT]; - - static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; - static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; - - void Set(size_t index, Address addr) - { - ASSERT(index < COUNT); - stubEntries_[index] = addr; - } - - Address Get(size_t index) const - { - ASSERT(index < COUNT); - return stubEntries_[index]; - } -}; -STATIC_ASSERT_EQ_ARCH(sizeof(RTStubEntries), RTStubEntries::SizeArch32, RTStubEntries::SizeArch64); - -struct COStubEntries { - static constexpr size_t COUNT = kungfu::CommonStubCSigns::NUM_OF_STUBS; - Address stubEntries_[COUNT]; - - static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; - static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; - - void Set(size_t index, Address addr) - { - ASSERT(index < COUNT); - stubEntries_[index] = addr; - } - - Address Get(size_t index) const - { - ASSERT(index < COUNT); - return stubEntries_[index]; - } -}; - -struct BCDebuggerStubEntries { - static constexpr size_t EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT = - kungfu::BytecodeStubCSigns::NUM_OF_ALL_NORMAL_STUBS; - static constexpr size_t COUNT = kungfu::BytecodeStubCSigns::LAST_VALID_OPCODE + 1; - Address stubEntries_[COUNT]; - - static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; - static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; - - void Set(size_t index, Address addr) - { - ASSERT(index < COUNT); - stubEntries_[index] = addr; - } - - Address Get(size_t index) const - { - ASSERT(index < COUNT); - return stubEntries_[index]; - } - - void SetNonexistentBCHandlerStubEntries(Address addr) - { - for (size_t i = EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT; i < COUNT; i++) { - if (stubEntries_[i] == 0) { - stubEntries_[i] = addr; - } - } - } -}; - -struct BuiltinStubEntries { - static constexpr size_t COUNT = kungfu::BuiltinsStubCSigns::NUM_OF_BUILTINS_STUBS; - Address stubEntries_[COUNT]; - - static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; - static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; - - void Set(size_t index, Address addr) - { - ASSERT(index < COUNT); - stubEntries_[index] = addr; - } - - Address Get(size_t index) const - { - ASSERT(index < COUNT); - return stubEntries_[index]; - } -}; -STATIC_ASSERT_EQ_ARCH(sizeof(COStubEntries), COStubEntries::SizeArch32, COStubEntries::SizeArch64); - class JSThread { public: static constexpr int CONCURRENT_MARKING_BITFIELD_NUM = 2; @@ -338,6 +212,21 @@ public: void ResetGuardians(); + void SetInitialBuiltinHClass(BuiltinTypeId type, JSHClass *builtinHClass, JSHClass *prototypeHClass); + + JSHClass *GetBuiltinHClass(BuiltinTypeId type) const; + + JSHClass *GetBuiltinPrototypeHClass(BuiltinTypeId type) const; + + static size_t GetBuiltinHClassOffset(BuiltinTypeId, bool isArch32); + + static size_t GetBuiltinPrototypeHClassOffset(BuiltinTypeId, bool isArch32); + + const BuiltinHClassEntries &GetBuiltinHClassEntries() const + { + return glueData_.builtinHClassEntries_; + } + JSTaggedValue GetCurrentLexenv() const; void RegisterRTInterface(size_t id, Address addr) @@ -742,6 +631,7 @@ public: RTStubEntries, COStubEntries, BuiltinStubEntries, + BuiltinHClassEntries, BCDebuggerStubEntries, base::AlignedUint64, base::AlignedPointer, @@ -768,6 +658,7 @@ public: RTStubEntriesIndex, COStubEntriesIndex, BuiltinsStubEntriesIndex, + BuiltinHClassEntriesIndex, BCDebuggerStubEntriesIndex, StateBitFieldIndex, FrameBaseIndex, @@ -855,6 +746,21 @@ public: return GetOffset(Index::BuiltinsStubEntriesIndex)>(isArch32); } + static size_t GetBuiltinHClassEntriesOffset(bool isArch32) + { + return GetOffset(Index::BuiltinHClassEntriesIndex)>(isArch32); + } + + static size_t GetBuiltinHClassOffset(BuiltinTypeId type, bool isArch32) + { + return GetBuiltinHClassEntriesOffset(isArch32) + BuiltinHClassEntries::GetBuiltinHClassOffset(type); + } + + static size_t GetBuiltinPrototypeHClassOffset(BuiltinTypeId type, bool isArch32) + { + return GetBuiltinHClassEntriesOffset(isArch32) + BuiltinHClassEntries::GetPrototypeHClassOffset(type); + } + static size_t GetBCDebuggerStubEntriesOffset(bool isArch32) { return GetOffset(Index::BCDebuggerStubEntriesIndex)>(isArch32); @@ -917,6 +823,7 @@ public: alignas(EAS) RTStubEntries rtStubEntries_; alignas(EAS) COStubEntries coStubEntries_; alignas(EAS) BuiltinStubEntries builtinStubEntries_; + alignas(EAS) BuiltinHClassEntries builtinHClassEntries_; alignas(EAS) BCDebuggerStubEntries bcDebuggerStubEntries_; alignas(EAS) volatile uint64_t gcStateBitField_ {0ULL}; alignas(EAS) JSTaggedType *frameBase_ {nullptr}; diff --git a/ecmascript/js_thread_hclass_entries.h b/ecmascript/js_thread_hclass_entries.h new file mode 100644 index 0000000000..aa995a6a43 --- /dev/null +++ b/ecmascript/js_thread_hclass_entries.h @@ -0,0 +1,84 @@ +/* + * 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_JS_THREAD_HCLASS_ENTRIES_H +#define ECMASCRIPT_JS_THREAD_HCLASS_ENTRIES_H + +#include +#include "ecmascript/common.h" +#include "ecmascript/ts_types/builtin_type_id.h" + +namespace panda::ecmascript { +class GlobalEnv; +class JSHClass; + +// Records initial HClass of builtin objects. +// Let X be the builtin object (e.g. X = Array, object, etc.), +// HClass address mismatch happens if properties in X or X.prototype are modified (with HClass change), +// thus the record entries are useful to detect builtin object modification. +struct BuiltinHClassEntries { +#define TS_BUILTIN_TYPE_ITEM(TYPE) BuiltinTypeId::TYPE, + static constexpr std::array BUILTIN_TYPES = { + TS_BUILTIN_TYPE_LIST(TS_BUILTIN_TYPE_ITEM) + }; + static constexpr size_t N_ENTRIES = static_cast(BuiltinTypeId::NUM_OF_BUILTIN_TYPES); +#undef TS_BUILTIN_TYPE_ITEM + + struct Entry { + // Let X be the builtin object (e.g. X = Array, Object, etc.) + // builtinHClass = HClass of X + JSHClass *builtinHClass = nullptr; + // prototypeHClass = HClass of X.prototype + JSHClass *prototypeHClass = nullptr; + }; + Entry entries[N_ENTRIES]; + + static size_t GetEntryIndex(BuiltinTypeId type) + { + size_t res = static_cast(type) - INDEX_OFFSET; + ASSERT(res < N_ENTRIES); + return res; + } + + size_t EntryIsValid(BuiltinTypeId type) const + { + size_t index = GetEntryIndex(type); + return entries[index].builtinHClass != nullptr && entries[index].prototypeHClass != nullptr; + } + + static size_t GetBuiltinHClassOffset(BuiltinTypeId type) + { + size_t index = GetEntryIndex(type); + return sizeof(Entry) * index + MEMBER_OFFSET(Entry, builtinHClass); + } + + static size_t GetPrototypeHClassOffset(BuiltinTypeId type) + { + size_t index = GetEntryIndex(type); + return sizeof(Entry) * index + MEMBER_OFFSET(Entry, prototypeHClass); + } + + static constexpr size_t SizeArch32 = sizeof(entries); + static constexpr size_t SizeArch64 = sizeof(entries); + +private: + static constexpr size_t INDEX_OFFSET = static_cast(BuiltinTypeId::BUILTIN_OFFSET) + 1; +}; +STATIC_ASSERT_EQ_ARCH(sizeof(BuiltinHClassEntries), + BuiltinHClassEntries::SizeArch32, + BuiltinHClassEntries::SizeArch64); +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JS_THREAD_HCLASS_ENTRIES_H diff --git a/ecmascript/js_thread_stub_entries.h b/ecmascript/js_thread_stub_entries.h new file mode 100644 index 0000000000..65238d12dc --- /dev/null +++ b/ecmascript/js_thread_stub_entries.h @@ -0,0 +1,148 @@ +/* + * 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_JS_THREAD_STUB_ENTRIES_H +#define ECMASCRIPT_JS_THREAD_STUB_ENTRIES_H + +#include "ecmascript/compiler/bc_call_signature.h" +#include "ecmascript/compiler/common_stubs.h" + +namespace panda::ecmascript { +struct BCStubEntries { + static constexpr size_t EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT = + kungfu::BytecodeStubCSigns::NUM_OF_ALL_NORMAL_STUBS; + // The number of bytecodes. + static constexpr size_t BC_HANDLER_COUNT = kungfu::BytecodeStubCSigns::LAST_VALID_OPCODE + 1; + static constexpr size_t COUNT = kungfu::BytecodeStubCSigns::NUM_OF_STUBS; + static_assert(EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT <= COUNT); + Address stubEntries_[COUNT] = {0}; + + static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; + static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; + + void Set(size_t index, Address addr) + { + ASSERT(index < COUNT); + stubEntries_[index] = addr; + } + + Address* GetAddr() + { + return reinterpret_cast(stubEntries_); + } + + Address Get(size_t index) const + { + ASSERT(index < COUNT); + return stubEntries_[index]; + } +}; +STATIC_ASSERT_EQ_ARCH(sizeof(BCStubEntries), BCStubEntries::SizeArch32, BCStubEntries::SizeArch64); + +struct RTStubEntries { + static constexpr size_t COUNT = kungfu::RuntimeStubCSigns::NUM_OF_STUBS; + Address stubEntries_[COUNT]; + + static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; + static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; + + void Set(size_t index, Address addr) + { + ASSERT(index < COUNT); + stubEntries_[index] = addr; + } + + Address Get(size_t index) const + { + ASSERT(index < COUNT); + return stubEntries_[index]; + } +}; +STATIC_ASSERT_EQ_ARCH(sizeof(RTStubEntries), RTStubEntries::SizeArch32, RTStubEntries::SizeArch64); + +struct COStubEntries { + static constexpr size_t COUNT = kungfu::CommonStubCSigns::NUM_OF_STUBS; + Address stubEntries_[COUNT]; + + static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; + static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; + + void Set(size_t index, Address addr) + { + ASSERT(index < COUNT); + stubEntries_[index] = addr; + } + + Address Get(size_t index) const + { + ASSERT(index < COUNT); + return stubEntries_[index]; + } +}; + +struct BCDebuggerStubEntries { + static constexpr size_t EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT = + kungfu::BytecodeStubCSigns::NUM_OF_ALL_NORMAL_STUBS; + static constexpr size_t COUNT = kungfu::BytecodeStubCSigns::LAST_VALID_OPCODE + 1; + Address stubEntries_[COUNT]; + + static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; + static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; + + void Set(size_t index, Address addr) + { + ASSERT(index < COUNT); + stubEntries_[index] = addr; + } + + Address Get(size_t index) const + { + ASSERT(index < COUNT); + return stubEntries_[index]; + } + + void SetNonexistentBCHandlerStubEntries(Address addr) + { + for (size_t i = EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT; i < COUNT; i++) { + if (stubEntries_[i] == 0) { + stubEntries_[i] = addr; + } + } + } +}; + +struct BuiltinStubEntries { + static constexpr size_t COUNT = kungfu::BuiltinsStubCSigns::NUM_OF_BUILTINS_STUBS; + Address stubEntries_[COUNT]; + + static constexpr size_t SizeArch32 = sizeof(uint32_t) * COUNT; + static constexpr size_t SizeArch64 = sizeof(uint64_t) * COUNT; + + void Set(size_t index, Address addr) + { + ASSERT(index < COUNT); + stubEntries_[index] = addr; + } + + Address Get(size_t index) const + { + ASSERT(index < COUNT); + return stubEntries_[index]; + } +}; +STATIC_ASSERT_EQ_ARCH(sizeof(COStubEntries), COStubEntries::SizeArch32, COStubEntries::SizeArch64); +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JS_THREAD_STUB_ENTRIES_H diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 6f3909aeba..7308e1b85d 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -390,12 +390,20 @@ void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, vo JSHandle ObjectFactory::NewEcmaHClass(uint32_t size, JSType type, const JSHandle &prototype, bool isOptimized, bool canFastCall) +{ + const int inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS; + return NewEcmaHClass(size, inlinedProps, type, prototype, isOptimized, canFastCall); +} + +JSHandle ObjectFactory::NewEcmaHClass(uint32_t size, uint32_t inlinedProps, JSType type, + const JSHandle &prototype, + bool isOptimized, bool canFastCall) { NewObjectHook(); uint32_t classSize = JSHClass::SIZE; auto *newClass = static_cast(heap_->AllocateNonMovableOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetHClassClass().GetTaggedObject()), classSize)); - newClass->Initialize(thread_, size, type, JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS, isOptimized, canFastCall); + newClass->Initialize(thread_, size, type, inlinedProps, isOptimized, canFastCall); JSHandle hclass(thread_, newClass); hclass->SetPrototype(thread_, prototype.GetTaggedValue()); return hclass; @@ -691,10 +699,10 @@ JSHandle ObjectFactory::CreateJSRegExpInstanceClass(JSHandle ObjectFactory::CreateJSArrayInstanceClass(JSHandle proto) +JSHandle ObjectFactory::CreateJSArrayInstanceClass(JSHandle proto, uint32_t inlinedProps) { const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - JSHandle arrayClass = NewEcmaHClass(JSArray::SIZE, JSType::JS_ARRAY, proto); + JSHandle arrayClass = NewEcmaHClass(JSArray::SIZE, inlinedProps, JSType::JS_ARRAY, proto); uint32_t fieldOrder = 0; ASSERT(JSArray::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 39e63adff9..0f551fb2c4 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -553,6 +553,9 @@ public: // used for creating jshclass in Builtins, Function, Class_Linker JSHandle NewEcmaHClass(uint32_t size, JSType type, const JSHandle &prototype, bool isOptimized = false, bool canFastCall = false); + JSHandle NewEcmaHClass(uint32_t size, uint32_t inlinedProps, JSType type, + const JSHandle &prototype, + bool isOptimized = false, bool canFastCall = false); // used for creating jshclass in Builtins, Function, Class_Linker JSHandle NewEcmaHClass(uint32_t size, JSType type, @@ -706,7 +709,8 @@ private: JSHandle NewEmptyArray(); // only used for EcmaVM. JSHandle CreateJSArguments(const JSHandle &env); - JSHandle CreateJSArrayInstanceClass(JSHandle proto); + JSHandle CreateJSArrayInstanceClass(JSHandle proto, + uint32_t inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS); JSHandle CreateJSRegExpInstanceClass(JSHandle proto); inline TaggedObject *AllocObjectWithSpaceType(size_t size, JSHClass *cls, MemSpaceType type); diff --git a/ecmascript/ts_types/builtin_type_id.h b/ecmascript/ts_types/builtin_type_id.h new file mode 100644 index 0000000000..9d0f81b808 --- /dev/null +++ b/ecmascript/ts_types/builtin_type_id.h @@ -0,0 +1,132 @@ +/* + * 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_TS_TYPES_BUILTIN_TYPE_ID_H +#define ECMASCRIPT_TS_TYPES_BUILTIN_TYPE_ID_H + +#include +#include + +#define TS_BUILTIN_TYPE_LIST(V) \ + V(FUNCTION) \ + V(RANGE_ERROR) \ + V(ERROR) \ + V(OBJECT) \ + V(SYNTAX_ERROR) \ + V(TYPE_ERROR) \ + V(REFERENCE_ERROR) \ + V(URI_ERROR) \ + V(SYMBOL) \ + V(EVAL_ERROR) \ + V(NUMBER) \ + V(PARSE_FLOAT) \ + V(DATE) \ + V(BOOLEAN) \ + V(BIG_INT) \ + V(PARSE_INT) \ + V(WEAK_MAP) \ + V(REG_EXP) \ + V(SET) \ + V(MAP) \ + V(WEAK_REF) \ + V(WEAK_SET) \ + V(FINALIZATION_REGISTRY) \ + V(ARRAY) \ + V(UINT8_CLAMPED_ARRAY) \ + V(UINT8_ARRAY) \ + V(TYPED_ARRAY) \ + V(INT8_ARRAY) \ + V(UINT16_ARRAY) \ + V(UINT32_ARRAY) \ + V(INT16_ARRAY) \ + V(INT32_ARRAY) \ + V(FLOAT32_ARRAY) \ + V(FLOAT64_ARRAY) \ + V(BIGINT64_ARRAY) \ + V(BIGUINT64_ARRAY) \ + V(SHARED_ARRAY_BUFFER) \ + V(DATA_VIEW) \ + V(STRING) \ + V(ARRAY_BUFFER) \ + V(EVAL) \ + V(IS_FINITE) \ + V(ARK_PRIVATE) \ + V(PRINT) \ + V(DECODE_URI) \ + V(DECODE_URI_COMPONENT) \ + V(IS_NAN) \ + V(ENCODE_URI) \ + V(JS_NAN) \ + V(GLOBAL_THIS) \ + V(ENCODE_URI_COMPONENT) \ + V(JS_INFINITY) \ + V(MATH) \ + V(JSON) \ + V(ATOMICS) \ + V(UNDEFINED) \ + V(REFLECT) \ + V(PROMISE) \ + V(PROXY) \ + V(GENERATOR_FUNCTION) \ + V(INTL) + +namespace panda::ecmascript { +#define TS_BUILTIN_TYPE_ENUM_ITEM(TYPE) TYPE, + +/* Since AOT allows loading lib_ark_builtins.d.ts optionally, the localId of the GlobalTSTypeRef + * (abbreviated as GT) of one builtin object will be different in different cases. + * + * In case where AOT does not load lib_ark_builtins.d.ts, builtin objects will be assigned localIds + * according to the following enum order. For example, the GT of FUNCTION will be (1, 21), where 1 + * is the index of builtin TSTypeTable. Note that in this case, it is prohibited to get TSType from + * builtin TSTypeTable. + * + * In case where AOT has loaded lib_ark_builtins.d.ts, builtin objects will be assigned localIds in + * the order in which they appear in bytecodes. To identify types of builtin objects, the following + * enum is required as a parameter to the TSManager::GetBuiltinOffset to help to get the GT of some + * builtin object. + */ +enum class BuiltinTypeId : uint8_t { // keep the same with enum BuiltinType in ets_frontend + NUM_INDEX_IN_SUMMARY = 0, + BUILTIN_OFFSET = 20, + TS_BUILTIN_TYPE_LIST(TS_BUILTIN_TYPE_ENUM_ITEM) + NUM_OF_BUILTIN_TYPES = INTL - BUILTIN_OFFSET, + TYPED_ARRAY_FIRST = UINT8_CLAMPED_ARRAY, + TYPED_ARRAY_LAST = BIGUINT64_ARRAY, +}; +#undef TS_BUILTIN_TYPE_ENUM_ITEM + +inline constexpr std::string_view ToString(BuiltinTypeId type) +{ +#define TS_BUILTIN_TYPE_SWITCH_CASE(TYPE) \ + case BuiltinTypeId::TYPE: \ + return #TYPE; + + switch (type) { + TS_BUILTIN_TYPE_LIST(TS_BUILTIN_TYPE_SWITCH_CASE) + default: + return "(Invalid BuiltinTypeId)"; + } +} + +inline constexpr bool IsTypedArrayType(BuiltinTypeId type) +{ + size_t index = static_cast(type); + size_t first = static_cast(BuiltinTypeId::TYPED_ARRAY_FIRST); + size_t last = static_cast(BuiltinTypeId::TYPED_ARRAY_LAST); + return first <= index && index <= last; +} +} // namespace panda::ecmascript +#endif // ECMASCRIPT_TS_TYPES_BUILTIN_TYPE_ID_H diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index c0927308dd..cd6b87ead1 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -1132,9 +1132,9 @@ std::string TSManager::GetBuiltinsName(uint32_t index) const return "Float32Array"; case BuiltinTypeId::FLOAT64_ARRAY: return "Float64Array"; - case BuiltinTypeId::BIG_INT64_ARRAY: + case BuiltinTypeId::BIGINT64_ARRAY: return "BigInt64Array"; - case BuiltinTypeId::BIG_UINT64_ARRAY: + case BuiltinTypeId::BIGUINT64_ARRAY: return "BigUint64Array"; case BuiltinTypeId::SHARED_ARRAY_BUFFER: return "SharedArrayBuffer"; diff --git a/ecmascript/ts_types/ts_manager.h b/ecmascript/ts_types/ts_manager.h index 9c09338403..e757e9b417 100644 --- a/ecmascript/ts_types/ts_manager.h +++ b/ecmascript/ts_types/ts_manager.h @@ -20,9 +20,10 @@ #include "ecmascript/compiler/compilation_driver.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/ts_types/builtin_type_id.h" #include "ecmascript/ts_types/global_ts_type_ref.h" -#include "ecmascript/ts_types/ts_obj_layout_info.h" #include "ecmascript/ts_types/global_type_info.h" +#include "ecmascript/ts_types/ts_obj_layout_info.h" namespace panda::ecmascript { using ProfileType = pgo::ProfileType; @@ -32,88 +33,6 @@ enum class PropertyType : uint8_t { OTHERS, }; -/* Since AOT allows loading lib_ark_builtins.d.ts optionally, the localId of the GlobalTSTypeRef - * (abbreviated as GT) of one builtin object will be different in different cases. - * - * In case where AOT does not load lib_ark_builtins.d.ts, builtin objects will be assigned localIds - * according to the following enum order. For example, the GT of FUNCTION will be (1, 21), where 1 - * is the index of builtin TSTypeTable. Note that in this case, it is prohibited to get TSType from - * builtin TSTypeTable. - * - * In case where AOT has loaded lib_ark_builtins.d.ts, builtin objects will be assigned localIds in - * the order in which they appear in bytecodes. To identify types of builtin objects, the following - * enum is required as a parameter to the TSManager::GetBuiltinOffset to help to get the GT of some - * builtin object. - */ -enum class BuiltinTypeId : uint8_t { // keep the same with enum BuiltinType in ets_frontend - NUM_INDEX_IN_SUMMARY = 0, - BUILTIN_OFFSET = 20, - FUNCTION, - RANGE_ERROR, - ERROR, - OBJECT, - SYNTAX_ERROR, - TYPE_ERROR, - REFERENCE_ERROR, - URI_ERROR, - SYMBOL, - EVAL_ERROR, - NUMBER, - PARSE_FLOAT, - DATE, - BOOLEAN, - BIG_INT, - PARSE_INT, - WEAK_MAP, - REG_EXP, - SET, - MAP, - WEAK_REF, - WEAK_SET, - FINALIZATION_REGISTRY, - ARRAY, - UINT8_CLAMPED_ARRAY, - UINT8_ARRAY, - TYPED_ARRAY, - INT8_ARRAY, - UINT16_ARRAY, - UINT32_ARRAY, - INT16_ARRAY, - INT32_ARRAY, - FLOAT32_ARRAY, - FLOAT64_ARRAY, - BIG_INT64_ARRAY, - BIG_UINT64_ARRAY, - SHARED_ARRAY_BUFFER, - DATA_VIEW, - STRING, - ARRAY_BUFFER, - EVAL, - IS_FINITE, - ARK_PRIVATE, - PRINT, - DECODE_URI, - DECODE_URI_COMPONENT, - IS_NAN, - ENCODE_URI, - JS_NAN, - GLOBAL_THIS, - ENCODE_URI_COMPONENT, - JS_INFINITY, - MATH, - JSON, - ATOMICS, - UNDEFINED, - REFLECT, - PROMISE, - PROXY, - GENERATOR_FUNCTION, - INTL, - NUM_OF_BUILTIN_TYPES = INTL - BUILTIN_OFFSET, - TYPED_ARRAY_FIRST = UINT8_CLAMPED_ARRAY, - TYPED_ARRAY_LAST = BIG_UINT64_ARRAY, -}; - struct ModuleInfo { const JSPandaFile *jsPandaFile {nullptr}; // there may be serval merged abc files. const CString recordName {""}; // distinguish different files which are all merged to one abc file. diff --git a/test/aottest/BUILD.gn b/test/aottest/BUILD.gn index 561d1e33e2..3cdaf6e2e5 100644 --- a/test/aottest/BUILD.gn +++ b/test/aottest/BUILD.gn @@ -138,6 +138,7 @@ group("ark_aot_ts_test") { "ldfunctionpref", "ldglobalvar", "ldobjbyname", + "ldobjbyname_typed_path", "ldobjbyvalue", "ldstlexvar", "ldsuperbyname", diff --git a/test/aottest/ldobjbyname_typed_path/BUILD.gn b/test/aottest/ldobjbyname_typed_path/BUILD.gn new file mode 100644 index 0000000000..388c3ebb1b --- /dev/null +++ b/test/aottest/ldobjbyname_typed_path/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_aot_test_action("ldobjbyname_typed_path") { + deps = [] +} diff --git a/test/aottest/ldobjbyname_typed_path/expect_output.txt b/test/aottest/ldobjbyname_typed_path/expect_output.txt new file mode 100644 index 0000000000..ab611bca01 --- /dev/null +++ b/test/aottest/ldobjbyname_typed_path/expect_output.txt @@ -0,0 +1,60 @@ +# 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. + +Testing Array literal: + - get length: 3 + - Array.prototype.reverse: 9,8,7 + - Array.prototype.shift: 9 +Testing new Array(): + - get length: 6 + - Array.prototype.slice: 11,12,13 + - Array.prototype.includes: true +Testing DataView: + - DataView.prototype.getInt32: 0 + - DataView.prototype.getFloat32: 0 +Testing Date: + - Date.prototype.setFullYear: 1664156730000 + - Date.prototype.toDateString: Mon Sep 26 2022 +Testing Map: + - get size: 3 + - Map.prototype.has: false + - Map.prototype.get: 1 +Testing Set: + - get size: 3 + - Set.prototype.has: false +Testing string literal: + - get length: 21 + - String.prototype.charAt: a + - String.prototype.substring: string literal +Testing new String(): + - get length: 22 + - String.prototype.indexOf: 7 + - String.prototype.startsWith: true +Testing Int16Array: + - get length: 3 + - Int16Array.prototype.indexOf: 2 + - Int16Array.prototype.join: 1 - 2 - 3 +Testing BigUint64Array: + - get length: 3 + - BigUint64Array.prototype.includes: false + - BigUint64Array.prototype.lastIndexOf: 0 +Testing object literal with prototype changed (via obj.__proto__): + - obj.substring: obj.substring +Testing Array with prototype changed (via arr.__proto__): + - arr.substring: arr.substring +Testing with Array.prototype.pop changed to another function: + - Array.prototype.pop: Array.prototype.pop changed to another function. +Testing with Array.prototype.pop changed to a string: + - Array.prototype.pop: Array.prototype.pop changed to a string. +Testing with Array.prototype.pop changed to a getter: + - Array.prototype.pop: Array.prototype.pop changed to a getter. diff --git a/test/aottest/ldobjbyname_typed_path/ldobjbyname_typed_path.ts b/test/aottest/ldobjbyname_typed_path/ldobjbyname_typed_path.ts new file mode 100644 index 0000000000..61e387194b --- /dev/null +++ b/test/aottest/ldobjbyname_typed_path/ldobjbyname_typed_path.ts @@ -0,0 +1,149 @@ +/* + * 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. + */ + +declare function print(...args: any[]): void; + +// Test Array.prototype methods +{ + // May be slow path (since the type of arrayLiteral is not marked explicitly) + print("Testing Array literal:"); + let arrayLiteral = [7, 8, 9]; + print(" - get length: ", arrayLiteral.length); + print(" - Array.prototype.reverse: ", arrayLiteral.reverse()); // arr = [9, 8, 7] + print(" - Array.prototype.shift: ", arrayLiteral.shift()); // return: 9, arr = [8, 7] + + // Expects AOT typed path. + print("Testing new Array():"); + let newArrayNumber = new Array(10, 11, 12, 13, 14, 15); + print(" - get length: ", newArrayNumber.length); + print(" - Array.prototype.slice: ", newArrayNumber.slice(1, 4)); // return: [11, 12, 13] + print(" - Array.prototype.includes: ", newArrayNumber.includes(12)); // return: true +} +// Test DataView.prototype.methods +// Expects AOT typed path +{ + print("Testing DataView:"); + let data = new ArrayBuffer(16); + let dataView = new DataView(data); + print(" - DataView.prototype.getInt32: ", dataView.getInt32(0)); // return: 0 + print(" - DataView.prototype.getFloat32: ", dataView.getBigInt64(8)); // return: 0 +} +// Test Date.prototype methods +// Expects AOT typed path. +{ + print("Testing Date:"); + let date = new Date(2023, 8, 26, 9, 45, 30); // 2023/9/26 9:45:30 + print(" - Date.prototype.setFullYear: ", date.setFullYear(2022)); // return: 1664156730000 + print(" - Date.prototype.toDateString: ", date.toDateString()); // return: 'Mon Sep 26 2022' +} +// Test Map.prototype methods +// Expects AOT typed path. +{ + print("Testing Map:"); + let map = new Map([ + ['a', 1], + ['b', 2], + ['c', 3] + ]); + print(" - get size: ", map.size); + print(" - Map.prototype.has: ", map.has('A')); // return: false + print(" - Map.prototype.get: ", map.get('a')); // return: 1 +} +// Test Set.prototype methods +// Expects AOT typed path. +{ + print("Testing Set:"); + let set = new Set([1, 2, 3]); + print(" - get size: ", set.size); // return: 3 + print(" - Set.prototype.has: ", set.has(4)); // return: false +} +// Test String.prototype.methods +{ + // Expects AOT typed path. + print("Testing string literal:"); + let strLiteral = "I am a string literal"; + print(" - get length: ", strLiteral.length); + print(" - String.prototype.charAt: ", strLiteral.charAt(2)); // return: 'a' + print(" - String.prototype.substring: ", strLiteral.substring(7)); // return: 'string literal' + + // May be slow path (since JS_PRIMITIVE_REF is not included in type paths currently) + print("Testing new String():"); + let newString = new String("I am a String instance"); + print(" - get length: ", newString.length); + print(" - String.prototype.indexOf: ", newString.indexOf("String")); // return: 7 + print(" - String.prototype.startsWith: ", newString.startsWith("I am a")); // return: true +} +// Test %TypedArray%.prototype methods +// Expects AOT typed path +{ + print("Testing Int16Array:"); + let i16Array = new Int16Array([1, 2, 3]); + print(" - get length: ", i16Array.length); + print(" - Int16Array.prototype.indexOf: ", i16Array.indexOf(3)); // return: 2 + print(" - Int16Array.prototype.join: ", i16Array.join(' - ')); // return: '1 - 2 - 3' + + print("Testing BigUint64Array:"); + let u64Array = new BigUint64Array([4n, 5n, 6n]); + print(" - get length: ", u64Array.length); + print(" - BigUint64Array.prototype.includes: ", u64Array.includes(7n)); // return: false + print(" - BigUint64Array.prototype.lastIndexOf: ", u64Array.lastIndexOf(4n)); // return: 0 +} +// Test object literal with prototype changes. +{ + print("Testing object literal with prototype changed (via obj.__proto__):"); + let obj = { + substring: function() { + return "obj.substring"; + } + }; + obj.__proto__ = String.prototype; + print(" - obj.substring: ", obj.substring()); // return: 'obj.substring' +} +// Test instance of type A whose prototype is changed to B.prototype +{ + print("Testing Array with prototype changed (via arr.__proto__):"); + let arr: Array = [7, 8, 9]; + arr.substring = function() { + return "arr.substring"; + }; + arr.__proto__ = String.prototype; + print(" - arr.substring: ", arr.substring()); // return: 'arr.substring' +} +// Test modifying properties Array.prototype +// Expects AOT Typed path (if array stability is kept) since HClass of Array.prototype is not changed +Array.prototype.pop = function (): any { + return "Array.prototype.pop changed to another function."; +}; +{ + print("Testing with Array.prototype.pop changed to another function:"); + let arr: Array = [1, 2, 3]; + print(" - Array.prototype.pop: ", arr.pop()); +} +// Expects AOT Typed path (if array stability is kept) since HClass of Array.prototype is still not changed +Object.defineProperty(Array.prototype, 'pop', { value: "Array.prototype.pop changed to a string." }); +{ + print("Testing with Array.prototype.pop changed to a string:"); + let arr: Array = [1, 2, 3]; + print(" - Array.prototype.pop: ", arr.pop); +} +// Expects de-opt due to HClass of Array.prototype mismatch +Object.defineProperty(Array.prototype, 'pop', { + get() { return "Array.prototype.pop changed to a getter."; } +}); +{ + print("Testing with Array.prototype.pop changed to a getter:"); + let arr: Array = [1, 2, 3]; + print(" - Array.prototype.pop: ", arr.pop); +} From 3f67e23bb638f2f9567dbc21778877fedef9a1fb Mon Sep 17 00:00:00 2001 From: K0u1hw Date: Thu, 12 Oct 2023 14:54:14 +0800 Subject: [PATCH 19/50] Bugfix for GetObjectLiteralFromCache Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87JDX Signed-off-by: K0u1hw Change-Id: I751881fdddb4d1d49699ecd29c2a6a6dbe0c39a3 --- ecmascript/compiler/circuit_builder.cpp | 9 ++++++++- ecmascript/jspandafile/program_object.h | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index d094e50fdb..a2329a99db 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -26,6 +26,7 @@ #include "ecmascript/global_env.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_function.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/mem/region.h" #include "ecmascript/method.h" @@ -563,13 +564,19 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga } } else if (type == ConstPoolType::OBJECT_LITERAL) { Label isAOTLiteralInfo(env_); - Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); + Label notAotLiteralInfo(env_); + Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, ¬AotLiteralInfo); Bind(&isAOTLiteralInfo); { result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index), module }, hirGate); Jump(&exit); } + Bind(¬AotLiteralInfo); + { + result = GetValueFromTaggedArray(cacheValue, Int32(ConstantPool::OBJECT_LITERAL_INFO_OBJECT_INDEX)); + Jump(&exit); + } } else { Jump(&exit); } diff --git a/ecmascript/jspandafile/program_object.h b/ecmascript/jspandafile/program_object.h index 5f65901c38..ec9f08c15c 100644 --- a/ecmascript/jspandafile/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -309,7 +309,7 @@ public: JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); bool hasMethod = false; size_t propertiesLen = properties->GetLength(); - for (size_t i = 0; i < propertiesLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { // 2: Each literal buffer has a pair of key-value. + for (size_t i = 0; i < propertiesLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { key.Update(properties->Get(i)); if (key->IsHole()) { break; @@ -320,7 +320,7 @@ public: } } size_t elementsLen = elements->GetLength(); - for (size_t i = 0; i < elementsLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { // 2: Each literal buffer has a pair of key-value. + for (size_t i = 0; i < elementsLen; i += ConstantPool::KEY_VALUE_PAIR_SIZE) { key.Update(elements->Get(i)); if (key->IsHole()) { break; From 34a00d5a77fa91c7da0534bd77b0f6153d687ad4 Mon Sep 17 00:00:00 2001 From: edwardcaoyue Date: Thu, 12 Oct 2023 17:01:58 +0800 Subject: [PATCH 20/50] qos migrate from frame_aware_sched to qos_manager Signed-off-by: edwardcaoyue Change-Id: Ie18a16243cd32599f05d67bfaab75d745ef3cacf --- BUILD.gn | 4 ++-- bundle.json | 2 +- ecmascript/taskpool/runner.cpp | 2 +- js_runtime_config.gni | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index cf3d38d741..78170b1075 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -979,7 +979,7 @@ ohos_source_set("libark_jsruntime_set") { if (is_ohos && is_standard_system && product_name != "ohos-sdk") { if (!is_cross_platform_build) { defines += [ "ENABLE_QOS" ] - external_deps += [ "frame_aware_sched:qos_manager" ] + external_deps += [ "qos_manager:qos" ] } } @@ -1069,7 +1069,7 @@ ohos_source_set("libark_jsruntime_test_set") { if (is_ohos && is_standard_system && product_name != "ohos-sdk") { if (!is_cross_platform_build) { defines += [ "ENABLE_QOS" ] - external_deps += [ "frame_aware_sched:qos_manager" ] + external_deps += [ "qos_manager:qos" ] } } diff --git a/bundle.json b/bundle.json index 135711abeb..02390d7718 100644 --- a/bundle.json +++ b/bundle.json @@ -23,9 +23,9 @@ "deps": { "components": [ "faultloggerd", - "frame_aware_sched", "hitrace", "hilog", + "qos_manager", "runtime_core", "c_utils", "code_signature" diff --git a/ecmascript/taskpool/runner.cpp b/ecmascript/taskpool/runner.cpp index f67b365a55..26a05a6533 100644 --- a/ecmascript/taskpool/runner.cpp +++ b/ecmascript/taskpool/runner.cpp @@ -70,7 +70,7 @@ void Runner::SetQosPriority([[maybe_unused]] bool isForeground) #ifdef ENABLE_QOS if (isForeground) { for (uint32_t threadId : gcThreadId_) { - OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::qos_user_initiated, threadId); + OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::QOS_USER_INITIATED, threadId); } } else { for (uint32_t threadId : gcThreadId_) { diff --git a/js_runtime_config.gni b/js_runtime_config.gni index 93b28211d3..02827c7c97 100644 --- a/js_runtime_config.gni +++ b/js_runtime_config.gni @@ -36,7 +36,7 @@ ark_root = "//arkcompiler/runtime_core" js_root = "//arkcompiler/ets_runtime" global_root = "//base/global/i18n" hilog_root = "//base/hiviewdfx/hilog/interfaces/native/innerkits" -qos_root = "//foundation/resourceschedule/frame_aware_sched" +qos_root = "//foundation/resourceschedule/qos_manager" compile_llvm_online = false run_with_asan = false enable_leak_check = false From b4519666d41ba8c9f4e8771fbadf89fa45d9c879 Mon Sep 17 00:00:00 2001 From: liu-zelin Date: Thu, 12 Oct 2023 17:10:22 +0800 Subject: [PATCH 21/50] fix typo in runtime_mode judgement Signed-off-by: liu-zelin Change-Id: I2aed7c763132f8d3499e2c094181bd96fc4794f1 --- js_runtime_config.gni | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/js_runtime_config.gni b/js_runtime_config.gni index ae771a9688..7074fee992 100644 --- a/js_runtime_config.gni +++ b/js_runtime_config.gni @@ -43,10 +43,9 @@ enable_cow_array = true enable_coverage = false enable_asm_assert = false ark_compile_mode = "debug" -if (is_cross_platform_build) { - if (defined(runtime_mode) && runtime_mode == "relase") { - ark_compile_mode = "release" - } +if (is_cross_platform_build && defined(runtime_mode) && + runtime_mode == "release") { + ark_compile_mode = "release" } asan_lib_path = "/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux" From ccf5348bb73c63ce571b3abbacb20a3f02b51843 Mon Sep 17 00:00:00 2001 From: zWX1234017 Date: Mon, 9 Oct 2023 11:15:26 +0800 Subject: [PATCH 22/50] =?UTF-8?q?=E6=96=B0=E5=A2=9EToBigInt=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I86EBH Signed-off-by: zWX1234017 --- ecmascript/napi/include/jsnapi.h | 2 ++ ecmascript/napi/jsnapi.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 23956147c6..10e33e9cb3 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -44,6 +44,7 @@ class Local; class JSValueRef; class PrimitiveRef; class ArrayRef; +class BigIntRef; class StringRef; class ObjectRef; class FunctionRef; @@ -401,6 +402,7 @@ public: Local ToNumber(const EcmaVM *vm); Local ToBoolean(const EcmaVM *vm); + Local ToBigInt(const EcmaVM *vm); Local ToString(const EcmaVM *vm); Local ToObject(const EcmaVM *vm); Local ToNativePointer(const EcmaVM *vm); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 2fec514759..966e972ca5 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -2995,6 +2995,16 @@ Local JSValueRef::ToBoolean(const EcmaVM *vm) return JSNApiHelper::ToLocal(booleanObj); } +Local JSValueRef::ToBigInt(const EcmaVM *vm) +{ + CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); + JSThread *thread = vm->GetJSThread(); + JSHandle obj = JSNApiHelper::ToJSHandle(this); + LOG_IF_SPECIAL(obj, ERROR); + JSHandle bigIntObj(thread, JSTaggedValue::ToBigInt(thread, obj)); + return JSNApiHelper::ToLocal(bigIntObj); +} + Local JSValueRef::ToNumber(const EcmaVM *vm) { CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); From 0793413be4a638316f4dafbb67b92841f7c36146 Mon Sep 17 00:00:00 2001 From: lukai Date: Wed, 27 Sep 2023 14:40:32 +0800 Subject: [PATCH 23/50] Support typedarray pgo Implement typedarray ic for pgo Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84SEM?from=project-issue Signed-off-by: lukai Change-Id: Id2ca267ecd8569ecfe20c465895b288967f886a8 --- ecmascript/compiler/ic_stub_builder.cpp | 22 +++- ecmascript/compiler/stub_builder-inl.h | 9 ++ ecmascript/compiler/stub_builder.cpp | 12 +++ ecmascript/compiler/stub_builder.h | 1 + .../compiler/typed_array_stub_builder.cpp | 82 ++++++++++++++ .../compiler/typed_array_stub_builder.h | 3 + ecmascript/ic/ic_handler.h | 16 +++ ecmascript/ic/ic_runtime.cpp | 100 +++++++++++++++++- ecmascript/ic/ic_runtime.h | 4 + ecmascript/ic/ic_runtime_stub-inl.h | 40 ++++++- ecmascript/ic/ic_runtime_stub.h | 3 + ecmascript/js_hclass.h | 2 +- ecmascript/pgo_profiler/pgo_profiler.cpp | 4 +- test/moduletest/typearray/typearray.js | 23 +++- 14 files changed, 311 insertions(+), 10 deletions(-) diff --git a/ecmascript/compiler/ic_stub_builder.cpp b/ecmascript/compiler/ic_stub_builder.cpp index 068c8d08f2..468847802e 100644 --- a/ecmascript/compiler/ic_stub_builder.cpp +++ b/ecmascript/compiler/ic_stub_builder.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/compiler/ic_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" +#include "ecmascript/compiler/typed_array_stub_builder.h" namespace panda::ecmascript::kungfu { void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler) @@ -161,6 +162,7 @@ void ICStubBuilder::LoadICByValue( Label handlerInfoNotElement(env); Label handlerInfoIsStringElement(env); Label handlerInfoNotStringElement(env); + Label handlerInfoIsTypedArrayElement(env); Label exit(env); SetLabels(tryFastPath, slowPath, success); @@ -182,11 +184,23 @@ void ICStubBuilder::LoadICByValue( Bind(&handlerInfoNotElement); { Branch(IsStringElement(handlerInfo), &handlerInfoIsStringElement, &handlerInfoNotStringElement); - Bind(&handlerInfoNotStringElement); - Jump(&exit); Bind(&handlerInfoIsStringElement); - ret = LoadStringElement(glue_, receiver_, propKey_); - Jump(&exit); + { + ret = LoadStringElement(glue_, receiver_, propKey_); + Jump(&exit); + } + Bind(&handlerInfoNotStringElement); + { + Branch(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArrayElement, &exit); + Bind(&handlerInfoIsTypedArrayElement); + { + GateRef hclass = LoadHClass(receiver_); + GateRef jsType = GetObjectType(hclass); + TypedArrayStubBuilder typedArrayBuilder(reinterpret_cast(this)); + ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType); + Jump(&exit); + } + } } } Bind(&loadWithHandler); diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index e677d080e3..d1908b991c 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1425,6 +1425,15 @@ inline GateRef StubBuilder::IsStringLength(GateRef attr) Int32(HandlerBase::HandlerKind::STRING_LENGTH)); } +inline GateRef StubBuilder::IsTypedArrayElement(GateRef attr) +{ + return Int32Equal( + Int32And( + Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), + Int32(HandlerBase::HandlerKind::TYPED_ARRAY)); +} + inline GateRef StubBuilder::IsNonExist(GateRef attr) { return Int32Equal( diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index beaf2fe0d6..dc5e305879 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -1784,6 +1784,8 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, Label exit(env); Label indexLessZero(env); Label indexNotLessZero(env); + Label handlerInfoIsTypedArray(env); + Label handerInfoNotTypedArray(env); Label handerInfoIsJSArray(env); Label handerInfoNotJSArray(env); Label isJsCOWArray(env); @@ -1824,6 +1826,16 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, Bind(&handlerIsInt); { GateRef handlerInfo = GetInt32OfTInt(*varHandler); + Branch(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArray, &handerInfoNotTypedArray); + Bind(&handlerInfoIsTypedArray); + { + GateRef hclass = LoadHClass(receiver); + GateRef jsType = GetObjectType(hclass); + TypedArrayStubBuilder typedArrayBuilder(this); + result = typedArrayBuilder.StoreTypedArrayElement(glue, receiver, index64, value, jsType); + Jump(&exit); + } + Bind(&handerInfoNotTypedArray); Branch(HandlerBaseIsJSArray(handlerInfo), &handerInfoIsJSArray, &handerInfoNotJSArray); Bind(&handerInfoIsJSArray); { diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index e353ac05e1..88e828a5ad 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -330,6 +330,7 @@ public: GateRef IsElement(GateRef attr); GateRef IsStringElement(GateRef attr); GateRef IsStringLength(GateRef attr); + GateRef IsTypedArrayElement(GateRef attr); GateRef IsNonExist(GateRef attr); GateRef IsJSAPIVector(GateRef attr); GateRef IsJSAPIStack(GateRef obj); diff --git a/ecmascript/compiler/typed_array_stub_builder.cpp b/ecmascript/compiler/typed_array_stub_builder.cpp index 9df29670fb..d2182732bb 100644 --- a/ecmascript/compiler/typed_array_stub_builder.cpp +++ b/ecmascript/compiler/typed_array_stub_builder.cpp @@ -78,6 +78,88 @@ GateRef TypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf) return ret; } +GateRef TypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRef index) +{ + auto env = GetEnvironment(); + Label entryPass(env); + env->SubCfgEntry(&entryPass); + DEFVARIABLE(result, VariableType::BOOL(), False()); + Label exit(env); + Label indexIsvalid(env); + Label indexNotLessZero(env); + Branch(Int64LessThan(index, Int64(0)), &exit, &indexNotLessZero); + Bind(&indexNotLessZero); + { + GateRef arrLen = GetArrayLength(array); + Branch(Int64GreaterThanOrEqual(index, ZExtInt32ToInt64(arrLen)), &exit, &indexIsvalid); + Bind(&indexIsvalid); + { + result = True(); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef TypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType) +{ + auto env = GetEnvironment(); + Label entryPass(env); + env->SubCfgEntry(&entryPass); + DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); + Label exit(env); + Label notDetached(env); + Label indexIsvalid(env); + GateRef buffer = GetViewedArrayBuffer(array); + Branch(IsDetachedBuffer(buffer), &exit, ¬Detached); + Bind(¬Detached); + { + GateRef index = TryToElementsIndex(glue, key); + Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit); + Bind(&indexIsvalid); + { + GateRef offset = GetByteOffset(array); + result = GetValueFromBuffer(buffer, TruncInt64ToInt32(index), offset, jsType); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef TypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, + GateRef jsType) +{ + auto env = GetEnvironment(); + Label entryPass(env); + env->SubCfgEntry(&entryPass); + DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); + Label exit(env); + Label notDetached(env); + Label indexIsvalid(env); + GateRef buffer = GetViewedArrayBuffer(array); + Branch(IsDetachedBuffer(buffer), &exit, ¬Detached); + Bind(¬Detached); + { + Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit); + Bind(&indexIsvalid); + { + result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex), + { array, IntToTaggedInt(index), value, IntToTaggedInt(jsType) }); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + GateRef TypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/typed_array_stub_builder.h b/ecmascript/compiler/typed_array_stub_builder.h index 6bfa831bb3..6b5b8f5e5e 100644 --- a/ecmascript/compiler/typed_array_stub_builder.h +++ b/ecmascript/compiler/typed_array_stub_builder.h @@ -31,6 +31,9 @@ public: void GenerateCircuit() override {} GateRef FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType); GateRef FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array); + GateRef LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType); + GateRef StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, GateRef jsType); + GateRef CheckTypedArrayIndexInRange(GateRef array, GateRef index); GateRef GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType); GateRef IsDetachedBuffer(GateRef buffer); GateRef GetDataPointFromBuffer(GateRef arrBuf); diff --git a/ecmascript/ic/ic_handler.h b/ecmascript/ic/ic_handler.h index c6abc7e874..7560e967c5 100644 --- a/ecmascript/ic/ic_handler.h +++ b/ecmascript/ic/ic_handler.h @@ -31,7 +31,9 @@ public: DICTIONARY, STRING, STRING_LENGTH, + TYPED_ARRAY, NON_EXIST, + TOTAL_KINDS, }; using KindBit = BitField; @@ -43,6 +45,8 @@ public: using RepresentationBit = OffsetBit::NextField; using AttrIndexBit = RepresentationBit::NextField; + static_assert(static_cast(HandlerKind::TOTAL_KINDS) <= (1 << KIND_BIT_LENGTH)); + HandlerBase() = default; virtual ~HandlerBase() = default; @@ -86,6 +90,11 @@ public: return GetKind(handler) == HandlerKind::STRING; } + static inline bool IsTypedArrayElement(uint32_t handler) + { + return GetKind(handler) == HandlerKind::TYPED_ARRAY; + } + static inline bool IsDictionary(uint32_t handler) { return GetKind(handler) == HandlerKind::DICTIONARY; @@ -186,6 +195,13 @@ public: KindBit::Set(HandlerKind::STRING, &handler); return JSHandle(thread, JSTaggedValue(handler)); } + + static inline JSHandle LoadTypedArrayElement(const JSThread *thread) + { + uint32_t handler = 0; + KindBit::Set(HandlerKind::TYPED_ARRAY, &handler); + return JSHandle(thread, JSTaggedValue(handler)); + } }; class StoreHandler final : public HandlerBase { diff --git a/ecmascript/ic/ic_runtime.cpp b/ecmascript/ic/ic_runtime.cpp index 5d268ba49a..4aebc7ac8b 100644 --- a/ecmascript/ic/ic_runtime.cpp +++ b/ecmascript/ic/ic_runtime.cpp @@ -89,6 +89,16 @@ void ICRuntime::UpdateLoadStringHandler(JSHandle receiver) icAccessor_.AddElementHandler(JSHandle::Cast(hclass), handlerValue); } +void ICRuntime::UpdateTypedArrayHandler(JSHandle receiver) +{ + if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) { + return; + } + JSHandle handlerValue = LoadHandler::LoadTypedArrayElement(thread_); + JSHandle hclass(GetThread(), receiver->GetTaggedObject()->GetClass()); + icAccessor_.AddElementHandler(JSHandle::Cast(hclass), handlerValue); +} + void ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle key, JSHandle receiver) { @@ -162,7 +172,9 @@ JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle receiver, JSH RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue(); } - + if (receiver->IsTypedArray()) { + return LoadTypedArrayValueMiss(receiver, key); + } ObjectOperator op(GetThread(), receiver, key); auto result = JSHandle(thread_, JSObject::GetProperty(GetThread(), &op)); @@ -243,6 +255,45 @@ JSTaggedValue LoadICRuntime::LoadMiss(JSHandle receiver, JSHandle return result.GetTaggedValue(); } +JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle receiver, JSHandle key) +{ + JSHandle propKey = JSTaggedValue::ToPropertyKey(GetThread(), key); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + if (!numericIndex.IsUndefined()) { + if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || !GetThread()->GetEcmaVM()->ICEnabled()) { + icAccessor_.SetAsMega(); + return JSTaggedValue::GetProperty(GetThread(), receiver, propKey).GetValue().GetTaggedValue(); + } + UpdateTypedArrayHandler(receiver); + JSHandle indexHandle(GetThread(), numericIndex); + uint32_t index = static_cast(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32()); + JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType(); + return JSTypedArray::FastGetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index, type); + } else { + ObjectOperator op(GetThread(), receiver, key); + auto result = JSHandle(GetThread(), JSObject::GetProperty(GetThread(), &op)); + if (op.GetValue().IsInternalAccessor()) { + op = ObjectOperator(GetThread(), receiver, key); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + // ic-switch + if (!GetThread()->GetEcmaVM()->ICEnabled()) { + icAccessor_.SetAsMega(); + return result.GetTaggedValue(); + } + TraceIC(receiver, key); + // do not cache element + if (!op.IsFastMode()) { + icAccessor_.SetAsMega(); + return result.GetTaggedValue(); + } + UpdateLoadHandler(op, key, receiver); + return result.GetTaggedValue(); + } +} + JSTaggedValue StoreICRuntime::StoreMiss(JSHandle receiver, JSHandle key, JSHandle value) { @@ -251,6 +302,9 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle receiver, JSHand bool success = JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true); return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception(); } + if (receiver->IsTypedArray()) { + return StoreTypedArrayValueMiss(receiver, key, value); + } ICKind kind = GetICKind(); // global variable find from global record firstly @@ -296,4 +350,48 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle receiver, JSHand } return JSTaggedValue::Exception(); } + +JSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle receiver, JSHandle key, + JSHandle value) +{ + JSHandle propKey = JSTaggedValue::ToPropertyKey(GetThread(), key); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + if (!numericIndex.IsUndefined()) { + if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || value->IsECMAObject() || + !GetThread()->GetEcmaVM()->ICEnabled()) { + icAccessor_.SetAsMega(); + bool success = JSTaggedValue::SetProperty(GetThread(), receiver, propKey, value, true); + return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception(); + } + UpdateTypedArrayHandler(receiver); + JSHandle indexHandle(GetThread(), numericIndex); + uint32_t index = static_cast(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32()); + JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType(); + return JSTypedArray::FastSetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index, + value.GetTaggedValue(), type); + } else { + UpdateReceiverHClass(JSHandle(GetThread(), JSHandle::Cast(receiver)->GetClass())); + ObjectOperator op(GetThread(), receiver, key); + bool success = JSObject::SetProperty(&op, value, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread()); + // ic-switch + if (!GetThread()->GetEcmaVM()->ICEnabled()) { + icAccessor_.SetAsMega(); + return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception(); + } + TraceIC(receiver, key); + // do not cache element + if (!op.IsFastMode()) { + icAccessor_.SetAsMega(); + return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception(); + } + if (success) { + UpdateStoreHandler(op, key, receiver); + return JSTaggedValue::Undefined(); + } + return JSTaggedValue::Exception(); + } +} } // namespace panda::ecmascript diff --git a/ecmascript/ic/ic_runtime.h b/ecmascript/ic/ic_runtime.h index 54ae9b881f..14085ea2b3 100644 --- a/ecmascript/ic/ic_runtime.h +++ b/ecmascript/ic/ic_runtime.h @@ -38,6 +38,7 @@ public: void UpdateLoadHandler(const ObjectOperator &op, JSHandle key, JSHandle receiver); void UpdateLoadStringHandler(JSHandle receiver); + void UpdateTypedArrayHandler(JSHandle receiver); void UpdateStoreHandler(const ObjectOperator &op, JSHandle key, JSHandle receiver); JSThread *GetThread() const @@ -74,6 +75,7 @@ public: JSTaggedValue LoadMiss(JSHandle receiver, JSHandle key); JSTaggedValue LoadValueMiss(JSHandle receiver, JSHandle key); + JSTaggedValue LoadTypedArrayValueMiss(JSHandle receiver, JSHandle key); }; class StoreICRuntime : public ICRuntime { @@ -87,6 +89,8 @@ public: JSTaggedValue StoreMiss(JSHandle receiver, JSHandle key, JSHandle value); + JSTaggedValue StoreTypedArrayValueMiss(JSHandle receiver, JSHandle key, + JSHandle value); }; } // namespace panda::ecmascript diff --git a/ecmascript/ic/ic_runtime_stub-inl.h b/ecmascript/ic/ic_runtime_stub-inl.h index 2356b87ff5..bbf5a56fd3 100644 --- a/ecmascript/ic/ic_runtime_stub-inl.h +++ b/ecmascript/ic/ic_runtime_stub-inl.h @@ -115,6 +115,8 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTag if (firstValue.GetWeakReferentUnChecked() == hclass) { if (HandlerBase::IsElement(secondValue.GetInt())) { return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key); + } else if (HandlerBase::IsTypedArrayElement(secondValue.GetInt())) { + return LoadTypedArrayElement(thread, receiver, key); } ASSERT(HandlerBase::IsStringElement(secondValue.GetInt())); return LoadStringElement(thread, receiver, key); @@ -443,6 +445,8 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *threa auto handlerInfo = static_cast(handler.GetInt()); if (HandlerBase::IsElement(handlerInfo)) { return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key); + } else if (HandlerBase::IsTypedArrayElement(handlerInfo)) { + return LoadTypedArrayElement(thread, receiver, key); } ASSERT(HandlerBase::IsStringElement(handlerInfo)); return LoadStringElement(thread, receiver, key); @@ -488,6 +492,22 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadStringElement(JSThread *thread, JSTa return value.GetTaggedValue(); } +ARK_INLINE JSTaggedValue ICRuntimeStub::LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver, + JSTaggedValue key) +{ + auto index = TryToElementsIndex(key); + if (index < 0) { + return JSTaggedValue::Hole(); + } + auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject()); + uint32_t arrLen = typedarrayObj->GetArrayLength(); + if (index >= arrLen) { + return JSTaggedValue::Hole(); + } + JSType type = typedarrayObj->GetJSHClass()->GetObjectType(); + return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, type); +} + JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key, JSTaggedValue value, JSTaggedValue handler) { @@ -501,7 +521,9 @@ JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, auto handlerInfo = static_cast(handler.GetInt()); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle receiverHandle(thread, receiver); - if (HandlerBase::IsJSArray(handlerInfo)) { + if (HandlerBase::IsTypedArrayElement(handlerInfo)) { + return StoreTypedArrayElement(thread, JSTaggedValue::Cast(receiver), key, value); + } else if (HandlerBase::IsJSArray(handlerInfo)) { JSTaggedValue receiveValue = receiverHandle.GetTaggedValue(); if (receiveValue.IsJSCOWArray()) { // Copy on write array. @@ -541,6 +563,22 @@ JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, return JSTaggedValue::Undefined(); } +ARK_INLINE JSTaggedValue ICRuntimeStub::StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver, + JSTaggedValue key, JSTaggedValue value) +{ + auto index = TryToElementsIndex(key); + if (index < 0) { + return JSTaggedValue::Hole(); + } + auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject()); + uint32_t arrLen = typedarrayObj->GetArrayLength(); + if (index >= arrLen) { + return JSTaggedValue::Hole(); + } + JSType type = typedarrayObj->GetJSHClass()->GetObjectType(); + return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, type); +} + ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key) { if (LIKELY(key.IsInt())) { diff --git a/ecmascript/ic/ic_runtime_stub.h b/ecmascript/ic/ic_runtime_stub.h index dc275e505f..f47edb99f8 100644 --- a/ecmascript/ic/ic_runtime_stub.h +++ b/ecmascript/ic/ic_runtime_stub.h @@ -72,8 +72,11 @@ public: uint32_t slotId); static inline JSTaggedValue LoadElement(JSObject *receiver, JSTaggedValue key); static inline JSTaggedValue LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key); + static inline JSTaggedValue LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key); static inline JSTaggedValue StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key, JSTaggedValue value, JSTaggedValue handlerInfo); + static inline JSTaggedValue StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, + JSTaggedValue value); static inline int64_t TryToElementsIndex(JSTaggedValue key); static inline JSTaggedValue LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId, ICKind kind); diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 5fbc528e61..59de15f934 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -622,7 +622,7 @@ public: inline bool HasOrdinaryGet() const { - return (IsTypedArray() || IsSpecialContainer() || IsModuleNamespace()); + return (IsSpecialContainer() || IsModuleNamespace() || IsJSBigInt64Array() || IsJSBigUint64Array()); } inline bool IsJSTypedArray() const diff --git a/ecmascript/pgo_profiler/pgo_profiler.cpp b/ecmascript/pgo_profiler/pgo_profiler.cpp index 3393b46672..5439734ff4 100644 --- a/ecmascript/pgo_profiler/pgo_profiler.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler.cpp @@ -608,7 +608,7 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco if (secondValue.IsInt()) { auto handlerInfo = static_cast(secondValue.GetInt()); PGOObjKind kind = PGOObjKind::LOCAL; - if (HandlerBase::IsJSArray(handlerInfo)) { + if (HandlerBase::IsJSArray(handlerInfo) || HandlerBase::IsTypedArrayElement(handlerInfo)) { kind = PGOObjKind::ELEMENT; } AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind); @@ -618,7 +618,7 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco if (secondValue.IsInt()) { auto handlerInfo = static_cast(secondValue.GetInt()); PGOObjKind kind = PGOObjKind::LOCAL; - if (HandlerBase::IsJSArray(handlerInfo)) { + if (HandlerBase::IsJSArray(handlerInfo) || HandlerBase::IsTypedArrayElement(handlerInfo)) { kind = PGOObjKind::ELEMENT; } AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind); diff --git a/test/moduletest/typearray/typearray.js b/test/moduletest/typearray/typearray.js index 3eeb2e1b60..1702f6b535 100644 --- a/test/moduletest/typearray/typearray.js +++ b/test/moduletest/typearray/typearray.js @@ -32,7 +32,8 @@ ].forEach(function(ctor, i) { if (testTypeArray1(ctor) && testTypeArray2(ctor) && testTypeArray3(ctor) && testTypeArray4(ctor) && - testTypeArray6(ctor) && testTypeArray7(ctor)) { + testTypeArray6(ctor) && testTypeArray7(ctor) && + testTypeArrayIC(ctor)) { print(ctor.name + " test success !!!") } else { print(ctor.name + " test fail !!!") @@ -167,6 +168,26 @@ function testTypeArray7(ctor) { return true; } +function testTypeArrayIC(ctor) { + let result = [] + let obj = new ctor(100); + for (var i = 0; i < 100; i++) { + obj[i] = i; + } + for (var i = 0; i < 100; i++) { + result.push(obj[i] == i); + } + for (var i = 0; i < 100; i++) { + result.push(obj.at(i) == i); + } + for (let i = 0; i < result.length; i++) { + if (!result[i]) { + return false; + } + } + return true; +} + let a1 = new ArrayBuffer(1024*1024*8); let a2 = new Uint8Array(a1); let a3 = Uint8Array.from(a2); From c79e5f84deb7bd4e95aec8ee7af0d846b84fc4ab Mon Sep 17 00:00:00 2001 From: yaoyuan Date: Thu, 12 Oct 2023 20:50:01 +0800 Subject: [PATCH 24/50] CallThis1 FastCall Bugfix Enable the orignal normal call fastpath Issue: I87PAU Signed-off-by: yaoyuan Change-Id: I4fcac81c94b3d0bd0f74954771eade72844d2210 --- ecmascript/compiler/ts_hcr_lowering.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ecmascript/compiler/ts_hcr_lowering.cpp b/ecmascript/compiler/ts_hcr_lowering.cpp index 0afd013cfb..153bf3dec7 100644 --- a/ecmascript/compiler/ts_hcr_lowering.cpp +++ b/ecmascript/compiler/ts_hcr_lowering.cpp @@ -1435,20 +1435,19 @@ void TSHCRLowering::LowerTypedCallthis1(GateRef gate) if (id != BuiltinsStubCSigns::ID::NONE) { AddProfiling(gate); SpeculateCallBuiltin(gate, func, { a0 }, id, true); + return; } - } else { - if (a0Type.IsNumberType()) { + } else if (a0Type.IsNumberType()) { AddProfiling(gate); SpeculateCallBuiltin(gate, func, { a0 }, id, false); - } else { - if (!CanOptimizeAsFastCall(func)) { - return; - } - GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate), - EcmaOpcode::CALLTHIS1_IMM8_V8_V8)); - LowerTypedThisCall(gate, func, actualArgc, 1); - } + return; } + if (!CanOptimizeAsFastCall(func)) { + return; + } + GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate), + EcmaOpcode::CALLTHIS1_IMM8_V8_V8)); + LowerTypedThisCall(gate, func, actualArgc, 1); } void TSHCRLowering::LowerTypedCallthis2(GateRef gate) From 44298d525336717b8aeab554a89eb937a6e1eed3 Mon Sep 17 00:00:00 2001 From: hzzhouzebin Date: Fri, 6 Oct 2023 06:51:47 +0800 Subject: [PATCH 25/50] Use abcId for pgo compiling Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I85J73 Signed-off-by: hzzhouzebin Change-Id: Idef759ff55f1fb490d33ed5005df9d407887d27c --- .../compiler/bytecode_info_collector.cpp | 2 +- ecmascript/compiler/compilation_driver.cpp | 6 +- ecmascript/compiler/compilation_driver.h | 6 +- ecmascript/compiler/type_recorder.cpp | 2 +- ecmascript/jspandafile/js_pandafile.cpp | 4 - .../pgo_profiler/ap_file/pgo_record_pool.h | 36 +- .../pgo_profiler/ap_file/pool_template.h | 1 - ecmascript/pgo_profiler/pgo_profiler.cpp | 63 ++- ecmascript/pgo_profiler/pgo_profiler.h | 6 +- .../pgo_profiler/pgo_profiler_decoder.cpp | 22 +- .../pgo_profiler/pgo_profiler_decoder.h | 23 +- .../pgo_profiler/pgo_profiler_encoder.cpp | 15 + .../pgo_profiler/pgo_profiler_encoder.h | 1 + ecmascript/pgo_profiler/pgo_profiler_info.cpp | 57 ++- ecmascript/pgo_profiler/pgo_profiler_info.h | 74 +++- .../pgo_profiler/pgo_profiler_manager.h | 10 + ecmascript/pgo_profiler/tests/BUILD.gn | 1 + .../pgo_profiler/tests/pgo_profiler_test.cpp | 403 ++++++++---------- .../tests/pgo_test_case/sample_test.js | 13 + .../pgo_profiler/types/pgo_profile_type.h | 2 + ecmascript/ts_types/ts_manager.cpp | 4 +- ecmascript/ts_types/ts_manager.h | 6 +- 22 files changed, 455 insertions(+), 302 deletions(-) create mode 100644 ecmascript/pgo_profiler/tests/pgo_test_case/sample_test.js diff --git a/ecmascript/compiler/bytecode_info_collector.cpp b/ecmascript/compiler/bytecode_info_collector.cpp index 61c91e4e02..8fa4cb0f8c 100644 --- a/ecmascript/compiler/bytecode_info_collector.cpp +++ b/ecmascript/compiler/bytecode_info_collector.cpp @@ -128,7 +128,7 @@ void BytecodeInfoCollector::ProcessClasses() SetMethodPcInfoIndex(methodOffset, processedMethod[methodOffset]); jsPandaFile_->SetMethodLiteralToMap(methodLiteral); - pfDecoder_.MatchAndMarkMethod(recordName, name.c_str(), methodId); + pfDecoder_.MatchAndMarkMethod(jsPandaFile_, recordName, name.c_str(), methodId); }); } // class Construct need to use new target, can not fastcall diff --git a/ecmascript/compiler/compilation_driver.cpp b/ecmascript/compiler/compilation_driver.cpp index f0236fefba..46a4de3300 100644 --- a/ecmascript/compiler/compilation_driver.cpp +++ b/ecmascript/compiler/compilation_driver.cpp @@ -160,7 +160,7 @@ void CompilationDriver::FetchPGOMismatchResult() uint32_t totalMethodCount = 0; uint32_t mismatchMethodCount = 0; std::set> mismatchMethodSet {}; - pfDecoder_.GetMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet); + pfDecoder_.GetMismatchResult(jsPandaFile_, totalMethodCount, mismatchMethodCount, mismatchMethodSet); log_->SetPGOMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet); } @@ -177,7 +177,7 @@ void CompilationDriver::UpdatePGO() SearchForCompilation(recordName, oldIds, newMethodIds, mainMethodOffset, false); return newMethodIds; }; - pfDecoder_.Update(dfs); + pfDecoder_.Update(jsPandaFile_, dfs); FetchPGOMismatchResult(); } @@ -194,7 +194,7 @@ bool CompilationDriver::FilterMethod(const CString &recordName, const MethodLite const MethodPcInfo &methodPCInfo, const std::string &methodName) const { if (methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize() || - !pfDecoder_.Match(recordName, methodLiteral->GetMethodId())) { + !pfDecoder_.Match(jsPandaFile_, recordName, methodLiteral->GetMethodId())) { return true; } diff --git a/ecmascript/compiler/compilation_driver.h b/ecmascript/compiler/compilation_driver.h index 47bebd365f..faa754ed08 100644 --- a/ecmascript/compiler/compilation_driver.h +++ b/ecmascript/compiler/compilation_driver.h @@ -51,7 +51,7 @@ public: { const auto &methodList = bytecodeInfo_.GetMethodList(); auto &resolvedMethodInfo = methodList.at(resolvedMethod.GetOffset()); - if (pfDecoder_.Match(recordName, resolvedMethod) && !resolvedMethodInfo.IsTypeInferAbort()) { + if (pfDecoder_.Match(jsPandaFile_, recordName, resolvedMethod) && !resolvedMethodInfo.IsTypeInferAbort()) { return; } // update profile and update compile queue @@ -66,7 +66,7 @@ public: return fullResolvedMethodSet; }; - pfDecoder_.Update(recordName, dfs); + pfDecoder_.Update(jsPandaFile_, recordName, dfs); if (fullResolvedMethodSet.size() > 0) { bytecodeInfo_.AddRecordName(recordName); @@ -279,7 +279,7 @@ private: } importNames.emplace_back(importRecord); mainMethodInfo.SetIsPGO(true); - pfDecoder_.Update(importRecord, getMainMethodSet); + pfDecoder_.Update(jsPandaFile_, importRecord, getMainMethodSet); AddDependList(importRecord, mainMethodOffset, importList); } }; diff --git a/ecmascript/compiler/type_recorder.cpp b/ecmascript/compiler/type_recorder.cpp index 9a02e1da51..1ff8953a6f 100644 --- a/ecmascript/compiler/type_recorder.cpp +++ b/ecmascript/compiler/type_recorder.cpp @@ -179,7 +179,7 @@ void TypeRecorder::CreateTypesForPGO(const JSPandaFile *jsPandaFile, const Metho return; } // Target method was not compiled by AOT. - if (!decoder_->Match(recordName, pgo::PGOMethodId(callTargetMethodOffset))) { + if (!decoder_->Match(jsPandaFile, recordName, pgo::PGOMethodId(callTargetMethodOffset))) { tsManager->SetHotnessFunc(funcGT, false); } GateType callTargetType = GateType(funcGT); diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index e33b3029d5..3e36715a85 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -351,10 +351,6 @@ FunctionKind JSPandaFile::GetFunctionKind(ConstPoolType type) */ CString JSPandaFile::GetNormalizedFileDesc(const CString &desc) { - // file not in OHOS package. - if (desc.rfind('/', 0) != 0) { - return desc; - } auto etsTokenPos = desc.rfind(OHOS_PKG_ABC_PATH_ROOT); if (etsTokenPos == std::string::npos) { // file not in OHOS package. diff --git a/ecmascript/pgo_profiler/ap_file/pgo_record_pool.h b/ecmascript/pgo_profiler/ap_file/pgo_record_pool.h index 70d57d711b..034a8f2532 100644 --- a/ecmascript/pgo_profiler/ap_file/pgo_record_pool.h +++ b/ecmascript/pgo_profiler/ap_file/pgo_record_pool.h @@ -22,11 +22,13 @@ #include #include "ecmascript/common.h" +#include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" #include "ecmascript/pgo_profiler/ap_file/pool_template.h" #include "ecmascript/pgo_profiler/pgo_utils.h" +#include "ecmascript/pgo_profiler/types/pgo_profile_type.h" #include "macros.h" namespace panda::ecmascript::pgo { @@ -154,9 +156,39 @@ public: void Merge(const PGORecordPool &recordPool, std::map &idMapping) { - pool_->Merge(*recordPool.pool_, - [&](ApEntityId oldId, ApEntityId newId) { idMapping.try_emplace(oldId, newId); }); + if (!recordPool.ModuleRecordTypeEmpty()) { + MergeWithModuleRecordType(recordPool, idMapping); + } else { + pool_->Merge(*recordPool.pool_, + [&](ApEntityId oldId, ApEntityId newId) { idMapping.try_emplace(oldId, newId); }); + } } + + void AddModuleRecordType(ProfileType profileType, const CString &recordName) + { + ASSERT(profileType.GetKind() == ProfileType::Kind::ModuleRecordId); + LOG_ECMA(DEBUG) << "Add profileType: " << profileType.GetTypeString() << ", recordName: " << recordName; + moduleRecordTypeToName_.try_emplace(profileType.GetRaw(), recordName); + } + + bool ModuleRecordTypeEmpty() const + { + return moduleRecordTypeToName_.empty(); + } + +private: + void MergeWithModuleRecordType(const PGORecordPool &recordPool, std::map &idMapping) + { + for (const auto &entry : recordPool.moduleRecordTypeToName_) { + ApEntityId id {0}; + pool_->TryAdd(entry.second, id); + LOG_ECMA(DEBUG) << "MergeWithModuleRecordType. recordName: " << entry.second.c_str() + << ", id: " << ProfileType(entry.first).GetId() << " -> " << id; + idMapping.emplace(ProfileType(entry.first).GetId(), id); + } + } + + std::unordered_map moduleRecordTypeToName_; }; class PGOAbcFilePool : public PGOStringPool { diff --git a/ecmascript/pgo_profiler/ap_file/pool_template.h b/ecmascript/pgo_profiler/ap_file/pool_template.h index af8b10aca9..19290bc907 100644 --- a/ecmascript/pgo_profiler/ap_file/pool_template.h +++ b/ecmascript/pgo_profiler/ap_file/pool_template.h @@ -158,7 +158,6 @@ public: result.first->second.SetEntryId(entryId); result.first->second.ParseFromBinary(buffer, header); } - LOG_ECMA(DEBUG) << "ParseFromBinary. name: " << poolName_ << ", count: " << secInfo.number_; return 1; } diff --git a/ecmascript/pgo_profiler/pgo_profiler.cpp b/ecmascript/pgo_profiler/pgo_profiler.cpp index 23988f6f74..3c020158a7 100644 --- a/ecmascript/pgo_profiler/pgo_profiler.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler.cpp @@ -22,6 +22,7 @@ #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/js_function.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/pgo_profiler/pgo_context.h" #include "ecmascript/pgo_profiler/pgo_profiler_info.h" @@ -1003,24 +1004,61 @@ ApEntityId PGOProfiler::GetMethodAbcId(JSFunction *jsFunction) return abcId; } -ApEntityId PGOProfiler::GetRecordId(const CString &recordName) -{ - ApEntityId recordId(0); - recordInfos_->GetRecordPool()->TryAdd(recordName, recordId); - return recordId; -} - ProfileType PGOProfiler::GetRecordProfileType(JSFunction *jsFunction, const CString &recordName) { - return GetRecordProfileType(GetMethodAbcId(jsFunction), GetRecordId(recordName)); + CString pfName; + auto jsMethod = jsFunction->GetMethod(); + if (jsMethod.IsMethod()) { + const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile(); + if (pf != nullptr) { + pfName = pf->GetJSPandaFileDesc(); + } + } + const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfName); + if (pf == nullptr) { + LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfName: " << pfName + << ", recordName: " << recordName; + return ProfileType::PROFILE_TYPE_NONE; + } + return GetRecordProfileType(pf, GetMethodAbcId(jsFunction), recordName); } ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, const CString &recordName) { - return GetRecordProfileType(abcId, GetRecordId(recordName)); + CString pfDesc; + PGOProfilerManager::GetInstance()->GetPandaFileDesc(abcId, pfDesc); + const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfDesc); + if (pf == nullptr) { + LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfDesc: " << pfDesc + << ", recordName: " << recordName; + return ProfileType::PROFILE_TYPE_NONE; + } + return GetRecordProfileType(pf, abcId, recordName); } -ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, ApEntityId recordId) +ProfileType PGOProfiler::GetRecordProfileType(const std::shared_ptr &pf, ApEntityId abcId, + const CString &recordName) +{ + ASSERT(pf != nullptr); + JSRecordInfo recordInfo; + bool hasRecord = pf->CheckAndGetRecordInfo(recordName, recordInfo); + if (!hasRecord) { + LOG_ECMA(ERROR) << "Get recordInfo failed. recordName: " << recordName; + return ProfileType::PROFILE_TYPE_NONE; + } + ProfileType recordType {0}; + if (recordInfo.moduleRecordIdx != -1) { + recordType = GetModuleRecordProfileType(abcId, recordInfo.moduleRecordIdx); + recordInfos_->GetRecordPool()->AddModuleRecordType(recordType, recordName); + return recordType; + } + ApEntityId recordId {0}; + recordInfos_->GetRecordPool()->TryAdd(recordName, recordId); + recordType = GetLocalRecordProfileType(abcId, recordId); + return recordType; +} + +ProfileType PGOProfiler::GetLocalRecordProfileType(ApEntityId abcId, ApEntityId recordId) { return {abcId, recordId, ProfileType::Kind::LocalRecordId}; } @@ -1084,4 +1122,9 @@ void PGOProfiler::WorkList::Iterate(Callback callback) const current = next; } } + +ProfileType PGOProfiler::GetModuleRecordProfileType(ApEntityId abcId, ApEntityId moduleRecordId) +{ + return {abcId, moduleRecordId, ProfileType::Kind::ModuleRecordId}; +} } // namespace panda::ecmascript::pgo diff --git a/ecmascript/pgo_profiler/pgo_profiler.h b/ecmascript/pgo_profiler/pgo_profiler.h index 30590cdcb9..0c7ea63892 100644 --- a/ecmascript/pgo_profiler/pgo_profiler.h +++ b/ecmascript/pgo_profiler/pgo_profiler.h @@ -48,7 +48,8 @@ public: NO_COPY_SEMANTIC(PGOProfiler); NO_MOVE_SEMANTIC(PGOProfiler); - static ProfileType GetRecordProfileType(ApEntityId abcId, ApEntityId recordId); + static ProfileType GetLocalRecordProfileType(ApEntityId abcId, ApEntityId recordId); + static ProfileType GetModuleRecordProfileType(ApEntityId abcId, ApEntityId moduleRecordId); void ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId); void ProfileDefineClass(JSTaggedType ctor); @@ -216,9 +217,10 @@ private: virtual ~PGOProfiler(); static ApEntityId GetMethodAbcId(JSFunction *jsFunction); - ApEntityId GetRecordId(const CString &recordName); ProfileType GetRecordProfileType(JSFunction *jsFunction, const CString &recordName); ProfileType GetRecordProfileType(ApEntityId abcId, const CString &recordName); + ProfileType GetRecordProfileType(const std::shared_ptr &pf, ApEntityId abcId, + const CString &recordName); void Reset(bool isEnable); diff --git a/ecmascript/pgo_profiler/pgo_profiler_decoder.cpp b/ecmascript/pgo_profiler/pgo_profiler_decoder.cpp index b0b271a12f..3ef9e104fc 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_decoder.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler_decoder.cpp @@ -17,6 +17,7 @@ #include #include "ecmascript/base/file_header.h" +#include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/pgo_profiler/pgo_profiler_info.h" @@ -49,7 +50,7 @@ bool PGOProfilerDecoder::Load() if (header_->SupportProfileTypeWithAbcId()) { PGOFileSectionInterface::ParseSectionFromBinary(addr, header_, *abcFilePool_->GetPool()); } - recordSimpleInfos_->ParseFromBinary(addr, header_); + recordSimpleInfos_->ParseFromBinary(addr, header_, abcFilePool_); UnLoadAPBinaryFile(); isLoaded_ = true; @@ -192,7 +193,7 @@ void PGOProfilerDecoder::Clear() } } -bool PGOProfilerDecoder::Match(const CString &recordName, PGOMethodId methodId) +bool PGOProfilerDecoder::Match(const JSPandaFile *jsPandaFile, const CString &recordName, PGOMethodId methodId) { if (!isLoaded_) { return true; @@ -200,7 +201,7 @@ bool PGOProfilerDecoder::Match(const CString &recordName, PGOMethodId methodId) if (!isVerifySuccess_) { return false; } - return recordSimpleInfos_->Match(recordName, EntityId(methodId)); + return recordSimpleInfos_->Match(GetNormalizedFileDesc(jsPandaFile), recordName, EntityId(methodId)); } bool PGOProfilerDecoder::GetHClassLayoutDesc(PGOSampleType profileType, PGOHClassLayoutDesc **desc) const @@ -211,13 +212,24 @@ bool PGOProfilerDecoder::GetHClassLayoutDesc(PGOSampleType profileType, PGOHClas return recordSimpleInfos_->GetHClassLayoutDesc(profileType, desc); } -void PGOProfilerDecoder::GetMismatchResult(uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, +void PGOProfilerDecoder::GetMismatchResult(const JSPandaFile *jsPandaFile, uint32_t &totalMethodCount, + uint32_t &mismatchMethodCount, std::set> &mismatchMethodSet) const { if (!isLoaded_ || !isVerifySuccess_) { return; } - return recordSimpleInfos_->GetMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet); + return recordSimpleInfos_->GetMismatchResult(GetNormalizedFileDesc(jsPandaFile), totalMethodCount, + mismatchMethodCount, mismatchMethodSet); +} + +CString PGOProfilerDecoder::GetNormalizedFileDesc(const JSPandaFile *jsPandaFile) const +{ + ASSERT(jsPandaFile != nullptr); + if (header_->SupportProfileTypeWithAbcId()) { + return jsPandaFile->GetNormalizedFileDesc(); + } + return ""; } bool PGOProfilerDecoder::InitMergeData() diff --git a/ecmascript/pgo_profiler/pgo_profiler_decoder.h b/ecmascript/pgo_profiler/pgo_profiler_decoder.h index b23ecf3107..1fbef7950d 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_decoder.h +++ b/ecmascript/pgo_profiler/pgo_profiler_decoder.h @@ -39,7 +39,7 @@ public: NO_COPY_SEMANTIC(PGOProfilerDecoder); NO_MOVE_SEMANTIC(PGOProfilerDecoder); - bool PUBLIC_API Match(const CString &recordName, PGOMethodId methodId); + bool PUBLIC_API Match(const JSPandaFile *jsPandaFile, const CString &recordName, PGOMethodId methodId); bool PUBLIC_API LoadAndVerify(uint32_t checksum); bool PUBLIC_API LoadFull(); @@ -64,21 +64,21 @@ public: } template - void Update(Callback callback) + void Update(const JSPandaFile *jsPandaFile, Callback callback) { if (!isLoaded_ || !isVerifySuccess_) { return; } - recordSimpleInfos_->Update(callback); + recordSimpleInfos_->Update(GetNormalizedFileDesc(jsPandaFile), callback); } template - void Update(const CString &recordName, Callback callback) + void Update(const JSPandaFile *jsPandaFile, const CString &recordName, Callback callback) { if (!isLoaded_ || !isVerifySuccess_) { return; } - recordSimpleInfos_->Update(recordName, callback); + recordSimpleInfos_->Update(GetNormalizedFileDesc(jsPandaFile), recordName, callback); } template @@ -94,20 +94,22 @@ public: PGOMethodInfo::CalcChecksum(methodName, methodLiteral->GetBytecodeArray(), MethodLiteral::GetCodeSize(jsPandaFile, methodLiteral->GetMethodId())); - return recordSimpleInfos_->GetTypeInfo(recordName, methodName, checksum, callback); + return recordSimpleInfos_->GetTypeInfo(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, checksum, + callback); } - recordSimpleInfos_->GetTypeInfo(recordName, methodName, callback); + recordSimpleInfos_->GetTypeInfo(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, callback); } - void MatchAndMarkMethod(const CString &recordName, const char *methodName, EntityId methodId) + void MatchAndMarkMethod(const JSPandaFile *jsPandaFile, const CString &recordName, const char *methodName, + EntityId methodId) { if (!isLoaded_ || !isVerifySuccess_) { return; } - recordSimpleInfos_->MatchAndMarkMethod(recordName, methodName, methodId); + recordSimpleInfos_->MatchAndMarkMethod(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, methodId); } - void GetMismatchResult(uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, + void GetMismatchResult(const JSPandaFile *jsPandaFile, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, std::set> &mismatchMethodSet) const; bool IsMethodMatchEnabled() const @@ -165,6 +167,7 @@ private: bool LoadAPBinaryFile(int prot = PAGE_PROT_READ); void UnLoadAPBinaryFile(); + CString GetNormalizedFileDesc(const JSPandaFile *jsPandaFile) const; bool isLoaded_ {false}; bool isVerifySuccess_ {false}; diff --git a/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp b/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp index 40569f0a2f..7b46150535 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler_encoder.cpp @@ -21,6 +21,7 @@ #include "ecmascript/log_wrapper.h" #include "ecmascript/ohos/white_list_helper.h" +#include "ecmascript/mem/c_string.h" #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h" @@ -104,6 +105,20 @@ bool PGOProfilerEncoder::GetPandaFileId(const CString &abcName, ApEntityId &entr return abcFilePool_->GetEntryId(abcName, entryId); } +bool PGOProfilerEncoder::GetPandaFileDesc(ApEntityId abcId, CString &desc) +{ + if (!isInitialized_) { + return false; + } + os::memory::ReadLockHolder lock(rwLock_); + const auto *entry = abcFilePool_->GetEntry(abcId); + if (entry == nullptr) { + return false; + } + desc = entry->GetData(); + return true; +} + void PGOProfilerEncoder::Merge(const PGORecordDetailInfos &recordInfos) { if (!isInitialized_) { diff --git a/ecmascript/pgo_profiler/pgo_profiler_encoder.h b/ecmascript/pgo_profiler/pgo_profiler_encoder.h index 9a191913ae..6cf6f47cd9 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_encoder.h +++ b/ecmascript/pgo_profiler/pgo_profiler_encoder.h @@ -51,6 +51,7 @@ public: void SamplePandaFileInfo(uint32_t checksum, const CString &abcName); bool GetPandaFileId(const CString &abcName, ApEntityId &entryId); + bool GetPandaFileDesc(ApEntityId abcId, CString &desc); void Merge(const PGORecordDetailInfos &recordInfos); void Merge(const PGOPandaFileInfos &pandaFileInfos); void Merge(const PGOProfilerEncoder &encoder); diff --git a/ecmascript/pgo_profiler/pgo_profiler_info.cpp b/ecmascript/pgo_profiler/pgo_profiler_info.cpp index 0a5a18faa8..26ecb5be42 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_info.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler_info.cpp @@ -18,11 +18,14 @@ #include #include #include +#include #include "ecmascript/base/bit_helper.h" #include "ecmascript/base/file_header.h" #include "ecmascript/js_function.h" +#include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/method_literal.h" +#include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" @@ -668,7 +671,7 @@ void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos) if (newIter == idMapping.end()) { continue; } - auto newRecordType = PGOProfiler::GetRecordProfileType(oldRecordType.GetAbcId(), newIter->second); + auto newRecordType = PGOProfiler::GetLocalRecordProfileType(oldRecordType.GetAbcId(), newIter->second); auto fromMethodInfos = iter->second; auto recordInfosIter = recordInfos_.find(newRecordType); @@ -920,16 +923,24 @@ void PGORecordDetailInfos::Clear() InitSections(); } -bool PGORecordSimpleInfos::Match(const CString &recordName, EntityId methodId) +bool PGORecordSimpleInfos::Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId) { - auto methodIdsIter = methodIds_.find(recordName); - if (methodIdsIter == methodIds_.end()) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + LOG_COMPILER(DEBUG) << "AbcDesc not found. abcNormalizedDesc: " << abcNormalizedDesc + << ", methodIdsCount: " << methodIds_.size(); + return false; + } + auto methodIdsIter = abcMethodIds->second.find(recordName); + if (methodIdsIter == abcMethodIds->second.end()) { + LOG_COMPILER(DEBUG) << "AbcDesc not found. recordName: " << recordName; return false; } return methodIdsIter->second->Match(methodId); } -void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header) +void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header, + std::shared_ptr &abcFilePool) { header_ = header; ParseSectionsFromBinary(apSectionList_, buffer, header); @@ -937,12 +948,18 @@ void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *cons void *addr = reinterpret_cast(reinterpret_cast(buffer) + info->offset_); for (uint32_t i = 0; i < info->number_; i++) { CString recordName; + const char *abcDesc = ""; ProfileType recordType; if (header->SupportProfileTypeWithAbcId()) { auto recordTypeRef = ProfileTypeRef(base::ReadBuffer(&addr, sizeof(ApEntityId))); recordType = ProfileType(*this, recordTypeRef); auto recordId = recordType.GetId(); recordName = recordPool_->GetEntry(recordId)->GetData(); + auto abcId = recordType.GetAbcId(); + const auto *entry = abcFilePool->GetPool()->GetEntry(abcId); + if (entry != nullptr) { + abcDesc = entry->GetData().c_str(); + } } else if (header->SupportRecordPool()) { auto recordId = base::ReadBuffer(&addr, sizeof(ApEntityId)); recordName = recordPool_->GetEntry(recordId)->GetData(); @@ -951,7 +968,8 @@ void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *cons } PGOMethodIdSet *methodIds = nativeAreaAllocator_.New(chunk_.get()); if (methodIds->ParseFromBinary(*this, &addr)) { - methodIds_.emplace(recordName, methodIds); + auto methodIdsResult = methodIds_.try_emplace(JSPandaFile::GetNormalizedFileDesc(abcDesc)); + (methodIdsResult.first->second).emplace(recordName, methodIds); } } @@ -968,15 +986,18 @@ void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos) { std::map idMapping; recordPool_->Merge(*simpleInfos.recordPool_, idMapping); - for (const auto &method : simpleInfos.methodIds_) { - auto result = methodIds_.find(method.first); - if (result == methodIds_.end()) { - PGOMethodIdSet *methodIds = nativeAreaAllocator_.New(chunk_.get()); - auto ret = methodIds_.emplace(method.first, methodIds); - ASSERT(ret.second); - result = ret.first; + for (const auto &fromAbcMethodIds : simpleInfos.methodIds_) { + auto toAbcMethodIds = methodIds_.try_emplace(fromAbcMethodIds.first); + for (const auto &method : fromAbcMethodIds.second) { + auto result = toAbcMethodIds.first->second.find(method.first); + if (result == toAbcMethodIds.first->second.end()) { + PGOMethodIdSet *methodIds = nativeAreaAllocator_.New(chunk_.get()); + auto ret = toAbcMethodIds.first->second.emplace(method.first, methodIds); + ASSERT(ret.second); + result = ret.first; + } + const_cast(*result->second).Merge(*method.second); } - const_cast(*result->second).Merge(*method.second); } // Merge global layout desc infos to global method info map for (const auto &moduleLayoutDescInfo : simpleInfos.moduleLayoutDescInfos_) { @@ -1013,9 +1034,11 @@ void PGORecordSimpleInfos::InitSections() void PGORecordSimpleInfos::Clear() { - for (const auto &iter : methodIds_) { - iter.second->Clear(); - nativeAreaAllocator_.Delete(iter.second); + for (const auto &abcMethodIds: methodIds_) { + for (const auto &iter : abcMethodIds.second) { + iter.second->Clear(); + nativeAreaAllocator_.Delete(iter.second); + } } methodIds_.clear(); recordPool_->Clear(); diff --git a/ecmascript/pgo_profiler/pgo_profiler_info.h b/ecmascript/pgo_profiler/pgo_profiler_info.h index 9cadfa5e99..4b09f3fc7e 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_info.h +++ b/ecmascript/pgo_profiler/pgo_profiler_info.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ecmascript/common.h" @@ -536,12 +537,16 @@ public: void InitSections(); - bool Match(const CString &recordName, EntityId methodId); + bool Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId); template - void Update(Callback callback) + void Update(const CString &abcNormalizedDesc, Callback callback) { - for (auto iter = methodIds_.begin(); iter != methodIds_.end(); iter++) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + for (auto iter = abcMethodIds->second.begin(); iter != abcMethodIds->second.end(); iter++) { auto recordName = iter->first; auto methodIds = iter->second; methodIds->Update(recordName, callback); @@ -549,35 +554,49 @@ public: } template - void Update(const CString &recordName, Callback callback) + void Update(const CString &abcNormalizedDesc, const CString &recordName, Callback callback) { - auto iter = methodIds_.find(recordName); - if (iter != methodIds_.end()) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + auto iter = abcMethodIds->second.find(recordName); + if (iter != abcMethodIds->second.end()) { iter->second->Update(recordName, callback); } else { - PGOMethodIdSet *methodIds = nativeAreaAllocator_.New(chunk_.get()); - if (methodIds->Update(recordName, callback)) { - methodIds_.emplace(recordName, methodIds); + PGOMethodIdSet *methodIdSet = nativeAreaAllocator_.New(chunk_.get()); + if (methodIdSet->Update(recordName, callback)) { + abcMethodIds->second.emplace(recordName, methodIdSet); } else { - nativeAreaAllocator_.Delete(methodIds); + nativeAreaAllocator_.Delete(methodIdSet); } } } template - void GetTypeInfo(const CString &recordName, const char *methodName, Callback callback) + void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, + Callback callback) { - auto iter = methodIds_.find(recordName); - if (iter != methodIds_.end()) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + auto iter = abcMethodIds->second.find(recordName); + if (iter != abcMethodIds->second.end()) { iter->second->GetTypeInfo(methodName, callback); } } template - void GetTypeInfo(const CString &recordName, const char *methodName, uint32_t checksum, Callback callback) + void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, + uint32_t checksum, Callback callback) { - auto iter = methodIds_.find(recordName); - if (iter != methodIds_.end()) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + auto iter = abcMethodIds->second.find(recordName); + if (iter != abcMethodIds->second.end()) { iter->second->GetTypeInfo(methodName, checksum, callback); } } @@ -592,24 +611,33 @@ public: return false; } - void MatchAndMarkMethod(const CString &recordName, const char *methodName, EntityId methodId) + void MatchAndMarkMethod(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, + EntityId methodId) { - auto iter = methodIds_.find(recordName); - if (iter != methodIds_.end()) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + auto iter = abcMethodIds->second.find(recordName); + if (iter != abcMethodIds->second.end()) { return iter->second->MatchAndMarkMethod(methodName, methodId); } } - void GetMismatchResult(uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, + void GetMismatchResult(const CString &abcNormalizedDesc, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, std::set> &mismatchMethodSet) const { - for (const auto &methodId : methodIds_) { + auto abcMethodIds = methodIds_.find(abcNormalizedDesc); + if (abcMethodIds == methodIds_.end()) { + return; + } + for (const auto &methodId : abcMethodIds->second) { methodId.second->GetMismatchResult(methodId.first, totalMethodCount, mismatchMethodCount, mismatchMethodSet); } } - void ParseFromBinary(void *buffer, PGOProfilerHeader *const header); + void ParseFromBinary(void *buffer, PGOProfilerHeader *const header, std::shared_ptr &abcFilePool); void Merge(const PGORecordSimpleInfos &simpleInfos); @@ -643,7 +671,7 @@ private: uint32_t hotnessThreshold_ {2}; NativeAreaAllocator nativeAreaAllocator_; std::unique_ptr chunk_; - CUnorderedMap methodIds_; + CUnorderedMap> methodIds_; PGOProfilerHeader *header_ {nullptr}; std::list> apSectionList_; std::shared_ptr recordPool_; diff --git a/ecmascript/pgo_profiler/pgo_profiler_manager.h b/ecmascript/pgo_profiler/pgo_profiler_manager.h index 1b0a5679aa..e755883017 100644 --- a/ecmascript/pgo_profiler/pgo_profiler_manager.h +++ b/ecmascript/pgo_profiler/pgo_profiler_manager.h @@ -46,6 +46,8 @@ public: { // For FA jsvm, merge with existed output file encoder_ = std::make_unique(outDir, hotnessThreshold, ApGenMode::OVERWRITE); + // InitData in appspawn + encoder_->InitializeData(); } void SetBundleName(const std::string &bundleName) @@ -134,6 +136,14 @@ public: return false; } + bool GetPandaFileDesc(ApEntityId abcId, CString &desc) const + { + if (encoder_) { + return encoder_->GetPandaFileDesc(abcId, desc); + } + return false; + } + void SetApGenMode(ApGenMode mode) { if (encoder_) { diff --git a/ecmascript/pgo_profiler/tests/BUILD.gn b/ecmascript/pgo_profiler/tests/BUILD.gn index 996965fa2c..975fd6d0d6 100644 --- a/ecmascript/pgo_profiler/tests/BUILD.gn +++ b/ecmascript/pgo_profiler/tests/BUILD.gn @@ -25,6 +25,7 @@ test_js_files = [ "call_test", "array_test", "object_literal", + "sample_test", ] foreach(file, test_js_files) { diff --git a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp index 0d8f1c8923..6179181f9d 100644 --- a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp +++ b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp @@ -65,13 +65,39 @@ public: void TearDown() override { + JSPandaFileManager::GetInstance()->RemoveJSPandaFileVm(vm_, pf_.get()); vm_ = nullptr; + pf_.reset(); PGOProfilerManager::GetInstance()->Destroy(); } protected: - std::shared_ptr CreateJSPandaFile(const char *source, const CString filename, - std::vector &methodLiterals) + void CreateJSPandaFile(const CString filename, std::vector &methodLiterals) + { + std::string targetAbcPath = std::string(TARGET_ABC_PATH) + filename.c_str(); + auto pfPtr = panda_file::OpenPandaFileOrZip(targetAbcPath, panda_file::File::READ_WRITE); + JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance(); + pf_ = pfManager->NewJSPandaFile(pfPtr.release(), filename); + + const File *file = pf_->GetPandaFile(); + auto classes = pf_->GetClasses(); + + for (size_t i = 0; i < classes.Size(); i++) { + panda_file::File::EntityId classId(classes[i]); + if (!classId.IsValid() || pf_->IsExternal(classId)) { + continue; + } + ClassDataAccessor cda(*file, classId); + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + auto *methodLiteral = new MethodLiteral(mda.GetMethodId()); + methodLiteral->Initialize(pf_.get()); + pf_->SetMethodLiteralToMap(methodLiteral); + methodLiterals.push_back(methodLiteral); + }); + } + } + + void CreateJSPandaFile(const char *source, const CString filename, std::vector &methodLiterals) { Parser parser; const std::string fn = "SRC.abc"; // test file name : "SRC.abc" @@ -79,9 +105,9 @@ protected: std::unique_ptr pfPtr = pandasm::AsmEmitter::Emit(res.Value()); JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance(); - std::shared_ptr pf = pfManager->NewJSPandaFile(pfPtr.release(), filename); + pf_ = pfManager->NewJSPandaFile(pfPtr.release(), filename); - const File *file = pf->GetPandaFile(); + const File *file = pf_->GetPandaFile(); const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;"); File::EntityId classId = file->GetClassId(typeDesc); EXPECT_TRUE(classId.IsValid()); @@ -89,14 +115,13 @@ protected: ClassDataAccessor cda(*file, classId); cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { auto *methodLiteral = new MethodLiteral(mda.GetMethodId()); - methodLiteral->Initialize(pf.get()); - pf->SetMethodLiteralToMap(methodLiteral); + methodLiteral->Initialize(pf_.get()); + pf_->SetMethodLiteralToMap(methodLiteral); methodLiterals.push_back(methodLiteral); }); - return pf; } - std::shared_ptr ExecuteAndLoadJSPandaFile(std::string profDir, std::string recordName) + void ExecuteAndLoadJSPandaFile(std::string profDir, std::string recordName) { RuntimeOption option; option.SetLogLevel(LOG_LEVEL::INFO); @@ -109,25 +134,19 @@ protected: auto result = JSNApi::Execute(vm_, targetAbcPath, recordName, false); EXPECT_TRUE(result); - std::shared_ptr jsPandaFile = - JSPandaFileManager::GetInstance()->FindJSPandaFile(CString(targetAbcPath)); + pf_ = JSPandaFileManager::GetInstance()->FindJSPandaFile(CString(targetAbcPath)); JSNApi::DestroyJSVM(vm_); - return jsPandaFile; } EcmaVM *vm_ = nullptr; + std::shared_ptr pf_; }; HWTEST_F_L0(PGOProfilerTest, Sample) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - )"; std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 1); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); mkdir("ark-profiler/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; @@ -135,7 +154,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample) option.SetProfileDir("ark-profiler/"); vm_ = JSNApi::CreateJSVM(option); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; @@ -148,13 +167,13 @@ HWTEST_F_L0(PGOProfilerTest, Sample) JSNApi::DestroyJSVM(vm_); // Loader PGOProfilerDecoder loader("ark-profiler/modules.ap", 2); - CString expectRecordName = "test"; + CString expectRecordName = "sample_test"; #if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader.LoadAndVerify(checksum)); - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); #else ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); #endif unlink("ark-profiler/modules.ap"); rmdir("ark-profiler/"); @@ -162,18 +181,9 @@ HWTEST_F_L0(PGOProfilerTest, Sample) HWTEST_F_L0(PGOProfilerTest, Sample1) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) { - lda.str "helloworld" - return - } - .function void foo2(any a0, any a1, any a2) {} - .function void foo3(any a0, any a1, any a2) {} - )"; + mkdir("ark-profiler1/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler1.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 3); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); mkdir("ark-profiler1/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; @@ -181,7 +191,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample1) option.SetProfileDir("ark-profiler1/"); vm_ = JSNApi::CreateJSVM(option); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler1.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; @@ -201,20 +211,20 @@ HWTEST_F_L0(PGOProfilerTest, Sample1) // Loader PGOProfilerDecoder loader("ark-profiler1/modules.ap", 2); - CString expectRecordName = "test"; + CString expectRecordName = "sample_test"; #if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader.LoadAndVerify(checksum)); for (uint32_t idx = 0; idx < 3; idx++) { - loader.MatchAndMarkMethod(expectRecordName, - methodLiterals[idx]->GetMethodName(pf.get(), methodLiterals[idx]->GetMethodId()), + loader.MatchAndMarkMethod(pf_.get(), expectRecordName, + methodLiterals[idx]->GetMethodName(pf_.get(), methodLiterals[idx]->GetMethodId()), methodLiterals[idx]->GetMethodId()); } - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[2]->GetMethodId())); - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[2]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[1]->GetMethodId())); #else ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[1]->GetMethodId())); #endif unlink("ark-profiler1/modules.ap"); rmdir("ark-profiler1/"); @@ -222,14 +232,9 @@ HWTEST_F_L0(PGOProfilerTest, Sample1) HWTEST_F_L0(PGOProfilerTest, Sample2) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - .function void foo2(any a0, any a1, any a2) {} - )"; + mkdir("ark-profiler2/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler2.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 2); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); mkdir("ark-profiler2/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; @@ -237,7 +242,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample2) option.SetProfileDir("ark-profiler2/"); vm_ = JSNApi::CreateJSVM(option); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler2.abc"); @@ -255,24 +260,24 @@ HWTEST_F_L0(PGOProfilerTest, Sample2) // Loader PGOProfilerDecoder loader("ark-profiler2/modules.ap", 2); - CString expectRecordName = "test"; - CString expectRecordName1 = "test1"; + CString expectRecordName = "sample_test"; + CString expectRecordName1 = "sample_test"; #if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader.LoadAndVerify(checksum)); for (uint32_t idx = 0; idx < 2; idx++) { - loader.MatchAndMarkMethod(expectRecordName, - methodLiterals[idx]->GetMethodName(pf.get(), methodLiterals[idx]->GetMethodId()), + loader.MatchAndMarkMethod(pf_.get(), expectRecordName, + methodLiterals[idx]->GetMethodName(pf_.get(), methodLiterals[idx]->GetMethodId()), methodLiterals[idx]->GetMethodId()); - loader.MatchAndMarkMethod(expectRecordName1, - methodLiterals[idx]->GetMethodName(pf.get(), methodLiterals[idx]->GetMethodId()), + loader.MatchAndMarkMethod(pf_.get(), expectRecordName1, + methodLiterals[idx]->GetMethodName(pf_.get(), methodLiterals[idx]->GetMethodId()), methodLiterals[idx]->GetMethodId()); } - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); - ASSERT_TRUE(!loader.Match(expectRecordName1, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName1, methodLiterals[1]->GetMethodId())); #else ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); - ASSERT_TRUE(loader.Match(expectRecordName1, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName1, methodLiterals[1]->GetMethodId())); #endif unlink("ark-profiler2/modules.ap"); rmdir("ark-profiler2/"); @@ -280,37 +285,33 @@ HWTEST_F_L0(PGOProfilerTest, Sample2) HWTEST_F_L0(PGOProfilerTest, DisEnableSample) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - )"; std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler3.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 1); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); + EXPECT_GE(methodLiterals.size(), 1); mkdir("ark-profiler3/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; option.SetEnableProfile(false); option.SetProfileDir("ark-profiler3/"); vm_ = JSNApi::CreateJSVM(option); + JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); - uint32_t checksum = 304293; - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler3.abc"); + constPool->SetJSPandaFile(pf_.get()); + uint32_t checksum = pf_->GetChecksum(); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); method->SetModule(vm_->GetJSThread(), recordName); JSNApi::DestroyJSVM(vm_); // Loader PGOProfilerDecoder loader("ark-profiler3/modules.ap", 2); - // path is empty() - ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - CString expectRecordName = "test"; - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(loader.LoadAndVerify(checksum)); + CString expectRecordName = "sample_test"; + ASSERT_FALSE(loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); rmdir("ark-profiler3/"); } @@ -368,43 +369,40 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerManagerSample) HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - .function void foo2(any a0, any a1, any a2) {} - )"; + mkdir("ark-profiler5/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler5.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 2); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); + EXPECT_GE(methodLiterals.size(), 2); // number of methods mkdir("ark-profiler5/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; option.SetEnableProfile(true); // outDir is empty option.SetProfileDir("ark-profiler5/"); vm_ = JSNApi::CreateJSVM(option); + JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler5.abc"); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; // worker vm read profile enable from PGOProfilerManager singleton option.SetEnableProfile(false); auto vm2 = JSNApi::CreateJSVM(option); JSHandle constPool2 = vm2->GetFactory()->NewConstantPool(4); - constPool2->SetJSPandaFile(pf.get()); - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler5.abc"); + constPool2->SetJSPandaFile(pf_.get()); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm2 != nullptr) << "Cannot create Runtime"; JSHandle method = vm2->GetFactory()->NewMethod(methodLiterals[0]); method->SetConstantPool(vm2->GetJSThread(), constPool2.GetTaggedValue()); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); method->SetModule(vm2->GetJSThread(), recordName); JSHandle method1 = vm_->GetFactory()->NewMethod(methodLiterals[0]); JSHandle method2 = vm_->GetFactory()->NewMethod(methodLiterals[1]); method1->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); method2->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - JSHandle recordName1(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName1(vm_->GetFactory()->NewFromStdString("sample_test")); method1->SetModule(vm_->GetJSThread(), recordName); method2->SetModule(vm_->GetJSThread(), recordName); @@ -414,16 +412,16 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM) PGOProfilerDecoder loader("ark-profiler5/profiler", 2); mkdir("ark-profiler5/profiler", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - CString expectRecordName = "test"; - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[1]->GetMethodId())); + CString expectRecordName = "sample_test"; + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[1]->GetMethodId())); PGOProfilerDecoder loader1("ark-profiler5/modules.ap", 2); #if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader1.LoadAndVerify(checksum)); - ASSERT_TRUE(!loader1.Match(expectRecordName, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(!loader1.Match(pf_.get(), expectRecordName, methodLiterals[1]->GetMethodId())); #else ASSERT_TRUE(!loader1.LoadAndVerify(checksum)); - ASSERT_TRUE(loader1.Match(expectRecordName, methodLiterals[1]->GetMethodId())); + ASSERT_TRUE(loader1.Match(pf_.get(), expectRecordName, methodLiterals[1]->GetMethodId())); #endif unlink("ark-profiler5/modules.ap"); @@ -433,38 +431,35 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM) HWTEST_F_L0(PGOProfilerTest, PGOProfilerDecoderNoHotMethod) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - )"; std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler8.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 1); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); + EXPECT_GE(methodLiterals.size(), 1); // number of methods mkdir("ark-profiler8/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; option.SetEnableProfile(true); option.SetProfileDir("ark-profiler8/"); vm_ = JSNApi::CreateJSVM(option); + JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); - uint32_t checksum = 304293; - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler8.abc"); + constPool->SetJSPandaFile(pf_.get()); + uint32_t checksum = pf_->GetChecksum(); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); method->SetModule(vm_->GetJSThread(), recordName); JSNApi::DestroyJSVM(vm_); PGOProfilerDecoder loader("ark-profiler8/modules.ap", 2); - CString expectRecordName = "test"; + CString expectRecordName = "sample_test"; #if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader.LoadAndVerify(checksum)); - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); #else ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); #endif unlink("ark-profiler8/modules.ap"); @@ -479,21 +474,21 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask) sourceStream << " .function void foo" << std::to_string(funcIdx) << "(any a0, any a1, any a2) {}" << std::endl; } std::vector methodLiterals {}; - std::shared_ptr pf = - CreateJSPandaFile(sourceStream.str().c_str(), "ark-profiler9.abc", methodLiterals); + CreateJSPandaFile(sourceStream.str().c_str(), "ark-profiler9.abc", methodLiterals); EXPECT_EQ(methodLiterals.size(), 100); // number of methods mkdir("ark-profiler9/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; option.SetEnableProfile(true); option.SetProfileDir("ark-profiler9/"); vm_ = JSNApi::CreateJSVM(option); + JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SetApGenMode(ApGenMode::OVERWRITE); PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler9.abc"); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName(vm_->GetFactory()->NewFromStdString("ark-profiler9.abc")); for (int i = 61; i < 91; i++) { JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[i]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); @@ -508,22 +503,23 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask) #else ASSERT_TRUE(!loader.LoadAndVerify(checksum)); #endif - CString expectRecordName = "test"; + CString expectRecordName = "ark-profiler9.abc"; for (int i = 0; i < 100; i++) { EntityId methodId = methodLiterals[i]->GetMethodId(); - loader.MatchAndMarkMethod(expectRecordName, methodLiterals[i]->GetMethodName(pf.get(), methodId), methodId); + loader.MatchAndMarkMethod(pf_.get(), expectRecordName, + methodLiterals[i]->GetMethodName(pf_.get(), methodId), methodId); } for (int i = 61; i < 91; i++) { #if defined(SUPPORT_ENABLE_ASM_INTERP) if (i % 3 == 0) { - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[i]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[i]->GetMethodId())); } else { - ASSERT_TRUE(!loader.Match(expectRecordName, methodLiterals[i]->GetMethodId())); + ASSERT_TRUE(!loader.Match(pf_.get(), expectRecordName, methodLiterals[i]->GetMethodId())); #else if (i % 3 == 0) { - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[i]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[i]->GetMethodId())); } else { - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[i]->GetMethodId())); + ASSERT_TRUE(loader.Match(pf_.get(), expectRecordName, methodLiterals[i]->GetMethodId())); #endif } } @@ -602,40 +598,36 @@ HWTEST_F_L0(PGOProfilerTest, TextToBinary) HWTEST_F_L0(PGOProfilerTest, FailResetProfilerInWorker) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - )"; std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler12.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 1); // number of methods + CreateJSPandaFile("sample_test.abc", methodLiterals); + EXPECT_GE(methodLiterals.size(), 1); // number of methods mkdir("ark-profiler12/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); RuntimeOption option; - // Although enableProfle is set in option, but it will not work when isWorker is set. + // Although enableProfile is set in option, but it will not work when isWorker is set. option.SetEnableProfile(true); option.SetIsWorker(); option.SetProfileDir("ark-profiler12/"); // PgoProfiler is disabled as default. vm_ = JSNApi::CreateJSVM(option); - uint32_t checksum = 304293; - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler12.abc"); + JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); + uint32_t checksum = pf_->GetChecksum(); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); + constPool->SetJSPandaFile(pf_.get()); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); method->SetModule(vm_->GetJSThread(), recordName); JSNApi::DestroyJSVM(vm_); // Loader PGOProfilerDecoder loader("ark-profiler12/modules.ap", 2); - // path is empty() - ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - CString expectRecordName = "test"; - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); + ASSERT_TRUE(loader.LoadAndVerify(checksum)); + CString expectRecordName = "sample_test"; + ASSERT_FALSE(loader.Match(pf_.get(), expectRecordName, methodLiterals[0]->GetMethodId())); rmdir("ark-profiler12/"); } @@ -644,9 +636,9 @@ 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(); + ExecuteAndLoadJSPandaFile("ark-profiler13/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler13/modules.ap", 1); @@ -655,21 +647,21 @@ HWTEST_F_L0(PGOProfilerTest, ProfileCallTest) ASSERT_TRUE(decoder.LoadAndVerify(checksum)); ASSERT_TRUE(decoder1.LoadAndVerify(checksum)); ASSERT_TRUE(decoder2.LoadAndVerify(checksum)); - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->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)); + auto methodName = methodLiteral->GetMethodName(pf_.get(), methodId); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + decoder1.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + decoder2.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); if (std::string(methodName) == "Test") { - ASSERT_TRUE(decoder1.Match(targetRecordName, methodId)); - ASSERT_TRUE(decoder2.Match(targetRecordName, methodId)); + ASSERT_TRUE(decoder1.Match(pf_.get(), targetRecordName, methodId)); + ASSERT_TRUE(decoder2.Match(pf_.get(), targetRecordName, methodId)); } else { - ASSERT_TRUE(decoder1.Match(targetRecordName, methodId)); - ASSERT_TRUE(decoder2.Match(targetRecordName, methodId)); + ASSERT_TRUE(decoder1.Match(pf_.get(), targetRecordName, methodId)); + ASSERT_TRUE(decoder2.Match(pf_.get(), targetRecordName, methodId)); } } unlink("ark-profiler13/modules.ap"); @@ -680,20 +672,20 @@ 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(); + ExecuteAndLoadJSPandaFile("ark-profiler14/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler14/modules.ap", 1); ASSERT_TRUE(decoder.LoadAndVerify(checksum)); - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->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 methodName = methodLiteral->GetMethodName(pf_.get(), methodId); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); auto callback = [methodName, methodId](uint32_t offset, PGOType *type) { ASSERT_NE(offset, 0); if (type->IsScalarOpType()) { @@ -710,7 +702,8 @@ HWTEST_F_L0(PGOProfilerTest, UseClassTypeTest) ASSERT_TRUE(false); } }; - decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + decoder.GetTypeInfo(pf_.get(), targetRecordName, methodLiteral, + callback); } unlink("ark-profiler14/modules.ap"); rmdir("ark-profiler14/"); @@ -720,21 +713,21 @@ 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(); + ExecuteAndLoadJSPandaFile("ark-profiler15/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler15/modules.ap", 1); ASSERT_TRUE(decoder.LoadAndVerify(checksum)); - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->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) { + auto methodName = methodLiteral->GetMethodName(pf_.get(), methodId); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); + auto callback = [methodName, &decoder, jsPandaFile = pf_](uint32_t offset, PGOType *type) { ASSERT_NE(offset, 0); if (type->IsScalarOpType()) { auto sampleType = *reinterpret_cast(type); @@ -765,7 +758,8 @@ HWTEST_F_L0(PGOProfilerTest, DefineClassTypeTest) } } }; - decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + decoder.GetTypeInfo(pf_.get(), targetRecordName, methodLiteral, + callback); } unlink("ark-profiler15/modules.ap"); rmdir("ark-profiler15/"); @@ -775,9 +769,9 @@ 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(); + ExecuteAndLoadJSPandaFile("ark-profiler16/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler16/modules.ap", 1); @@ -785,14 +779,14 @@ HWTEST_F_L0(PGOProfilerTest, OpTypeTest) std::string types[17] = { "1", "5", "4", "4", "4", "4", "4", "4", "5", "4", "4", "1", "4", "5", "1" }; int index = 0; - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->GetMethodLiteralMap(); for (auto iter : methodLiterals) { auto methodLiteral = iter.second; auto methodId = methodLiteral->GetMethodId(); - auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId); + auto methodName = methodLiteral->GetMethodName(pf_.get(), methodId); if (std::string(methodName) != "sun" && std::string(methodName) != "sun1") { - decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId); - ASSERT_TRUE(decoder.Match(targetRecordName, methodId)); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); } auto callback = [methodName, types, &index](uint32_t offset, PGOType *type) { ASSERT_NE(offset, 0); @@ -814,7 +808,8 @@ HWTEST_F_L0(PGOProfilerTest, OpTypeTest) } } }; - decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + decoder.GetTypeInfo(pf_.get(), targetRecordName, methodLiteral, + callback); } unlink("ark-profiler16/modules.ap"); rmdir("ark-profiler16/"); @@ -824,21 +819,21 @@ HWTEST_F_L0(PGOProfilerTest, ArrayProfileTest) { mkdir("ark-profiler18/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); const char *targetRecordName = "array_test"; - std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName); - ASSERT_NE(jsPandaFile, nullptr); - uint32_t checksum = jsPandaFile->GetChecksum(); + ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler18/modules.ap", 1); ASSERT_TRUE(decoder.LoadAndVerify(checksum)); - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->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) { + auto methodName = methodLiteral->GetMethodName(pf_.get(), methodId); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); + auto callback = [methodName, &decoder, jsPandaFile = pf_](uint32_t offset, PGOType *type) { if (type->IsScalarOpType()) { auto sampleType = *reinterpret_cast(type); if (sampleType.IsProfileType()) { @@ -874,7 +869,8 @@ HWTEST_F_L0(PGOProfilerTest, ArrayProfileTest) } } }; - decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + decoder.GetTypeInfo(pf_.get(), targetRecordName, methodLiteral, + callback); } unlink("ark-profiler18/modules.ap"); rmdir("ark-profiler18/"); @@ -884,21 +880,21 @@ HWTEST_F_L0(PGOProfilerTest, ObjectLiteralProfileTest) { mkdir("ark-profiler20/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); const char *targetRecordName = "object_literal"; - std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler20/", targetRecordName); - ASSERT_NE(jsPandaFile, nullptr); - uint32_t checksum = jsPandaFile->GetChecksum(); + ExecuteAndLoadJSPandaFile("ark-profiler20/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // Loader PGOProfilerDecoder decoder("ark-profiler20/modules.ap", 1); ASSERT_TRUE(decoder.LoadAndVerify(checksum)); - auto methodLiterals = jsPandaFile->GetMethodLiteralMap(); + auto methodLiterals = pf_->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) { + auto methodName = methodLiteral->GetMethodName(pf_.get(), methodId); + decoder.MatchAndMarkMethod(pf_.get(), targetRecordName, methodName, methodId); + ASSERT_TRUE(decoder.Match(pf_.get(), targetRecordName, methodId)); + auto callback = [methodName, &decoder, jsPandaFile = pf_](uint32_t offset, PGOType *type) { if (type->IsScalarOpType()) { auto sampleType = *reinterpret_cast(type); if (sampleType.IsProfileType()) { @@ -936,40 +932,22 @@ HWTEST_F_L0(PGOProfilerTest, ObjectLiteralProfileTest) } } }; - decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback); + decoder.GetTypeInfo(pf_.get(), targetRecordName, methodLiteral, + callback); } unlink("ark-profiler20/modules.ap"); rmdir("ark-profiler20/"); } #endif +#if defined(SUPPORT_ENABLE_ASM_INTERP) HWTEST_F_L0(PGOProfilerTest, FileConsistencyCheck) { - const char *source = R"( - .language ECMAScript - .function void foo1(any a0, any a1, any a2) {} - )"; - std::vector methodLiterals {}; - std::shared_ptr pf = CreateJSPandaFile(source, "ark-profiler.abc", methodLiterals); - EXPECT_EQ(methodLiterals.size(), 1); // number of methods - mkdir("ark-profiler17/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - RuntimeOption option; - option.SetEnableProfile(true); - option.SetProfileDir("ark-profiler17/"); - vm_ = JSNApi::CreateJSVM(option); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); - constPool->SetJSPandaFile(pf.get()); - uint32_t checksum = 304293; - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler.abc"); - ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); - method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); - method->SetModule(vm_->GetJSThread(), recordName); - vm_->GetPGOProfiler()->SetSaveTimestamp(std::chrono::system_clock::now()); - JSNApi::DestroyJSVM(vm_); + const char *targetRecordName = "sample_test"; + ExecuteAndLoadJSPandaFile("ark-profiler17/", targetRecordName); + ASSERT_NE(pf_, nullptr); + uint32_t checksum = pf_->GetChecksum(); // write to corrupt the ap file's consistency std::ofstream fWriter("ark-profiler17/modules.ap", std::fstream::app); @@ -981,24 +959,17 @@ HWTEST_F_L0(PGOProfilerTest, FileConsistencyCheck) // Loader PGOProfilerDecoder loader("ark-profiler17/modules.ap", 2); - CString expectRecordName = "test"; -#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_FALSE(loader.LoadAndVerify(checksum)); -#else - ASSERT_TRUE(!loader.LoadAndVerify(checksum)); - ASSERT_TRUE(loader.Match(expectRecordName, methodLiterals[0]->GetMethodId())); -#endif unlink("ark-profiler17/modules.ap"); rmdir("ark-profiler17/"); } -#if defined(SUPPORT_ENABLE_ASM_INTERP) HWTEST_F_L0(PGOProfilerTest, MergeApSelfTwice) { mkdir("ark-profiler18/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); const char *targetRecordName = "op_type_test"; - std::shared_ptr jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName); - ASSERT_NE(jsPandaFile, nullptr); + ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName); + ASSERT_NE(pf_, nullptr); // Loader PGOProfilerDecoder decoder("ark-profiler18/modules_merge.ap", 1); diff --git a/ecmascript/pgo_profiler/tests/pgo_test_case/sample_test.js b/ecmascript/pgo_profiler/tests/pgo_test_case/sample_test.js new file mode 100644 index 0000000000..302c5137da --- /dev/null +++ b/ecmascript/pgo_profiler/tests/pgo_test_case/sample_test.js @@ -0,0 +1,13 @@ +function foo1() {} +function foo2() {} +function foo3() {} + +for (let i = 0; i < 5 ; i++) { + foo1(); +} + +for (let i = 0; i < 50 ; i++) { + foo3(); +} + +foo2(); diff --git a/ecmascript/pgo_profiler/types/pgo_profile_type.h b/ecmascript/pgo_profiler/types/pgo_profile_type.h index 01f8235557..e2ebe6cd5f 100644 --- a/ecmascript/pgo_profiler/types/pgo_profile_type.h +++ b/ecmascript/pgo_profiler/types/pgo_profile_type.h @@ -42,6 +42,7 @@ public: BuiltinsId, LegacyKind = BuiltinsId, LocalRecordId, + ModuleRecordId, TotalKinds, UnknowId }; @@ -58,6 +59,7 @@ public: static_assert(KindBits::IsValid(Kind::TotalKinds)); ProfileType() = default; + explicit ProfileType(uint64_t rawType) : type_(rawType) {}; ProfileType(PGOContext &context, ProfileTypeRef typeRef); ProfileType(ApEntityId abcId, uint32_t type, Kind kind = Kind::ClassId) { diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index c0927308dd..6912ff17a0 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/ts_types/ts_manager.h" +#include #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/global_env_constants-inl.h" @@ -172,7 +173,8 @@ int TSManager::GetHClassIndex(GlobalTSTypeRef classGT, bool isConstructor) if (HasOffsetFromGT(classGT)) { uint32_t literalOffset = 0; CString recordName = ""; - std::tie(recordName, literalOffset) = GetOffsetFromGt(classGT); + CString abcNormalizedDesc = ""; + std::tie(abcNormalizedDesc, recordName, literalOffset) = GetOffsetFromGt(classGT); GetCompilationDriver()->AddResolvedMethod(recordName, literalOffset); } // make sure already setting correct curCP_ and curCPID_ before calling this method diff --git a/ecmascript/ts_types/ts_manager.h b/ecmascript/ts_types/ts_manager.h index 9c09338403..959475e8b8 100644 --- a/ecmascript/ts_types/ts_manager.h +++ b/ecmascript/ts_types/ts_manager.h @@ -496,7 +496,7 @@ public: idGTMap_.emplace(id, gt); } if (!isImportType && !id.IsPGOType()) { - auto value = std::make_pair(recordName, id.GetTypeId()); + auto value = std::make_tuple(id.GetJSPandaFile()->GetNormalizedFileDesc(), recordName, id.GetTypeId()); gtLiteralOffsetMap_.emplace(gt, value); } } @@ -516,7 +516,7 @@ public: return gtLiteralOffsetMap_.find(gt) != gtLiteralOffsetMap_.end(); } - inline std::pair GetOffsetFromGt(GlobalTSTypeRef gt) const + inline std::tuple GetOffsetFromGt(GlobalTSTypeRef gt) const { return gtLiteralOffsetMap_.at(gt); } @@ -1114,7 +1114,7 @@ private: SnapshotData snapshotData_ {}; std::unordered_map idGTMap_ {}; - std::map> gtLiteralOffsetMap_ {}; + std::map> gtLiteralOffsetMap_ {}; std::vector builtinOffsets_ {}; JSPandaFile *builtinPandaFile_ {nullptr}; CString builtinsRecordName_ {""}; From 16df19e210c828a248cb0e4f7b9f52381736bc7b Mon Sep 17 00:00:00 2001 From: wu_zhang_da Date: Thu, 12 Oct 2023 21:18:01 +0800 Subject: [PATCH 26/50] NewJSError StackOverflow Bugfix Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87PJ9 Signed-off-by: wu_zhang_da Change-Id: I9dc4c7ce635181854bc48014afe53c4a7e94ff26 --- ecmascript/stubs/runtime_stubs.cpp | 1 + test/aottest/compiler_test/compiler_test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index e54af254d4..4087bdfb94 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2379,6 +2379,7 @@ JSTaggedValue RuntimeStubs::NewObject(EcmaRuntimeCallInfo *info) JSThread *thread = info->GetThread(); JSHandle func(info->GetFunction()); if (!func->IsHeapObject()) { + RETURN_STACK_BEFORE_THROW_IF_ASM(thread); THROW_TYPE_ERROR_AND_RETURN(thread, "function is nullptr", JSTaggedValue::Exception()); } diff --git a/test/aottest/compiler_test/compiler_test.ts b/test/aottest/compiler_test/compiler_test.ts index 2549270f8c..19e7b7b91f 100644 --- a/test/aottest/compiler_test/compiler_test.ts +++ b/test/aottest/compiler_test/compiler_test.ts @@ -55,4 +55,15 @@ function f59() : number[] {} class C60 extends f59 {} const v75 : number = new C60() +// case6: NewJSError Stack Overflow +function f230():string { + const v292:number = -2; + const v303:number[] = [1000,-1970969808,536870887,257,17933,11,1024]; + try { new v292(64, ...v303, ...v303, ...v303, ...v303); } catch (e) {} + return "bigint"; +} +for (let v316:number = 0; v316 < 5; v316++) { + f230(); +} + print("compiler success"); \ No newline at end of file From fe7caeb6e84c727650112dcc4648e5f43ed187a1 Mon Sep 17 00:00:00 2001 From: hwx1163501 Date: Tue, 10 Oct 2023 09:13:43 +0800 Subject: [PATCH 27/50] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=A8=E4=BE=8Bbind?= =?UTF-8?q?=E6=97=B6assert=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hwx1163501 issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I86O7V --- ecmascript/builtins/builtins_function.cpp | 12 ++++++++++-- test/moduletest/bindfunction/bindfunction.js | 6 +++++- test/moduletest/bindfunction/expect_output.txt | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ecmascript/builtins/builtins_function.cpp b/ecmascript/builtins/builtins_function.cpp index f1f0e01c38..1a9e6c7815 100644 --- a/ecmascript/builtins/builtins_function.cpp +++ b/ecmascript/builtins/builtins_function.cpp @@ -271,8 +271,16 @@ JSTaggedValue BuiltinsFunction::FunctionPrototypeToString(EcmaRuntimeCallInfo *a [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle thisValue = GetThis(argv); if (thisValue->IsJSObject() && thisValue->IsCallable()) { - JSHandle func = JSHandle::Cast(thisValue); - JSHandle method(thread, func->GetMethod()); + JSHandle method; + if (thisValue->IsBoundFunction()) { + JSHandle func = JSHandle::Cast(thisValue); + JSHandle methodHandle(thread, func->GetMethod()); + method = JSHandle::Cast(methodHandle); + } else { + JSHandle func = JSHandle::Cast(thisValue); + JSHandle methodHandle(thread, func->GetMethod()); + method = JSHandle::Cast(methodHandle); + } if (method->IsNativeWithCallField()) { JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); JSHandle methodName(JSObject::GetProperty(thread, thisValue, nameKey).GetValue()); diff --git a/test/moduletest/bindfunction/bindfunction.js b/test/moduletest/bindfunction/bindfunction.js index 8a920b6bfc..a7d542948a 100644 --- a/test/moduletest/bindfunction/bindfunction.js +++ b/test/moduletest/bindfunction/bindfunction.js @@ -72,4 +72,8 @@ var bfoo = foo.bind(undefined, 1); bfoo(2); var array = [1]; -array.forEach(bfoo); \ No newline at end of file +array.forEach(bfoo); + +const v6 = [] +const v21 = Float32Array.bind(v6, 1, 2); +print(v21) \ No newline at end of file diff --git a/test/moduletest/bindfunction/expect_output.txt b/test/moduletest/bindfunction/expect_output.txt index 5cf4f35edf..2cd4b1a220 100644 --- a/test/moduletest/bindfunction/expect_output.txt +++ b/test/moduletest/bindfunction/expect_output.txt @@ -18,3 +18,4 @@ 37,1,2,3 42 42 +function bound Float32Array() { [native code] } From 09d6c268b4eacc2bea1abb940e701a5fd3ca9062 Mon Sep 17 00:00:00 2001 From: liuzhijie Date: Thu, 12 Oct 2023 16:04:44 +0800 Subject: [PATCH 28/50] BugFix: ElementsKind::None Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87LOG?from=project-issue Signed-off-by: liuzhijie Change-Id: Ie889d73e72c83bb6ac185cea80d716286d7c4298 --- ecmascript/compiler/type_recorder.cpp | 7 +++++++ test/aottest/elements_kind/elements_kind.ts | 20 +++++++++++++++++++ test/aottest/elements_kind/expect_output.txt | 1 + .../elements_kind/pgo_expect_output.txt | 1 + 4 files changed, 29 insertions(+) diff --git a/ecmascript/compiler/type_recorder.cpp b/ecmascript/compiler/type_recorder.cpp index 1ff8953a6f..1b92aa0b5c 100644 --- a/ecmascript/compiler/type_recorder.cpp +++ b/ecmascript/compiler/type_recorder.cpp @@ -374,6 +374,13 @@ std::vector TypeRecorder::LoadElementsKinds(int32_t offset) const elementsKinds.emplace_back(elementsKind); } + // fiterate ElementsKind::None + for (uint32_t i = 0; i < elementsKinds.size(); i++) { + if (elementsKinds[i] == ElementsKind::NONE) { + elementsKinds[i] = ElementsKind::GENERIC; + } + } + return elementsKinds; } diff --git a/test/aottest/elements_kind/elements_kind.ts b/test/aottest/elements_kind/elements_kind.ts index 8db98a2fb4..e641878f6c 100644 --- a/test/aottest/elements_kind/elements_kind.ts +++ b/test/aottest/elements_kind/elements_kind.ts @@ -48,3 +48,23 @@ function testObject() { testObject(); +class OrderedCollection { + elms: number[]; + constructor() { + this.elms = []; + } + add(elm: number):void { + this.elms.push(elm); + } + + at(index: number):number{ + return this.elms[index]; + } +} + +let constraints: OrderedCollection = new OrderedCollection(); +constraints.add(0); +constraints.add(1); +constraints.add(2); +print(constraints.at(0)); + diff --git a/test/aottest/elements_kind/expect_output.txt b/test/aottest/elements_kind/expect_output.txt index 129b552121..7f75c274ec 100644 --- a/test/aottest/elements_kind/expect_output.txt +++ b/test/aottest/elements_kind/expect_output.txt @@ -17,3 +17,4 @@ undefined 1 2 +0 diff --git a/test/aottest/elements_kind/pgo_expect_output.txt b/test/aottest/elements_kind/pgo_expect_output.txt index 129b552121..7f75c274ec 100644 --- a/test/aottest/elements_kind/pgo_expect_output.txt +++ b/test/aottest/elements_kind/pgo_expect_output.txt @@ -17,3 +17,4 @@ undefined 1 2 +0 From f364d2d2fd8645a8c156a3fdad15617894540c8b Mon Sep 17 00:00:00 2001 From: EurusHomles-zH Date: Sat, 23 Sep 2023 15:17:37 +0800 Subject: [PATCH 29/50] Description:add jsHeapDumpInfo Signed-off-by: EurusHomles-zH --- ecmascript/dfx/hprof/heap_profiler.cpp | 28 ++++++++++++------- ecmascript/dfx/hprof/heap_profiler.h | 5 ++-- .../dfx/hprof/heap_profiler_interface.h | 3 +- ecmascript/mem/heap.cpp | 7 +++++ ecmascript/mem/heap.h | 2 ++ ecmascript/napi/dfx_jsnapi.cpp | 18 +++++++++--- ecmascript/napi/include/dfx_jsnapi.h | 7 +++-- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/ecmascript/dfx/hprof/heap_profiler.cpp b/ecmascript/dfx/hprof/heap_profiler.cpp index 2189c6eca6..10b8564a13 100644 --- a/ecmascript/dfx/hprof/heap_profiler.cpp +++ b/ecmascript/dfx/hprof/heap_profiler.cpp @@ -127,18 +127,24 @@ void HeapProfiler::UpdateHeapObjects(HeapSnapshot *snapshot) } bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress, - bool isVmMode, bool isPrivate, bool captureNumericValue) + bool isVmMode, bool isPrivate, bool captureNumericValue, bool isFullGC) { - [[maybe_unused]] bool heapClean = ForceFullGC(vm_); - ASSERT(heapClean); + if (isFullGC) { + [[maybe_unused]] bool heapClean = ForceFullGC(vm_); + ASSERT(heapClean); + } LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot start"; size_t heapSize = vm_->GetHeap()->GetHeapObjectSize(); LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot heap size " << heapSize; - int32_t heapCount = static_cast(vm_->GetHeap()->GetHeapObjectCount()); - if (progress != nullptr) { - progress->ReportProgress(0, heapCount); + int32_t heapCount = 0; + if (isFullGC) { + heapCount = static_cast(vm_->GetHeap()->GetHeapObjectCount()); + if (progress != nullptr) { + progress->ReportProgress(0, heapCount); + } } - HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue); + HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue, + false, isFullGC); ASSERT(snapshot != nullptr); entryIdMap_->RemoveDeadEntryId(snapshot); isProfiling_ = true; @@ -278,11 +284,13 @@ bool HeapProfiler::ForceFullGC(const EcmaVM *vm) } HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMode, bool isPrivate, - bool captureNumericValue, bool traceAllocation) + bool captureNumericValue, bool traceAllocation, bool isFullGC) { LOG_ECMA(INFO) << "HeapProfiler::MakeHeapSnapshot"; - DISALLOW_GARBAGE_COLLECTION; - const_cast(vm_->GetHeap())->Prepare(); + if (isFullGC) { + DISALLOW_GARBAGE_COLLECTION; + const_cast(vm_->GetHeap())->Prepare(); + } switch (sampleType) { case SampleType::ONE_SHOT: { auto *snapshot = GetChunk()->New(vm_, isVmMode, isPrivate, captureNumericValue, diff --git a/ecmascript/dfx/hprof/heap_profiler.h b/ecmascript/dfx/hprof/heap_profiler.h index 4facdb9b58..4fbacc8b67 100644 --- a/ecmascript/dfx/hprof/heap_profiler.h +++ b/ecmascript/dfx/hprof/heap_profiler.h @@ -76,7 +76,8 @@ public: * dump the specific snapshot in target format */ bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr, - bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false) override; + bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false, + bool isFullGC = true) override; void AddSnapshot(HeapSnapshot *snapshot); @@ -110,7 +111,7 @@ private: */ HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false, - bool traceAllocation = false); + bool traceAllocation = false, bool isFullGC = true); std::string GenDumpFileName(DumpFormat dumpFormat); CString GetTimeStamp(); void UpdateHeapObjects(HeapSnapshot *snapshot); diff --git a/ecmascript/dfx/hprof/heap_profiler_interface.h b/ecmascript/dfx/hprof/heap_profiler_interface.h index 385161cc78..8953efe26a 100644 --- a/ecmascript/dfx/hprof/heap_profiler_interface.h +++ b/ecmascript/dfx/hprof/heap_profiler_interface.h @@ -41,7 +41,8 @@ public: virtual void AllocationEvent(TaggedObject *address, size_t size) = 0; virtual void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size)= 0; virtual bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr, - bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false) = 0; + bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false, + bool isFullGC = true) = 0; virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr, bool traceAllocation = false, bool newThread = true) = 0; diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index c22e0416f7..3c315a8862 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -1257,6 +1257,13 @@ size_t Heap::GetArrayBufferSize() const return result; } +size_t Heap::GetHeapLimitSize() const +{ + // Obtains the theoretical upper limit of space that can be allocated to JS heap. + auto &config = ecmaVm_->GetEcmaParamConfiguration(); + return config.GetMaxHeapSize(); +} + bool Heap::IsAlive(TaggedObject *object) const { if (!ContainObject(object)) { diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index d51fb9e54e..6be04d4dc5 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -380,6 +380,8 @@ public: size_t GetArrayBufferSize() const; + size_t GetHeapLimitSize() const; + uint32_t GetMaxMarkTaskCount() const { return maxMarkTaskCount_; diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index f21e55ad9d..14e1b51369 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -65,14 +65,14 @@ void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unus void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat, [[maybe_unused]] Stream *stream, [[maybe_unused]] Progress *progress, [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate, - [[maybe_unused]] bool captureNumericValue) + [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC) { #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) ecmascript::base::BlockHookScope blockScope; ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( const_cast(vm)); heapProfile->DumpHeapSnapshot(ecmascript::DumpFormat(dumpFormat), stream, progress, - isVmMode, isPrivate, captureNumericValue); + isVmMode, isPrivate, captureNumericValue, isFullGC); #else LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; #endif @@ -82,7 +82,7 @@ void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unus void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat, [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate, - [[maybe_unused]] bool captureNumericValue) + [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC) { #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) #if defined(ENABLE_DUMP_IN_FAULTLOG) @@ -115,7 +115,7 @@ void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unus return; } FileDescriptorStream stream(fd); - DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate, captureNumericValue); + DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate, captureNumericValue, isFullGC); #endif // ENABLE_DUMP_IN_FAULTLOG #else LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; @@ -250,6 +250,16 @@ size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm) return vm->GetHeap()->GetHeapObjectSize(); } +size_t DFXJSNApi::GetHeapLimitSize(const EcmaVM *vm) +{ + return vm->GetHeap()->GetHeapLimitSize(); +} + +void DFXJSNApi::GetHeapPrepare(const EcmaVM *vm) +{ + const_cast(vm->GetHeap())->Prepare(); +} + void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground) { const_cast(vm->GetHeap())->ChangeGCParams(inBackground); diff --git a/ecmascript/napi/include/dfx_jsnapi.h b/ecmascript/napi/include/dfx_jsnapi.h index c2db828c80..eb29c74554 100644 --- a/ecmascript/napi/include/dfx_jsnapi.h +++ b/ecmascript/napi/include/dfx_jsnapi.h @@ -53,9 +53,10 @@ public: static void DumpHeapSnapshot(const EcmaVM *vm, int dumpFormat, const std::string &path, bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false); static void DumpHeapSnapshot(const EcmaVM *vm, int dumpFormat, Stream *stream, Progress *progress = nullptr, - bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false); + bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false, + bool isFullGC = true); static void DumpHeapSnapshot(const EcmaVM *vm, int dumpFormat, bool isVmMode = true, bool isPrivate = false, - bool captureNumericValue = false); + bool captureNumericValue = false, bool isFullGC = true); static void DestroyHeapProfiler(const EcmaVM *vm); static bool BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr); @@ -71,6 +72,8 @@ public: static size_t GetArrayBufferSize(const EcmaVM *vm); static size_t GetHeapTotalSize(const EcmaVM *vm); static size_t GetHeapUsedSize(const EcmaVM *vm); + static size_t GetHeapLimitSize(const EcmaVM *vm); + static void GetHeapPrepare(const EcmaVM *vm); static void NotifyApplicationState(EcmaVM *vm, bool inBackground); static void NotifyIdleStatusControl(const EcmaVM *vm, std::function callback); static void NotifyIdleTime(const EcmaVM *vm, int idleMicroSec); From 74b003a0e124faee22419931bc21c3839f200df1 Mon Sep 17 00:00:00 2001 From: miaojianzhuang Date: Fri, 13 Oct 2023 15:18:49 +0800 Subject: [PATCH 30/50] ExtendClassType Bugfix Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87SMO Signed-off-by: miaojianzhuang Change-Id: I701c3da68a8f5a831be22aae8a2af4d41cdeaa29 --- ecmascript/ts_types/ts_type_parser.cpp | 4 +++- test/aottest/compiler_test/compiler_test.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ecmascript/ts_types/ts_type_parser.cpp b/ecmascript/ts_types/ts_type_parser.cpp index f17514b49d..e61d46286d 100644 --- a/ecmascript/ts_types/ts_type_parser.cpp +++ b/ecmascript/ts_types/ts_type_parser.cpp @@ -495,7 +495,9 @@ void TSTypeParser::SetSuperClassType(const JSHandle &classType, classType->SetHasLinked(true); } else { auto extensionGT = CreateGT(jsPandaFile, recordName, extendsTypeId); - classType->SetExtensionGT(extensionGT); + if (tsManager_->IsClassTypeKind(extensionGT)){ + classType->SetExtensionGT(extensionGT); + } if (extensionGT.IsDefault()) { classType->SetHasLinked(true); } diff --git a/test/aottest/compiler_test/compiler_test.ts b/test/aottest/compiler_test/compiler_test.ts index 19e7b7b91f..9f4f83a913 100644 --- a/test/aottest/compiler_test/compiler_test.ts +++ b/test/aottest/compiler_test/compiler_test.ts @@ -66,4 +66,13 @@ for (let v316:number = 0; v316 < 5; v316++) { f230(); } +// case7: extendClassType check +const v1455:{} = ("boolean")[Symbol.iterator]; +try { + class C1723 extends v1455 { + [a1718]; + static [v1705] = a1719; + } +} catch (e) {} + print("compiler success"); \ No newline at end of file From db21da8c5fcaa2822b2402cb36ef579426c0bf6d Mon Sep 17 00:00:00 2001 From: bdf1 Date: Sun, 15 Oct 2023 00:59:21 +1000 Subject: [PATCH 31/50] Fix: ASSERT(stackmapNum % 2 == 0) Signed-off-by: bdf1 --- ecmascript/stackmap/ark_stackmap_parser.cpp | 1 - test/aottest/compiler_test/compiler_test.ts | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ecmascript/stackmap/ark_stackmap_parser.cpp b/ecmascript/stackmap/ark_stackmap_parser.cpp index 7adad46df7..8ba4148345 100644 --- a/ecmascript/stackmap/ark_stackmap_parser.cpp +++ b/ecmascript/stackmap/ark_stackmap_parser.cpp @@ -190,7 +190,6 @@ void ArkStackMapParser::ParseArkStackMap(const CallsiteHeader& callsiteHead, uin LLVMStackMapType::OffsetType offsetType; uint32_t offset = callsiteHead.stackmapOffset; uint16_t stackmapNum = callsiteHead.stackmapNum; - ASSERT(stackmapNum % 2 == 0); // 2:base and derive for (uint32_t j = 0; j < stackmapNum; j++) { auto [regOffset, regOffsetSize, is_full] = panda::leb128::DecodeSigned(ptr + offset); diff --git a/test/aottest/compiler_test/compiler_test.ts b/test/aottest/compiler_test/compiler_test.ts index 19e7b7b91f..422c59f2a2 100644 --- a/test/aottest/compiler_test/compiler_test.ts +++ b/test/aottest/compiler_test/compiler_test.ts @@ -66,4 +66,9 @@ for (let v316:number = 0; v316 < 5; v316++) { f230(); } +// case7: stackmapNum % 2 +let v39:any = 129 || C3; +Math.sign("12"); +v39++; + print("compiler success"); \ No newline at end of file From 41c10686df36dd39387a1a2b92131f5efa1a8fa3 Mon Sep 17 00:00:00 2001 From: yaochaonan Date: Wed, 11 Oct 2023 17:36:29 +0800 Subject: [PATCH 32/50] Optimize MatchResult to reduce substring Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I84ZJQ?from=project-issue Signed-off-by: yaochaonan Change-Id: Ic304bc49d82436562c8f45ff8fbce6113a17762f --- ecmascript/builtins/builtins_regexp.cpp | 177 +++--- ecmascript/builtins/builtins_regexp.h | 100 +++- ecmascript/ecma_context.cpp | 2 +- ecmascript/regexp/regexp_executor.cpp | 76 ++- ecmascript/regexp/regexp_executor.h | 17 +- ecmascript/regexp/tests/regexp_test.cpp | 700 +++++++++++++++--------- 6 files changed, 680 insertions(+), 392 deletions(-) diff --git a/ecmascript/builtins/builtins_regexp.cpp b/ecmascript/builtins/builtins_regexp.cpp index b0cd6deb72..f8c07a5fb8 100644 --- a/ecmascript/builtins/builtins_regexp.cpp +++ b/ecmascript/builtins/builtins_regexp.cpp @@ -703,20 +703,26 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); // 12. Let done be false. // 13. Repeat, while done is false for (;;) { if (lastIndex > inputLength) { break; } - bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); - auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced(); - const uint8_t *strBuffer = inputPtr.get(); - - RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, inputLength, lastIndex, isUtf16); - if (!matchResult.isSuccess_) { + FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString); + if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString + inputString = JSHandle(thread, flatStrInfo.GetString()); + } + const uint8_t *strBuffer; + if (isUtf16) { + strBuffer = reinterpret_cast(flatStrInfo.GetDataUtf16()); + } else { + strBuffer = flatStrInfo.GetDataUtf8(); + } + bool matchResult = Matcher(thread, regexp, strBuffer, inputLength, lastIndex, isUtf16); + if (!matchResult) { if (flags & (RegExpParser::FLAG_STICKY | RegExpParser::FLAG_GLOBAL)) { lastIndex = 0; ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), @@ -725,8 +731,8 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandleGetStartOfCaptureIndex(0).GetInt(); + uint32_t endIndex = globalTable->GetEndIndex().GetInt(); lastIndex = endIndex; if (nextPosition < startIndex) { auto substr = EcmaStringAccessor::FastSubString( @@ -1410,9 +1416,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) } // NOLINTNEXTLINE(readability-non-const-parameter) -RegExpExecutor::MatchResult BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle ®exp, - const uint8_t *buffer, size_t length, int32_t lastIndex, - bool isUtf16) +bool BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle ®exp, + const uint8_t *buffer, size_t length, int32_t lastIndex, + bool isUtf16) { BUILTINS_API_TRACE(thread, RegExp, Matcher); // get bytecode @@ -1426,8 +1432,10 @@ RegExpExecutor::MatchResult BuiltinsRegExp::Matcher(JSThread *thread, const JSHa lastIndex = 0; } bool ret = executor.Execute(buffer, lastIndex, static_cast(length), bytecodeBuffer, isUtf16); - RegExpExecutor::MatchResult result = executor.GetResult(thread, ret); - return result; + if (ret) { + executor.GetResult(thread); + } + return ret; } uint32_t BuiltinsRegExp::AdvanceStringIndex(const JSHandle &inputStr, uint32_t index, @@ -1599,14 +1607,21 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Null(); } - JSHandle inputString = JSTaggedValue::ToString(thread, inputStr); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); - auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced(); - const uint8_t *strBuffer = inputPtr.get(); + JSHandle inputString = JSHandle::Cast(inputStr); size_t stringLength = EcmaStringAccessor(inputString).GetLength(); - RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16); - if (!matchResult.isSuccess_) { + bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); + FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString); + if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString + inputString = JSHandle(thread, flatStrInfo.GetString()); + } + const uint8_t *strBuffer; + if (isUtf16) { + strBuffer = reinterpret_cast(flatStrInfo.GetDataUtf16()); + } else { + strBuffer = flatStrInfo.GetDataUtf8(); + } + bool matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16); + if (!matchResult) { if (global || sticky) { JSHandle lastIndexValue(thread, JSTaggedValue(0)); ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), @@ -1616,7 +1631,10 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle } return JSTaggedValue::Null(); } - uint32_t endIndex = matchResult.endIndex_; + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + globalTable->ResetDollar(thread); + globalTable->SetInputString(thread, inputString.GetTaggedValue()); + uint32_t endIndex = globalTable->GetEndIndex().GetInt(); if (global || sticky) { // a. Let setStatus be Set(R, "lastIndex", e, true). ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), @@ -1624,13 +1642,12 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle // b. ReturnIfAbrupt(setStatus). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - uint32_t capturesSize = matchResult.captures_.size(); + uint32_t capturesSize = globalTable->GetTotalCaptureCounts().GetInt(); JSHandle results(JSArray::ArrayCreate(thread, JSTaggedNumber(capturesSize))); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - uint32_t matchIndex = matchResult.index_; // 24. Perform CreateDataProperty(A, "index", matchIndex). JSHandle indexKey = globalConst->GetHandledIndexString(); - JSHandle indexValue(thread, JSTaggedValue(matchIndex)); + JSHandle indexValue(thread, globalTable->GetStartOfCaptureIndex(0)); JSObject::CreateDataProperty(thread, results, indexKey, indexValue); // 25. Perform CreateDataProperty(A, "input", S). JSHandle inputKey = globalConst->GetHandledInputString(); @@ -1638,16 +1655,18 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle JSObject::CreateDataProperty(thread, results, inputKey, inputValue); // 27. Perform CreateDataProperty(A, "0", matched_substr). - JSHandle zeroValue(matchResult.captures_[0].second.capturedValue); + uint32_t startIndex = globalTable->GetStartOfCaptureIndex(0).GetInt(); + uint32_t len = globalTable->GetEndOfCaptureIndex(0).GetInt() - startIndex; + JSHandle zeroValue(thread, JSTaggedValue(EcmaStringAccessor::FastSubString( + thread->GetEcmaVM(), inputString, startIndex, len))); JSObject::CreateDataProperty(thread, results, 0, zeroValue); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // Let indices be a new empty List. // Let groupNames be a new empty List. // Append match to indices. std::vector> indices; std::vector> groupNames; - indices.emplace_back(std::make_pair(JSTaggedValue(matchIndex), JSTaggedValue(endIndex))); + indices.emplace_back(std::make_pair(globalTable->GetStartOfCaptureIndex(0), JSTaggedValue(endIndex))); // If R contains any GroupName, then // a. Let groups be OrdinaryObjectCreate(null). // b. Let hasGroups be true. @@ -1658,6 +1677,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle JSMutableHandle groups(thread, JSTaggedValue::Undefined()); bool hasGroups = false; if (!groupName->IsUndefined()) { + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle nullObj = factory->OrdinaryNewJSObjectCreate(nullHandle); groups.Update(nullObj.GetTaggedValue()); @@ -1669,23 +1689,24 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle // Create a new RegExp on global uint32_t captureIndex = 1; JSHandle undefined = globalConst->GetHandledUndefined(); - JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSMutableHandle iValue(thread, JSTaggedValue::Undefined()); // 28. For each integer i such that i > 0 and i <= n for (; captureIndex < capturesSize; captureIndex++) { // a. Let capture_i be ith element of r's captures List - JSTaggedValue capturedValue; - if (matchResult.captures_[captureIndex].first) { - capturedValue = JSTaggedValue::Undefined(); + uint32_t captureStartIndex = globalTable->GetStartOfCaptureIndex(captureIndex).GetInt(); + uint32_t captureEndIndex = globalTable->GetEndOfCaptureIndex(captureIndex).GetInt(); + int32_t subStrLen = captureEndIndex - captureStartIndex; + if (subStrLen < 0) { + iValue.Update(JSTaggedValue::Undefined()); indices.emplace_back(std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined())); } else { - auto captureI = matchResult.captures_[captureIndex].second; - capturedValue = captureI.capturedValue.GetTaggedValue(); - indices.emplace_back(std::make_pair(JSTaggedValue(captureI.startIndex), JSTaggedValue(captureI.endIndex))); + iValue.Update(JSTaggedValue(EcmaStringAccessor::FastSubString( + thread->GetEcmaVM(), inputString, captureStartIndex, subStrLen))); + indices.emplace_back(std::make_pair(captureStartIndex, captureEndIndex)); } - JSHandle iValue(thread, capturedValue); // add to RegExp.$i and i must <= 9 if (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) { - globalTable->SetCapture(thread, captureIndex, capturedValue); + globalTable->SetCapture(thread, captureIndex, iValue.GetTaggedValue()); } JSObject::CreateDataProperty(thread, results, captureIndex, iValue); @@ -1825,53 +1846,40 @@ JSTaggedValue BuiltinsRegExp::RegExpExecForTestFast(JSThread *thread, JSHandle inputString = JSHandle::Cast(inputStr); + size_t stringLength = EcmaStringAccessor(inputString).GetLength(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); - auto inputPtr = EcmaStringAccessor(inputString).ToOneByteDataForced(); - const uint8_t *strBuffer = inputPtr.get(); - size_t stringLength = EcmaStringAccessor(inputString).GetLength(); - RegExpExecutor::MatchResult matchResult = Matcher(thread, regexp, strBuffer, stringLength, - lastIndex, isUtf16); - if (!matchResult.isSuccess_) { + FlatStringInfo flatStrInfo = EcmaStringAccessor::FlattenAllString(thread->GetEcmaVM(), inputString); + if (flatStrInfo.GetStartIndex() == 0) { // IsNotSlicedString + inputString = JSHandle(thread, flatStrInfo.GetString()); + } + const uint8_t *strBuffer; + if (isUtf16) { + strBuffer = reinterpret_cast(flatStrInfo.GetDataUtf16()); + } else { + strBuffer = flatStrInfo.GetDataUtf8(); + } + bool matchResult = Matcher(thread, regexp, strBuffer, stringLength, lastIndex, isUtf16); + if (!matchResult) { if (global || sticky) { object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0)); } return JSTaggedValue::False(); } - uint32_t endIndex = matchResult.endIndex_; - if (global || sticky) { - object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(endIndex)); - } - uint32_t capturesSize = matchResult.captures_.size(); JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); - uint32_t captureIndex = 1; - // For each integer i such that i > 0 and i <= n - for (; captureIndex < capturesSize; captureIndex++) { - // Let capture_i be ith element of r's captures List - JSTaggedValue capturedValue; - if (matchResult.captures_[captureIndex].first) { - capturedValue = JSTaggedValue::Undefined(); - } else { - auto captureI = matchResult.captures_[captureIndex].second; - capturedValue = captureI.capturedValue.GetTaggedValue(); - } - // add to RegExp.$i and i must <= 9 - if (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) { - globalTable->SetCapture(thread, captureIndex, capturedValue); - } - } - JSHandle emptyString = thread->GlobalConstants()->GetHandledEmptyString(); - while (captureIndex <= REGEXP_GLOBAL_ARRAY_SIZE) { - globalTable->SetCapture(thread, captureIndex, emptyString.GetTaggedValue()); - ++captureIndex; + globalTable->ResetDollar(thread); + globalTable->SetInputString(thread, inputString.GetTaggedValue()); + JSTaggedValue endIndex = globalTable->GetEndIndex(); + if (global || sticky) { + object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, endIndex); } if (useCache) { RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr, - JSHandle(thread, JSTaggedValue(matchResult.isSuccess_)), + JSHandle(thread, JSTaggedValue(matchResult)), RegExpExecResultCache::TEST_TYPE, - lastIndexInput, endIndex); + lastIndexInput, endIndex.GetInt()); } - return GetTaggedBoolean(matchResult.isSuccess_); + return GetTaggedBoolean(matchResult); } // 21.2.3.2.1 @@ -2107,8 +2115,7 @@ EcmaString *BuiltinsRegExp::EscapeRegExpPattern(JSThread *thread, const JSHandle #define SET_GET_CAPTURE_IMPL(index) \ JSTaggedValue BuiltinsRegExp::GetCapture##index(JSThread *thread, [[maybe_unused]] const JSHandle &obj) \ { \ - JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); \ - return globalTable->GetCapture(); \ + return RegExpGlobalResult::GetCapture(thread); \ } \ bool BuiltinsRegExp::SetCapture##index([[maybe_unused]] JSThread *thread, \ [[maybe_unused]] const JSHandle &obj, \ @@ -2393,16 +2400,34 @@ bool RegExpExecResultCache::Match(int entry, JSTaggedValue &pattern, JSTaggedVal extendEqual; } -JSTaggedValue RegExpGlobalResult::CreateGloablResultTable(JSThread *thread) +JSTaggedValue RegExpGlobalResult::CreateGlobalResultTable(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + uint32_t initialLength = GLOBAL_TABLE_SIZE + INITIAL_CAPTURE_INDICES; auto table = static_cast( - *factory->NewTaggedArray(GLOBAL_TABLE_SIZE, JSTaggedValue::Undefined())); + *factory->NewTaggedArray(initialLength, JSTaggedValue::Undefined())); // initialize dollars with empty string JSTaggedValue emptyString = factory->GetEmptyString().GetTaggedValue(); - for (int i = 1; i <= DOLLAR_NUMBER; i++) { + for (uint32_t i = 1; i <= DOLLAR_NUMBER; i++) { table->SetCapture(thread, CAPTURE_START_INDEX + i, emptyString); } + // initialize match info + table->SetTotalCaptureCounts(thread, JSTaggedValue(0)); + table->SetInputString(thread, emptyString); + for (uint32_t i = 0; i < INITIAL_CAPTURE_INDICES / 2; i++) { + table->SetStartOfCaptureIndex(thread, i, JSTaggedValue(0)); + table->SetEndOfCaptureIndex(thread, i, JSTaggedValue(0)); + } return JSTaggedValue(table); } + +JSHandle RegExpGlobalResult::GrowCapturesCapacity(JSThread *thread, + JSHandleresult, uint32_t length) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle newResult = factory->ExtendArray( + JSHandle(result), length, JSTaggedValue(0)); + thread->GetCurrentEcmaContext()->SetRegExpGlobalResult(newResult.GetTaggedValue()); + return JSHandle(newResult); +} } // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_regexp.h b/ecmascript/builtins/builtins_regexp.h index b890251ada..9e6f89b336 100644 --- a/ecmascript/builtins/builtins_regexp.h +++ b/ecmascript/builtins/builtins_regexp.h @@ -103,8 +103,8 @@ private: static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9; static constexpr uint32_t LAST_INDEX_OFFSET = 0; - static RegExpExecutor::MatchResult Matcher(JSThread *thread, const JSHandle ®exp, - const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16); + static bool Matcher(JSThread *thread, const JSHandle ®exp, + const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16); static bool GetFlagsInternal(JSThread *thread, const JSHandle &obj, const uint8_t mask); @@ -271,7 +271,7 @@ public: { return reinterpret_cast(object); } - static JSTaggedValue CreateGloablResultTable(JSThread *thread); + static JSTaggedValue CreateGlobalResultTable(JSThread *thread); void SetCapture(JSThread *thread, int index, JSTaggedValue value) { @@ -279,17 +279,101 @@ public: Set(thread, CAPTURE_START_INDEX + index - 1, value); } - template - JSTaggedValue GetCapture() + void ResetDollar(JSThread *thread) { - return Get(CAPTURE_START_INDEX + N - 1); + for (uint32_t i = 0; i < DOLLAR_NUMBER; i++) { + Set(thread, CAPTURE_START_INDEX + i, JSTaggedValue::Hole()); + } } + template + static JSTaggedValue GetCapture(JSThread *thread) + { + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSTaggedValue res = globalTable->Get(CAPTURE_START_INDEX + N - 1); + int captureNum = globalTable->GetTotalCaptureCounts().GetInt(); + if (res.IsHole() && (N < captureNum)) { + uint32_t startIndex = globalTable->GetStartOfCaptureIndex(N).GetInt(); + uint32_t endIndex = globalTable->GetEndOfCaptureIndex(N).GetInt(); + uint32_t len = endIndex - startIndex; + if (len < 0) { + res = JSTaggedValue::Undefined(); + } else { + res = JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), + JSHandle(thread, EcmaString::Cast(globalTable->GetInputString())), startIndex, len)); + } + globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res); + } else if (res.IsHole()) { + res = thread->GetEcmaVM()->GetFactory()->GetEmptyString().GetTaggedValue(); + globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res); + } + return res; + } + + void SetTotalCaptureCounts(JSThread *thread, JSTaggedValue counts) + { + Set(thread, TOTAL_CAPTURE_COUNTS_INDEX, counts); + } + + JSTaggedValue GetTotalCaptureCounts() + { + return Get(TOTAL_CAPTURE_COUNTS_INDEX); + } + + void SetEndIndex(JSThread *thread, JSTaggedValue endIndex) + { + Set(thread, END_INDEX, endIndex); + } + + JSTaggedValue GetEndIndex() + { + return Get(END_INDEX); + } + + void SetInputString(JSThread *thread, JSTaggedValue string) + { + Set(thread, INPUT_STRING_INDEX, string); + } + + JSTaggedValue GetInputString() + { + return Get(INPUT_STRING_INDEX); + } + + void SetStartOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value) + { + Set(thread, FIRST_CAPTURE_INDEX + index * 2, value); + } + + void SetEndOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value) + { + Set(thread, FIRST_CAPTURE_INDEX + index * 2 + 1, value); + } + + JSTaggedValue GetStartOfCaptureIndex(uint32_t index) + { + return Get(FIRST_CAPTURE_INDEX + index * 2); + } + + JSTaggedValue GetEndOfCaptureIndex(uint32_t index) + { + return Get(FIRST_CAPTURE_INDEX + index * 2 + 1); + } + + static JSHandle GrowCapturesCapacity(JSThread *thread, + JSHandleresult, uint32_t length); + + static constexpr int FIRST_CAPTURE_INDEX = 12; // capture index starts here + private: - static constexpr int GLOBAL_TABLE_SIZE = 9; + static constexpr int GLOBAL_TABLE_SIZE = 12; // initial length static constexpr int DOLLAR_NUMBER = 9; static constexpr int CAPTURE_START_INDEX = 0; -}; + static constexpr int TOTAL_CAPTURE_COUNTS_INDEX = 9; // save total capture size + static constexpr int INPUT_STRING_INDEX = 10; // save input string + static constexpr int END_INDEX = 11; // save last index + static constexpr int INITIAL_CAPTURE_INDICES = 18; // length: pairs of capture start index and end index +}; } // namespace panda::ecmascript::builtins #endif // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 940d103ce5..88d50b34e7 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -670,7 +670,7 @@ void EcmaContext::SetupRegExpResultCache() void EcmaContext::SetupRegExpGlobalResult() { - regexpGlobal_ = builtins::RegExpGlobalResult::CreateGloablResultTable(thread_); + regexpGlobal_ = builtins::RegExpGlobalResult::CreateGlobalResultTable(thread_); } void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) diff --git a/ecmascript/regexp/regexp_executor.cpp b/ecmascript/regexp/regexp_executor.cpp index 43c04bce73..5fbc6709be 100644 --- a/ecmascript/regexp/regexp_executor.cpp +++ b/ecmascript/regexp/regexp_executor.cpp @@ -16,6 +16,7 @@ #include "ecmascript/regexp/regexp_executor.h" #include "ecmascript/base/string_helper.h" +#include "ecmascript/js_object-inl.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/mem/dyn_chunk.h" #include "ecmascript/regexp/regexp_opcode.h" @@ -23,7 +24,7 @@ namespace panda::ecmascript { using RegExpState = RegExpExecutor::RegExpState; -using MatchResult = RegExpExecutor::MatchResult; +using RegExpGlobalResult = builtins::RegExpGlobalResult; bool RegExpExecutor::Execute(const uint8_t *input, uint32_t lastIndex, uint32_t length, uint8_t *buf, bool isWideChar) { DynChunk buffer(buf, chunk_); @@ -248,53 +249,42 @@ void RegExpExecutor::DumpResult(std::ostream &out) const } } -MatchResult RegExpExecutor::GetResult(const JSThread *thread, bool isSuccess) const +void RegExpExecutor::GetResult(JSThread *thread) { - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - MatchResult result; - std::vector> captures; - result.isSuccess_ = isSuccess; - if (isSuccess) { - for (uint32_t i = 0; i < nCapture_; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - CaptureState *captureState = &captureResultList_[i]; - if (i == 0) { - result.index_ = captureState->captureStart - input_; - if (isWideChar_) { - result.index_ /= WIDE_CHAR_SIZE; - } - } - int32_t len = captureState->captureEnd - captureState->captureStart; - std::pair pair; - if ((captureState->captureStart != nullptr && captureState->captureEnd != nullptr) && (len >= 0)) { - pair.first = false; - Capture capture; - if (isWideChar_) { - pair.second.startIndex = (captureState->captureStart - input_) / WIDE_CHAR_SIZE; - pair.second.endIndex = (captureState->captureEnd - input_) / WIDE_CHAR_SIZE; - // create utf-16 string - pair.second.capturedValue = factory->NewFromUtf16( - reinterpret_cast(captureState->captureStart), len / 2); - } else { - // create utf-8 string - pair.second.capturedValue = - factory->NewFromUtf8(reinterpret_cast(captureState->captureStart), len); - pair.second.startIndex = captureState->captureStart - input_; - pair.second.endIndex = captureState->captureEnd - input_; - } + JSHandle matchResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + matchResult->SetTotalCaptureCounts(thread, JSTaggedValue(nCapture_)); + uint32_t firstIndex = RegExpGlobalResult::FIRST_CAPTURE_INDEX; + uint32_t availableCaptureSlot = matchResult->GetLength() - firstIndex; + uint32_t requiredLength = nCapture_ * 2; + if (requiredLength > availableCaptureSlot) { + matchResult = RegExpGlobalResult::GrowCapturesCapacity(thread, matchResult, requiredLength + firstIndex); + } + for (uint32_t i = 0; i < nCapture_; i++) { + CaptureState *captureState = &captureResultList_[i]; + int32_t len = captureState->captureEnd - captureState->captureStart; + if ((captureState->captureStart != nullptr && captureState->captureEnd != nullptr) && (len >= 0)) { + if (isWideChar_) { + matchResult->SetStartOfCaptureIndex(thread, i, JSTaggedValue( + static_cast((captureState->captureStart - input_) / WIDE_CHAR_SIZE))); + matchResult->SetEndOfCaptureIndex(thread, i, JSTaggedValue( + static_cast((captureState->captureEnd - input_) / WIDE_CHAR_SIZE))); } else { - // undefined - pair.first = true; + matchResult->SetStartOfCaptureIndex(thread, i, JSTaggedValue( + static_cast(captureState->captureStart - input_))); + matchResult->SetEndOfCaptureIndex(thread, i, JSTaggedValue( + static_cast(captureState->captureEnd - input_))); } - captures.emplace_back(pair); - } - result.captures_ = captures; - result.endIndex_ = currentPtr_ - input_; - if (isWideChar_) { - result.endIndex_ /= WIDE_CHAR_SIZE; + } else { + // undefined + matchResult->SetStartOfCaptureIndex(thread, i, JSTaggedValue(0)); + matchResult->SetEndOfCaptureIndex(thread, i, JSTaggedValue(-1)); } } - return result; + uint32_t endIndex = currentPtr_ - input_; + if (isWideChar_) { + endIndex /= WIDE_CHAR_SIZE; + } + matchResult->SetEndIndex(thread, JSTaggedValue(endIndex)); } void RegExpExecutor::PushRegExpState(StateType type, uint32_t pc) diff --git a/ecmascript/regexp/regexp_executor.h b/ecmascript/regexp/regexp_executor.h index 39e14c13ba..d8d2b4e23e 100644 --- a/ecmascript/regexp/regexp_executor.h +++ b/ecmascript/regexp/regexp_executor.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_REGEXP_REGEXP_EXECUTOR_H #define ECMASCRIPT_REGEXP_REGEXP_EXECUTOR_H +#include "ecmascript/builtins/builtins_regexp.h" #include "ecmascript/regexp/regexp_parser.h" #include "ecmascript/mem/regexp_cached_chunk.h" #include "ecmascript/js_handle.h" @@ -42,20 +43,6 @@ public: __extension__ CaptureState *captureResultList_[0]; // NOLINT(modernize-avoid-c-arrays) }; - struct Capture { - uint32_t startIndex = 0; - uint32_t endIndex = 0; - JSHandle capturedValue; - }; - - struct MatchResult { - uint32_t endIndex_ = 0; - uint32_t index_ = 0; - // first value is true if result is undefined - std::vector> captures_; - bool isSuccess_ = false; - }; - explicit RegExpExecutor(RegExpCachedChunk *chunk) : chunk_(chunk) { ASSERT(chunk_ != nullptr); @@ -650,7 +637,7 @@ public: void DumpResult(std::ostream &out) const; - MatchResult GetResult(const JSThread *thread, bool isSuccess) const; + void GetResult(JSThread *thread); void PushRegExpState(StateType type, uint32_t pc); diff --git a/ecmascript/regexp/tests/regexp_test.cpp b/ecmascript/regexp/tests/regexp_test.cpp index 11d4e90b4d..e14ea72f77 100644 --- a/ecmascript/regexp/tests/regexp_test.cpp +++ b/ecmascript/regexp/tests/regexp_test.cpp @@ -22,7 +22,7 @@ namespace panda::test { using namespace panda::ecmascript; -using MatchResult = RegExpExecutor::MatchResult; +using RegExpGlobalResult = ecmascript::builtins::RegExpGlobalResult; class RegExpTest : public testing::Test { public: @@ -99,6 +99,15 @@ public: } } + JSHandle GetSubString(JSHandleregExpGlobalResult, + JSHandle inputStr, uint32_t index) + { + uint32_t startIndex = regExpGlobalResult->GetStartOfCaptureIndex(index).GetInt(); + uint32_t len = regExpGlobalResult->GetEndOfCaptureIndex(index).GetInt() - startIndex; + return JSHandle(thread, EcmaStringAccessor::FastSubString( + thread->GetEcmaVM(), inputStr, startIndex, len)); + } + protected: EcmaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; @@ -653,10 +662,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec1) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSHandle inputStr = factory->NewFromASCII("abc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); JSHandle str = factory->NewFromASCII("ab"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec2) @@ -675,19 +687,25 @@ HWTEST_F_L0(RegExpTest, ParseAndExec2) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 10U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 10U); + JSHandle inputStr = factory->NewFromASCII("cabd"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); JSHandle str = factory->NewFromASCII("ab"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str) == 0); - ASSERT_TRUE(result.captures_[4].first); - ASSERT_TRUE(result.captures_[5].first); - ASSERT_TRUE(result.captures_[6].first); - ASSERT_TRUE(result.captures_[7].first); - ASSERT_TRUE(result.captures_[8].first); - ASSERT_TRUE(result.captures_[9].first); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str) == 0); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(4).GetInt(), -1); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(5).GetInt(), -1); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(6).GetInt(), -1); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(7).GetInt(), -1); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(8).GetInt(), -1); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(9).GetInt(), -1); } HWTEST_F_L0(RegExpTest, ParseAndExec3) @@ -706,12 +724,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec3) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("aabaac"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); JSHandle str1 = factory->NewFromASCII("aaba"); JSHandle str2 = factory->NewFromASCII("ba"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str2) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec4) @@ -730,10 +752,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec4) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("aabaac"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("aa"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec5) @@ -752,10 +777,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec5) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("b"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII(""); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec6) @@ -774,19 +802,26 @@ HWTEST_F_L0(RegExpTest, ParseAndExec6) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 6U); - JSHandle str1 = factory->NewFromASCII("zaacbbbcac"); - JSHandle str2 = factory->NewFromASCII("z"); - JSHandle str3 = factory->NewFromASCII("ac"); - JSHandle str4 = factory->NewFromASCII("a"); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 6U); + JSHandle inputStr = factory->NewFromASCII("zaacbbbcac"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); + JSHandle resultStr5 = GetSubString(regExpGlobalResult, inputStr, 5); + JSHandle str0 = factory->NewFromASCII("zaacbbbcac"); + JSHandle str1 = factory->NewFromASCII("z"); + JSHandle str2 = factory->NewFromASCII("ac"); + JSHandle str3 = factory->NewFromASCII("a"); JSHandle str5 = factory->NewFromASCII("c"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str4) == 0); - ASSERT_TRUE(result.captures_[4].first); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[5].second.capturedValue, str5) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str3) == 0); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(4).GetInt(), -1); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr5, str5) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec7) @@ -805,10 +840,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec7) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("ab\nabc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("abc"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec8) @@ -827,10 +865,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec8) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("ab\nabc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("abc"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec9) @@ -849,10 +890,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec9) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("erv"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("er"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec10) @@ -871,10 +915,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec10) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("bad good"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("d"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec11) @@ -893,10 +940,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec11) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\na"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec12) @@ -915,10 +965,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec12) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\n"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("\n"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec13) @@ -937,10 +990,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec13) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\naabc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("abc"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec14) @@ -959,10 +1015,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec14) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\nbbabc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("abc"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec15) @@ -981,10 +1040,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec15) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("aabc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec16) @@ -1003,10 +1065,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec16) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("ABC"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("ABC"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec17) @@ -1025,10 +1090,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec17) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("a\n"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a\n"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec18) @@ -1063,10 +1131,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec19) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("ababc"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec20) @@ -1085,12 +1156,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec20) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII(""); - JSHandle str2 = factory->NewFromASCII("aaa"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("baaabac"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII(""); + JSHandle str1 = factory->NewFromASCII("aaa"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec21) @@ -1109,10 +1184,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec21) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("caab"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec22) @@ -1131,10 +1209,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec22) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("aaaa:aa"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("aaaa:"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec23) @@ -1153,10 +1234,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec23) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("caab"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("a"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec24) @@ -1191,12 +1275,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec25) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII(""); - JSHandle str2 = factory->NewFromASCII("ab"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("cabab"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII(""); + JSHandle str1 = factory->NewFromASCII("ab"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec26) @@ -1215,10 +1303,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec26) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("A"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("A"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec27) @@ -1237,10 +1328,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec27) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("Z"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("Z"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec28) @@ -1259,10 +1353,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec28) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\n"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("\n"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec29) @@ -1281,11 +1378,15 @@ HWTEST_F_L0(RegExpTest, ParseAndExec29) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str = factory->NewFromASCII(""); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII(""); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII(""); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str0) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec30) @@ -1304,11 +1405,14 @@ HWTEST_F_L0(RegExpTest, ParseAndExec30) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str = factory->NewFromASCII(""); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); - ASSERT_TRUE(result.captures_[1].first); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII(""); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle str0 = factory->NewFromASCII(""); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(1).GetInt(), -1); } HWTEST_F_L0(RegExpTest, ParseAndExec31) @@ -1325,12 +1429,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec31) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII("abb"); - JSHandle str2 = factory->NewFromASCII("b"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("aabb"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII("abb"); + JSHandle str1 = factory->NewFromASCII("b"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec32) @@ -1347,14 +1455,19 @@ HWTEST_F_L0(RegExpTest, ParseAndExec32) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 3U); - JSHandle str1 = factory->NewFromASCII("abb"); - JSHandle str2 = factory->NewFromASCII("ab"); - JSHandle str3 = factory->NewFromASCII("b"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 3U); + JSHandle inputStr = factory->NewFromASCII("aabb"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle str0 = factory->NewFromASCII("abb"); + JSHandle str1 = factory->NewFromASCII("ab"); + JSHandle str2 = factory->NewFromASCII("b"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec33) @@ -1371,10 +1484,14 @@ HWTEST_F_L0(RegExpTest, ParseAndExec33) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("qyqya"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("qya"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec34) @@ -1391,10 +1508,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec34) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("qyqy "); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("qy"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec35) @@ -1411,16 +1531,22 @@ HWTEST_F_L0(RegExpTest, ParseAndExec35) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 4U); - JSHandle str1 = factory->NewFromASCII("2021-01-09"); - JSHandle str2 = factory->NewFromASCII("2021"); - JSHandle str3 = factory->NewFromASCII("01"); - JSHandle str4 = factory->NewFromASCII("09"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str4) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 4U); + JSHandle inputStr = factory->NewFromASCII("xx2021-01-09"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); + JSHandle str0 = factory->NewFromASCII("2021-01-09"); + JSHandle str1 = factory->NewFromASCII("2021"); + JSHandle str2 = factory->NewFromASCII("01"); + JSHandle str3 = factory->NewFromASCII("09"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str3) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec36) @@ -1437,14 +1563,19 @@ HWTEST_F_L0(RegExpTest, ParseAndExec36) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 3U); - JSHandle str1 = factory->NewFromASCII("Quick Brown Fox Jumps"); - JSHandle str2 = factory->NewFromASCII("Brown"); - JSHandle str3 = factory->NewFromASCII("Jumps"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 3U); + JSHandle inputStr = factory->NewFromASCII("The Quick Brown Fox Jumps Over The Lazy Dog"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle str0 = factory->NewFromASCII("Quick Brown Fox Jumps"); + JSHandle str1 = factory->NewFromASCII("Brown"); + JSHandle str2 = factory->NewFromASCII("Jumps"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec37) @@ -1461,12 +1592,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec37) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII("abABc"); - JSHandle str2 = factory->NewFromASCII("AB"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("abABc"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII("abABc"); + JSHandle str1 = factory->NewFromASCII("AB"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec38) @@ -1483,14 +1618,19 @@ HWTEST_F_L0(RegExpTest, ParseAndExec38) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 3U); - JSHandle str1 = factory->NewFromASCII("www.netscape.com"); - JSHandle str2 = factory->NewFromASCII("netscape."); - JSHandle str3 = factory->NewFromASCII("netscap"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 3U); + JSHandle inputStr = factory->NewFromASCII("www.netscape.com"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle str0 = factory->NewFromASCII("www.netscape.com"); + JSHandle str1 = factory->NewFromASCII("netscape."); + JSHandle str2 = factory->NewFromASCII("netscap"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec39) @@ -1507,12 +1647,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec39) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII("b"); - JSHandle str2 = factory->NewFromASCII(""); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("baaaac"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII("b"); + JSHandle str1 = factory->NewFromASCII(""); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec40) @@ -1529,10 +1673,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec40) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("ab"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII(""); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec41) @@ -1549,15 +1696,20 @@ HWTEST_F_L0(RegExpTest, ParseAndExec41) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 4U); - JSHandle str1 = factory->NewFromASCII("baaabaac"); - JSHandle str2 = factory->NewFromASCII("ba"); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 4U); + JSHandle inputStr = factory->NewFromASCII("baaabaac"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); + JSHandle str0 = factory->NewFromASCII("baaabaac"); + JSHandle str1 = factory->NewFromASCII("ba"); JSHandle str3 = factory->NewFromASCII("abaac"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(result.captures_[2].first); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str3) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_EQ(regExpGlobalResult->GetEndOfCaptureIndex(2).GetInt(), -1); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str3) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec42) @@ -1574,10 +1726,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec42) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\n\n\\abc324234"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("abc324234"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec43) @@ -1594,10 +1749,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec43) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("line1\nline2"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("1\nl"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec44) @@ -1614,10 +1772,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec44) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("abc\bdef"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("c\bd"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec45) @@ -1634,10 +1795,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec45) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("easy\bto\u0008ride"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("easy"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec46) @@ -1654,14 +1818,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec46) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 3U); - JSHandle str1 = factory->NewFromASCII("Course_Creator = Test"); - JSHandle str2 = factory->NewFromASCII("Course_Creator"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_FALSE(result.captures_[1].first); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(result.captures_[2].first); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 3U); + JSHandle inputStr = factory->NewFromASCII("Course_Creator = Test"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII("Course_Creator = Test"); + JSHandle str1 = factory->NewFromASCII("Course_Creator"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec47) @@ -1678,10 +1844,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec47) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("pilOt\nsoviet robot\topenoffice"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("et"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec49) @@ -1698,18 +1867,25 @@ HWTEST_F_L0(RegExpTest, ParseAndExec49) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 5U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 5U); + JSHandle inputStr = factory->NewFromASCII("ab55"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); + JSHandle resultStr4 = GetSubString(regExpGlobalResult, inputStr, 4); + JSHandle str0 = factory->NewFromASCII("ab55"); JSHandle str1 = factory->NewFromASCII("ab55"); - JSHandle str2 = factory->NewFromASCII("ab55"); - JSHandle str3 = factory->NewFromASCII("b"); + JSHandle str2 = factory->NewFromASCII("b"); + JSHandle str3 = factory->NewFromASCII("5"); JSHandle str4 = factory->NewFromASCII("5"); - JSHandle str5 = factory->NewFromASCII("5"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str4) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[4].second.capturedValue, str5) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str3) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr4, str4) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec50) @@ -1726,16 +1902,22 @@ HWTEST_F_L0(RegExpTest, ParseAndExec50) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 4U); - JSHandle str1 = factory->NewFromASCII("2020-12-31"); - JSHandle str2 = factory->NewFromASCII("2020"); - JSHandle str3 = factory->NewFromASCII("12-31"); - JSHandle str4 = factory->NewFromASCII("31"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[2].second.capturedValue, str3) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[3].second.capturedValue, str4) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 4U); + JSHandle inputStr = factory->NewFromASCII("2020-12-31"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle resultStr2 = GetSubString(regExpGlobalResult, inputStr, 2); + JSHandle resultStr3 = GetSubString(regExpGlobalResult, inputStr, 3); + JSHandle str0 = factory->NewFromASCII("2020-12-31"); + JSHandle str1 = factory->NewFromASCII("2020"); + JSHandle str2 = factory->NewFromASCII("12-31"); + JSHandle str3 = factory->NewFromASCII("31"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr2, str2) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr3, str3) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec51) @@ -1751,8 +1933,9 @@ HWTEST_F_L0(RegExpTest, ParseAndExec51) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length() + 1, parser.GetOriginBuffer(), true); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); } HWTEST_F_L0(RegExpTest, ParseAndExec52) @@ -1769,12 +1952,16 @@ HWTEST_F_L0(RegExpTest, ParseAndExec52) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 2U); - JSHandle str1 = factory->NewFromASCII("aabcdaa"); - JSHandle str2 = factory->NewFromASCII("aa"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str1) == 0); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[1].second.capturedValue, str2) == 0); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 2U); + JSHandle inputStr = factory->NewFromASCII("aabcdaabcd"); + JSHandle resultStr0 = GetSubString(regExpGlobalResult, inputStr, 0); + JSHandle resultStr1 = GetSubString(regExpGlobalResult, inputStr, 1); + JSHandle str0 = factory->NewFromASCII("aabcdaa"); + JSHandle str1 = factory->NewFromASCII("aa"); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr0, str0) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr1, str1) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec53) @@ -1791,10 +1978,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec53) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer(), true); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromUtf16(u"\u0001"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("\u0001"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec54) @@ -1826,10 +2016,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec55) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer(), false); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("c\u0065"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("e"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec56) @@ -1846,10 +2039,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec56) bool ret = executor.Execute(reinterpret_cast(input.c_str()), 0, input.length(), parser.GetOriginBuffer(), true); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromUtf16(u"a啊"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromUtf8("a啊"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec57) @@ -1879,11 +2075,14 @@ HWTEST_F_L0(RegExpTest, ParseAndExec58) char16_t data[] = {0xd834, 0xdf06}; bool ret = executor.Execute(reinterpret_cast(data), 0, 2, parser.GetOriginBuffer(), true); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromUtf16(reinterpret_cast(data), 2); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); char16_t data1[] = {0xdf06}; JSHandle str = factory->NewFromUtf16(reinterpret_cast(data1), 1); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, ParseAndExec59) @@ -1902,10 +2101,13 @@ HWTEST_F_L0(RegExpTest, ParseAndExec59) executor.Execute(reinterpret_cast(input.c_str()), 0, input.size(), parser.GetOriginBuffer()); ASSERT_TRUE(ret); - MatchResult result = executor.GetResult(thread, ret); - ASSERT_EQ(result.captures_.size(), 1U); + executor.GetResult(thread); + JSHandle regExpGlobalResult(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + ASSERT_EQ(regExpGlobalResult->GetTotalCaptureCounts().GetInt(), 1U); + JSHandle inputStr = factory->NewFromASCII("\u000B"); + JSHandle resultStr = GetSubString(regExpGlobalResult, inputStr, 0); JSHandle str = factory->NewFromASCII("\u000B"); - ASSERT_TRUE(EcmaStringAccessor::Compare(instance, result.captures_[0].second.capturedValue, str) == 0); + ASSERT_TRUE(EcmaStringAccessor::Compare(instance, resultStr, str) == 0); } HWTEST_F_L0(RegExpTest, RangeSet1) From 29ff0a1ea37d2b0a832e171b4f20fd247eb57b3f Mon Sep 17 00:00:00 2001 From: g00416891 Date: Wed, 11 Oct 2023 14:43:13 +0800 Subject: [PATCH 33/50] Modify get hash use RandomGenerator instead of address Signed-off-by: g00416891 Change-Id: I56f1690513b36ee182060fc7a91dd25e50251356 --- ecmascript/base/number_helper.cpp | 11 +++++++++++ ecmascript/base/number_helper.h | 2 ++ ecmascript/builtins/builtins.cpp | 2 +- ecmascript/js_api/js_api_lightweightmap.cpp | 3 +-- ecmascript/js_api/js_api_lightweightset.cpp | 3 +-- ecmascript/linked_hash_table.cpp | 4 +--- ecmascript/tagged_node.h | 4 +--- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/ecmascript/base/number_helper.cpp b/ecmascript/base/number_helper.cpp index 795808d6e0..2748d7fc54 100644 --- a/ecmascript/base/number_helper.cpp +++ b/ecmascript/base/number_helper.cpp @@ -877,4 +877,15 @@ double RandomGenerator::ToDouble(uint64_t state) uint64_t random = (state >> base::RIGHT12) | EXPONENTBITS_RANGE_IN_ONE_AND_TWO; return base::bit_cast(random) - 1; } + +int32_t RandomGenerator::Next(int bits) +{ + uint64_t val = XorShift64(&randomState_); + return static_cast(val >> (INT64_BITS - bits)); +} + +int32_t RandomGenerator::GenerateIdentityHash() +{ + return RandomGenerator::Next(INT32_BITS) & INT32_MAX; +} } // namespace panda::ecmascript::base diff --git a/ecmascript/base/number_helper.h b/ecmascript/base/number_helper.h index 721ecf17ac..dfa51f025d 100644 --- a/ecmascript/base/number_helper.h +++ b/ecmascript/base/number_helper.h @@ -133,6 +133,8 @@ class RandomGenerator { public: static void InitRandom(); static double NextDouble(); + static int32_t GenerateIdentityHash(); + static int32_t Next(int bits); private: static uint64_t XorShift64(uint64_t *pVal); diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index 99e8447fde..69b010edae 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -314,8 +314,8 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool env->SetArgumentsClass(thread_, argumentsClass); SetArgumentsSharedAccessor(env); - InitializeGlobalObject(env, globalObject); InitializeMath(env, objFuncPrototypeVal); + InitializeGlobalObject(env, globalObject); InitializeAtomics(env, objFuncPrototypeVal); InitializeJson(env, objFuncPrototypeVal); InitializeIterator(env, objFuncClass); diff --git a/ecmascript/js_api/js_api_lightweightmap.cpp b/ecmascript/js_api/js_api_lightweightmap.cpp index f434f61df9..de7c3e669a 100644 --- a/ecmascript/js_api/js_api_lightweightmap.cpp +++ b/ecmascript/js_api/js_api_lightweightmap.cpp @@ -466,8 +466,7 @@ int32_t JSAPILightWeightMap::Hash(JSTaggedValue key) if (key.IsECMAObject()) { uint32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(); if (hash == 0) { - uint64_t keyValue = key.GetRawData(); - hash = GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + hash = base::RandomGenerator::GenerateIdentityHash(); ECMAObject::Cast(key.GetTaggedObject())->SetHash(hash); } return hash; diff --git a/ecmascript/js_api/js_api_lightweightset.cpp b/ecmascript/js_api/js_api_lightweightset.cpp index 0adfc0fcf9..01c82fa37a 100644 --- a/ecmascript/js_api/js_api_lightweightset.cpp +++ b/ecmascript/js_api/js_api_lightweightset.cpp @@ -462,8 +462,7 @@ uint32_t JSAPILightWeightSet::Hash(JSTaggedValue key) if (key.IsECMAObject()) { uint32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(); if (hash == 0) { - uint64_t keyValue = key.GetRawData(); - hash = GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + hash = base::RandomGenerator::GenerateIdentityHash(); ECMAObject::Cast(key.GetTaggedObject())->SetHash(hash); } return hash; diff --git a/ecmascript/linked_hash_table.cpp b/ecmascript/linked_hash_table.cpp index cea7dd613c..2f155dfd69 100644 --- a/ecmascript/linked_hash_table.cpp +++ b/ecmascript/linked_hash_table.cpp @@ -243,9 +243,7 @@ int LinkedHash::Hash(JSTaggedValue key) if (key.IsECMAObject()) { int32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(); if (hash == 0) { - uint64_t keyValue = key.GetRawData(); - hash = static_cast( - GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t))); + hash = base::RandomGenerator::GenerateIdentityHash(); ECMAObject::Cast(key.GetTaggedObject())->SetHash(hash); } return hash; diff --git a/ecmascript/tagged_node.h b/ecmascript/tagged_node.h index 21bbb03182..2b982908ee 100644 --- a/ecmascript/tagged_node.h +++ b/ecmascript/tagged_node.h @@ -65,9 +65,7 @@ public: if (key.IsECMAObject()) { int32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(); if (hash == 0) { - uint64_t keyValue = key.GetRawData(); - hash = static_cast(GetHash32(reinterpret_cast(&keyValue), - sizeof(keyValue) / sizeof(uint8_t))); + hash = base::RandomGenerator::GenerateIdentityHash(); ECMAObject::Cast(key.GetTaggedObject())->SetHash(hash); } return hash; From 44602d28f8a7b2254dcd3f227876588342cf0a66 Mon Sep 17 00:00:00 2001 From: yang-19970325 Date: Wed, 11 Oct 2023 15:03:05 +0800 Subject: [PATCH 34/50] Signed-off-by: yang-19970325 Change-Id: Iab6a3f2865453282ef63daf7f3879ab4271c9885 Change-Id: Ie64362dee9bd73d1a4000e3b101e0ab8a574ea17 --- ecmascript/debugger/debugger_api.cpp | 4 ++-- ecmascript/debugger/debugger_api.h | 2 +- ecmascript/debugger/hot_reload_manager.cpp | 7 ++++--- ecmascript/debugger/hot_reload_manager.h | 4 ++-- ecmascript/debugger/tests/hot_reload_manager_test.cpp | 6 +++--- ecmascript/jspandafile/debug_info_extractor.h | 10 ++++++---- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/ecmascript/debugger/debugger_api.cpp b/ecmascript/debugger/debugger_api.cpp index 185d2ab0e7..f944febc7f 100644 --- a/ecmascript/debugger/debugger_api.cpp +++ b/ecmascript/debugger/debugger_api.cpp @@ -822,10 +822,10 @@ bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm) return false; } -DebugInfoExtractor *DebuggerApi::GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url) +std::vector DebuggerApi::GetPatchExtractors(const EcmaVM *ecmaVm, const std::string &url) { const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager(); - return hotReloadManager->GetPatchExtractor(url); + return hotReloadManager->GetPatchExtractors(url); } const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile) diff --git a/ecmascript/debugger/debugger_api.h b/ecmascript/debugger/debugger_api.h index f2e7807e33..6f3a3f70f4 100644 --- a/ecmascript/debugger/debugger_api.h +++ b/ecmascript/debugger/debugger_api.h @@ -127,7 +127,7 @@ public: std::string_view entryPoint); // HotReload - static DebugInfoExtractor *GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url); + static std::vector GetPatchExtractors(const EcmaVM *ecmaVm, const std::string &url); static const JSPandaFile *GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile); static std::vector GetNativePointer(const EcmaVM *ecmaVm); diff --git a/ecmascript/debugger/hot_reload_manager.cpp b/ecmascript/debugger/hot_reload_manager.cpp index 29f29def9e..a446356019 100644 --- a/ecmascript/debugger/hot_reload_manager.cpp +++ b/ecmascript/debugger/hot_reload_manager.cpp @@ -52,11 +52,12 @@ const JSPandaFile *HotReloadManager::GetBaseJSPandaFile(const JSPandaFile *jsPan return iter->second; } -DebugInfoExtractor *HotReloadManager::GetPatchExtractor(const std::string &url) const +std::vector HotReloadManager::GetPatchExtractors(const std::string &url) const { + std::vector extractors; auto iter = patchExtractors_.find(url); if (iter == patchExtractors_.end()) { - return nullptr; + return extractors; } return iter->second; } @@ -78,7 +79,7 @@ void HotReloadManager::ExtractPatch(const JSPandaFile *jsPandaFile) continue; } notificationMgr->LoadModuleEvent(jsPandaFile->GetJSPandaFileDesc(), recordName); - patchExtractors_[url] = patchExtractor; + patchExtractors_[url].emplace_back(patchExtractor); } } } // namespace panda::ecmascript::tooling diff --git a/ecmascript/debugger/hot_reload_manager.h b/ecmascript/debugger/hot_reload_manager.h index 146f39b707..4764ffd78e 100644 --- a/ecmascript/debugger/hot_reload_manager.h +++ b/ecmascript/debugger/hot_reload_manager.h @@ -31,7 +31,7 @@ public: void NotifyPatchLoaded(const JSPandaFile *baseFile, const JSPandaFile *patchFile); void NotifyPatchUnloaded(const JSPandaFile *patchFile); - DebugInfoExtractor *GetPatchExtractor(const std::string &url) const; + std::vector GetPatchExtractors(const std::string &url) const; const JSPandaFile *GetBaseJSPandaFile(const JSPandaFile *jsPandaFile) const; private: @@ -39,7 +39,7 @@ private: const EcmaVM *vm_; CUnorderedMap baseJSPandaFiles_ {}; - CUnorderedMap patchExtractors_ {}; + CUnorderedMap> patchExtractors_ {}; }; } // namespace panda::ecmascript::tooling #endif // ECMASCRIPT_DEBUGGER_HOT_RELOAD_MANAGER_H diff --git a/ecmascript/debugger/tests/hot_reload_manager_test.cpp b/ecmascript/debugger/tests/hot_reload_manager_test.cpp index 032bc872cc..2008557074 100644 --- a/ecmascript/debugger/tests/hot_reload_manager_test.cpp +++ b/ecmascript/debugger/tests/hot_reload_manager_test.cpp @@ -82,8 +82,8 @@ HWTEST_F_L0(HotReloadManagerTest, LoadAndUnload) EXPECT_TRUE(patchFile != nullptr); EXPECT_TRUE(hotReloadManager->GetBaseJSPandaFile(patchFile.get()) == baseFile.get()); - [[maybe_unused]] auto *patchExtractor = hotReloadManager->GetPatchExtractor(sourceFile); - EXPECT_TRUE(patchExtractor != nullptr); + [[maybe_unused]] auto patchExtractors = hotReloadManager->GetPatchExtractors(sourceFile); + EXPECT_TRUE(!patchExtractors.empty()); Local exception = JSNApi::GetAndClearUncaughtException(ecmaVm); result = JSNApi::IsQuickFixCausedException(ecmaVm, exception, patchFileName); @@ -92,6 +92,6 @@ HWTEST_F_L0(HotReloadManagerTest, LoadAndUnload) res = JSNApi::UnloadPatch(ecmaVm, patchFileName); EXPECT_TRUE(res == PatchErrorCode::SUCCESS); EXPECT_TRUE(hotReloadManager->GetBaseJSPandaFile(patchFile.get()) != baseFile.get()); - EXPECT_TRUE(hotReloadManager->GetPatchExtractor(sourceFile) == nullptr); + EXPECT_TRUE(hotReloadManager->GetPatchExtractors(sourceFile).empty()); } } // namespace panda::test diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h index c70ae26c3f..2594fd3e00 100644 --- a/ecmascript/jspandafile/debug_info_extractor.h +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -93,7 +93,7 @@ public: template bool MatchWithLocation(const Callback &cb, int32_t line, int32_t column, - const std::string &url, const std::string &debugRecordName) + const std::string &url, const std::unordered_set &debugRecordName) { if (line == SPECIAL_LINE_MARK) { return false; @@ -110,9 +110,11 @@ public: panda_file::ClassDataAccessor cda(pandaFile, id); CString recordName = JSPandaFile::ParseEntryPoint(utf::Mutf8AsCString(cda.GetDescriptor())); // the recordName for testcases is empty - if (!debugRecordName.empty() && recordName != debugRecordName.c_str() - && debugRecordName != JSPandaFile::ENTRY_MAIN_FUNCTION) { - continue; + if (!debugRecordName.empty()) { + auto iter = debugRecordName.find(std::string(recordName)); + if (iter == debugRecordName.end()) { + continue; + } } cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { methodIds.push_back(mda.GetMethodId()); From f7c68ad35446f3954538d6f683b59b37ae492bca Mon Sep 17 00:00:00 2001 From: DaiHN Date: Tue, 17 Oct 2023 15:02:07 +0800 Subject: [PATCH 35/50] fix hap crash issue by parsing Constantstring in wedgets.abc issue : https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I88QRY?from=project-issue Signed-off-by: DaiHN Change-Id: Ic552c1bf39579d8d9430c2bd077bc0a7b3df70c2 --- ecmascript/jspandafile/js_pandafile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index 3e36715a85..f0774f662b 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -36,7 +36,7 @@ JSPandaFile::JSPandaFile(const panda_file::File *pf, const CString &descriptor) } checksum_ = pf->GetHeader()->checksum; isNewVersion_ = pf_->GetHeader()->version > OLD_VERSION; - if (!loadedFirstPandaFile && !isBundlePack_) { + if (!loadedFirstPandaFile && !isBundlePack_ && strstr(desc_.c_str(), MERGE_ABC_NAME) != NULL) { // Tag the first merged abc to use constant string. The lifetime of this first panda file is the same // as the vm. And make sure the first pandafile is the same at the compile time and runtime. isFirstPandafile_ = true; From b60e7fcdc26c9172e6b16697ad5bafa644e5cebd Mon Sep 17 00:00:00 2001 From: hecunmao Date: Fri, 13 Oct 2023 19:28:55 +0800 Subject: [PATCH 36/50] where dateStyle,timeStyle is not effective in Intl.DateTimeFormat add dateStyle,timeStyle to simpleDateFormatIcu issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87XK3 Signed-off-by: hecunmao Change-Id: Ia2ce83678e0c7636cc7f66217bc07dbfcec0a772 --- .../tests/builtins_date_time_format_test.cpp | 24 +++ ecmascript/js_date_time_format.cpp | 137 ++++++++++++++++++ ecmascript/js_date_time_format.h | 8 + 3 files changed, 169 insertions(+) diff --git a/ecmascript/builtins/tests/builtins_date_time_format_test.cpp b/ecmascript/builtins/tests/builtins_date_time_format_test.cpp index fd86ae446c..0d09ed38b9 100644 --- a/ecmascript/builtins/tests/builtins_date_time_format_test.cpp +++ b/ecmascript/builtins/tests/builtins_date_time_format_test.cpp @@ -647,4 +647,28 @@ HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_003) JSHandle elements(thread, resultHandle->GetElements()); EXPECT_EQ(elements->GetLength(), 16U); } + +// DateTimeFormat_004 +HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_004) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle localesString(factory->NewFromASCII("zh-CN")); + auto jsObj = JSHandle(thread, JSDateTimeFormatForObj_002(thread)); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + JSHandle objFun = env->GetObjectFunction(); + JSHandle optionsObj = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); + JSHandle fullValue(factory->NewFromASCII("full")); + JSHandle falseValue(thread, JSTaggedValue(false)); + JSHandle dateStyleValue(factory->NewFromASCII("dateStyle")); + JSHandle timeStyleeValue(factory->NewFromASCII("timeStyle")); + JSHandle hour12Value(factory->NewFromASCII("hour12")); + JSObject::SetProperty(thread, optionsObj, dateStyleValue, fullValue); + JSObject::SetProperty(thread, optionsObj, timeStyleeValue, fullValue); + JSObject::SetProperty(thread, optionsObj, hour12Value, falseValue); + auto constructorResult = JSDateTimeFormatConstructor(thread, optionsObj, localesString); + JSHandle resultStr = + JSDateTimeFormat::FormatDateTime(thread, JSHandle(thread, constructorResult), 0.0); + EXPECT_STREQ("1970年1月1日星期四 中国标准时间 08:00:00", EcmaStringAccessor(resultStr).ToCString().c_str()); +} } // namespace panda::test + diff --git a/ecmascript/js_date_time_format.cpp b/ecmascript/js_date_time_format.cpp index 8bc273c1a0..d06571be4a 100644 --- a/ecmascript/js_date_time_format.cpp +++ b/ecmascript/js_date_time_format.cpp @@ -189,6 +189,134 @@ JSHandle JSDateTimeFormat::ToValueString(JSThread *thread, const Val return result; } +icu::DateFormat::EStyle DateTimeStyleToEStyle(DateTimeStyleOption style) +{ + switch (style) { + case DateTimeStyleOption::FULL: { + return icu::DateFormat::kFull; + } + case DateTimeStyleOption::LONG: { + return icu::DateFormat::kLong; + } + case DateTimeStyleOption::MEDIUM: { + return icu::DateFormat::kMedium; + } + case DateTimeStyleOption::SHORT: { + return icu::DateFormat::kShort; + } + case DateTimeStyleOption::UNDEFINED: { + return icu::DateFormat::kNone; + } + default: { + return icu::DateFormat::kNone; + } + } +} + +HourCycleOption HourCycleFromPattern(const icu::UnicodeString pattern) +{ + bool inQuote = false; + for (int32_t i = 0; i < pattern.length(); i++) { + char16_t ch = pattern[i]; + switch (ch) { + case '\'': + inQuote = !inQuote; + break; + case 'K': + if (!inQuote) { + return HourCycleOption::H11; + } + break; + case 'h': + if (!inQuote) { + return HourCycleOption::H12; + } + break; + case 'H': + if (!inQuote) { + return HourCycleOption::H23; + } + break; + case 'k': + if (!inQuote) { + return HourCycleOption::H24; + } + break; + default : { + break; + } + } + } + return HourCycleOption::UNDEFINED; +} + +icu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, HourCycleOption hc) +{ + icu::UnicodeString result; + char16_t to; + switch (hc) { + case HourCycleOption::H11: + to = 'K'; + break; + case HourCycleOption::H12: + to = 'h'; + break; + case HourCycleOption::H23: + to = 'H'; + break; + case HourCycleOption::H24: + to = 'k'; + break; + default: + UNREACHABLE(); + break; + } + int inputLength = input.length(); + for (int32_t i = 0; i < inputLength; ++i) { + switch (input[i]) { + case 'a': + case 'b': + case 'B': + break; + case 'h': + case 'H': + case 'k': + case 'K': + result += to; + break; + default: + result += input[i]; + break; + } + } + return result; +} + +std::unique_ptr DateTimeStylePattern(DateTimeStyleOption dateStyle, + DateTimeStyleOption timeStyle, + icu::Locale &icuLocale, + HourCycleOption hc, + icu::DateTimePatternGenerator *generator) +{ + std::unique_ptr result; + icu::DateFormat::EStyle icuDateStyle = DateTimeStyleToEStyle(dateStyle); + icu::DateFormat::EStyle icuTimeStyle = DateTimeStyleToEStyle(timeStyle); + result.reset(reinterpret_cast( + icu::DateFormat::createDateTimeInstance(icuDateStyle, icuTimeStyle, icuLocale))); + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString pattern; + pattern = result->toPattern(pattern); + icu::UnicodeString skeleton = icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status); + ASSERT_PRINT(U_SUCCESS(status), "staticGetSkeleton failed"); + if (hc == HourCycleFromPattern(pattern)) { + return result; + } + skeleton = ReplaceSkeleton(skeleton, hc); + pattern = generator->getBestPattern(skeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH, status); + result = std::make_unique(pattern, icuLocale, status); + return result; +} + // 13.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) // NOLINTNEXTLINE(readability-function-size) JSHandle JSDateTimeFormat::InitializeDateTimeFormat(JSThread *thread, @@ -379,6 +507,7 @@ JSHandle JSDateTimeFormat::InitializeDateTimeFormat(JSThread * // c. Set opt.[[]] to value. std::string skeleton; std::vector data = GetIcuPatternDesc(hc); + int32_t explicitFormatComponents = 0; for (const IcuPatternDesc &item : data) { // prop be [[TimeZoneName]] if (item.property == "timeZoneName") { @@ -392,6 +521,7 @@ JSHandle JSDateTimeFormat::InitializeDateTimeFormat(JSThread * bool isFind = JSLocale::GetOptionOfString(thread, dateTimeOptions, property, item.allowedValues, &value); RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDateTimeFormat, thread); if (isFind) { + explicitFormatComponents = 1; skeleton += item.map.find(value)->second; // [[Hour]] is defined. isHourDefined = (item.property == "hour") ? true : isHourDefined; @@ -449,6 +579,13 @@ JSHandle JSDateTimeFormat::InitializeDateTimeFormat(JSThread * generator.get()->getBestPattern(dtfSkeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH, status), dtfHourCycle); ASSERT_PRINT((U_SUCCESS(status) != 0), "get best pattern failed"); auto simpleDateFormatIcu(std::make_unique(pattern, icuLocale, status)); + if (dateStyle != DateTimeStyleOption::UNDEFINED || timeStyle != DateTimeStyleOption::UNDEFINED) { + if (explicitFormatComponents != 0) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Invalid option : option", dateTimeFormat); + } + simpleDateFormatIcu = DateTimeStylePattern(dateStyle, timeStyle, icuLocale, + hc, generator.get()); + } if (U_FAILURE(status) != 0) { simpleDateFormatIcu = std::unique_ptr(); } diff --git a/ecmascript/js_date_time_format.h b/ecmascript/js_date_time_format.h index 10490fa55c..e946e62edc 100644 --- a/ecmascript/js_date_time_format.h +++ b/ecmascript/js_date_time_format.h @@ -42,6 +42,14 @@ class IcuPatternDesc; std::vector BuildIcuPatternDescs(); std::vector InitializePattern(const IcuPatternDesc &hourData); +icu::DateFormat::EStyle DateTimeStyleToEStyle(DateTimeStyleOption style); +HourCycleOption HourCycleFromPattern(const icu::UnicodeString pattern); +icu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, HourCycleOption hc); +std::unique_ptr DateTimeStylePattern(DateTimeStyleOption dateStyle, + DateTimeStyleOption timeStyle, + icu::Locale &icuLocale, + HourCycleOption hc, + icu::DateTimePatternGenerator *generator); using IcuPatternDescVect = std::vector; using IcuPatternEntry = std::pair; From eb61cff682e6f240578dbd7911907f98a1d78525 Mon Sep 17 00:00:00 2001 From: chenjx-huawei Date: Tue, 17 Oct 2023 20:59:15 +0800 Subject: [PATCH 37/50] Bugfix on BuiltinsRegExp::FlagsBitsToString which flagsStr is OOB Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I88UUY?from=project-issue Signed-off-by: chenjx-huawei Change-Id: I6b41de6509e1c001cbd867a2108492817a9a0c4a --- ecmascript/builtins/builtins_regexp.cpp | 2 +- ecmascript/regexp/regexp_parser.h | 1 + test/moduletest/regexpflagd/expect_output.txt | 1 + test/moduletest/regexpflagd/regexpflagd.js | 3 +++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ecmascript/builtins/builtins_regexp.cpp b/ecmascript/builtins/builtins_regexp.cpp index b0cd6deb72..cce62af26e 100644 --- a/ecmascript/builtins/builtins_regexp.cpp +++ b/ecmascript/builtins/builtins_regexp.cpp @@ -1941,7 +1941,7 @@ JSTaggedValue BuiltinsRegExp::FlagsBitsToString(JSThread *thread, uint8_t flags) { ASSERT((flags & 0x80) == 0); // 0x80: first bit of flags must be 0 BUILTINS_API_TRACE(thread, RegExp, FlagsBitsToString); - uint8_t *flagsStr = new uint8_t[7]; // 7: maximum 6 flags + '\0' + uint8_t *flagsStr = new uint8_t[RegExpParser::FLAG_NUM + 1]; // FLAG_NUM flags + '\0' size_t flagsLen = 0; if (flags & RegExpParser::FLAG_HASINDICES) { flagsStr[flagsLen] = 'd'; diff --git a/ecmascript/regexp/regexp_parser.h b/ecmascript/regexp/regexp_parser.h index 588b3f5e88..7eb7e53d60 100644 --- a/ecmascript/regexp/regexp_parser.h +++ b/ecmascript/regexp/regexp_parser.h @@ -41,6 +41,7 @@ public: static constexpr auto FLAG_UTF16 = (1U << 4U); static constexpr auto FLAG_STICKY = (1U << 5U); static constexpr auto FLAG_HASINDICES = (1U << 6U); + static constexpr uint32_t FLAG_NUM = 7; static const uint32_t KEY_EOF = UINT32_MAX; static constexpr int CLASS_RANGE_BASE = 0x40000000; static constexpr uint32_t NUM_CAPTURE__OFFSET = 4; diff --git a/test/moduletest/regexpflagd/expect_output.txt b/test/moduletest/regexpflagd/expect_output.txt index ea7c46a46b..cebdd1cf10 100644 --- a/test/moduletest/regexpflagd/expect_output.txt +++ b/test/moduletest/regexpflagd/expect_output.txt @@ -30,3 +30,4 @@ dgm 1,2 1,2 undefined +dgimsuy diff --git a/test/moduletest/regexpflagd/regexpflagd.js b/test/moduletest/regexpflagd/regexpflagd.js index 854a99baf1..b5b2fc3f11 100644 --- a/test/moduletest/regexpflagd/regexpflagd.js +++ b/test/moduletest/regexpflagd/regexpflagd.js @@ -45,3 +45,6 @@ var result2 = "bπb".match(/(π)/du).indices; print(result2[0]); print(result2[1]); print(result2.groups); + +var regexpFlags = new RegExp("", "dgimsuy").flags; +print(regexpFlags); \ No newline at end of file From 2fc3873f4fa78b60cc79382658828c6da17f57ef Mon Sep 17 00:00:00 2001 From: like Date: Tue, 17 Oct 2023 09:27:19 +0800 Subject: [PATCH 38/50] fix exception does not throw after inline Signed-off-by: like Change-Id: Ia88a43317c6c7740f8eb4ace2a8f1989fbdd3bb0 --- ecmascript/compiler/bytecode_circuit_builder.cpp | 9 ++++++++- ecmascript/compiler/slowpath_lowering.cpp | 13 ++++++++++++- test/aottest/inline/inline.ts | 7 +++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ecmascript/compiler/bytecode_circuit_builder.cpp b/ecmascript/compiler/bytecode_circuit_builder.cpp index 358ff5abe6..416c13e5d0 100644 --- a/ecmascript/compiler/bytecode_circuit_builder.cpp +++ b/ecmascript/compiler/bytecode_circuit_builder.cpp @@ -905,9 +905,16 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR depend = gate; if (!bb.catchs.empty()) { + auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate}); + auto ifException = circuit_->NewGate(circuit_->IfException(), {gate, gate}); auto &bbNext = bb.catchs.at(0); - SetBlockPred(bb, *bbNext, gate, gate); + SetBlockPred(bb, *bbNext, ifException, ifException); bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true}); + auto constant = circuit_->GetConstantGate(MachineType::I64, + JSTaggedValue::VALUE_EXCEPTION, + GateType::TaggedValue()); + circuit_->NewGate(circuit_->Return(), + { ifSuccess, depend, constant, circuit_->GetReturnRoot() }); } else { auto constant = circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_EXCEPTION, diff --git a/ecmascript/compiler/slowpath_lowering.cpp b/ecmascript/compiler/slowpath_lowering.cpp index cf963ba51e..db2b3ccf58 100644 --- a/ecmascript/compiler/slowpath_lowering.cpp +++ b/ecmascript/compiler/slowpath_lowering.cpp @@ -189,7 +189,18 @@ void SlowPathLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool */ void SlowPathLowering::ReplaceHirToThrowCall(GateRef hirGate, GateRef value) { - acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value); + auto condition = builder_.HasPendingException(glue_); + GateRef state = builder_.GetState(); + GateRef depend = builder_.GetDepend(); + GateRef ifBranch = builder_.Branch(state, condition); + GateRef ifTrue = builder_.IfTrue(ifBranch); + GateRef ifFalse = builder_.IfFalse(ifBranch); + GateRef eDepend = builder_.DependRelay(ifTrue, depend); + GateRef sDepend = builder_.DependRelay(ifFalse, depend); + + StateDepend success(ifFalse, sDepend); + StateDepend exception(ifTrue, eDepend); + acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value); } void SlowPathLowering::Lower(GateRef gate) diff --git a/test/aottest/inline/inline.ts b/test/aottest/inline/inline.ts index 8001bfafad..a05f97ad81 100644 --- a/test/aottest/inline/inline.ts +++ b/test/aottest/inline/inline.ts @@ -21,3 +21,10 @@ class A { let a : A = new A(); print(a.foo(2)); print(a.bar(2)); + +function f523() { + throw "error"; + function f537() {} +} +f523(); +f523(); From 37498b574eb40f9ba675d17fb01c7dd42b8202a7 Mon Sep 17 00:00:00 2001 From: chenjx-huawei Date: Wed, 18 Oct 2023 10:12:50 +0800 Subject: [PATCH 39/50] Bugfix on StubBuilder::FastIntDiv when left is INT_MIN and right is -1 Issue: https://gitee.com/open_harmony/dashboard?issue_id=I88UI4 Signed-off-by: chenjx-huawei Change-Id: I85fba9f73d5775b7902d382c7c671204b63c3f0f --- ecmascript/compiler/stub_builder.cpp | 6 ++++++ test/moduletest/BUILD.gn | 2 ++ test/moduletest/div/BUILD.gn | 18 ++++++++++++++++++ test/moduletest/div/div.js | 24 ++++++++++++++++++++++++ test/moduletest/div/expect_output.txt | 14 ++++++++++++++ 5 files changed, 64 insertions(+) create mode 100755 test/moduletest/div/BUILD.gn create mode 100644 test/moduletest/div/div.js create mode 100755 test/moduletest/div/expect_output.txt diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 3942c0c149..8492c8bf40 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -4957,8 +4957,14 @@ GateRef StubBuilder::FastIntDiv(GateRef left, GateRef right, Label *bailout, Pro GateRef intRight = GetInt32OfTInt(right); Label exit(env); Label rightIsNotZero(env); + Label leftIsIntMin(env); + Label leftAndRightIsNotBoundary(env); Branch(Int32Equal(intRight, Int32(0)), bailout, &rightIsNotZero); Bind(&rightIsNotZero); + Branch(Int32Equal(intLeft, Int32(INT_MIN)), &leftIsIntMin, &leftAndRightIsNotBoundary); + Bind(&leftIsIntMin); + Branch(Int32Equal(intRight, Int32(-1)), bailout, &leftAndRightIsNotBoundary); + Bind(&leftAndRightIsNotBoundary); { Label leftIsZero(env); Label leftIsNotZero(env); diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 45e93bbb0f..159574584f 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -45,6 +45,7 @@ group("ark_js_moduletest") { "datecompare", "dateparse", "decodeuricomponent", + "div", "dynamicimport", "dyninstruction", "ecmastringtable", @@ -179,6 +180,7 @@ group("ark_asm_test") { "dataproperty", "dateparse", "decodeuricomponent", + "div", "dynamicimport", "dyninstruction", "ecmastringtable", diff --git a/test/moduletest/div/BUILD.gn b/test/moduletest/div/BUILD.gn new file mode 100755 index 0000000000..d91a2fd942 --- /dev/null +++ b/test/moduletest/div/BUILD.gn @@ -0,0 +1,18 @@ +# 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("div") { + deps = [] +} diff --git a/test/moduletest/div/div.js b/test/moduletest/div/div.js new file mode 100644 index 0000000000..75912a0bd8 --- /dev/null +++ b/test/moduletest/div/div.js @@ -0,0 +1,24 @@ +/* + * 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. + */ + +/* + * @tc.name:div + * @tc.desc:test boundary div + * @tc.type: FUNC + * @tc.require: issue#I88UI4 + */ + +var num1 = (1 << 31) / -1; +print(num1); \ No newline at end of file diff --git a/test/moduletest/div/expect_output.txt b/test/moduletest/div/expect_output.txt new file mode 100755 index 0000000000..3db4128aeb --- /dev/null +++ b/test/moduletest/div/expect_output.txt @@ -0,0 +1,14 @@ +# 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. + +2147483648 From a70152fdf78cf46a30af2b9b4124120f097b2698 Mon Sep 17 00:00:00 2001 From: chenjx-huawei Date: Wed, 18 Oct 2023 17:06:09 +0800 Subject: [PATCH 40/50] Bugfix on Array.filter&Array.forEach&instanceof callback is not callable Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I893QR Signed-off-by: chenjx-huawei Change-Id: I90ac1f3616e90cefd2cceae180184d8fabb3a60a --- .../builtins/builtins_array_stub_builder.cpp | 6 ++++++ ecmascript/compiler/stub_builder.cpp | 3 +++ test/moduletest/array/array.js | 7 +++++++ test/moduletest/array/expect_output.txt | 1 + test/moduletest/arrayforeach/arrayforeach.js | 8 +++++++- test/moduletest/arrayforeach/expect_output.txt | 1 + test/moduletest/instanceofic/expect_output.txt | 1 + test/moduletest/instanceofic/instanceofic.js | 12 +++++++++++- 8 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 6e07f5d729..469bcf6083 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -71,6 +71,9 @@ void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef n Bind(&thisIsEmpty); { Label isCallable(env); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(GetCallArg0(numArgs)), &isHeapObject, slowPath); + Bind(&isHeapObject); Branch(IsCallable(GetCallArg0(numArgs)), &isCallable, slowPath); // Creates an empty array on fast path Bind(&isCallable); @@ -86,6 +89,7 @@ void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef th { auto env = GetEnvironment(); Label thisIsEmpty(env); + Label isHeapObject(env); // Fast path if all the conditions below are satisfied: // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details); // (2) callbackFn is callable (otherwise a TypeError shall be thrown in the slow path) @@ -94,6 +98,8 @@ void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef th Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath); Bind(&thisIsEmpty); // Do nothing on fast path + Branch(TaggedIsHeapObject(GetCallArg0(numArgs)), &isHeapObject, slowPath); + Bind(&isHeapObject); Branch(IsCallable(GetCallArg0(numArgs)), exit, slowPath); } diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 3942c0c149..425250c4cb 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -3669,6 +3669,9 @@ GateRef StubBuilder::GetMethod(GateRef glue, GateRef obj, GateRef key, GateRef p { Label valueIsCallable(env); Label valueNotCallable(env); + Label valueIsHeapObject(env); + Branch(TaggedIsHeapObject(value), &valueIsHeapObject, &valueNotCallable); + Bind(&valueIsHeapObject); Branch(IsCallable(value), &valueIsCallable, &valueNotCallable); Bind(&valueNotCallable); { diff --git a/test/moduletest/array/array.js b/test/moduletest/array/array.js index e87988497c..77321a3981 100644 --- a/test/moduletest/array/array.js +++ b/test/moduletest/array/array.js @@ -346,3 +346,10 @@ try { handleUnexpectedErrorCaught(e); } print("======== End: Array.prototype.indexOf() & Array.prototype.lastIndexOf() ========"); + +// Test Array.prototype.filter when callbackFn is not callable +try { + [].filter(1); +} catch (e) { + print("CallbackFn is not callable"); +} \ No newline at end of file diff --git a/test/moduletest/array/expect_output.txt b/test/moduletest/array/expect_output.txt index 121f17f475..d6184d9fe8 100644 --- a/test/moduletest/array/expect_output.txt +++ b/test/moduletest/array/expect_output.txt @@ -113,3 +113,4 @@ Expected TypeError caught in lastIndexOf when fromIndex is bigint. Expected TypeError caught in indexOf when fromIndex is symbol. Expected TypeError caught in lastIndexOf when fromIndex is symbol. ======== End: Array.prototype.indexOf() & Array.prototype.lastIndexOf() ======== +CallbackFn is not callable diff --git a/test/moduletest/arrayforeach/arrayforeach.js b/test/moduletest/arrayforeach/arrayforeach.js index 4e6c2be88b..c40ceef852 100644 --- a/test/moduletest/arrayforeach/arrayforeach.js +++ b/test/moduletest/arrayforeach/arrayforeach.js @@ -43,4 +43,10 @@ let array4 = new Array(1024); array4.forEach((item, index) => { func(item, index); }); -print("test arrayforeach success!!!"); \ No newline at end of file +print("test arrayforeach success!!!"); + +try { + [].forEach(1.1); +} catch (e) { + print("CallbackFn is not callable") +} \ No newline at end of file diff --git a/test/moduletest/arrayforeach/expect_output.txt b/test/moduletest/arrayforeach/expect_output.txt index cfcb7ff3d4..be74ae05ca 100644 --- a/test/moduletest/arrayforeach/expect_output.txt +++ b/test/moduletest/arrayforeach/expect_output.txt @@ -20,3 +20,4 @@ 1_2 test arrayforeach success!!! test arrayforeach success!!! +CallbackFn is not callable diff --git a/test/moduletest/instanceofic/expect_output.txt b/test/moduletest/instanceofic/expect_output.txt index 579116f744..6df34d1be7 100644 --- a/test/moduletest/instanceofic/expect_output.txt +++ b/test/moduletest/instanceofic/expect_output.txt @@ -15,3 +15,4 @@ instanceoficsuccess instanceoficsuccess test success test success +CallbackFn is not callable diff --git a/test/moduletest/instanceofic/instanceofic.js b/test/moduletest/instanceofic/instanceofic.js index e74ff9dd59..18dd36fc6e 100644 --- a/test/moduletest/instanceofic/instanceofic.js +++ b/test/moduletest/instanceofic/instanceofic.js @@ -65,4 +65,14 @@ for (let index = 0; index <= 30; index++) { } foo(); } -print("test success") \ No newline at end of file +print("test success") + +// Test instanceof when hasInstance is modified uncallable +var instanceObj = { + [Symbol.hasInstance]: 1.1 +} +try { + print({} instanceof instanceObj); +} catch (e) { + print("CallbackFn is not callable"); +} \ No newline at end of file From b80d723b7db4a05f1587354192ad017984fe0ba2 Mon Sep 17 00:00:00 2001 From: hecunmao Date: Wed, 18 Oct 2023 18:32:00 +0800 Subject: [PATCH 41/50] Bug Fix in JsonStringifier::SerializeKeys , Modified jshclass but did not convert to dictionary mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get all keys to arrKeys,Iterate over the arrKeys, taking advantage of the key values in the arrKeys, and update the jshclass after executing the get function。 issue : https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I894O5 Signed-off-by: hecunmao Change-Id: Ib2d84f9485fc3cab17afdd438fe86f944f51b2c9 --- ecmascript/base/json_stringifier.cpp | 4 +++- test/moduletest/jsonstringifier/expect_output.txt | 1 + test/moduletest/jsonstringifier/jsonstringifier.js | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ecmascript/base/json_stringifier.cpp b/ecmascript/base/json_stringifier.cpp index 351e582023..6cfbed5560 100644 --- a/ecmascript/base/json_stringifier.cpp +++ b/ecmascript/base/json_stringifier.cpp @@ -673,6 +673,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl hasChangedToDictionaryMode = true; propertiesArr = JSHandle(thread_, obj->GetProperties()); } + jsHclass = JSHandle(thread_, obj->GetJSHClass()); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -685,7 +686,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl continue; } PropertyAttributes attr = nameDic->GetAttributes(index); - if (!attr.IsEnumerable()) { + if (!attr.IsEnumerable() || index < 0) { continue; } JSTaggedValue value = nameDic->GetValue(index); @@ -693,6 +694,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + jsHclass = JSHandle(thread_, obj->GetJSHClass()); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); diff --git a/test/moduletest/jsonstringifier/expect_output.txt b/test/moduletest/jsonstringifier/expect_output.txt index b386584197..14b5531aa0 100644 --- a/test/moduletest/jsonstringifier/expect_output.txt +++ b/test/moduletest/jsonstringifier/expect_output.txt @@ -15,3 +15,4 @@ test successful {"2147483648":2289} {"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0} {"g":9,"f1":1,"f2":1,"f3":1,"f4":1,"f5":1,"f6":1,"f7":1,"f8":1} +{"g":8,"f2":1} diff --git a/test/moduletest/jsonstringifier/jsonstringifier.js b/test/moduletest/jsonstringifier/jsonstringifier.js index 1dedf81035..482c9129f8 100644 --- a/test/moduletest/jsonstringifier/jsonstringifier.js +++ b/test/moduletest/jsonstringifier/jsonstringifier.js @@ -57,3 +57,12 @@ let o = { "f8":1, } print(JSON.stringify(o)) +let o2 = { + get g() { + delete this.f1; + return 8; + }, + "f1":1, + "f2":1, +} +print(JSON.stringify(o2)) \ No newline at end of file From 758357e0afea0ca14575715a8249575e388afc52 Mon Sep 17 00:00:00 2001 From: xiaoweidong Date: Wed, 13 Sep 2023 22:42:47 +0800 Subject: [PATCH 42/50] Opt dataview.setviewvalue Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I87B09 Signed-off-by: xiaoweidong Change-Id: Id877256649627c747a682addcf4453e09d60b7da --- ecmascript/builtins/builtins_dataview.cpp | 40 +++++++++----- test/perform/dataview/dataview.ts | 64 +++++++++++++++++++++++ 2 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 test/perform/dataview/dataview.ts diff --git a/ecmascript/builtins/builtins_dataview.cpp b/ecmascript/builtins/builtins_dataview.cpp index eb356e6624..877e465c49 100644 --- a/ecmascript/builtins/builtins_dataview.cpp +++ b/ecmascript/builtins/builtins_dataview.cpp @@ -360,11 +360,18 @@ JSTaggedValue BuiltinsDataView::GetViewValue(JSThread *thread, const JSHandleIsDataView()) { THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception()); } - // 3. Let numberIndex be ToNumber(requestIndex). - JSTaggedNumber numberIndex = JSTaggedValue::ToNumber(thread, requestIndex); - // 5. ReturnIfAbrupt(getIndex). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - int32_t indexInt = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber()); + + int32_t indexInt = 0; + if (requestIndex->IsInt()) { + // fast get index if requestIndex is int + indexInt = requestIndex->GetInt(); + } else { + // 3. Let numberIndex be ToNumber(requestIndex). + JSTaggedNumber numberIndex = JSTaggedValue::ToNumber(thread, requestIndex); + // 5. ReturnIfAbrupt(getIndex). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + indexInt = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber()); + } // 6. If numberIndex ≠ getIndex or getIndex < 0, throw a RangeError exception. if (indexInt < 0) { THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception()); @@ -415,17 +422,26 @@ JSTaggedValue BuiltinsDataView::SetViewValue(JSThread *thread, const JSHandleIsDataView()) { THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception()); } - // 3. Let numberIndex be ToNumber(requestIndex). - JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex); - // 5. ReturnIfAbrupt(getIndex). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - int64_t index = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber()); + int64_t index = 0; + if (requestIndex->IsInt()) { + // fast get index if requestIndex is int + index = requestIndex->GetInt(); + } else { + // 3. Let numberIndex be ToNumber(requestIndex). + JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex); + // 5. ReturnIfAbrupt(getIndex). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + index = base::NumberHelper::DoubleInRangeInt32(numberIndex.GetNumber()); + } // 6. If numberIndex ≠ getIndex or getIndex < 0, throw a RangeError exception. if (index < 0) { THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception()); } - JSHandle numValueHandle = JSTaggedValue::ToNumeric(thread, value); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSMutableHandle numValueHandle = JSMutableHandle(thread, value); + if (!value->IsNumber()) { + numValueHandle.Update(JSTaggedValue::ToNumeric(thread, value)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } // 7. Let isLittleEndian be ToBoolean(isLittleEndian). bool isLittleEndian = false; if (littleEndian->IsUndefined()) { diff --git a/test/perform/dataview/dataview.ts b/test/perform/dataview/dataview.ts new file mode 100644 index 0000000000..5077c9419d --- /dev/null +++ b/test/perform/dataview/dataview.ts @@ -0,0 +1,64 @@ +/* + * 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. + */ + +declare function print(arg:any) : string; +declare interface ArkTools { + timeInUs(arg:any):number +} + +function testGetVievValue() { + var buffer = new ArrayBuffer(8); + var dataview = new DataView(buffer); + let start = ArkTools.timeInUs(); + let res; + for (let i = 0; i < 1_000_000; i++) { + res = dataview.getInt32(2); + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print(res) + print("DataView GetVievValue:\t" + String(time) + "\tms"); +} + +function testSetVievValue() { + var buffer = new ArrayBuffer(8); + var dataview = new DataView(buffer); + let start = ArkTools.timeInUs(); + for (let i = 0; i < 1_000_000; i++) { + dataview.setInt32(1, 2); + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print("DataView SetVievValue:\t" + String(time) + "\tms"); +} + +function testGetByteLength() { + var buffer = new ArrayBuffer(8); + var dataview = new DataView(buffer); + let start = ArkTools.timeInUs(); + let res; + for (let i = 0; i < 1_000_000; i++) { + res = dataview.byteLength; + } + let end = ArkTools.timeInUs(); + let time = (end - start) / 1000 + print(res) + print("DataView ByteLength:\t" + String(time) + "\tms"); +} + +testSetVievValue(); +testGetVievValue(); +testGetByteLength(); + From 347ab4bd0fac1c7419c64f862b95aae4b198d69c Mon Sep 17 00:00:00 2001 From: maojunwei Date: Tue, 17 Oct 2023 15:42:52 +0800 Subject: [PATCH 43/50] bugfix icmiss & typedarray issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I88R6T Signed-off-by: maojunwei Change-Id: I3b45a50b1086d441acaea4682244d85d9edc0adf --- ecmascript/compiler/stub_builder.cpp | 3 +-- ecmascript/mem/parallel_marker.cpp | 2 +- ecmascript/object_fast_operator-inl.h | 4 +--- ecmascript/object_operator.cpp | 8 ++++++++ test/moduletest/typearray/typearray.js | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 77bcc60d56..c356397289 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -2355,8 +2355,7 @@ GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef } Bind(¬LessThanLength); { - result = Hole(); - Jump(&exit); + Jump(&loopExit); } } Bind(&isDictionaryElement); diff --git a/ecmascript/mem/parallel_marker.cpp b/ecmascript/mem/parallel_marker.cpp index 536ee715a0..8ce447206e 100644 --- a/ecmascript/mem/parallel_marker.cpp +++ b/ecmascript/mem/parallel_marker.cpp @@ -66,7 +66,7 @@ void NonMovableMarker::ProcessMarkStack(uint32_t threadId) { TRACE_GC(GCStats::Scope::ScopeId::ProcessMarkStack, heap_->GetEcmaVM()->GetEcmaGCStats()); bool isFullMark = heap_->IsFullMark(); - auto cb = [&](ObjectSlot s, Region *rootRegion,bool needBarrier) { + auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) { MarkValue(threadId, s, rootRegion, needBarrier); }; auto visitor = [this, threadId, isFullMark, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, diff --git a/ecmascript/object_fast_operator-inl.h b/ecmascript/object_fast_operator-inl.h index d67395957b..4e40033494 100644 --- a/ecmascript/object_fast_operator-inl.h +++ b/ecmascript/object_fast_operator-inl.h @@ -268,7 +268,7 @@ JSTaggedValue ObjectFastOperator::GetPropertyByIndex(JSThread *thread, JSTaggedV return JSTaggedValue::Hole(); } if (IsFastTypeArray(jsType)) { - return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, jsType); + return JSTypedArray::FastGetPropertyByIndex(thread, holder, index, jsType); } if (IsSpecialContainer(jsType)) { return GetContainerProperty(thread, holder, index, jsType); @@ -284,8 +284,6 @@ JSTaggedValue ObjectFastOperator::GetPropertyByIndex(JSThread *thread, JSTaggedV if (!value.IsHole()) { return value; } - } else { - return JSTaggedValue::Hole(); } } else { NumberDictionary *dict = NumberDictionary::Cast(elements); diff --git a/ecmascript/object_operator.cpp b/ecmascript/object_operator.cpp index 4acbf7c969..93ad4fbf2a 100644 --- a/ecmascript/object_operator.cpp +++ b/ecmascript/object_operator.cpp @@ -798,6 +798,14 @@ void ObjectOperator::LookupElementInlinedProps(const JSHandle &obj) } { DISALLOW_GARBAGE_COLLECTION; + if (obj->IsTypedArray()) { + JSTaggedValue val = JSTypedArray::FastElementGet(thread_, + JSHandle::Cast(obj), elementIndex_).GetValue().GetTaggedValue(); + if (!val.IsHole()) { + SetFound(elementIndex_, val, PropertyAttributes::GetDefaultAttributes(), true); + } + return; + } TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject()); if (elements->GetLength() == 0) { return; // Empty Array diff --git a/test/moduletest/typearray/typearray.js b/test/moduletest/typearray/typearray.js index 3eeb2e1b60..91f8c96af0 100644 --- a/test/moduletest/typearray/typearray.js +++ b/test/moduletest/typearray/typearray.js @@ -78,7 +78,7 @@ function testTypeArray2(ctor) { } let child = Object.create(obj); for (let i = 0; i < 5; i++) { - result.push(child[i] == undefined); + result.push(child[i] == i); } for (let i = 0; i < result.length; i++) { if (!result[i]) { From 7a38717731d71f837ce8c6999b21eda88cb2dde2 Mon Sep 17 00:00:00 2001 From: lijiamin2019 Date: Thu, 14 Sep 2023 19:50:46 +0800 Subject: [PATCH 44/50] Execute patch func_main_0 for HotReload Signed-off-by: lijiamin2019 Change-Id: I12e11097ab46f811841486db18baac60d2a0e355 --- ecmascript/ecma_context.cpp | 59 +++++-- ecmascript/ecma_context.h | 39 +++++ .../jspandafile/js_pandafile_executor.cpp | 12 +- ecmascript/module/js_module_manager.cpp | 34 +++- ecmascript/module/js_module_manager.h | 5 + ecmascript/object_factory.cpp | 4 +- ecmascript/patch/patch_loader.cpp | 146 +++++++++++------- ecmascript/patch/patch_loader.h | 14 +- ecmascript/patch/quick_fix_manager.cpp | 14 ++ ecmascript/quick_fix/main.cpp | 64 ++++---- test/quickfix/BUILD.gn | 24 ++- .../quickfix/class_mem_func/expect_output.txt | 4 +- test/quickfix/class_mem_func/module.js | 15 +- test/quickfix/class_mem_func/module_modify.js | 13 +- test/quickfix/class_mem_func/test.js | 4 +- test/quickfix/class_mem_var/expect_output.txt | 10 -- test/quickfix/class_mem_var/module.js | 12 +- test/quickfix/class_mem_var/module_modify.js | 11 +- test/quickfix/class_mem_var/test.js | 7 +- test/quickfix/closure/expect_output.txt | 16 -- test/quickfix/closure/module.js | 18 +-- test/quickfix/closure/module_modify.js | 24 +-- test/quickfix/closure/test.js | 4 +- test/quickfix/cold_classmemfunc/base.js | 29 ++++ test/quickfix/cold_classmemfunc/base.txt | 2 + .../quickfix/cold_classmemfunc/base_modify.js | 27 ++++ .../cold_classmemfunc/expect_output.txt | 18 +++ test/quickfix/cold_classmemfunc/module.js | 16 ++ .../cold_classmemfunc/module_modify.js | 16 ++ test/quickfix/cold_classmemfunc/patch.txt | 2 + test/quickfix/cold_classmemfunc/test.js | 16 ++ test/quickfix/cold_closure/base.js | 32 ++++ test/quickfix/cold_closure/base.txt | 2 + test/quickfix/cold_closure/base_modify.js | 38 +++++ test/quickfix/cold_closure/expect_output.txt | 24 +++ test/quickfix/cold_closure/module.js | 16 ++ test/quickfix/cold_closure/module_modify.js | 16 ++ test/quickfix/cold_closure/patch.txt | 2 + test/quickfix/cold_closure/test.js | 16 ++ test/quickfix/cold_printstring/base.js | 45 ++++++ test/quickfix/cold_printstring/base.txt | 2 + test/quickfix/cold_printstring/base_modify.js | 36 +++++ .../cold_printstring/expect_output.txt | 21 +++ test/quickfix/cold_printstring/module.js | 16 ++ .../cold_printstring/module_modify.js | 17 ++ test/quickfix/cold_printstring/patch.txt | 2 + test/quickfix/cold_printstring/test.js | 19 +++ test/quickfix/global_func/expect_output.txt | 3 +- test/quickfix/global_var/expect_output.txt | 4 +- test/quickfix/import_export/expect_output.txt | 2 +- test/quickfix/module_class/base.js | 23 +++ test/quickfix/module_class/base.txt | 2 + test/quickfix/module_class/base_modify.js | 27 ++++ test/quickfix/module_class/expect_output.txt | 26 ++++ test/quickfix/module_class/module.js | 31 ++++ test/quickfix/module_class/module_modify.js | 44 ++++++ test/quickfix/module_class/patch.txt | 2 + test/quickfix/module_class/test.js | 16 ++ .../quickfix/module_class_inheritance/base.js | 23 +++ .../module_class_inheritance/base.txt | 2 + .../module_class_inheritance/base_modify.js | 23 +++ .../expect_output.txt | 24 +++ .../module_class_inheritance/module.js | 23 +++ .../module_class_inheritance/module_modify.js | 31 ++++ .../module_class_inheritance/patch.txt | 2 + .../quickfix/module_class_inheritance/test.js | 16 ++ test/quickfix/module_func/base.js | 25 +++ test/quickfix/module_func/base.txt | 2 + test/quickfix/module_func/base_modify.js | 26 ++++ test/quickfix/module_func/expect_output.txt | 28 ++++ test/quickfix/module_func/module.js | 25 +++ test/quickfix/module_func/module_modify.js | 25 +++ test/quickfix/module_func/patch.txt | 2 + test/quickfix/module_func/test.js | 16 ++ test/quickfix/module_var/base.js | 23 +++ test/quickfix/module_var/base.txt | 2 + test/quickfix/module_var/base_modify.js | 26 ++++ test/quickfix/module_var/expect_output.txt | 27 ++++ test/quickfix/module_var/module.js | 20 +++ test/quickfix/module_var/module_modify.js | 21 +++ test/quickfix/module_var/patch.txt | 2 + test/quickfix/module_var/test.js | 16 ++ test/quickfix/multi_patch/expect_output.txt | 6 +- test/quickfix/print_string/expect_output.txt | 4 - test/quickfix/print_string/module.js | 5 +- test/quickfix/print_string/module_modify.js | 4 +- test/quickfix/print_string/test.js | 2 - 87 files changed, 1354 insertions(+), 260 deletions(-) create mode 100755 test/quickfix/cold_classmemfunc/base.js create mode 100644 test/quickfix/cold_classmemfunc/base.txt create mode 100755 test/quickfix/cold_classmemfunc/base_modify.js create mode 100644 test/quickfix/cold_classmemfunc/expect_output.txt create mode 100644 test/quickfix/cold_classmemfunc/module.js create mode 100644 test/quickfix/cold_classmemfunc/module_modify.js create mode 100644 test/quickfix/cold_classmemfunc/patch.txt create mode 100755 test/quickfix/cold_classmemfunc/test.js create mode 100755 test/quickfix/cold_closure/base.js create mode 100644 test/quickfix/cold_closure/base.txt create mode 100755 test/quickfix/cold_closure/base_modify.js create mode 100644 test/quickfix/cold_closure/expect_output.txt create mode 100644 test/quickfix/cold_closure/module.js create mode 100644 test/quickfix/cold_closure/module_modify.js create mode 100644 test/quickfix/cold_closure/patch.txt create mode 100755 test/quickfix/cold_closure/test.js create mode 100644 test/quickfix/cold_printstring/base.js create mode 100644 test/quickfix/cold_printstring/base.txt create mode 100644 test/quickfix/cold_printstring/base_modify.js create mode 100644 test/quickfix/cold_printstring/expect_output.txt create mode 100644 test/quickfix/cold_printstring/module.js create mode 100644 test/quickfix/cold_printstring/module_modify.js create mode 100644 test/quickfix/cold_printstring/patch.txt create mode 100644 test/quickfix/cold_printstring/test.js create mode 100755 test/quickfix/module_class/base.js create mode 100644 test/quickfix/module_class/base.txt create mode 100755 test/quickfix/module_class/base_modify.js create mode 100644 test/quickfix/module_class/expect_output.txt create mode 100644 test/quickfix/module_class/module.js create mode 100644 test/quickfix/module_class/module_modify.js create mode 100644 test/quickfix/module_class/patch.txt create mode 100755 test/quickfix/module_class/test.js create mode 100755 test/quickfix/module_class_inheritance/base.js create mode 100644 test/quickfix/module_class_inheritance/base.txt create mode 100755 test/quickfix/module_class_inheritance/base_modify.js create mode 100644 test/quickfix/module_class_inheritance/expect_output.txt create mode 100644 test/quickfix/module_class_inheritance/module.js create mode 100644 test/quickfix/module_class_inheritance/module_modify.js create mode 100644 test/quickfix/module_class_inheritance/patch.txt create mode 100755 test/quickfix/module_class_inheritance/test.js create mode 100755 test/quickfix/module_func/base.js create mode 100644 test/quickfix/module_func/base.txt create mode 100755 test/quickfix/module_func/base_modify.js create mode 100644 test/quickfix/module_func/expect_output.txt create mode 100644 test/quickfix/module_func/module.js create mode 100644 test/quickfix/module_func/module_modify.js create mode 100644 test/quickfix/module_func/patch.txt create mode 100755 test/quickfix/module_func/test.js create mode 100755 test/quickfix/module_var/base.js create mode 100644 test/quickfix/module_var/base.txt create mode 100755 test/quickfix/module_var/base_modify.js create mode 100644 test/quickfix/module_var/expect_output.txt create mode 100644 test/quickfix/module_var/module.js create mode 100644 test/quickfix/module_var/module_modify.js create mode 100644 test/quickfix/module_var/patch.txt create mode 100755 test/quickfix/module_var/test.js diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 88d50b34e7..3f1151ec3f 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -244,20 +244,9 @@ JSTaggedValue EcmaContext::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, return res; } -Expected EcmaContext::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, - std::string_view entryPoint, bool excuteFromJob) +Expected EcmaContext::CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, + std::string_view entryPoint, JSHandle &func) { - [[maybe_unused]] EcmaHandleScope scope(thread_); - JSHandle program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint); - if (program.IsEmpty()) { - LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed"; - return Unexpected(false); - } - // for debugger - vm_->GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent( - jsPandaFile->GetJSPandaFileDesc(), entryPoint); - - JSHandle func(thread_, program->GetMainFunction()); JSHandle method(thread_, func->GetMethod()); JSHandle global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject(); JSHandle undefined = thread_->GlobalConstants()->GetHandledUndefined(); @@ -303,6 +292,25 @@ Expected EcmaContext::InvokeEcmaEntrypoint(const JSPandaFil job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); } + return result; +} + +Expected EcmaContext::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, + std::string_view entryPoint, bool excuteFromJob) +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + JSHandle program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint); + if (program.IsEmpty()) { + LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed"; + return Unexpected(false); + } + // for debugger + vm_->GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent( + jsPandaFile->GetJSPandaFileDesc(), entryPoint); + + JSHandle func(thread_, program->GetMainFunction()); + Expected result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func); + // print exception information if (!excuteFromJob && thread_->HasPendingException()) { HandleUncaughtException(thread_->GetException()); @@ -310,6 +318,31 @@ Expected EcmaContext::InvokeEcmaEntrypoint(const JSPandaFil return result; } +Expected EcmaContext::InvokeEcmaEntrypointForHotReload( + const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool excuteFromJob) +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + JSHandle program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint); + + JSHandle func(thread_, program->GetMainFunction()); + Expected result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func); + + JSHandle finalModuleRecord(thread_, func->GetModule()); + // avoid GC problems. + GlobalHandleCollection gloalHandleCollection(thread_); + JSHandle moduleRecordHandle = + gloalHandleCollection.NewHandle(finalModuleRecord->GetRawData()); + CString recordName = entryPoint.data(); + AddPatchModule(recordName, moduleRecordHandle); + + // print exception information + if (!excuteFromJob && thread_->HasPendingException() && + Method::Cast(func->GetMethod())->GetMethodName() != JSPandaFile::PATCH_FUNCTION_NAME_0) { + HandleUncaughtException(thread_->GetException()); + } + return result; +} + void EcmaContext::CJSExecution(JSHandle &func, JSHandle &thisArg, const JSPandaFile *jsPandaFile, std::string_view entryPoint) { diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index 8ed73e9e9e..e4d177d2f6 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -26,6 +26,7 @@ #include "ecmascript/mem/visitor.h" #include "ecmascript/regexp/regexp_parser_cache.h" #include "ecmascript/waiter_list.h" +#include "global_handle_collection.h" #include "libpandafile/file.h" namespace panda { @@ -403,6 +404,36 @@ public: return &globalConst_; } + void AddPatchModule(const CString &recordName, const JSHandle moduleRecord) + { + cachedPatchModules_.emplace(recordName, moduleRecord); + } + JSHandle FindPatchModule(const CString &recordName) const + { + auto iter = cachedPatchModules_.find(recordName); + if (iter != cachedPatchModules_.end()) { + return iter->second; + } + return JSHandle(thread_, JSTaggedValue::Hole()); + } + void ClearPatchModules() + { + GlobalHandleCollection gloalHandleCollection(thread_); + for (auto &item : cachedPatchModules_) { + gloalHandleCollection.Dispose(item.second); + } + cachedPatchModules_.clear(); + } + + int32_t GetStageOfHotReload() const + { + return stageOfHotReload_; + } + void SetStageOfHotReload(int32_t stageOfHotReload) + { + stageOfHotReload_ = stageOfHotReload; + } + bool JoinStackPushFastPath(JSHandle receiver); bool JoinStackPush(JSHandle receiver); void JoinStackPopFastPath(JSHandle receiver); @@ -431,6 +462,10 @@ private: CJSInfo *cjsInfo = nullptr); Expected InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool excuteFromJob = false); + Expected InvokeEcmaEntrypointForHotReload( + const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool excuteFromJob); + Expected CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, + std::string_view entryPoint, JSHandle &func); bool LoadAOTFiles(const std::string &aotFileName); NO_MOVE_SEMANTIC(EcmaContext); NO_COPY_SEMANTIC(EcmaContext); @@ -453,6 +488,10 @@ private: CMap> cachedConstpools_ {}; + // for HotReload of module. + CMap> cachedPatchModules_ {}; + int32_t stageOfHotReload_ = 0; + // VM resources. ModuleManager *moduleManager_ {nullptr}; TSManager *tsManager_ {nullptr}; diff --git a/ecmascript/jspandafile/js_pandafile_executor.cpp b/ecmascript/jspandafile/js_pandafile_executor.cpp index e695b38d11..f5b5d85f39 100644 --- a/ecmascript/jspandafile/js_pandafile_executor.cpp +++ b/ecmascript/jspandafile/js_pandafile_executor.cpp @@ -224,10 +224,16 @@ Expected JSPandaFileExecutor::Execute(JSThread *thread, con // For Ark application startup EcmaContext *context = thread->GetCurrentEcmaContext(); - QuickFixManager *quickFixManager = thread->GetEcmaVM()->GetQuickFixManager(); - quickFixManager->LoadPatchIfNeeded(thread, jsPandaFile); + Expected result; - Expected result = context->InvokeEcmaEntrypoint(jsPandaFile, entryPoint, excuteFromJob); + if (context->GetStageOfHotReload() < 0) { + result = context->InvokeEcmaEntrypointForHotReload(jsPandaFile, entryPoint, excuteFromJob); + } else { + QuickFixManager *quickFixManager = thread->GetEcmaVM()->GetQuickFixManager(); + quickFixManager->LoadPatchIfNeeded(thread, jsPandaFile); + + result = context->InvokeEcmaEntrypoint(jsPandaFile, entryPoint, excuteFromJob); + } return result; } diff --git a/ecmascript/module/js_module_manager.cpp b/ecmascript/module/js_module_manager.cpp index 39f963afcc..ccfa1134f4 100644 --- a/ecmascript/module/js_module_manager.cpp +++ b/ecmascript/module/js_module_manager.cpp @@ -111,6 +111,18 @@ JSTaggedValue ModuleManager::GetModuleValueOutterInternal(int32_t index, JSTagge JSTaggedValue resolvedModule = binding->GetModule(); ASSERT(resolvedModule.IsSourceTextModule()); SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject()); + + // Support for only modifying var value of HotReload. + // Cause patchFile exclude the record of importing modifying var. Can't reresolve moduleRecord. + EcmaContext *context = thread->GetCurrentEcmaContext(); + int32_t InterceptGetModuleValue = 1; // 1: for Interceptint get module var + if (context->GetStageOfHotReload() == InterceptGetModuleValue) { + const JSHandle resolvedModuleOfHotReload = + context->FindPatchModule(ConvertToString(module->GetEcmaModuleRecordName())); + if (!resolvedModuleOfHotReload->IsHole()) { + resolvedModule = resolvedModuleOfHotReload.GetTaggedValue(); + } + } ModuleTypes moduleType = module->GetTypes(); if (SourceTextModule::IsNativeModule(moduleType)) { @@ -375,15 +387,26 @@ JSHandle ModuleManager::ResolveModuleInMergedABC(JSThread *thread JSHandle ModuleManager::HostResolveImportedModuleWithMerge(const CString &moduleFileName, const CString &recordName, bool excuteFromJob) { - JSThread *thread = vm_->GetJSThread(); - ObjectFactory *factory = vm_->GetFactory(); - - JSHandle recordNameHandle = factory->NewFromUtf8(recordName); + JSHandle recordNameHandle = vm_->GetFactory()->NewFromUtf8(recordName); NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject()); int entry = dict->FindEntry(recordNameHandle.GetTaggedValue()); if (entry != -1) { - return JSHandle(thread, dict->GetValue(entry)); + return JSHandle(vm_->GetJSThread(), dict->GetValue(entry)); } + return CommonResolveImportedModuleWithMerge(moduleFileName, recordName, excuteFromJob); +} + +JSHandle ModuleManager::HostResolveImportedModuleWithMergeForHotReload(const CString &moduleFileName, + const CString &recordName, bool excuteFromJob) +{ + return CommonResolveImportedModuleWithMerge(moduleFileName, recordName, excuteFromJob); +} + +JSHandle ModuleManager::CommonResolveImportedModuleWithMerge(const CString &moduleFileName, + const CString &recordName, bool excuteFromJob) +{ + JSThread *thread = vm_->GetJSThread(); + std::shared_ptr jsPandaFile = SkipDefaultBundleFile(moduleFileName) ? nullptr : JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, recordName, false); if (jsPandaFile == nullptr) { @@ -400,6 +423,7 @@ JSHandle ModuleManager::HostResolveImportedModuleWithMerge(const jsPandaFile.get(), recordName, excuteFromJob); RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); JSHandle handleDict(thread, resolvedModules_); + JSHandle recordNameHandle= vm_->GetFactory()->NewFromUtf8(recordName); resolvedModules_ = NameDictionary::Put(thread, handleDict, JSHandle(recordNameHandle), moduleRecord, PropertyAttributes::Default()).GetTaggedValue(); diff --git a/ecmascript/module/js_module_manager.h b/ecmascript/module/js_module_manager.h index b37af1887b..55ea5dc5a3 100644 --- a/ecmascript/module/js_module_manager.h +++ b/ecmascript/module/js_module_manager.h @@ -63,6 +63,8 @@ public: bool excuteFromJob = false); JSHandle PUBLIC_API HostResolveImportedModuleWithMerge(const CString &referencingModule, const CString &recordName, bool excuteFromJob = false); + JSHandle PUBLIC_API HostResolveImportedModuleWithMergeForHotReload(const CString &referencingModule, + const CString &recordName, bool excuteFromJob = false); JSHandle HostResolveImportedModule(const JSPandaFile *jsPandaFile, const CString &filename); JSTaggedValue GetCurrentModule(); @@ -110,6 +112,9 @@ private: bool excuteFromJob = false); JSHandle ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, const CString &recordName, bool excuteFromJob = false); + + JSHandle CommonResolveImportedModuleWithMerge(const CString &moduleFileName, + const CString &recordName, bool excuteFromJob = false); static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index a27d78fa5a..db41bd8f64 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -1643,7 +1643,9 @@ JSHandle ObjectFactory::NewMethod(const JSPandaFile *jsPandaFile, Method method = NewMethod(methodLiteral); method->SetConstantPool(thread_, constpool); } - method->SetModule(thread_, module); + if (method->GetModule().IsUndefined()) { + method->SetModule(thread_, module); + } if (needSetAotFlag) { thread_->GetCurrentEcmaContext()->GetAOTFileManager()-> SetAOTFuncEntry(jsPandaFile, *method, entryIndex, canFastCall); diff --git a/ecmascript/patch/patch_loader.cpp b/ecmascript/patch/patch_loader.cpp index 22baca2f18..4ed615e0c7 100644 --- a/ecmascript/patch/patch_loader.cpp +++ b/ecmascript/patch/patch_loader.cpp @@ -59,74 +59,94 @@ PatchErrorCode PatchLoader::LoadPatchInternal(JSThread *thread, const JSPandaFil thread->GetCurrentEcmaContext()->CreateAllConstpool(patchFile); FindAndReplaceSameMethod(thread, baseFile, patchFile, patchInfo); - if (!ExecutePatchMain(thread, patchFile, baseFile, patchInfo)) { - LOG_ECMA(ERROR) << "Execute patch main failed"; - return PatchErrorCode::INTERNAL_ERROR; - } + // cached patch modules can only be clear before load patch. + thread->GetCurrentEcmaContext()->ClearPatchModules(); + // execute patch func_main_0 for hot reload, and patch_main_0 for hot patch. + ExecuteFuncOrPatchMain(thread, patchFile, patchInfo); + ReplaceModuleOfMethod(thread, baseFile, patchInfo); vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchLoaded(baseFile, patchFile); return PatchErrorCode::SUCCESS; } -bool PatchLoader::ExecutePatchMain(JSThread *thread, const JSPandaFile *patchFile, - const JSPandaFile *baseFile, PatchInfo &patchInfo) +void PatchLoader::ExecuteFuncOrPatchMain( + JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch) { - EcmaVM *vm = thread->GetEcmaVM(); + LOG_ECMA(DEBUG) << "execute main begin"; + EcmaContext *context = thread->GetCurrentEcmaContext(); + context->SetStageOfHotReload(BEGIN_EXECUTE_PATCHMAIN); - const auto &recordInfos = patchFile->GetJSRecordInfo(); - bool isHotPatch = false; - bool isNewVersion = patchFile->IsNewVersion(); - for (const auto &item : recordInfos) { - const CString &recordName = item.first; - uint32_t mainMethodIndex = patchFile->GetMainMethodIndex(recordName); - ASSERT(mainMethodIndex != 0); - EntityId mainMethodId(mainMethodIndex); + const auto &replacedRecordNames = patchInfo.replacedRecordNames; - // For HotPatch, generate program and execute for every record. - if (!isHotPatch) { - CString mainMethodName = MethodLiteral::GetMethodName(patchFile, mainMethodId); - if (mainMethodName != JSPandaFile::PATCH_FUNCTION_NAME_0) { - LOG_ECMA(INFO) << "HotReload no need to execute patch main"; - return true; - } - isHotPatch = true; - } + // Resolve all patch module records. + CMap> moduleRecords {}; + for (const auto &recordName : replacedRecordNames) { + ModuleManager *moduleManager = context->GetModuleManager(); + JSHandle moduleRecord = moduleManager-> + HostResolveImportedModuleWithMergeForHotReload(jsPandaFile->GetJSPandaFileDesc(), recordName, false); + moduleRecords.emplace(recordName, moduleRecord); + } - JSTaggedValue constpoolVal = JSTaggedValue::Hole(); - if (isNewVersion) { - constpoolVal = thread->GetCurrentEcmaContext()->FindConstpool(patchFile, mainMethodId); - } else { - constpoolVal = thread->GetCurrentEcmaContext()->FindConstpool(patchFile, 0); - } - ASSERT(!constpoolVal.IsHole()); - JSHandle constpool(thread, constpoolVal); - MethodLiteral *mainMethodLiteral = patchFile->FindMethodLiteral(mainMethodIndex); - JSHandle program = PandaFileTranslator::GenerateProgramInternal(vm, mainMethodLiteral, constpool); - - if (program->GetMainFunction().IsUndefined()) { + for (const auto &recordName : replacedRecordNames) { + LOG_ECMA(DEBUG) << "patch main record name " << recordName; + JSHandle program = + JSPandaFileManager::GetInstance()->GenerateProgram(thread->GetEcmaVM(), jsPandaFile, recordName); + if (program.IsEmpty()) { + LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed"; continue; } - // For add a new function, Call patch_main_0. - JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); - JSHandle func(thread, program->GetMainFunction()); - JSHandle module = - thread->GetCurrentEcmaContext()->GetModuleManager()->HostResolveImportedModuleWithMerge( - patchFile->GetJSPandaFileDesc(), recordName); - Method::Cast(func->GetMethod())->SetModule(thread, module); - EcmaRuntimeCallInfo *info = - EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle(func), undefined, undefined, 0); - EcmaInterpreter::Execute(info); + JSHandle moduleRecord = moduleRecords[recordName]; - if (thread->HasPendingException()) { - // clear exception and rollback. - thread->ClearException(); - UnloadPatchInternal(thread, patchFile->GetJSPandaFileDesc(), baseFile->GetJSPandaFileDesc(), patchInfo); - LOG_ECMA(ERROR) << "execute patch main has exception"; - return false; - } + SourceTextModule::Instantiate(thread, moduleRecord, false); + JSHandle module = JSHandle::Cast(moduleRecord); + SourceTextModule::Evaluate(thread, module); + } + + if (loadPatch) { + context->SetStageOfHotReload(LOAD_END_EXECUTE_PATCHMAIN); + } else { + context->SetStageOfHotReload(UNLOAD_END_EXECUTE_PATCHMAIN); + } + LOG_ECMA(DEBUG) << "execute main end"; +} + +void PatchLoader::ReplaceModuleOfMethod(JSThread *thread, const JSPandaFile *baseFile, PatchInfo &patchInfo) +{ + EcmaContext *context = thread->GetCurrentEcmaContext(); + auto baseConstpoolValues = context->FindConstpools(baseFile); + if (!baseConstpoolValues.has_value()) { + return; + } + + const auto &baseMethodInfo = patchInfo.baseMethodInfo; + for (const auto &item : baseMethodInfo) { + const auto &methodIndex = item.first; + ConstantPool *baseConstpool = ConstantPool::Cast( + (baseConstpoolValues.value().get()[methodIndex.constpoolNum]).GetTaggedObject()); + + uint32_t constpoolIndex = methodIndex.constpoolIndex; + uint32_t literalIndex = methodIndex.literalIndex; + Method *patchMethod = nullptr; + if (literalIndex == UINT32_MAX) { + JSTaggedValue value = baseConstpool->GetObjectFromCache(constpoolIndex); + ASSERT(value.IsMethod()); + patchMethod = Method::Cast(value.GetTaggedObject()); + } else { + ClassLiteral *classLiteral = ClassLiteral::Cast(baseConstpool->GetObjectFromCache(constpoolIndex)); + TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray()); + JSTaggedValue value = literalArray->Get(thread, literalIndex); + ASSERT(value.IsJSFunctionBase()); + JSFunctionBase *func = JSFunctionBase::Cast(value.GetTaggedObject()); + patchMethod = Method::Cast(func->GetMethod().GetTaggedObject()); + } + + JSHandle moduleRecord = context->FindPatchModule(patchMethod->GetRecordNameStr()); + patchMethod->SetModule(thread, moduleRecord.GetTaggedValue()); + LOG_ECMA(INFO) << "Replace base method module: " + << patchMethod->GetRecordNameStr() + << ":" << patchMethod->GetMethodName(); } - return true; } PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString &patchFileName, @@ -187,6 +207,11 @@ PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString << ":" << patchMethod->GetMethodName(); } + thread->GetCurrentEcmaContext()->ClearPatchModules(); + // execute base func_main_0 for recover global object. + ExecuteFuncOrPatchMain(thread, baseFile.get(), patchInfo, false); + ReplaceModuleOfMethod(thread, baseFile.get(), patchInfo); + vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchUnloaded(patchFile.get()); // release base constpool. @@ -314,7 +339,8 @@ MethodLiteral* PatchLoader::FindSameMethod(PatchInfo &patchInfo, const JSPandaFi return nullptr; } - LOG_ECMA(INFO) << "Replace base method: " << baseRecordName << ":" << baseMethodName; + // Reserved for HotPatch. + patchInfo.replacedRecordNames.emplace(baseRecordName); return methodIter->second; } @@ -331,17 +357,22 @@ PatchInfo PatchLoader::GeneratePatchInfo(const JSPandaFile *patchFile) { const auto &map = patchFile->GetMethodLiteralMap(); CMap> methodLiterals; + PatchInfo patchInfo; for (const auto &item : map) { MethodLiteral *methodLiteral = item.second; EntityId methodId = EntityId(item.first); CString methodName = MethodLiteral::GetMethodName(patchFile, methodId); - if (methodName == JSPandaFile::ENTRY_FUNCTION_NAME || - methodName == JSPandaFile::PATCH_FUNCTION_NAME_0 || + if (methodName == JSPandaFile::PATCH_FUNCTION_NAME_0 || methodName == JSPandaFile::PATCH_FUNCTION_NAME_1) { continue; } + // if patchFile only include varibales, add recordName specially. CString recordName = MethodLiteral::GetRecordName(patchFile, methodId); + if (methodName == JSPandaFile::ENTRY_FUNCTION_NAME) { + patchInfo.replacedRecordNames.emplace(recordName); + } + auto iter = methodLiterals.find(recordName); if (iter != methodLiterals.end()) { iter->second.emplace(methodName, methodLiteral); @@ -351,7 +382,6 @@ PatchInfo PatchLoader::GeneratePatchInfo(const JSPandaFile *patchFile) } } - PatchInfo patchInfo; patchInfo.patchFileName = patchFile->GetJSPandaFileDesc(); patchInfo.patchMethodLiterals = std::move(methodLiterals); return patchInfo; diff --git a/ecmascript/patch/patch_loader.h b/ecmascript/patch/patch_loader.h index e6683a6922..88d1d3c8e4 100644 --- a/ecmascript/patch/patch_loader.h +++ b/ecmascript/patch/patch_loader.h @@ -20,6 +20,7 @@ #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" #include "ecmascript/mem/c_containers.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/napi/include/jsnapi.h" namespace panda::ecmascript { @@ -54,6 +55,8 @@ struct PatchInfo { CMap baseMethodInfo; // save base constpool in global for avoid gc. CVector> baseConstpools; + // patch replaced recordNames. + CUnorderedSet replacedRecordNames; }; class PatchLoader { public: @@ -68,6 +71,8 @@ public: const CString &baseFileName, PatchInfo &patchInfo); static MethodLiteral *FindSameMethod(PatchInfo &patchInfo, const JSPandaFile *baseFile, EntityId baseMethodId); + static void ExecuteFuncOrPatchMain( + JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch = true); private: static PatchInfo GeneratePatchInfo(const JSPandaFile *patchFile); @@ -82,10 +87,13 @@ private: MethodLiteral *srcMethodLiteral, JSTaggedValue srcConstpool); - static bool ExecutePatchMain(JSThread *thread, const JSPandaFile *patchFile, const JSPandaFile *baseFile, - PatchInfo &patchInfo); - static void ClearPatchInfo(JSThread *thread, const CString &patchFileName); + + static void ReplaceModuleOfMethod(JSThread *thread, const JSPandaFile *baseFile, PatchInfo &patchInfo); + + static constexpr int32_t BEGIN_EXECUTE_PATCHMAIN = -1; // -1: For intercepting Evaluate() + static constexpr int32_t LOAD_END_EXECUTE_PATCHMAIN = 1; // 1 :For intercepting get module value + static constexpr int32_t UNLOAD_END_EXECUTE_PATCHMAIN = 2; // 2 :for execute abc normally }; } // namespace panda::ecmascript #endif // ECMASCRIPT_PATCH_PATCH_LOADER_H diff --git a/ecmascript/patch/quick_fix_manager.cpp b/ecmascript/patch/quick_fix_manager.cpp index db8cded76c..a7aed84ea7 100644 --- a/ecmascript/patch/quick_fix_manager.cpp +++ b/ecmascript/patch/quick_fix_manager.cpp @@ -200,6 +200,20 @@ JSTaggedValue QuickFixManager::CheckAndGetPatch(JSThread *thread, const JSPandaF JSHandle newConstpool = thread->GetCurrentEcmaContext()->FindOrCreateConstPool( patchFile.get(), patchMethodLiteral->GetMethodId()); method->SetConstantPool(thread, newConstpool); + + CString recordName = MethodLiteral::GetRecordName(baseFile, baseMethodId); + EcmaContext *context = thread->GetCurrentEcmaContext(); + JSHandle moduleRecord = context->FindPatchModule(recordName); + if (moduleRecord->IsHole()) { + PatchLoader::ExecuteFuncOrPatchMain(thread, patchFile.get(), patchInfo); + moduleRecord = context->FindPatchModule(recordName); + if (moduleRecord->IsHole()) { + LOG_ECMA(ERROR) << "cold patch: moduleRecord is still hole after regeneration"; + method->SetModule(thread, JSTaggedValue::Undefined()); + return method.GetTaggedValue(); + } + } + method->SetModule(thread, moduleRecord.GetTaggedValue()); return method.GetTaggedValue(); } diff --git a/ecmascript/quick_fix/main.cpp b/ecmascript/quick_fix/main.cpp index 8d4c537fd4..4176d143a4 100644 --- a/ecmascript/quick_fix/main.cpp +++ b/ecmascript/quick_fix/main.cpp @@ -115,17 +115,22 @@ int Main(const int argc, const char **argv) arg_list_t entryList = base::StringHelper::SplitString(entry, ":"); uint32_t size = entryList.size(); - if (size != 2) { // 2: two entries - std::cout << "Must include 2 entries and with ':' to spilt" << std::endl; + uint32_t entryNum = 2; // 2: two entries, excluding coldpatch testcases. + if (size < entryNum) { // 2: two entries + std::cout << "Must include 2 entries at least and with ':' to spilt" << std::endl; JSNApi::DestroyJSVM(vm); return -1; } - auto res = JSNApi::Execute(vm, baseFileName, entryList[0]); - if (!res) { - std::cout << "Cannot execute panda file '" << baseFileName << "' with entry '" << entry << "'" << std::endl; - JSNApi::DestroyJSVM(vm); - return -1; + bool res = false; + if (size == entryNum) { + res = JSNApi::Execute(vm, baseFileName, entryList[0]); + if (!res) { + std::cout << "Cannot execute panda file '" << baseFileName << + "' with entry '" << entry << "'" << std::endl; + JSNApi::DestroyJSVM(vm); + return -1; + } } JSNApi::EnableUserUncaughtErrorHandler(vm); @@ -141,8 +146,9 @@ int Main(const int argc, const char **argv) } std::cout << "QuickFix load patch success" << std::endl; - // cold patch - res = JSNApi::Execute(vm, baseFileName, entryList[1]); // 1: second entrypoint, for cold patch. + if (size > entryNum) { + res = JSNApi::Execute(vm, baseFileName, entryList[0]); + } res = JSNApi::Execute(vm, testLoadFileName, TEST_ENTRY_POINT); if (!res) { @@ -151,28 +157,30 @@ int Main(const int argc, const char **argv) break; } - std::cout << "QuickFix start check exception" << std::endl; - Local exception = JSNApi::GetAndClearUncaughtException(vm); - res = JSNApi::IsQuickFixCausedException(vm, exception, patchFileName); - if (res) { - std::cout << "QuickFix have exception." << std::endl; - } else { - std::cout << "QuickFix have no exception" << std::endl; - } + if (size == entryNum) { + std::cout << "QuickFix start check exception" << std::endl; + Local exception = JSNApi::GetAndClearUncaughtException(vm); + res = JSNApi::IsQuickFixCausedException(vm, exception, patchFileName); + if (res) { + std::cout << "QuickFix have exception" << std::endl; + } else { + std::cout << "QuickFix have no exception" << std::endl; + } - std::cout << "QuickFix start unload patch" << std::endl; - result = JSNApi::UnloadPatch(vm, patchFileName); - if (result != PatchErrorCode::SUCCESS) { - std::cout << "UnloadPatch failed!" << std::endl; - break; - } - std::cout << "QuickFix unload patch success" << std::endl; + std::cout << "QuickFix start unload patch" << std::endl; + result = JSNApi::UnloadPatch(vm, patchFileName); + if (result != PatchErrorCode::SUCCESS) { + std::cout << "UnloadPatch failed!" << std::endl; + break; + } + std::cout << "QuickFix unload patch success" << std::endl; - res = JSNApi::Execute(vm, testUnloadFileName, RETEST_ENTRY_POINT); - if (!res) { - std::cout << "Cannot execute panda file '" << testUnloadFileName + res = JSNApi::Execute(vm, testUnloadFileName, RETEST_ENTRY_POINT); + if (!res) { + std::cout << "Cannot execute panda file '" << testUnloadFileName << "' with entry '" << entry << "'" << std::endl; - break; + break; + } } } std::cout << "QuickFix Execute end" << std::endl; diff --git a/test/quickfix/BUILD.gn b/test/quickfix/BUILD.gn index 39f8a2c5a8..a12c0a626c 100644 --- a/test/quickfix/BUILD.gn +++ b/test/quickfix/BUILD.gn @@ -15,6 +15,7 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") hot_reload_test_list = [ # "check_import", + # "same_methodname", "class_inheritance", "class_mem_func", "class_mem_var", @@ -25,10 +26,21 @@ hot_reload_test_list = [ "import_export", "print_string", "record_not_same", - "same_methodname", + "module_var", + "module_func", + "module_class", + "module_class_inheritance", ] +hot_reload_cold_patch_test_list = [] + if (!is_debug) { + hot_reload_cold_patch_test_list += [ + "cold_classmemfunc", + "cold_closure", + "cold_printstring", + ] + hot_reload_test_list += [ "multi_classconstpool", "multi_closureconstpool", @@ -65,6 +77,12 @@ foreach(testcase, hot_patch_test_list) { } } +foreach(testcase, hot_reload_cold_patch_test_list) { + host_quickfix_test_action("${testcase}") { + entry_point = "--entry-point=base:module:coldpatch" + } +} + group("ark_quickfix_test") { testonly = true @@ -77,5 +95,9 @@ group("ark_quickfix_test") { deps += [ ":${testcase}QuickfixAction" ] } + foreach(testcase, hot_reload_cold_patch_test_list) { + deps += [ ":${testcase}QuickfixAction" ] + } + deps += [ ":multi_patchQuickfixAction" ] } diff --git a/test/quickfix/class_mem_func/expect_output.txt b/test/quickfix/class_mem_func/expect_output.txt index c83cb0d3bd..214123381f 100644 --- a/test/quickfix/class_mem_func/expect_output.txt +++ b/test/quickfix/class_mem_func/expect_output.txt @@ -16,10 +16,8 @@ QuickFix start load patch QuickFix load patch success print base patch QuickFix start check exception -QuickFix have exception. +QuickFix have exception QuickFix start unload patch QuickFix unload patch success print base -test cold patch -print base patch QuickFix Execute end diff --git a/test/quickfix/class_mem_func/module.js b/test/quickfix/class_mem_func/module.js index 5ea264bea1..9f5509e479 100644 --- a/test/quickfix/class_mem_func/module.js +++ b/test/quickfix/class_mem_func/module.js @@ -13,17 +13,4 @@ * limitations under the License. */ -class D { - constructor() { - } - PrintBase() { - print("print base"); - } -} - -function E() { - var d = new D() - d.PrintBase() -} - -globalThis.E = E; +export var nop = undefined diff --git a/test/quickfix/class_mem_func/module_modify.js b/test/quickfix/class_mem_func/module_modify.js index dedab5eb43..f6dd7fba05 100644 --- a/test/quickfix/class_mem_func/module_modify.js +++ b/test/quickfix/class_mem_func/module_modify.js @@ -13,15 +13,4 @@ * limitations under the License. */ -class D { - constructor() { - } - PrintBase() { - print("print base patch" ); - } -} - -function E() { - var d = new D() - d.PrintBase() -} \ No newline at end of file +export var nop = undefined \ No newline at end of file diff --git a/test/quickfix/class_mem_func/test.js b/test/quickfix/class_mem_func/test.js index 598436b918..8a555ea3db 100755 --- a/test/quickfix/class_mem_func/test.js +++ b/test/quickfix/class_mem_func/test.js @@ -13,6 +13,4 @@ * limitations under the License. */ -A() -print("test cold patch") -E() \ No newline at end of file +A() \ No newline at end of file diff --git a/test/quickfix/class_mem_var/expect_output.txt b/test/quickfix/class_mem_var/expect_output.txt index a3f75e6845..6aa8fe0fff 100644 --- a/test/quickfix/class_mem_var/expect_output.txt +++ b/test/quickfix/class_mem_var/expect_output.txt @@ -18,20 +18,10 @@ print patch str :patch print patch new :a print patch str :base print patch new :undefined -test cold patch -print patch str :patch -print patch new :a -print patch str :patch -print patch new :a QuickFix start check exception QuickFix have no exception QuickFix start unload patch QuickFix unload patch success print base str :base print base str :base -test cold patch -print patch str :patch -print patch new :a -print patch str :patch -print patch new :a QuickFix Execute end diff --git a/test/quickfix/class_mem_var/module.js b/test/quickfix/class_mem_var/module.js index 1c4ded2b9e..9f5509e479 100644 --- a/test/quickfix/class_mem_var/module.js +++ b/test/quickfix/class_mem_var/module.js @@ -13,14 +13,4 @@ * limitations under the License. */ -class B { - constructor() { - this.str = "base" - } - PrintStr() { - print("print base str :" + this.str); - } -} - -globalThis.B = B; -globalThis.BB = new B(); +export var nop = undefined diff --git a/test/quickfix/class_mem_var/module_modify.js b/test/quickfix/class_mem_var/module_modify.js index 604ccd1e5f..9f5509e479 100644 --- a/test/quickfix/class_mem_var/module_modify.js +++ b/test/quickfix/class_mem_var/module_modify.js @@ -13,13 +13,4 @@ * limitations under the License. */ -class B { - constructor() { - this.str = "patch" - this.a = "a" - } - PrintStr() { - print("print patch str :" + this.str); - print("print patch new :" + this.a); - } -} +export var nop = undefined diff --git a/test/quickfix/class_mem_var/test.js b/test/quickfix/class_mem_var/test.js index 1275db0ba9..2827c37cc0 100755 --- a/test/quickfix/class_mem_var/test.js +++ b/test/quickfix/class_mem_var/test.js @@ -15,9 +15,4 @@ const a = new A(); a.PrintStr(); -AA.PrintStr() - -print("test cold patch") -const b = new B(); -b.PrintStr(); -BB.PrintStr() \ No newline at end of file +AA.PrintStr() \ No newline at end of file diff --git a/test/quickfix/closure/expect_output.txt b/test/quickfix/closure/expect_output.txt index 30f65ea73d..154b31d880 100644 --- a/test/quickfix/closure/expect_output.txt +++ b/test/quickfix/closure/expect_output.txt @@ -21,14 +21,6 @@ patch: 4 patch: 12 patch: 13 patch: 14 -test cold patch -patch: -1 -patch: 2 -patch: 3 -patch: 4 -patch: 12 -patch: 13 -patch: 14 QuickFix start check exception QuickFix have no exception QuickFix start unload patch @@ -36,12 +28,4 @@ QuickFix unload patch success base: -1 base: 1 base: 11 -test cold patch -patch: -1 -patch: 2 -patch: 3 -patch: 4 -patch: 12 -patch: 13 -patch: 14 QuickFix Execute end diff --git a/test/quickfix/closure/module.js b/test/quickfix/closure/module.js index f117b68561..9f5509e479 100644 --- a/test/quickfix/closure/module.js +++ b/test/quickfix/closure/module.js @@ -13,20 +13,4 @@ * limitations under the License. */ -var e2 = -1 - -function A1() { - var a1 = 1 - function B1() { - var b1 = 11 - function C1() { - print("base: " + e2) - print("base: " + a1) - print("base: " + b1) - } - C1() - } - B1() -} - -globalThis.A1 = A1 +export var nop = undefined diff --git a/test/quickfix/closure/module_modify.js b/test/quickfix/closure/module_modify.js index 5a39abb483..9f5509e479 100644 --- a/test/quickfix/closure/module_modify.js +++ b/test/quickfix/closure/module_modify.js @@ -13,26 +13,4 @@ * limitations under the License. */ -var e2 = -10 - -function A1() { - var a0 = 2 - var a1 = 3 - var a2 = 4 - function B1() { - var b0 = 12 - var b1 = 13 - var b2 = 14 - function C1() { - print("patch: " + e2) - print("patch: " + a0) - print("patch: " + a1) - print("patch: " + a2) - print("patch: " + b0) - print("patch: " + b1) - print("patch: " + b2) - } - C1() - } - B1() -} +export var nop = undefined diff --git a/test/quickfix/closure/test.js b/test/quickfix/closure/test.js index c49ffc9e0f..e54887df4c 100755 --- a/test/quickfix/closure/test.js +++ b/test/quickfix/closure/test.js @@ -13,6 +13,4 @@ * limitations under the License. */ -A(); -print("test cold patch") -A1(); \ No newline at end of file +A(); \ No newline at end of file diff --git a/test/quickfix/cold_classmemfunc/base.js b/test/quickfix/cold_classmemfunc/base.js new file mode 100755 index 0000000000..bb45fbc108 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/base.js @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 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 C { + constructor() { + } + PrintBase() { + print("print base"); + } +} + +function A() { + var c = new C(); + c.PrintBase(); +} + +globalThis.A = A; \ No newline at end of file diff --git a/test/quickfix/cold_classmemfunc/base.txt b/test/quickfix/cold_classmemfunc/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_classmemfunc/base_modify.js b/test/quickfix/cold_classmemfunc/base_modify.js new file mode 100755 index 0000000000..db37a00ab2 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/base_modify.js @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 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 C { + constructor() { + } + PrintBase() { + print("print base patch" ); + } +} + +function A() { + var c = new C(); + c.PrintBase(); +} diff --git a/test/quickfix/cold_classmemfunc/expect_output.txt b/test/quickfix/cold_classmemfunc/expect_output.txt new file mode 100644 index 0000000000..29d82ea591 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/expect_output.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +print base patch +QuickFix Execute end diff --git a/test/quickfix/cold_classmemfunc/module.js b/test/quickfix/cold_classmemfunc/module.js new file mode 100644 index 0000000000..9f5509e479 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/module.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined diff --git a/test/quickfix/cold_classmemfunc/module_modify.js b/test/quickfix/cold_classmemfunc/module_modify.js new file mode 100644 index 0000000000..f6dd7fba05 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/module_modify.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined \ No newline at end of file diff --git a/test/quickfix/cold_classmemfunc/patch.txt b/test/quickfix/cold_classmemfunc/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/cold_classmemfunc/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_classmemfunc/test.js b/test/quickfix/cold_classmemfunc/test.js new file mode 100755 index 0000000000..8a555ea3db --- /dev/null +++ b/test/quickfix/cold_classmemfunc/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A() \ No newline at end of file diff --git a/test/quickfix/cold_closure/base.js b/test/quickfix/cold_closure/base.js new file mode 100755 index 0000000000..1d5f2065c4 --- /dev/null +++ b/test/quickfix/cold_closure/base.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 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. + */ + +var e1 = -1 + +function A() { + var a1 = 1 + function B() { + var b1 = 11 + function C() { + print("base: " + e1) + print("base: " + a1) + print("base: " + b1) + } + C() + } + B() +} + +globalThis.A = A diff --git a/test/quickfix/cold_closure/base.txt b/test/quickfix/cold_closure/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/cold_closure/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_closure/base_modify.js b/test/quickfix/cold_closure/base_modify.js new file mode 100755 index 0000000000..8a0e1c762b --- /dev/null +++ b/test/quickfix/cold_closure/base_modify.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 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. + */ + +var e1 = -10 + +function A() { + var a0 = 2 + var a1 = 3 + var a2 = 4 + function B() { + var b0 = 12 + var b1 = 13 + var b2 = 14 + function C() { + print("patch: " + e1) + print("patch: " + a0) + print("patch: " + a1) + print("patch: " + a2) + print("patch: " + b0) + print("patch: " + b1) + print("patch: " + b2) + } + C() + } + B() +} \ No newline at end of file diff --git a/test/quickfix/cold_closure/expect_output.txt b/test/quickfix/cold_closure/expect_output.txt new file mode 100644 index 0000000000..50369c16f8 --- /dev/null +++ b/test/quickfix/cold_closure/expect_output.txt @@ -0,0 +1,24 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +patch: -1 +patch: 2 +patch: 3 +patch: 4 +patch: 12 +patch: 13 +patch: 14 +QuickFix Execute end diff --git a/test/quickfix/cold_closure/module.js b/test/quickfix/cold_closure/module.js new file mode 100644 index 0000000000..9f5509e479 --- /dev/null +++ b/test/quickfix/cold_closure/module.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined diff --git a/test/quickfix/cold_closure/module_modify.js b/test/quickfix/cold_closure/module_modify.js new file mode 100644 index 0000000000..9f5509e479 --- /dev/null +++ b/test/quickfix/cold_closure/module_modify.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined diff --git a/test/quickfix/cold_closure/patch.txt b/test/quickfix/cold_closure/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/cold_closure/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_closure/test.js b/test/quickfix/cold_closure/test.js new file mode 100755 index 0000000000..e54887df4c --- /dev/null +++ b/test/quickfix/cold_closure/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A(); \ No newline at end of file diff --git a/test/quickfix/cold_printstring/base.js b/test/quickfix/cold_printstring/base.js new file mode 100644 index 0000000000..5406aaef13 --- /dev/null +++ b/test/quickfix/cold_printstring/base.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 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. + */ + +// normal function. +function foo() { + print("base foo") +} + +// anonymous function. +function A() { + (()=>{ + print("anonymous: base A"); + })() +} + +// object literal. +function B() { + var obj_1 = {'a': 1, 'b': "base"} + var obj = {'a': 1, 'b': obj_1} + + print(JSON.stringify(obj)); +} + +// array literal. +function C() { + var arr = ["1", "2", "base"] + print(arr); +} + +globalThis.foo = foo +globalThis.A = A +globalThis.B = B +globalThis.C = C diff --git a/test/quickfix/cold_printstring/base.txt b/test/quickfix/cold_printstring/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/cold_printstring/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_printstring/base_modify.js b/test/quickfix/cold_printstring/base_modify.js new file mode 100644 index 0000000000..ca24a6ffe3 --- /dev/null +++ b/test/quickfix/cold_printstring/base_modify.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 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. + */ + +function foo() { + print("patch foo") +} + +function A() { + (()=>{ + print("anonymous: patch A"); + })() +} + +function B() { + var obj_1 = {'a': 1, 'b': "patch"} + var obj = {'a': 1, 'b': obj_1} + + print(JSON.stringify(obj)); +} + +function C() { + var arr = ["1", "2", "patch"] + print(arr); +} \ No newline at end of file diff --git a/test/quickfix/cold_printstring/expect_output.txt b/test/quickfix/cold_printstring/expect_output.txt new file mode 100644 index 0000000000..249af5b3ac --- /dev/null +++ b/test/quickfix/cold_printstring/expect_output.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +patch foo +anonymous: patch A +{"a":1,"b":{"a":1,"b":"patch"}} +1,2,patch +QuickFix Execute end diff --git a/test/quickfix/cold_printstring/module.js b/test/quickfix/cold_printstring/module.js new file mode 100644 index 0000000000..f6dd7fba05 --- /dev/null +++ b/test/quickfix/cold_printstring/module.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined \ No newline at end of file diff --git a/test/quickfix/cold_printstring/module_modify.js b/test/quickfix/cold_printstring/module_modify.js new file mode 100644 index 0000000000..a12ea21bc2 --- /dev/null +++ b/test/quickfix/cold_printstring/module_modify.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 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. + */ + +export var nop = undefined + diff --git a/test/quickfix/cold_printstring/patch.txt b/test/quickfix/cold_printstring/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/cold_printstring/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/cold_printstring/test.js b/test/quickfix/cold_printstring/test.js new file mode 100644 index 0000000000..42758e2efa --- /dev/null +++ b/test/quickfix/cold_printstring/test.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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. + */ + +globalThis.foo() +globalThis.A() +globalThis.B() +globalThis.C() diff --git a/test/quickfix/global_func/expect_output.txt b/test/quickfix/global_func/expect_output.txt index 3235b59a39..d893f6f0f5 100644 --- a/test/quickfix/global_func/expect_output.txt +++ b/test/quickfix/global_func/expect_output.txt @@ -15,8 +15,9 @@ QuickFix Execute start QuickFix start load patch QuickFix load patch success base A() +patch B() QuickFix start check exception -QuickFix have exception. +QuickFix have no exception QuickFix start unload patch QuickFix unload patch success base A() diff --git a/test/quickfix/global_var/expect_output.txt b/test/quickfix/global_var/expect_output.txt index 0d67cea312..6053ecc7c5 100644 --- a/test/quickfix/global_var/expect_output.txt +++ b/test/quickfix/global_var/expect_output.txt @@ -14,8 +14,8 @@ QuickFix Execute start QuickFix start load patch QuickFix load patch success -patch old global var :100 -patch new global var :undefined +patch old global var :200 +patch new global var :300 QuickFix start check exception QuickFix have no exception QuickFix start unload patch diff --git a/test/quickfix/import_export/expect_output.txt b/test/quickfix/import_export/expect_output.txt index cec490b4d2..333f1014f1 100644 --- a/test/quickfix/import_export/expect_output.txt +++ b/test/quickfix/import_export/expect_output.txt @@ -14,7 +14,7 @@ QuickFix Execute start QuickFix start load patch QuickFix load patch success -print patch: 100 +print patch: 200 patch foo QuickFix start check exception QuickFix have no exception diff --git a/test/quickfix/module_class/base.js b/test/quickfix/module_class/base.js new file mode 100755 index 0000000000..af851fa3f6 --- /dev/null +++ b/test/quickfix/module_class/base.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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. + */ + +import { B } from './module.js' + +function A() { + var b = new B(); + b.PrintB(); +} + +globalThis.A = A diff --git a/test/quickfix/module_class/base.txt b/test/quickfix/module_class/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/module_class/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_class/base_modify.js b/test/quickfix/module_class/base_modify.js new file mode 100755 index 0000000000..92b810af69 --- /dev/null +++ b/test/quickfix/module_class/base_modify.js @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 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. + */ +import { C } from './module.js' +import { B } from './module.js' +import { D } from './module.js' + +function A() { + var b = new B(); + b.PrintB(); + b.PrintP(); + var c = new C(); + c.PrintC(); + var d = new D(); + d.PrintD(); +} diff --git a/test/quickfix/module_class/expect_output.txt b/test/quickfix/module_class/expect_output.txt new file mode 100644 index 0000000000..62fe47acb8 --- /dev/null +++ b/test/quickfix/module_class/expect_output.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +module patch B : module patch name +module patch P : module patch age +module patch C +module patch D : module patch name +QuickFix start check exception +QuickFix have no exception +QuickFix start unload patch +QuickFix unload patch success +module base B : module base name +QuickFix Execute end diff --git a/test/quickfix/module_class/module.js b/test/quickfix/module_class/module.js new file mode 100644 index 0000000000..d6ebf6a1f7 --- /dev/null +++ b/test/quickfix/module_class/module.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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. + */ + +export class B { + constructor() { + this.name = "module base name" + } + PrintB() { + print("module base B : " + this.name); + } +} + +export class C { + constructor() { + } + PrintC() { + print("module base C"); + } +} diff --git a/test/quickfix/module_class/module_modify.js b/test/quickfix/module_class/module_modify.js new file mode 100644 index 0000000000..e024ae5f6e --- /dev/null +++ b/test/quickfix/module_class/module_modify.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 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. + */ + +export class D { + constructor() { + this.name = "module patch name" + } + PrintD() { + print("module patch D : " + this.name); + } +} + +export class C { + constructor() { + } + PrintC() { + print("module patch C"); + } +} + +export class B { + constructor() { + this.name = "module patch name" + this.age = "module patch age" + } + PrintB() { + print("module patch B : " + this.name); + } + PrintP() { + print ("module patch P : " + this.age); + } +} diff --git a/test/quickfix/module_class/patch.txt b/test/quickfix/module_class/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/module_class/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_class/test.js b/test/quickfix/module_class/test.js new file mode 100755 index 0000000000..8a555ea3db --- /dev/null +++ b/test/quickfix/module_class/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A() \ No newline at end of file diff --git a/test/quickfix/module_class_inheritance/base.js b/test/quickfix/module_class_inheritance/base.js new file mode 100755 index 0000000000..af851fa3f6 --- /dev/null +++ b/test/quickfix/module_class_inheritance/base.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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. + */ + +import { B } from './module.js' + +function A() { + var b = new B(); + b.PrintB(); +} + +globalThis.A = A diff --git a/test/quickfix/module_class_inheritance/base.txt b/test/quickfix/module_class_inheritance/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/module_class_inheritance/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_class_inheritance/base_modify.js b/test/quickfix/module_class_inheritance/base_modify.js new file mode 100755 index 0000000000..6a3bc4669b --- /dev/null +++ b/test/quickfix/module_class_inheritance/base_modify.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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. + */ +import { B } from './module.js' + +function A() { + var b = new B(); + b.PrintB(); + b.PrintC(); +} + +globalThis.A = A diff --git a/test/quickfix/module_class_inheritance/expect_output.txt b/test/quickfix/module_class_inheritance/expect_output.txt new file mode 100644 index 0000000000..5f2ad0e2a2 --- /dev/null +++ b/test/quickfix/module_class_inheritance/expect_output.txt @@ -0,0 +1,24 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +module patch B +module patch C +QuickFix start check exception +QuickFix have no exception +QuickFix start unload patch +QuickFix unload patch success +module base B +QuickFix Execute end diff --git a/test/quickfix/module_class_inheritance/module.js b/test/quickfix/module_class_inheritance/module.js new file mode 100644 index 0000000000..bd63d990c4 --- /dev/null +++ b/test/quickfix/module_class_inheritance/module.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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. + */ + +export class B { + constructor() { + } + PrintB() { + print("module base B"); + } +} + diff --git a/test/quickfix/module_class_inheritance/module_modify.js b/test/quickfix/module_class_inheritance/module_modify.js new file mode 100644 index 0000000000..eaef143434 --- /dev/null +++ b/test/quickfix/module_class_inheritance/module_modify.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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 C { + constructor() { + } + PrintC() { + print("module patch C"); + } +} + +export class B extends C{ + constructor() { + super(); + } + PrintB() { + print("module patch B"); + } +} diff --git a/test/quickfix/module_class_inheritance/patch.txt b/test/quickfix/module_class_inheritance/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/module_class_inheritance/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_class_inheritance/test.js b/test/quickfix/module_class_inheritance/test.js new file mode 100755 index 0000000000..8a555ea3db --- /dev/null +++ b/test/quickfix/module_class_inheritance/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A() \ No newline at end of file diff --git a/test/quickfix/module_func/base.js b/test/quickfix/module_func/base.js new file mode 100755 index 0000000000..050c9c5d9c --- /dev/null +++ b/test/quickfix/module_func/base.js @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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. + */ + +import { a } from './module.js' +import { foo1 } from './module.js' +import { foo2 } from './module.js' + +function A() { + print("print base: " + a); + foo1(); + foo2(); +} +globalThis.A = A; \ No newline at end of file diff --git a/test/quickfix/module_func/base.txt b/test/quickfix/module_func/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/module_func/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_func/base_modify.js b/test/quickfix/module_func/base_modify.js new file mode 100755 index 0000000000..a4353294eb --- /dev/null +++ b/test/quickfix/module_func/base_modify.js @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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. + */ + +import { a } from './module.js' +import { foo1 } from './module.js' +import { foo3 } from './module.js' +import { foo } from './module.js' + +function A() { + print("print patch: " + a); + foo1(); + foo3(); + foo(); +} \ No newline at end of file diff --git a/test/quickfix/module_func/expect_output.txt b/test/quickfix/module_func/expect_output.txt new file mode 100644 index 0000000000..319a62e5e3 --- /dev/null +++ b/test/quickfix/module_func/expect_output.txt @@ -0,0 +1,28 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +print patch: 100 +patch foo1 +patch foo3 +patch foo +QuickFix start check exception +QuickFix have no exception +QuickFix start unload patch +QuickFix unload patch success +print base: 100 +module foo1 +module foo2 +QuickFix Execute end diff --git a/test/quickfix/module_func/module.js b/test/quickfix/module_func/module.js new file mode 100644 index 0000000000..d003c8c92f --- /dev/null +++ b/test/quickfix/module_func/module.js @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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. + */ + +export var a = 100 +export function foo1() { + print("module foo1"); +} +export function foo2() { + print("module foo2"); +} +export function foo3() { + print("module foo3"); +} diff --git a/test/quickfix/module_func/module_modify.js b/test/quickfix/module_func/module_modify.js new file mode 100644 index 0000000000..4ca00c2c61 --- /dev/null +++ b/test/quickfix/module_func/module_modify.js @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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. + */ + +export var a = 100 +export function foo1() { + print("patch foo1"); +} +export function foo() { + print("patch foo"); +} +export function foo3() { + print("patch foo3"); +} diff --git a/test/quickfix/module_func/patch.txt b/test/quickfix/module_func/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/module_func/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_func/test.js b/test/quickfix/module_func/test.js new file mode 100755 index 0000000000..e54887df4c --- /dev/null +++ b/test/quickfix/module_func/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A(); \ No newline at end of file diff --git a/test/quickfix/module_var/base.js b/test/quickfix/module_var/base.js new file mode 100755 index 0000000000..4b86d3461d --- /dev/null +++ b/test/quickfix/module_var/base.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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. + */ + +import { a } from './module.js' +import { foo } from './module.js' + +function A() { + print("print base: " + a); + foo(); +} +globalThis.A = A; \ No newline at end of file diff --git a/test/quickfix/module_var/base.txt b/test/quickfix/module_var/base.txt new file mode 100644 index 0000000000..b36f5e0837 --- /dev/null +++ b/test/quickfix/module_var/base.txt @@ -0,0 +1,2 @@ +base.js;base;esm;base.js;entry +module.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_var/base_modify.js b/test/quickfix/module_var/base_modify.js new file mode 100755 index 0000000000..e871af47b5 --- /dev/null +++ b/test/quickfix/module_var/base_modify.js @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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. + */ + +import { a } from './module.js' +import { b } from './module.js' +import { c } from './module.js' +import { foo } from './module.js' + +function A() { + print("print patch: " + a); + print("print patch: " + b); + print("print patch: " + c); + foo(); +} \ No newline at end of file diff --git a/test/quickfix/module_var/expect_output.txt b/test/quickfix/module_var/expect_output.txt new file mode 100644 index 0000000000..57a02bf242 --- /dev/null +++ b/test/quickfix/module_var/expect_output.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2022 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. + +QuickFix Execute start +QuickFix start load patch +QuickFix load patch success +print patch: 200 +print patch: 300 +print patch: 400 +patch foo +QuickFix start check exception +QuickFix have no exception +QuickFix start unload patch +QuickFix unload patch success +print base: 100 +module foo +QuickFix Execute end diff --git a/test/quickfix/module_var/module.js b/test/quickfix/module_var/module.js new file mode 100644 index 0000000000..0a2a6bf60b --- /dev/null +++ b/test/quickfix/module_var/module.js @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 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. + */ + +export var a = 100 +export var c = 400 +export function foo() { + print("module foo"); +} diff --git a/test/quickfix/module_var/module_modify.js b/test/quickfix/module_var/module_modify.js new file mode 100644 index 0000000000..6fc0c0d28a --- /dev/null +++ b/test/quickfix/module_var/module_modify.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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. + */ + +export var a = 200 +export var b = 300 +export var c = 400 +export function foo() { + print("patch foo"); +} diff --git a/test/quickfix/module_var/patch.txt b/test/quickfix/module_var/patch.txt new file mode 100644 index 0000000000..7b77c184d0 --- /dev/null +++ b/test/quickfix/module_var/patch.txt @@ -0,0 +1,2 @@ +base_modify.js;base;esm;base.js;entry +module_modify.js;module;esm;module.js;entry \ No newline at end of file diff --git a/test/quickfix/module_var/test.js b/test/quickfix/module_var/test.js new file mode 100755 index 0000000000..e54887df4c --- /dev/null +++ b/test/quickfix/module_var/test.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 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. + */ + +A(); \ No newline at end of file diff --git a/test/quickfix/multi_patch/expect_output.txt b/test/quickfix/multi_patch/expect_output.txt index a6f5b0ec57..1d53f6aa0b 100644 --- a/test/quickfix/multi_patch/expect_output.txt +++ b/test/quickfix/multi_patch/expect_output.txt @@ -14,7 +14,7 @@ QuickFix Execute start QuickFix start load patch QuickFix load patch success -print patch:100 - 200 +print patch:200 - 200 QuickFix start check exception QuickFix have no exception QuickFix start unload patch @@ -22,7 +22,7 @@ QuickFix unload patch success print base:100 - 100 QuickFix start load patch QuickFix load patch success -print patch1:100 - 300 +print patch1:300 - 300 QuickFix start check exception QuickFix have no exception QuickFix start unload patch @@ -30,7 +30,7 @@ QuickFix unload patch success print base:100 - 100 QuickFix start load patch QuickFix load patch success -print patch2: 100 - 400 +print patch2: 400 - 400 QuickFix start check exception QuickFix have no exception QuickFix start unload patch diff --git a/test/quickfix/print_string/expect_output.txt b/test/quickfix/print_string/expect_output.txt index 43ddd59c27..0c5f2d465b 100644 --- a/test/quickfix/print_string/expect_output.txt +++ b/test/quickfix/print_string/expect_output.txt @@ -18,8 +18,6 @@ patch foo anonymous: patch A {"a":1,"b":{"a":1,"b":"patch"}} 1,2,patch -test cold patch -patch f QuickFix start check exception QuickFix have no exception QuickFix start unload patch @@ -28,6 +26,4 @@ base foo anonymous: base A {"a":1,"b":{"a":1,"b":"base"}} 1,2,base -test cold patch -patch f QuickFix Execute end diff --git a/test/quickfix/print_string/module.js b/test/quickfix/print_string/module.js index c8f9f3ff7a..f6dd7fba05 100644 --- a/test/quickfix/print_string/module.js +++ b/test/quickfix/print_string/module.js @@ -13,7 +13,4 @@ * limitations under the License. */ -function f() { - print("base f") -} -globalThis.f = f; \ No newline at end of file +export var nop = undefined \ No newline at end of file diff --git a/test/quickfix/print_string/module_modify.js b/test/quickfix/print_string/module_modify.js index e71de5f15d..a12ea21bc2 100644 --- a/test/quickfix/print_string/module_modify.js +++ b/test/quickfix/print_string/module_modify.js @@ -13,7 +13,5 @@ * limitations under the License. */ -function f() { - print("patch f") -} +export var nop = undefined diff --git a/test/quickfix/print_string/test.js b/test/quickfix/print_string/test.js index 3a99948d1b..42758e2efa 100644 --- a/test/quickfix/print_string/test.js +++ b/test/quickfix/print_string/test.js @@ -17,5 +17,3 @@ globalThis.foo() globalThis.A() globalThis.B() globalThis.C() -print("test cold patch") -globalThis.f() From 8ae8b906453be304001bc8b3b5c29ff40a8428a4 Mon Sep 17 00:00:00 2001 From: Onlynagesha Date: Thu, 19 Oct 2023 20:38:26 +0800 Subject: [PATCH 45/50] global_env_constants cleanup for strings Cleans up initialization of string constants in global_env_constants.cpp Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I89FU1 Signed-off-by: Onlynagesha Change-Id: I028c12a1bdd24e33c21f5c1bd2b2b20d4be8acb1 --- ecmascript/global_env_constants-inl.h | 28 +- ecmascript/global_env_constants.cpp | 312 +----------- ecmascript/global_env_constants.h | 696 +++++++++++++------------- 3 files changed, 381 insertions(+), 655 deletions(-) diff --git a/ecmascript/global_env_constants-inl.h b/ecmascript/global_env_constants-inl.h index c708004eec..7db7b51891 100644 --- a/ecmascript/global_env_constants-inl.h +++ b/ecmascript/global_env_constants-inl.h @@ -24,17 +24,17 @@ namespace panda::ecmascript { inline const JSTaggedValue *GlobalEnvConstants::BeginSlot() const { - return &constants_[static_cast(ConstantIndex::CONSTATNT_BEGIN)]; + return &constants_[static_cast(ConstantIndex::CONSTANT_BEGIN)]; } inline const JSTaggedValue *GlobalEnvConstants::EndSlot() const { - return &constants_[static_cast(ConstantIndex::CONSTATNT_END)]; + return &constants_[static_cast(ConstantIndex::CONSTANT_END)]; } inline void GlobalEnvConstants::SetConstant(ConstantIndex index, JSTaggedValue value) { - DASSERT_PRINT(index >= ConstantIndex::CONSTATNT_BEGIN && index < ConstantIndex::CONSTATNT_END, + DASSERT_PRINT(index >= ConstantIndex::CONSTANT_BEGIN && index < ConstantIndex::CONSTANT_END, "Root Index out of bound"); constants_[static_cast(index)] = value; } @@ -42,7 +42,7 @@ inline void GlobalEnvConstants::SetConstant(ConstantIndex index, JSTaggedValue v template inline void GlobalEnvConstants::SetConstant(ConstantIndex index, JSHandle value) { - DASSERT_PRINT(index >= ConstantIndex::CONSTATNT_BEGIN && index < ConstantIndex::CONSTATNT_END, + DASSERT_PRINT(index >= ConstantIndex::CONSTANT_BEGIN && index < ConstantIndex::CONSTANT_END, "Root Index out of bound"); constants_[static_cast(index)] = value.GetTaggedValue(); } @@ -54,7 +54,7 @@ inline uintptr_t GlobalEnvConstants::GetGlobalConstantAddr(ConstantIndex index) // clang-format off // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECL_GET_IMPL(Type, Name, Index, Desc) \ +#define DECL_GET_IMPL_COMMON(Type, Name, Index) \ inline const Type GlobalEnvConstants::Get##Name() const \ { \ return constants_[static_cast(ConstantIndex::Index)]; \ @@ -70,12 +70,18 @@ inline uintptr_t GlobalEnvConstants::GetGlobalConstantAddr(ConstantIndex index) * static_cast(ConstantIndex::Index); \ } - GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_IMPL) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_IMPL) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_IMPL) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CACHES(DECL_GET_IMPL) // NOLINT(readability-const-return-type) -#undef DECL_GET_IMPL +#define DECL_GET_IMPL_WITH_TYPE(Type, Name, Index, Desc) DECL_GET_IMPL_COMMON(Type, Name, Index) + GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CACHES(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + +#define DECL_GET_IMPL_STRING(Name, Index, Token) DECL_GET_IMPL_COMMON(JSTaggedValue, Name, Index) + GLOBAL_ENV_CONSTANT_STRING(DECL_GET_IMPL_STRING) // NOLINT(readability-const-return-type) +#undef DECL_GET_IMPL_STRING + +#undef DECL_GET_IMPL_COMMON // clang-format on } // namespace panda::ecmascript #endif // ECMASCRIPT_GLOBAL_ENV_CONSTANTS_INL_H diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 143d06f499..8fafa36635 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -312,314 +312,14 @@ void GlobalEnvConstants::InitGlobalConstantSpecial(JSThread *thread) void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - [[maybe_unused]] auto test = EcmaString::Cast(GetHandledEmptyString().GetObject()); - SetConstant(ConstantIndex::CONSTRUCTOR_STRING_INDEX, factory->NewFromASCIINonMovable("constructor")); - SetConstant(ConstantIndex::PROTOTYPE_STRING_INDEX, factory->NewFromASCIINonMovable("prototype")); - SetConstant(ConstantIndex::LENGTH_STRING_INDEX, factory->NewFromASCIINonMovable("length")); - SetConstant(ConstantIndex::VALUE_STRING_INDEX, factory->NewFromASCIINonMovable("value")); - SetConstant(ConstantIndex::SET_STRING_INDEX, factory->NewFromASCIINonMovable("set")); - SetConstant(ConstantIndex::GET_STRING_INDEX, factory->NewFromASCIINonMovable("get")); - SetConstant(ConstantIndex::WRITABLE_STRING_INDEX, factory->NewFromASCIINonMovable("writable")); - SetConstant(ConstantIndex::ENUMERABLE_STRING_INDEX, factory->NewFromASCIINonMovable("enumerable")); - SetConstant(ConstantIndex::CONFIGURABLE_STRING_INDEX, factory->NewFromASCIINonMovable("configurable")); /* non ECMA standard jsapi containers iterators, init to Undefined first */ InitJSAPIContainers(); - /* SymbolTable *RegisterSymbols */ - SetConstant(ConstantIndex::NAME_STRING_INDEX, factory->NewFromASCIINonMovable("name")); - SetConstant(ConstantIndex::GETPROTOTYPEOF_STRING_INDEX, factory->NewFromASCIINonMovable("getPrototypeOf")); - SetConstant(ConstantIndex::SETPROTOTYPEOF_STRING_INDEX, factory->NewFromASCIINonMovable("setPrototypeOf")); - SetConstant(ConstantIndex::ISEXTENSIBLE_STRING_INDEX, factory->NewFromASCIINonMovable("isExtensible")); - SetConstant(ConstantIndex::PREVENTEXTENSIONS_STRING_INDEX, - factory->NewFromASCIINonMovable("preventExtensions")); - SetConstant(ConstantIndex::GETOWNPROPERTYDESCRIPTOR_STRING_INDEX, - factory->NewFromASCIINonMovable("getOwnPropertyDescriptor")); - SetConstant(ConstantIndex::DEFINEPROPERTY_STRING_INDEX, factory->NewFromASCIINonMovable("defineProperty")); - SetConstant(ConstantIndex::HAS_STRING_INDEX, factory->NewFromASCIINonMovable("has")); - SetConstant(ConstantIndex::DELETEPROPERTY_STRING_INDEX, factory->NewFromASCIINonMovable("deleteProperty")); - SetConstant(ConstantIndex::ENUMERATE_STRING_INDEX, factory->NewFromASCIINonMovable("enumerate")); - SetConstant(ConstantIndex::OWNKEYS_STRING_INDEX, factory->NewFromASCIINonMovable("ownKeys")); - SetConstant(ConstantIndex::APPLY_STRING_INDEX, factory->NewFromASCIINonMovable("apply")); - SetConstant(ConstantIndex::NEGATIVE_ZERO_STRING_INDEX, factory->NewFromASCIINonMovable("-0")); - SetConstant(ConstantIndex::DONE_STRING_INDEX, factory->NewFromASCIINonMovable("done")); - SetConstant(ConstantIndex::PROXY_STRING_INDEX, factory->NewFromASCIINonMovable("proxy")); - SetConstant(ConstantIndex::REVOKE_STRING_INDEX, factory->NewFromASCIINonMovable("revoke")); - SetConstant(ConstantIndex::NEXT_STRING_INDEX, factory->NewFromASCIINonMovable("next")); - SetConstant(ConstantIndex::TO_STRING_STRING_INDEX, factory->NewFromASCIINonMovable("toString")); - SetConstant(ConstantIndex::TO_LOCALE_STRING_STRING_INDEX, factory->NewFromASCIINonMovable("toLocaleString")); - SetConstant(ConstantIndex::VALUE_OF_STRING_INDEX, factory->NewFromASCIINonMovable("valueOf")); - SetConstant(ConstantIndex::UNDEFINED_STRING_INDEX, factory->NewFromASCIINonMovable("undefined")); - SetConstant(ConstantIndex::NULL_STRING_INDEX, factory->NewFromASCIINonMovable("null")); - SetConstant(ConstantIndex::BOOLEAN_STRING_INDEX, factory->NewFromASCIINonMovable("boolean")); - SetConstant(ConstantIndex::NUMBER_STRING_INDEX, factory->NewFromASCIINonMovable("number")); - SetConstant(ConstantIndex::BIGINT_STRING_INDEX, factory->NewFromASCIINonMovable("bigint")); - SetConstant(ConstantIndex::FUNCTION_STRING_INDEX, factory->NewFromASCIINonMovable("function")); - SetConstant(ConstantIndex::STRING_STRING_INDEX, factory->NewFromASCIINonMovable("string")); - SetConstant(ConstantIndex::SYMBOL_STRING_INDEX, factory->NewFromASCIINonMovable("symbol")); - SetConstant(ConstantIndex::OBJECT_STRING_INDEX, factory->NewFromASCIINonMovable("object")); - SetConstant(ConstantIndex::TRUE_STRING_INDEX, factory->NewFromASCIINonMovable("true")); - SetConstant(ConstantIndex::FALSE_STRING_INDEX, factory->NewFromASCIINonMovable("false")); - SetConstant(ConstantIndex::RETURN_STRING_INDEX, factory->NewFromASCIINonMovable("return")); - SetConstant(ConstantIndex::PROXY_CONSTRUCT_STRING_INDEX, factory->NewFromASCIINonMovable("construct")); - SetConstant(ConstantIndex::PROXY_CALL_STRING_INDEX, factory->NewFromASCIINonMovable("call")); - SetConstant(ConstantIndex::PROMISE_THEN_STRING_INDEX, factory->NewFromASCIINonMovable("then")); - SetConstant(ConstantIndex::PROMISE_CATCH_STRING_INDEX, factory->NewFromASCIINonMovable("catch")); - SetConstant(ConstantIndex::PROMISE_FINALLY_STRING_INDEX, factory->NewFromASCII("finally")); - SetConstant(ConstantIndex::PROMISE_STATUS_STRING_INDEX, factory->NewFromASCII("status")); - SetConstant(ConstantIndex::PROMISE_FULFILLED_STRING_INDEX, factory->NewFromASCII("fulfilled")); - SetConstant(ConstantIndex::PROMISE_REJECTED_STRING_INDEX, factory->NewFromASCII("rejected")); - SetConstant(ConstantIndex::PROMISE_REASON_STRING_INDEX, factory->NewFromASCII("reason")); - SetConstant(ConstantIndex::SCRIPT_JOB_STRING_INDEX, factory->NewFromASCIINonMovable("ScriptJobs")); - SetConstant(ConstantIndex::PROMISE_STRING_INDEX, factory->NewFromASCIINonMovable("PrimiseJobs")); - SetConstant(ConstantIndex::THROWER_STRING_INDEX, factory->NewFromASCIINonMovable("Thrower")); - SetConstant(ConstantIndex::IDENTITY_STRING_INDEX, factory->NewFromASCIINonMovable("Identity")); - SetConstant(ConstantIndex::CALLER_STRING_INDEX, factory->NewFromASCIINonMovable("caller")); - SetConstant(ConstantIndex::CALLEE_STRING_INDEX, factory->NewFromASCIINonMovable("callee")); - SetConstant(ConstantIndex::INT8_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Int8Array")); - SetConstant(ConstantIndex::UINT8_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Uint8Array")); - SetConstant(ConstantIndex::UINT8_CLAMPED_ARRAY_STRING_INDEX, - factory->NewFromASCIINonMovable("Uint8ClampedArray")); - SetConstant(ConstantIndex::INT16_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Int16Array")); - SetConstant(ConstantIndex::UINT16_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Uint16Array")); - SetConstant(ConstantIndex::INT32_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Int32Array")); - SetConstant(ConstantIndex::UINT32_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Uint32Array")); - SetConstant(ConstantIndex::FLOAT32_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Float32Array")); - SetConstant(ConstantIndex::FLOAT64_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("Float64Array")); - SetConstant(ConstantIndex::BIGINT64_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("BigInt64Array")); - SetConstant(ConstantIndex::BIGUINT64_ARRAY_STRING_INDEX, factory->NewFromASCIINonMovable("BigUint64Array")); - SetConstant(ConstantIndex::ASYNC_FUNCTION_STRING_INDEX, factory->NewFromASCIINonMovable("AsyncFunction")); - SetConstant(ConstantIndex::PROMISE_RESOLVE_STRING_INDEX, factory->NewFromASCIINonMovable("resolve")); - SetConstant(ConstantIndex::ID_STRING_INDEX, factory->NewFromASCIINonMovable("id")); - SetConstant(ConstantIndex::METHOD_STRING_INDEX, factory->NewFromASCIINonMovable("method")); - SetConstant(ConstantIndex::PARAMS_STRING_INDEX, factory->NewFromASCIINonMovable("params")); - SetConstant(ConstantIndex::RESULT_STRING_INDEX, factory->NewFromASCIINonMovable("result")); - 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")); - SetConstant(ConstantIndex::RANGE_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("RangeError")); - SetConstant(ConstantIndex::REFERENCE_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("ReferenceError")); - SetConstant(ConstantIndex::TYPE_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("TypeError")); - SetConstant(ConstantIndex::URI_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("URIError")); - SetConstant(ConstantIndex::SYNTAX_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("SyntaxError")); - SetConstant(ConstantIndex::EVAL_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("EvalError")); - SetConstant(ConstantIndex::OOM_ERROR_STRING_INDEX, factory->NewFromASCIINonMovable("OutOfMemoryError")); - SetConstant(ConstantIndex::ERROR_FUNC_STRING_INDEX, factory->NewFromASCIINonMovable("errorfunc")); - SetConstant(ConstantIndex::STACK_STRING_INDEX, factory->NewFromASCIINonMovable("stack")); - SetConstant(ConstantIndex::STACK_EMPTY_STRING_INDEX, factory->NewFromASCIINonMovable("stackisempty")); - SetConstant(ConstantIndex::OBJ_NOT_COERCIBLE_STRING_INDEX, - factory->NewFromASCIINonMovable("objectnotcoercible")); - /* for Intl. */ - SetConstant(ConstantIndex::LANGUAGE_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("language")); - SetConstant(ConstantIndex::SCRIPT_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("script")); - SetConstant(ConstantIndex::REGION_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("region")); - SetConstant(ConstantIndex::BASE_NAME_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("baseName")); - SetConstant(ConstantIndex::CALENDAR_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("calendar")); - SetConstant(ConstantIndex::COLLATION_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("collation")); - SetConstant(ConstantIndex::HOUR_CYCLE_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("hourCycle")); - SetConstant(ConstantIndex::CASE_FIRST_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("caseFirst")); - SetConstant(ConstantIndex::NUMERIC_STRING_CLASS_INDEX, factory->NewFromASCIINonMovable("numeric")); - SetConstant(ConstantIndex::NUMBERING_SYSTEM_STRING_CLASS_INDEX, - factory->NewFromASCIINonMovable("numberingSystem")); - SetConstant(ConstantIndex::TYPE_STRING_INDEX, factory->NewFromASCIINonMovable("type")); - SetConstant(ConstantIndex::LOCALE_MATCHER_STRING_INDEX, factory->NewFromASCIINonMovable("localeMatcher")); - SetConstant(ConstantIndex::FORMAT_MATCHER_STRING_INDEX, factory->NewFromASCIINonMovable("formatMatcher")); - SetConstant(ConstantIndex::HOUR12_STRING_INDEX, factory->NewFromASCIINonMovable("hour12")); - SetConstant(ConstantIndex::H11_STRING_INDEX, factory->NewFromASCIINonMovable("h11")); - SetConstant(ConstantIndex::H12_STRING_INDEX, factory->NewFromASCIINonMovable("h12")); - SetConstant(ConstantIndex::H23_STRING_INDEX, factory->NewFromASCIINonMovable("h23")); - SetConstant(ConstantIndex::H24_STRING_INDEX, factory->NewFromASCIINonMovable("h24")); - SetConstant(ConstantIndex::WEEK_DAY_STRING_INDEX, factory->NewFromASCIINonMovable("weekday")); - SetConstant(ConstantIndex::ERA_STRING_INDEX, factory->NewFromASCIINonMovable("era")); - SetConstant(ConstantIndex::YEAR_STRING_INDEX, factory->NewFromASCIINonMovable("year")); - SetConstant(ConstantIndex::QUARTER_STRING_INDEX, factory->NewFromASCIINonMovable("quarter")); - SetConstant(ConstantIndex::MONTH_STRING_INDEX, factory->NewFromASCIINonMovable("month")); - SetConstant(ConstantIndex::DAY_STRING_INDEX, factory->NewFromASCIINonMovable("day")); - SetConstant(ConstantIndex::HOUR_STRING_INDEX, factory->NewFromASCIINonMovable("hour")); - SetConstant(ConstantIndex::MINUTE_STRING_INDEX, factory->NewFromASCIINonMovable("minute")); - SetConstant(ConstantIndex::SECOND_STRING_INDEX, factory->NewFromASCIINonMovable("second")); - SetConstant(ConstantIndex::YEARS_STRING_INDEX, factory->NewFromASCIINonMovable("years")); - SetConstant(ConstantIndex::QUARTERS_STRING_INDEX, factory->NewFromASCIINonMovable("quarters")); - SetConstant(ConstantIndex::MONTHS_STRING_INDEX, factory->NewFromASCIINonMovable("months")); - SetConstant(ConstantIndex::DAYS_STRING_INDEX, factory->NewFromASCIINonMovable("days")); - SetConstant(ConstantIndex::HOURS_STRING_INDEX, factory->NewFromASCIINonMovable("hours")); - SetConstant(ConstantIndex::MINUTES_STRING_INDEX, factory->NewFromASCIINonMovable("minutes")); - SetConstant(ConstantIndex::SECONDS_STRING_INDEX, factory->NewFromASCIINonMovable("seconds")); - SetConstant(ConstantIndex::TIME_ZONE_NAME_STRING_INDEX, factory->NewFromASCIINonMovable("timeZoneName")); - SetConstant(ConstantIndex::LOCALE_STRING_INDEX, factory->NewFromASCIINonMovable("locale")); - SetConstant(ConstantIndex::TIME_ZONE_STRING_INDEX, factory->NewFromASCIINonMovable("timeZone")); - SetConstant(ConstantIndex::LITERAL_STRING_INDEX, factory->NewFromASCIINonMovable("literal")); - SetConstant(ConstantIndex::YEAR_NAME_STRING_INDEX, factory->NewFromASCIINonMovable("yearName")); - SetConstant(ConstantIndex::DAY_PERIOD_STRING_INDEX, factory->NewFromASCIINonMovable("dayPeriod")); - SetConstant(ConstantIndex::FRACTIONAL_SECOND_DIGITS_STRING_INDEX, - factory->NewFromASCIINonMovable("fractionalSecondDigits")); - SetConstant(ConstantIndex::FRACTIONAL_SECOND_STRING_INDEX, factory->NewFromASCIINonMovable("fractionalSecond")); - SetConstant(ConstantIndex::RELATED_YEAR_STRING_INDEX, factory->NewFromASCIINonMovable("relatedYear")); - SetConstant(ConstantIndex::LOOK_UP_STRING_INDEX, factory->NewFromASCIINonMovable("lookup")); - SetConstant(ConstantIndex::BEST_FIT_STRING_INDEX, factory->NewFromASCIINonMovable("bestfit")); - SetConstant(ConstantIndex::DATE_STYLE_STRING_INDEX, factory->NewFromASCIINonMovable("dateStyle")); - SetConstant(ConstantIndex::TIME_STYLE_STRING_INDEX, factory->NewFromASCIINonMovable("timeStyle")); - SetConstant(ConstantIndex::UTC_STRING_INDEX, factory->NewFromASCIINonMovable("UTC")); - SetConstant(ConstantIndex::WEEK_STRING_INDEX, factory->NewFromASCIINonMovable("week")); - SetConstant(ConstantIndex::WEEKS_STRING_INDEX, factory->NewFromASCIINonMovable("weeks")); - SetConstant(ConstantIndex::SOURCE_STRING_INDEX, factory->NewFromASCIINonMovable("source")); - SetConstant(ConstantIndex::FORMAT_STRING_INDEX, factory->NewFromASCIINonMovable("format")); - SetConstant(ConstantIndex::EN_US_STRING_INDEX, factory->NewFromASCIINonMovable("en-US")); - SetConstant(ConstantIndex::UND_STRING_INDEX, factory->NewFromASCIINonMovable("und")); - SetConstant(ConstantIndex::LATN_STRING_INDEX, factory->NewFromASCIINonMovable("latn")); - SetConstant(ConstantIndex::STYLE_STRING_INDEX, factory->NewFromASCIINonMovable("style")); - SetConstant(ConstantIndex::UNIT_STRING_INDEX, factory->NewFromASCIINonMovable("unit")); - SetConstant(ConstantIndex::INTEGER_STRING_INDEX, factory->NewFromASCIINonMovable("integer")); - SetConstant(ConstantIndex::NAN_STRING_INDEX, factory->NewFromASCIINonMovable("nan")); - SetConstant(ConstantIndex::INFINITY_STRING_INDEX, factory->NewFromASCIINonMovable("infinity")); - SetConstant(ConstantIndex::FRACTION_STRING_INDEX, factory->NewFromASCIINonMovable("fraction")); - SetConstant(ConstantIndex::DECIMAL_STRING_INDEX, factory->NewFromASCIINonMovable("decimal")); - SetConstant(ConstantIndex::GROUP_STRING_INDEX, factory->NewFromASCIINonMovable("group")); - SetConstant(ConstantIndex::GROUPS_STRING_INDEX, factory->NewFromASCIINonMovable("groups")); - SetConstant(ConstantIndex::CURRENCY_STRING_INDEX, factory->NewFromASCIINonMovable("currency")); - SetConstant(ConstantIndex::CURRENCY_SIGN_STRING_INDEX, factory->NewFromASCIINonMovable("currencySign")); - SetConstant(ConstantIndex::CURRENCY_DISPLAY_STRING_INDEX, factory->NewFromASCIINonMovable("currencyDisplay")); - SetConstant(ConstantIndex::PERCENT_SIGN_STRING_INDEX, factory->NewFromASCIINonMovable("percentSign")); - SetConstant(ConstantIndex::PERCENT_STRING_INDEX, factory->NewFromASCIINonMovable("percent")); - SetConstant(ConstantIndex::MINUS_SIGN_STRING_INDEX, factory->NewFromASCIINonMovable("minusSign")); - SetConstant(ConstantIndex::PLUS_SIGN_STRING_INDEX, factory->NewFromASCIINonMovable("plusSign")); - SetConstant(ConstantIndex::EXPONENT_SEPARATOR_STRING_INDEX, - factory->NewFromASCIINonMovable("exponentSeparator")); - SetConstant(ConstantIndex::EXPONENT_MINUS_SIGN_INDEX, factory->NewFromASCIINonMovable("exponentMinusSign")); - SetConstant(ConstantIndex::EXPONENT_INTEGER_STRING_INDEX, factory->NewFromASCIINonMovable("exponentInteger")); - SetConstant(ConstantIndex::LONG_STRING_INDEX, factory->NewFromASCIINonMovable("long")); - SetConstant(ConstantIndex::SHORT_STRING_INDEX, factory->NewFromASCIINonMovable("short")); - SetConstant(ConstantIndex::FULL_STRING_INDEX, factory->NewFromASCIINonMovable("full")); - SetConstant(ConstantIndex::MEDIUM_STRING_INDEX, factory->NewFromASCIINonMovable("medium")); - SetConstant(ConstantIndex::NARROW_STRING_INDEX, factory->NewFromASCIINonMovable("narrow")); - SetConstant(ConstantIndex::ALWAYS_STRING_INDEX, factory->NewFromASCIINonMovable("always")); - SetConstant(ConstantIndex::AUTO_STRING_INDEX, factory->NewFromASCIINonMovable("auto")); - SetConstant(ConstantIndex::THROW_STRING_INDEX, factory->NewFromASCIINonMovable("throw")); - SetConstant(ConstantIndex::UNIT_DISPLAY_INDEX, factory->NewFromASCIINonMovable("unitDisplay")); - SetConstant(ConstantIndex::NOTATION_INDEX, factory->NewFromASCIINonMovable("notation")); - SetConstant(ConstantIndex::COMPACT_DISPALY_INDEX, factory->NewFromASCIINonMovable("compactDisplay")); - SetConstant(ConstantIndex::USER_GROUPING_INDEX, factory->NewFromASCIINonMovable("useGrouping")); - SetConstant(ConstantIndex::SIGN_DISPLAY_INDEX, factory->NewFromASCIINonMovable("signDisplay")); - SetConstant(ConstantIndex::CODE_INDEX, factory->NewFromASCIINonMovable("code")); - SetConstant(ConstantIndex::NARROW_SYMBOL_INDEX, factory->NewFromASCIINonMovable("narrowSymbol")); - SetConstant(ConstantIndex::STANDARD_INDEX, factory->NewFromASCIINonMovable("standard")); - SetConstant(ConstantIndex::ACCOUNTING_INDEX, factory->NewFromASCIINonMovable("accounting")); - SetConstant(ConstantIndex::SCIENTIFIC_INDEX, factory->NewFromASCIINonMovable("scientific")); - SetConstant(ConstantIndex::ENGINEERING_INDEX, factory->NewFromASCIINonMovable("engineering")); - SetConstant(ConstantIndex::COMPACT_STRING_INDEX, factory->NewFromASCIINonMovable("compact")); - SetConstant(ConstantIndex::NEVER_INDEX, factory->NewFromASCIINonMovable("never")); - SetConstant(ConstantIndex::EXPECT_ZERO_INDEX, factory->NewFromASCIINonMovable("exceptZero")); - SetConstant(ConstantIndex::MINIMUM_INTEGER_DIGITS_INDEX, - factory->NewFromASCIINonMovable("minimumIntegerDigits")); - SetConstant(ConstantIndex::MINIMUM_FRACTIONDIGITS_INDEX, - factory->NewFromASCIINonMovable("minimumFractionDigits")); - SetConstant(ConstantIndex::MAXIMUM_FRACTIONDIGITS_INDEX, - factory->NewFromASCIINonMovable("maximumFractionDigits")); - SetConstant(ConstantIndex::MINIMUM_SIGNIFICANTDIGITS_INDEX, - factory->NewFromASCIINonMovable("minimumSignificantDigits")); - SetConstant(ConstantIndex::MAXIMUM_SIGNIFICANTDIGITS_INDEX, - factory->NewFromASCIINonMovable("maximumSignificantDigits")); - SetConstant(ConstantIndex::INVALID_DATE_INDEX, factory->NewFromASCIINonMovable("Invalid Date")); - SetConstant(ConstantIndex::USAGE_INDEX, factory->NewFromASCIINonMovable("usage")); - SetConstant(ConstantIndex::COMPARE_INDEX, factory->NewFromASCIINonMovable("compare")); - SetConstant(ConstantIndex::SENSITIVITY_INDEX, factory->NewFromASCIINonMovable("sensitivity")); - SetConstant(ConstantIndex::IGNORE_PUNCTUATION_INDEX, factory->NewFromASCIINonMovable("ignorePunctuation")); - SetConstant(ConstantIndex::CARDINAL_INDEX, factory->NewFromASCIINonMovable("cardinal")); - SetConstant(ConstantIndex::ORDINAL_INDEX, factory->NewFromASCIINonMovable("ordinal")); - SetConstant(ConstantIndex::EXEC_INDEX, factory->NewFromASCIINonMovable("exec")); - SetConstant(ConstantIndex::LAST_INDEX_INDEX, factory->NewFromASCIINonMovable("lastIndex")); - SetConstant(ConstantIndex::PLURAL_CATEGORIES_INDEX, factory->NewFromASCIINonMovable("pluralCategories")); - SetConstant(ConstantIndex::SORT_INDEX, factory->NewFromASCIINonMovable("sort")); - SetConstant(ConstantIndex::SEARCH_INDEX, factory->NewFromASCIINonMovable("search")); - SetConstant(ConstantIndex::BASE_INDEX, factory->NewFromASCIINonMovable("base")); - SetConstant(ConstantIndex::ACCENT_INDEX, factory->NewFromASCIINonMovable("accent")); - SetConstant(ConstantIndex::CASE_INDEX, factory->NewFromASCIINonMovable("case")); - SetConstant(ConstantIndex::VARIANT_INDEX, factory->NewFromASCIINonMovable("variant")); - SetConstant(ConstantIndex::EN_US_POSIX_STRING_INDEX, factory->NewFromASCIINonMovable("en-US-POSIX")); - SetConstant(ConstantIndex::UPPER_INDEX, factory->NewFromASCIINonMovable("upper")); - SetConstant(ConstantIndex::LOWER_INDEX, factory->NewFromASCIINonMovable("lower")); - SetConstant(ConstantIndex::DEFAULT_INDEX, factory->NewFromASCIINonMovable("default")); - SetConstant(ConstantIndex::SHARED_INDEX, factory->NewFromASCIINonMovable("shared")); - SetConstant(ConstantIndex::START_RANGE_INDEX, factory->NewFromASCIINonMovable("startRange")); - SetConstant(ConstantIndex::END_RANGE_INDEX, factory->NewFromASCIINonMovable("endRange")); - SetConstant(ConstantIndex::ISO8601_INDEX, factory->NewFromASCIINonMovable("iso8601")); - SetConstant(ConstantIndex::GREGORY_INDEX, factory->NewFromASCIINonMovable("gregory")); - SetConstant(ConstantIndex::ETHIOAA_INDEX, factory->NewFromASCIINonMovable("ethioaa")); - SetConstant(ConstantIndex::STICKY_INDEX, factory->NewFromASCIINonMovable("sticky")); - SetConstant(ConstantIndex::HAS_INDICES_INDEX, factory->NewFromASCIINonMovable("hasIndices")); - SetConstant(ConstantIndex::INDICES_INDEX, factory->NewFromASCIINonMovable("indices")); - SetConstant(ConstantIndex::U_INDEX, factory->NewFromASCIINonMovable("u")); - SetConstant(ConstantIndex::INDEX_INDEX, factory->NewFromASCIINonMovable("index")); - SetConstant(ConstantIndex::INPUT_INDEX, factory->NewFromASCIINonMovable("input")); - SetConstant(ConstantIndex::UNICODE_INDEX, factory->NewFromASCIINonMovable("unicode")); - SetConstant(ConstantIndex::ZERO_INDEX, factory->NewFromASCIINonMovable("0")); - SetConstant(ConstantIndex::VALUES_INDEX, factory->NewFromASCIINonMovable("values")); - SetConstant(ConstantIndex::ADD_INDEX, factory->NewFromASCIINonMovable("add")); - SetConstant(ConstantIndex::AMBIGUOUS_INDEX, factory->NewFromASCIINonMovable("ambiguous")); - SetConstant(ConstantIndex::MODULE_INDEX, factory->NewFromASCIINonMovable("Module")); - SetConstant(ConstantIndex::STAR_INDEX, factory->NewFromASCIINonMovable("*")); - SetConstant(ConstantIndex::DATETIMEFIELD_INDEX, factory->NewFromASCIINonMovable("datetimefield")); - SetConstant(ConstantIndex::CONJUNCTION_INDEX, factory->NewFromASCIINonMovable("conjunction")); - SetConstant(ConstantIndex::NONE_INDEX, factory->NewFromASCIINonMovable("none")); - SetConstant(ConstantIndex::FALLBACK_INDEX, factory->NewFromASCIINonMovable("fallback")); - SetConstant(ConstantIndex::DISJUNCTION_INDEX, factory->NewFromASCIINonMovable("disjunction")); - SetConstant(ConstantIndex::ELEMENT_INDEX, factory->NewFromASCIINonMovable("element")); - SetConstant(ConstantIndex::FLAGS_INDEX, factory->NewFromASCIINonMovable("flags")); - SetConstant(ConstantIndex::G_INDEX, factory->NewFromASCIINonMovable("g")); - SetConstant(ConstantIndex::NFC_INDEX, factory->NewFromASCIINonMovable("NFC")); - SetConstant(ConstantIndex::ENTRIES_INDEX, factory->NewFromASCIINonMovable("entries")); - SetConstant(ConstantIndex::LEFT_SQUARE_BRACKET_INDEX, factory->NewFromASCIINonMovable("[")); - SetConstant(ConstantIndex::RIGHT_SQUARE_BRACKET_INDEX, factory->NewFromASCIINonMovable("]")); - SetConstant(ConstantIndex::Y_INDEX, factory->NewFromASCIINonMovable("y")); - SetConstant(ConstantIndex::DOLLAR_INDEX, factory->NewFromASCIINonMovable("$")); - SetConstant(ConstantIndex::COMMA_INDEX, factory->NewFromASCIINonMovable(",")); - SetConstant(ConstantIndex::JOIN_INDEX, factory->NewFromASCIINonMovable("join")); - SetConstant(ConstantIndex::COPY_WITHIN_INDEX, factory->NewFromASCIINonMovable("copyWithin")); - SetConstant(ConstantIndex::FILL_INDEX, factory->NewFromASCIINonMovable("fill")); - SetConstant(ConstantIndex::FIND_INDEX, factory->NewFromASCIINonMovable("find")); - SetConstant(ConstantIndex::FIND_INDEX_INDEX, factory->NewFromASCIINonMovable("findIndex")); - SetConstant(ConstantIndex::FLAT_INDEX, factory->NewFromASCIINonMovable("flat")); - SetConstant(ConstantIndex::FLATMAP_INDEX, factory->NewFromASCIINonMovable("flatMap")); - SetConstant(ConstantIndex::INCLUDES_INDEX, factory->NewFromASCIINonMovable("includes")); - SetConstant(ConstantIndex::KEYS_INDEX, factory->NewFromASCIINonMovable("keys")); - SetConstant(ConstantIndex::BOUND_INDEX, factory->NewFromASCIINonMovable("bound")); - SetConstant(ConstantIndex::BACKSLASH_INDEX, factory->NewFromASCIINonMovable("/")); - SetConstant(ConstantIndex::SPACE_INDEX, factory->NewFromASCIINonMovable(" ")); - SetConstant(ConstantIndex::NAN_INDEX, factory->NewFromASCIINonMovable("NaN")); - SetConstant(ConstantIndex::NOT_EQUAL_INDEX, factory->NewFromASCIINonMovable("not-equal")); - SetConstant(ConstantIndex::OK_INDEX, factory->NewFromASCIINonMovable("ok")); - SetConstant(ConstantIndex::TIMEOUT_INDEX, factory->NewFromASCIINonMovable("timed-out")); - SetConstant(ConstantIndex::CJS_EXPORTS_INDEX, factory->NewFromASCIINonMovable("exports")); - SetConstant(ConstantIndex::CJS_CACHE_INDEX, factory->NewFromASCIINonMovable("_cache")); - SetConstant(ConstantIndex::NAPI_WRAPPER_INDEX, factory->NewFromASCIINonMovable("_napiwrapper")); - // for require native module - SetConstant(ConstantIndex::REQUIRE_NATIVE_MOUDULE_FUNC_INDEX, - factory->NewFromASCIINonMovable("requireNativeModule")); - SetConstant(ConstantIndex::REQUIRE_NAPI_FUNC_INDEX, factory->NewFromASCIINonMovable("requireNapi")); - SetConstant(ConstantIndex::DOLLAR_STRING_ONE_INDEX, factory->NewFromASCIINonMovable("$1")); - SetConstant(ConstantIndex::DOLLAR_STRING_TWO_INDEX, factory->NewFromASCIINonMovable("$2")); - SetConstant(ConstantIndex::DOLLAR_STRING_THREE_INDEX, factory->NewFromASCIINonMovable("$3")); - SetConstant(ConstantIndex::DOLLAR_STRING_FOUR_INDEX, factory->NewFromASCIINonMovable("$4")); - SetConstant(ConstantIndex::DOLLAR_STRING_FIVE_INDEX, factory->NewFromASCIINonMovable("$5")); - SetConstant(ConstantIndex::DOLLAR_STRING_SIX_INDEX, factory->NewFromASCIINonMovable("$6")); - SetConstant(ConstantIndex::DOLLAR_STRING_SEVEN_INDEX, factory->NewFromASCIINonMovable("$7")); - SetConstant(ConstantIndex::DOLLAR_STRING_EIGHT_INDEX, factory->NewFromASCIINonMovable("$8")); - SetConstant(ConstantIndex::DOLLAR_STRING_NINE_INDEX, factory->NewFromASCIINonMovable("$9")); - // for object to string - SetConstant(ConstantIndex::UNDEFINED_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Undefined]")); - SetConstant(ConstantIndex::NULL_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Null]")); - SetConstant(ConstantIndex::OBJECT_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Object]")); - SetConstant(ConstantIndex::ARRAY_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Array]")); - SetConstant(ConstantIndex::STRING_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object String]")); - SetConstant(ConstantIndex::BOOLEAN_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Boolean]")); - SetConstant(ConstantIndex::NUMBER_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Number]")); - SetConstant(ConstantIndex::ARGUMENTS_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Arguments]")); - SetConstant(ConstantIndex::FUNCTION_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Function]")); - SetConstant(ConstantIndex::DATE_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Date]")); - SetConstant(ConstantIndex::ERROR_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object Error]")); - SetConstant(ConstantIndex::REGEXP_TO_STRING_INDEX, factory->NewFromASCIINonMovable("[object RegExp]")); + +#define INIT_GLOBAL_ENV_CONSTANT_STRING(Name, Index, Token) \ + SetConstant(ConstantIndex::Index, factory->NewFromASCIINonMovable(Token)); + + GLOBAL_ENV_CONSTANT_STRING(INIT_GLOBAL_ENV_CONSTANT_STRING) +#undef INIT_GLOBAL_ENV_CONSTANT_STRING auto accessor = factory->NewInternalAccessor(reinterpret_cast(JSFunction::PrototypeSetter), reinterpret_cast(JSFunction::PrototypeGetter)); diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index ed115b7e38..821b7b41cf 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -163,322 +163,327 @@ class ObjectFactory; V(JSTaggedValue, ArraySortFunction, ARRAY_SORT_FUNCTION_INDEX, ecma_roots_special) \ V(JSTaggedValue, JsonStringifyFunction, JSON_STRINGIFY_FUNCTION_INDEX, ecma_roots_special) +// All of type JSTaggedValue +#define GLOBAL_ENV_CONSTANT_STRING(V) \ + V(ConstructorString, CONSTRUCTOR_STRING_INDEX, "constructor") \ + V(PrototypeString, PROTOTYPE_STRING_INDEX, "prototype") \ + V(LengthString, LENGTH_STRING_INDEX, "length") \ + V(ValueString, VALUE_STRING_INDEX, "value") \ + V(SetString, SET_STRING_INDEX, "set") \ + V(GetString, GET_STRING_INDEX, "get") \ + V(WritableString, WRITABLE_STRING_INDEX, "writable") \ + V(EnumerableString, ENUMERABLE_STRING_INDEX, "enumerable") \ + V(ConfigurableString, CONFIGURABLE_STRING_INDEX, "configurable") \ + V(NameString, NAME_STRING_INDEX, "name") \ + /* SymbolTable * RegisterSymbols */ \ + V(GetPrototypeOfString, GETPROTOTYPEOF_STRING_INDEX, "getPrototypeOf") \ + V(SetPrototypeOfString, SETPROTOTYPEOF_STRING_INDEX, "setPrototypeOf") \ + V(IsExtensibleString, ISEXTENSIBLE_STRING_INDEX, "isExtensible") \ + V(PreventExtensionsString, PREVENTEXTENSIONS_STRING_INDEX, "preventExtensions") \ + V(GetOwnPropertyDescriptorString, GETOWNPROPERTYDESCRIPTOR_STRING_INDEX, "getOwnPropertyDescriptor") \ + V(DefinePropertyString, DEFINEPROPERTY_STRING_INDEX, "defineProperty") \ + V(HasString, HAS_STRING_INDEX, "has") \ + V(DeletePropertyString, DELETEPROPERTY_STRING_INDEX, "deleteProperty") \ + V(EnumerateString, ENUMERATE_STRING_INDEX, "enumerate") \ + V(OwnKeysString, OWNKEYS_STRING_INDEX, "ownKeys") \ + V(ApplyString, APPLY_STRING_INDEX, "apply") \ + V(NegativeZeroString, NEGATIVE_ZERO_STRING_INDEX, "-0") \ + V(DoneString, DONE_STRING_INDEX, "done") \ + V(ProxyString, PROXY_STRING_INDEX, "proxy") \ + V(RevokeString, REVOKE_STRING_INDEX, "revoke") \ + V(NextString, NEXT_STRING_INDEX, "next") \ + V(ToStringString, TO_STRING_STRING_INDEX, "toString") \ + V(ToLocaleStringString, TO_LOCALE_STRING_STRING_INDEX, "toLocaleString") \ + V(ValueOfString, VALUE_OF_STRING_INDEX, "valueOf") \ + V(UndefinedString, UNDEFINED_STRING_INDEX, "undefined") \ + V(NullString, NULL_STRING_INDEX, "null") \ + V(BooleanString, BOOLEAN_STRING_INDEX, "boolean") \ + V(NumberString, NUMBER_STRING_INDEX, "number") \ + V(BigIntString, BIGINT_STRING_INDEX, "bigint") \ + V(FunctionString, FUNCTION_STRING_INDEX, "function") \ + V(StringString, STRING_STRING_INDEX, "string") \ + V(SymbolString, SYMBOL_STRING_INDEX, "symbol") \ + V(ObjectString, OBJECT_STRING_INDEX, "object") \ + V(TrueString, TRUE_STRING_INDEX, "true") \ + V(FalseString, FALSE_STRING_INDEX, "false") \ + V(ReturnString, RETURN_STRING_INDEX, "return") \ + V(ProxyConstructString, PROXY_CONSTRUCT_STRING_INDEX, "construct") \ + V(ProxyCallString, PROXY_CALL_STRING_INDEX, "call") \ + V(PromiseThenString, PROMISE_THEN_STRING_INDEX, "then") \ + V(PromiseCatchString, PROMISE_CATCH_STRING_INDEX, "catch") \ + V(PromiseFinallyString, PROMISE_FINALLY_STRING_INDEX, "finally") \ + V(PromiseStatusString, PROMISE_STATUS_STRING_INDEX, "status") \ + V(PromiseFulfilledString, PROMISE_FULFILLED_STRING_INDEX, "fulfilled") \ + V(PromiseRejectedString, PROMISE_REJECTED_STRING_INDEX, "rejected") \ + V(PromiseReasonString, PROMISE_REASON_STRING_INDEX, "reason") \ + V(ScriptJobString, SCRIPT_JOB_STRING_INDEX, "ScriptJobs") \ + V(PromiseString, PROMISE_STRING_INDEX, "PrimiseJobs") \ + V(ThrowerString, THROWER_STRING_INDEX, "Thrower") \ + V(IdentityString, IDENTITY_STRING_INDEX, "Identity") \ + V(CallerString, CALLER_STRING_INDEX, "caller") \ + V(CalleeString, CALLEE_STRING_INDEX, "callee") \ + V(Int8ArrayString, INT8_ARRAY_STRING_INDEX, "Int8Array") \ + V(Uint8ArrayString, UINT8_ARRAY_STRING_INDEX, "Uint8Array") \ + V(Uint8ClampedArrayString, UINT8_CLAMPED_ARRAY_STRING_INDEX, "Uint8ClampedArray") \ + V(Int16ArrayString, INT16_ARRAY_STRING_INDEX, "Int16Array") \ + V(Uint16ArrayString, UINT16_ARRAY_STRING_INDEX, "Uint16Array") \ + V(Int32ArrayString, INT32_ARRAY_STRING_INDEX, "Int32Array") \ + V(Uint32ArrayString, UINT32_ARRAY_STRING_INDEX, "Uint32Array") \ + V(Float32ArrayString, FLOAT32_ARRAY_STRING_INDEX, "Float32Array") \ + V(Float64ArrayString, FLOAT64_ARRAY_STRING_INDEX, "Float64Array") \ + V(BigInt64ArrayString, BIGINT64_ARRAY_STRING_INDEX, "BigInt64Array") \ + V(BigUint64ArrayString, BIGUINT64_ARRAY_STRING_INDEX, "BigUint64Array") \ + V(AsyncFunctionString, ASYNC_FUNCTION_STRING_INDEX, "AsyncFunction") \ + V(PromiseResolveString, PROMISE_RESOLVE_STRING_INDEX, "resolve") \ + V(IdString, ID_STRING_INDEX, "id") \ + V(MethodString, METHOD_STRING_INDEX, "method") \ + V(ParamsString, PARAMS_STRING_INDEX, "params") \ + V(ResultString, RESULT_STRING_INDEX, "result") \ + V(ToJsonString, TO_JSON_STRING_INDEX, "toJSON") \ + V(GlobalString, GLOBAL_STRING_INDEX, "global") \ + V(MessageString, MESSAGE_STRING_INDEX, "message") \ + V(CauseString, CAUSE_STRING_INDEX, "cause") \ + V(ErrorString, ERROR_STRING_INDEX, "Error") \ + V(ErrorsString, ERRORS_STRING_INDEX, "errors") \ + V(AggregateErrorString, AGGREGATE_ERROR_STRING_INDEX, "AggregateError") \ + V(RangeErrorString, RANGE_ERROR_STRING_INDEX, "RangeError") \ + V(ReferenceErrorString, REFERENCE_ERROR_STRING_INDEX, "ReferenceError") \ + V(TypeErrorString, TYPE_ERROR_STRING_INDEX, "TypeError") \ + V(URIErrorString, URI_ERROR_STRING_INDEX, "URIError") \ + V(SyntaxErrorString, SYNTAX_ERROR_STRING_INDEX, "SyntaxError") \ + V(EvalErrorString, EVAL_ERROR_STRING_INDEX, "EvalError") \ + V(OOMErrorString, OOM_ERROR_STRING_INDEX, "OutOfMemoryError") \ + V(ErrorFuncString, ERROR_FUNC_STRING_INDEX, "errorfunc") \ + V(StackString, STACK_STRING_INDEX, "stack") \ + V(StackEmptyString, STACK_EMPTY_STRING_INDEX, "stackisempty") \ + V(ObjNotCoercibleString, OBJ_NOT_COERCIBLE_STRING_INDEX, "objectnotcoercible") \ + /* for Intl. */ \ + V(LanguageString, LANGUAGE_STRING_CLASS_INDEX, "language") \ + V(ScriptString, SCRIPT_STRING_CLASS_INDEX, "script") \ + V(RegionString, REGION_STRING_CLASS_INDEX, "region") \ + V(BaseNameString, BASE_NAME_STRING_CLASS_INDEX, "baseName") \ + V(CalendarString, CALENDAR_STRING_CLASS_INDEX, "calendar") \ + V(CollationString, COLLATION_STRING_CLASS_INDEX, "collation") \ + V(HourCycleString, HOUR_CYCLE_STRING_CLASS_INDEX, "hourCycle") \ + V(CaseFirstString, CASE_FIRST_STRING_CLASS_INDEX, "caseFirst") \ + V(NumericString, NUMERIC_STRING_CLASS_INDEX, "numeric") \ + V(NumberingSystemString, NUMBERING_SYSTEM_STRING_CLASS_INDEX, "numberingSystem") \ + V(TypeString, TYPE_STRING_INDEX, "type") \ + V(LocaleMatcherString, LOCALE_MATCHER_STRING_INDEX, "localeMatcher") \ + V(FormatMatcherString, FORMAT_MATCHER_STRING_INDEX, "formatMatcher") \ + V(Hour12String, HOUR12_STRING_INDEX, "hour12") \ + V(H11String, H11_STRING_INDEX, "h11") \ + V(H12String, H12_STRING_INDEX, "h12") \ + V(H23String, H23_STRING_INDEX, "h23") \ + V(H24String, H24_STRING_INDEX, "h24") \ + V(WeekdayString, WEEK_DAY_STRING_INDEX, "weekday") \ + V(EraString, ERA_STRING_INDEX, "era") \ + V(YearString, YEAR_STRING_INDEX, "year") \ + V(QuarterString, QUARTER_STRING_INDEX, "quarter") \ + V(MonthString, MONTH_STRING_INDEX, "month") \ + V(DayString, DAY_STRING_INDEX, "day") \ + V(HourString, HOUR_STRING_INDEX, "hour") \ + V(MinuteString, MINUTE_STRING_INDEX, "minute") \ + V(SecondString, SECOND_STRING_INDEX, "second") \ + V(YearsString, YEARS_STRING_INDEX, "years") \ + V(QuartersString, QUARTERS_STRING_INDEX, "quarters") \ + V(MonthsString, MONTHS_STRING_INDEX, "months") \ + V(DaysString, DAYS_STRING_INDEX, "days") \ + V(HoursString, HOURS_STRING_INDEX, "hours") \ + V(MinutesString, MINUTES_STRING_INDEX, "minutes") \ + V(SecondsString, SECONDS_STRING_INDEX, "seconds") \ + V(TimeZoneNameString, TIME_ZONE_NAME_STRING_INDEX, "timeZoneName") \ + V(LocaleString, LOCALE_STRING_INDEX, "locale") \ + V(TimeZoneString, TIME_ZONE_STRING_INDEX, "timeZone") \ + V(LiteralString, LITERAL_STRING_INDEX, "literal") \ + V(YearNameString, YEAR_NAME_STRING_INDEX, "yearName") \ + V(DayPeriodString, DAY_PERIOD_STRING_INDEX, "dayPeriod") \ + V(FractionalSecondDigitsString, FRACTIONAL_SECOND_DIGITS_STRING_INDEX, "fractionalSecondDigits") \ + V(FractionalSecondString, FRACTIONAL_SECOND_STRING_INDEX, "fractionalSecond") \ + V(RelatedYearString, RELATED_YEAR_STRING_INDEX, "relatedYear") \ + V(LookUpString, LOOK_UP_STRING_INDEX, "lookup") \ + V(BestFitString, BEST_FIT_STRING_INDEX, "bestfit") \ + V(DateStyleString, DATE_STYLE_STRING_INDEX, "dateStyle") \ + V(TimeStyleString, TIME_STYLE_STRING_INDEX, "timeStyle") \ + V(UTCString, UTC_STRING_INDEX, "UTC") \ + V(WeekString, WEEK_STRING_INDEX, "week") \ + V(WeeksString, WEEKS_STRING_INDEX, "weeks") \ + V(SourceString, SOURCE_STRING_INDEX, "source") \ + V(FormatString, FORMAT_STRING_INDEX, "format") \ + V(EnUsString, EN_US_STRING_INDEX, "en-US") \ + V(UndString, UND_STRING_INDEX, "und") \ + V(LatnString, LATN_STRING_INDEX, "latn") \ + V(StyleString, STYLE_STRING_INDEX, "style") \ + V(UnitString, UNIT_STRING_INDEX, "unit") \ + V(IntegerString, INTEGER_STRING_INDEX, "integer") \ + V(NanString, NAN_STRING_INDEX, "nan") \ + V(InfinityString, INFINITY_STRING_INDEX, "infinity") \ + V(FractionString, FRACTION_STRING_INDEX, "fraction") \ + V(DecimalString, DECIMAL_STRING_INDEX, "decimal") \ + V(GroupString, GROUP_STRING_INDEX, "group") \ + V(GroupsString, GROUPS_STRING_INDEX, "groups") \ + V(CurrencyString, CURRENCY_STRING_INDEX, "currency") \ + V(CurrencySignString, CURRENCY_SIGN_STRING_INDEX, "currencySign") \ + V(CurrencyDisplayString, CURRENCY_DISPLAY_STRING_INDEX, "currencyDisplay") \ + V(PercentSignString, PERCENT_SIGN_STRING_INDEX, "percentSign") \ + V(PercentString, PERCENT_STRING_INDEX, "percent") \ + V(MinusSignString, MINUS_SIGN_STRING_INDEX, "minusSign") \ + V(PlusSignString, PLUS_SIGN_STRING_INDEX, "plusSign") \ + V(ExponentSeparatorString, EXPONENT_SEPARATOR_STRING_INDEX, "exponentSeparator") \ + V(ExponentMinusSignString, EXPONENT_MINUS_SIGN_INDEX, "exponentMinusSign") \ + V(ExponentIntegerString, EXPONENT_INTEGER_STRING_INDEX, "exponentInteger") \ + V(LongString, LONG_STRING_INDEX, "long") \ + V(ShortString, SHORT_STRING_INDEX, "short") \ + V(FullString, FULL_STRING_INDEX, "full") \ + V(MediumString, MEDIUM_STRING_INDEX, "medium") \ + V(NarrowString, NARROW_STRING_INDEX, "narrow") \ + V(AlwaysString, ALWAYS_STRING_INDEX, "always") \ + V(AutoString, AUTO_STRING_INDEX, "auto") \ + V(ThrowString, THROW_STRING_INDEX, "throw") \ + V(UnitDisplayString, UNIT_DISPLAY_INDEX, "unitDisplay") \ + V(NotationString, NOTATION_INDEX, "notation") \ + V(CompactDisplayString, COMPACT_DISPALY_INDEX, "compactDisplay") \ + V(UserGroupingString, USER_GROUPING_INDEX, "useGrouping") \ + V(SignDisplayString, SIGN_DISPLAY_INDEX, "signDisplay") \ + V(CodeString, CODE_INDEX, "code") \ + V(NarrowSymbolString, NARROW_SYMBOL_INDEX, "narrowSymbol") \ + V(StandardString, STANDARD_INDEX, "standard") \ + V(AccountingString, ACCOUNTING_INDEX, "accounting") \ + V(ScientificString, SCIENTIFIC_INDEX, "scientific") \ + V(EngineeringString, ENGINEERING_INDEX, "engineering") \ + V(CompactString, COMPACT_STRING_INDEX, "compact") \ + V(NeverString, NEVER_INDEX, "never") \ + V(ExceptZeroString, EXPECT_ZERO_INDEX, "exceptZero") \ + V(MinimumIntegerDigitsString, MINIMUM_INTEGER_DIGITS_INDEX, "minimumIntegerDigits") \ + V(MinimumFractionDigitsString, MINIMUM_FRACTIONDIGITS_INDEX, "minimumFractionDigits") \ + V(MaximumFractionDigitsString, MAXIMUM_FRACTIONDIGITS_INDEX, "maximumFractionDigits") \ + V(MinimumSignificantDigitsString, MINIMUM_SIGNIFICANTDIGITS_INDEX, "minimumSignificantDigits") \ + V(MaximumSignificantDigitsString, MAXIMUM_SIGNIFICANTDIGITS_INDEX, "maximumSignificantDigits") \ + V(InvalidDateString, INVALID_DATE_INDEX, "Invalid Date") \ + V(UsageString, USAGE_INDEX, "usage") \ + V(CompareString, COMPARE_INDEX, "compare") \ + V(SensitivityString, SENSITIVITY_INDEX, "sensitivity") \ + V(IgnorePunctuationString, IGNORE_PUNCTUATION_INDEX, "ignorePunctuation") \ + V(CardinalString, CARDINAL_INDEX, "cardinal") \ + V(OrdinalString, ORDINAL_INDEX, "ordinal") \ + V(ExecString, EXEC_INDEX, "exec") \ + V(LastIndexString, LAST_INDEX_INDEX, "lastIndex") \ + V(PluralCategoriesString, PLURAL_CATEGORIES_INDEX, "pluralCategories") \ + V(SortString, SORT_INDEX, "sort") \ + V(SearchString, SEARCH_INDEX, "search") \ + V(BaseString, BASE_INDEX, "base") \ + V(AccentString, ACCENT_INDEX, "accent") \ + V(CaseString, CASE_INDEX, "case") \ + V(VariantString, VARIANT_INDEX, "variant") \ + V(EnUsPosixString, EN_US_POSIX_STRING_INDEX, "en-US-POSIX") \ + V(UpperString, UPPER_INDEX, "upper") \ + V(LowerString, LOWER_INDEX, "lower") \ + V(DefaultString, DEFAULT_INDEX, "default") \ + V(SharedString, SHARED_INDEX, "shared") \ + V(StartRangeString, START_RANGE_INDEX, "startRange") \ + V(EndRangeString, END_RANGE_INDEX, "endRange") \ + V(Iso8601String, ISO8601_INDEX, "iso8601") \ + V(GregoryString, GREGORY_INDEX, "gregory") \ + V(EthioaaString, ETHIOAA_INDEX, "ethioaa") \ + V(StickyString, STICKY_INDEX, "sticky") \ + V(HasIndicesString, HAS_INDICES_INDEX, "hasIndices") \ + V(IndicesString, INDICES_INDEX, "indices") \ + V(UString, U_INDEX, "u") \ + V(IndexString, INDEX_INDEX, "index") \ + V(InputString, INPUT_INDEX, "input") \ + V(UnicodeString, UNICODE_INDEX, "unicode") \ + V(ZeroString, ZERO_INDEX, "0") \ + V(ValuesString, VALUES_INDEX, "values") \ + V(AddString, ADD_INDEX, "add") \ + V(AmbiguousString, AMBIGUOUS_INDEX, "ambiguous") \ + V(ModuleString, MODULE_INDEX, "Module") \ + V(StarString, STAR_INDEX, "*") \ + V(DateTimeFieldString, DATETIMEFIELD_INDEX, "datetimefield") \ + V(ConjunctionString, CONJUNCTION_INDEX, "conjunction") \ + V(NoneString, NONE_INDEX, "none") \ + V(FallbackString, FALLBACK_INDEX, "fallback") \ + V(DisjunctionString, DISJUNCTION_INDEX, "disjunction") \ + V(ElementString, ELEMENT_INDEX, "element") \ + V(FlagsString, FLAGS_INDEX, "flags") \ + V(GString, G_INDEX, "g") \ + V(NfcString, NFC_INDEX, "NFC") \ + V(EntriesString, ENTRIES_INDEX, "entries") \ + V(LeftSquareBracketString, LEFT_SQUARE_BRACKET_INDEX, "[") \ + V(RightSquareBracketString, RIGHT_SQUARE_BRACKET_INDEX, "]") \ + V(YString, Y_INDEX, "y") \ + V(DollarString, DOLLAR_INDEX, "$") \ + V(CommaString, COMMA_INDEX, ",") \ + V(JoinString, JOIN_INDEX, "join") \ + V(CopyWithinString, COPY_WITHIN_INDEX, "copyWithin") \ + V(FillString, FILL_INDEX, "fill") \ + V(FindString, FIND_INDEX, "find") \ + V(FindIndexString, FIND_INDEX_INDEX, "findIndex") \ + V(FlatString, FLAT_INDEX, "flat") \ + V(FlatMapString, FLATMAP_INDEX, "flatMap") \ + V(IncludesString, INCLUDES_INDEX, "includes") \ + V(KeysString, KEYS_INDEX, "keys") \ + V(BoundString, BOUND_INDEX, "bound") \ + V(BackslashString, BACKSLASH_INDEX, "/") \ + V(SpaceString, SPACE_INDEX, " ") \ + V(NanCapitalString, NAN_INDEX, "NaN") \ + V(NotEqualString, NOT_EQUAL_INDEX, "not-equal") \ + V(OkString, OK_INDEX, "ok") \ + V(TimeoutString, TIMEOUT_INDEX, "timed-out") \ + V(CjsExportsString, CJS_EXPORTS_INDEX, "exports") \ + V(CjsCacheString, CJS_CACHE_INDEX, "_cache") \ + V(NapiWrapperString, NAPI_WRAPPER_INDEX, "_napiwrapper") \ + /* for require native module */ \ + V(RequireNativeModuleString, REQUIRE_NATIVE_MOUDULE_FUNC_INDEX, "requireNativeModule") \ + V(RequireNapiString, REQUIRE_NAPI_FUNC_INDEX, "requireNapi") \ + V(DollarStringOne, DOLLAR_STRING_ONE_INDEX, "$1") \ + V(DollarStringTwo, DOLLAR_STRING_TWO_INDEX, "$2") \ + V(DollarStringThree, DOLLAR_STRING_THREE_INDEX, "$3") \ + V(DollarStringFour, DOLLAR_STRING_FOUR_INDEX, "$4") \ + V(DollarStringFive, DOLLAR_STRING_FIVE_INDEX, "$5") \ + V(DollarStringSix, DOLLAR_STRING_SIX_INDEX, "$6") \ + V(DollarStringSeven, DOLLAR_STRING_SEVEN_INDEX, "$7") \ + V(DollarStringEight, DOLLAR_STRING_EIGHT_INDEX, "$8") \ + V(DollarStringNine, DOLLAR_STRING_NINE_INDEX, "$9") \ + /* for object to string */ \ + V(UndefinedToString, UNDEFINED_TO_STRING_INDEX, "[object Undefined]") \ + V(NullToString, NULL_TO_STRING_INDEX, "[object Null]") \ + V(ObjectToString, OBJECT_TO_STRING_INDEX, "[object Object]") \ + V(ArrayToString, ARRAY_TO_STRING_INDEX, "[object Array]") \ + V(StringToString, STRING_TO_STRING_INDEX, "[object String]") \ + V(BooleanToString, BOOLEAN_TO_STRING_INDEX, "[object Boolean]") \ + V(NumberToString, NUMBER_TO_STRING_INDEX, "[object Number]") \ + V(ArgumentsToString, ARGUMENTS_TO_STRING_INDEX, "[object Arguments]") \ + V(FunctionToString, FUNCTION_TO_STRING_INDEX, "[object Function]") \ + V(DateToString, DATE_TO_STRING_INDEX, "[object Date]") \ + V(ErrorToString, ERROR_TO_STRING_INDEX, "[object Error]") \ + V(RegExpToString, REGEXP_TO_STRING_INDEX, "[object RegExp]") + /* GlobalConstant */ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GLOBAL_ENV_CONSTANT_CONSTANT(V) \ - V(JSTaggedValue, ConstructorString, CONSTRUCTOR_STRING_INDEX, constructor) \ - V(JSTaggedValue, PrototypeString, PROTOTYPE_STRING_INDEX, prototype) \ - V(JSTaggedValue, LengthString, LENGTH_STRING_INDEX, length) \ - V(JSTaggedValue, ValueString, VALUE_STRING_INDEX, value) \ - V(JSTaggedValue, GetString, GET_STRING_INDEX, get) \ - V(JSTaggedValue, SetString, SET_STRING_INDEX, set) \ - V(JSTaggedValue, WritableString, WRITABLE_STRING_INDEX, writable) \ - V(JSTaggedValue, EnumerableString, ENUMERABLE_STRING_INDEX, enumerable) \ - V(JSTaggedValue, ConfigurableString, CONFIGURABLE_STRING_INDEX, configurable) \ - /* non ECMA standard jsapi containers iterators */ \ - V(JSTaggedValue, ArrayListFunction, ARRAYLIST_FUNCTION_INDEX, ArrayListFunction) \ - V(JSTaggedValue, ArrayListIteratorPrototype, ARRAYLIST_ITERATOR_PROTOTYPE_INDEX, ArrayListIterator) \ - V(JSTaggedValue, HashMapIteratorPrototype, HASHMAP_ITERATOR_PROTOTYPE_INDEX, HashMapIterator) \ - V(JSTaggedValue, HashSetIteratorPrototype, HASHSET_ITERATOR_PROTOTYPE_INDEX, HashSetIterator) \ - V(JSTaggedValue, LightWeightMapIteratorPrototype, LIGHTWEIGHTMAP_ITERATOR_PROTOTYPE_INDEX, LightWeightMapIterator) \ - V(JSTaggedValue, LightWeightSetIteratorPrototype, LIGHTWEIGHTSET_ITERATOR_PROTOTYPE_INDEX, LightWeightSetIterator) \ - V(JSTaggedValue, TreeMapIteratorPrototype, TREEMAP_ITERATOR_PROTOTYPE_INDEX, TreeMapIterator) \ - V(JSTaggedValue, TreeSetIteratorPrototype, TREESET_ITERATOR_PROTOTYPE_INDEX, TreeSetIterator) \ - V(JSTaggedValue, VectorFunction, VECTOR_FUNCTION_INDEX, VectorFunction) \ - V(JSTaggedValue, VectorIteratorPrototype, VECTOR_ITERATOR_PROTOTYPE_INDEX, VectorIterator) \ - V(JSTaggedValue, QueueIteratorPrototype, QUEUE_ITERATOR_PROTOTYPE_INDEX, QueueIterator) \ - V(JSTaggedValue, PlainArrayIteratorPrototype, PLAIN_ARRAY_ITERATOR_PROTOTYPE_INDEX, PlainArrayIterator) \ - V(JSTaggedValue, PlainArrayFunction, PLAIN_ARRAY_FUNCTION_INDEX, PlainArrayFunction) \ - V(JSTaggedValue, DequeIteratorPrototype, DEQUE_ITERATOR_PROTOTYPE_INDEX, DequeIterator) \ - V(JSTaggedValue, StackIteratorPrototype, STACK_ITERATOR_PROTOTYPE_INDEX, StackIterator) \ - V(JSTaggedValue, ListFunction, LIST_FUNCTION_INDEX, ListFunction) \ - V(JSTaggedValue, LinkedListFunction, LINKED_LIST_FUNCTION_INDEX, LinkedListFunction) \ - V(JSTaggedValue, ListIteratorPrototype, LIST_ITERATOR_PROTOTYPE_INDEX, ListIterator) \ - V(JSTaggedValue, UndefinedIterResult, UNDEFINED_INTERATOR_RESULT_INDEX, UndefinedIterResult) \ - V(JSTaggedValue, LinkedListIteratorPrototype, LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, LinkedListIterator) \ - /* SymbolTable*RegisterSymbols */ \ - V(JSTaggedValue, NameString, NAME_STRING_INDEX, name) \ - V(JSTaggedValue, GetPrototypeOfString, GETPROTOTYPEOF_STRING_INDEX, getPrototypeOf) \ - V(JSTaggedValue, SetPrototypeOfString, SETPROTOTYPEOF_STRING_INDEX, setPrototypeOf) \ - V(JSTaggedValue, IsExtensibleString, ISEXTENSIBLE_STRING_INDEX, isExtensible) \ - V(JSTaggedValue, PreventExtensionsString, PREVENTEXTENSIONS_STRING_INDEX, preventExtensions) \ - V(JSTaggedValue, GetOwnPropertyDescriptorString, GETOWNPROPERTYDESCRIPTOR_STRING_INDEX, getOwnPropertyDescriptor) \ - V(JSTaggedValue, DefinePropertyString, DEFINEPROPERTY_STRING_INDEX, defineProperty) \ - V(JSTaggedValue, HasString, HAS_STRING_INDEX, has) \ - V(JSTaggedValue, DeletePropertyString, DELETEPROPERTY_STRING_INDEX, deleteProperty) \ - V(JSTaggedValue, EnumerateString, ENUMERATE_STRING_INDEX, enumerate) \ - V(JSTaggedValue, OwnKeysString, OWNKEYS_STRING_INDEX, ownKeys) \ - V(JSTaggedValue, ApplyString, APPLY_STRING_INDEX, apply) \ - V(JSTaggedValue, NegativeZeroString, NEGATIVE_ZERO_STRING_INDEX, -0) \ - V(JSTaggedValue, DoneString, DONE_STRING_INDEX, done) \ - V(JSTaggedValue, ProxyString, PROXY_STRING_INDEX, proxy) \ - V(JSTaggedValue, RevokeString, REVOKE_STRING_INDEX, revoke) \ - V(JSTaggedValue, NextString, NEXT_STRING_INDEX, next) \ - V(JSTaggedValue, ToStringString, TO_STRING_STRING_INDEX, toString) \ - V(JSTaggedValue, ToLocaleStringString, TO_LOCALE_STRING_STRING_INDEX, toLocaleString) \ - V(JSTaggedValue, ValueOfString, VALUE_OF_STRING_INDEX, valueOf) \ - V(JSTaggedValue, UndefinedString, UNDEFINED_STRING_INDEX, undefined) \ - V(JSTaggedValue, NullString, NULL_STRING_INDEX, null) \ - V(JSTaggedValue, BooleanString, BOOLEAN_STRING_INDEX, boolean) \ - V(JSTaggedValue, NumberString, NUMBER_STRING_INDEX, number) \ - V(JSTaggedValue, BigIntString, BIGINT_STRING_INDEX, bigint) \ - V(JSTaggedValue, FunctionString, FUNCTION_STRING_INDEX, function) \ - V(JSTaggedValue, StringString, STRING_STRING_INDEX, string) \ - V(JSTaggedValue, SymbolString, SYMBOL_STRING_INDEX, symbol) \ - V(JSTaggedValue, ObjectString, OBJECT_STRING_INDEX, object) \ - V(JSTaggedValue, TrueString, TRUE_STRING_INDEX, true) \ - V(JSTaggedValue, FalseString, FALSE_STRING_INDEX, false) \ - V(JSTaggedValue, ReturnString, RETURN_STRING_INDEX, return ) \ - V(JSTaggedValue, ProxyConstructString, PROXY_CONSTRUCT_STRING_INDEX, construct) \ - V(JSTaggedValue, ProxyCallString, PROXY_CALL_STRING_INDEX, call) \ - V(JSTaggedValue, PromiseThenString, PROMISE_THEN_STRING_INDEX, then) \ - V(JSTaggedValue, PromiseCatchString, PROMISE_CATCH_STRING_INDEX, catch) \ - V(JSTaggedValue, PromiseFinallyString, PROMISE_FINALLY_STRING_INDEX, finally) \ - V(JSTaggedValue, PromiseStatusString, PROMISE_STATUS_STRING_INDEX, status) \ - V(JSTaggedValue, PromiseFulfilledString, PROMISE_FULFILLED_STRING_INDEX, fulfilled) \ - V(JSTaggedValue, PromiseRejectedString, PROMISE_REJECTED_STRING_INDEX, rejected) \ - V(JSTaggedValue, PromiseReasonString, PROMISE_REASON_STRING_INDEX, reason) \ - V(JSTaggedValue, ScriptJobString, SCRIPT_JOB_STRING_INDEX, ScriptJobs) \ - V(JSTaggedValue, PromiseString, PROMISE_STRING_INDEX, PrimiseJobs) \ - V(JSTaggedValue, ThrowerString, THROWER_STRING_INDEX, Thrower) \ - V(JSTaggedValue, IdentityString, IDENTITY_STRING_INDEX, Identity) \ - V(JSTaggedValue, CallerString, CALLER_STRING_INDEX, caller) \ - V(JSTaggedValue, CalleeString, CALLEE_STRING_INDEX, callee) \ - V(JSTaggedValue, Int8ArrayString, INT8_ARRAY_STRING_INDEX, Int8Array) \ - V(JSTaggedValue, Uint8ArrayString, UINT8_ARRAY_STRING_INDEX, Uint8Array) \ - V(JSTaggedValue, Uint8ClampedArrayString, UINT8_CLAMPED_ARRAY_STRING_INDEX, Uint8ClampedArray) \ - V(JSTaggedValue, Int16ArrayString, INT16_ARRAY_STRING_INDEX, Int16Array) \ - V(JSTaggedValue, Uint16ArrayString, UINT16_ARRAY_STRING_INDEX, Uint16Array) \ - V(JSTaggedValue, Int32ArrayString, INT32_ARRAY_STRING_INDEX, Int32Array) \ - V(JSTaggedValue, Uint32ArrayString, UINT32_ARRAY_STRING_INDEX, Uint32Array) \ - V(JSTaggedValue, Float32ArrayString, FLOAT32_ARRAY_STRING_INDEX, Float32Array) \ - V(JSTaggedValue, Float64ArrayString, FLOAT64_ARRAY_STRING_INDEX, Float64Array) \ - V(JSTaggedValue, BigInt64ArrayString, BIGINT64_ARRAY_STRING_INDEX, BigInt64Array) \ - V(JSTaggedValue, BigUint64ArrayString, BIGUINT64_ARRAY_STRING_INDEX, BigUint64Array) \ - V(JSTaggedValue, AsyncFunctionString, ASYNC_FUNCTION_STRING_INDEX, AsyncFunction) \ - V(JSTaggedValue, PromiseResolveString, PROMISE_RESOLVE_STRING_INDEX, resolve) \ - V(JSTaggedValue, IdString, ID_STRING_INDEX, id) \ - V(JSTaggedValue, MethodString, METHOD_STRING_INDEX, method) \ - V(JSTaggedValue, ParamsString, PARAMS_STRING_INDEX, params) \ - V(JSTaggedValue, ResultString, RESULT_STRING_INDEX, result) \ - 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) \ - V(JSTaggedValue, TypeErrorString, TYPE_ERROR_STRING_INDEX, TypeError) \ - V(JSTaggedValue, ErrorsString, ERRORS_STRING_INDEX, Errors) \ - V(JSTaggedValue, AggregateErrorString, AGGREGATE_ERROR_STRING_INDEX, AggregateError) \ - V(JSTaggedValue, URIErrorString, URI_ERROR_STRING_INDEX, URIError) \ - V(JSTaggedValue, SyntaxErrorString, SYNTAX_ERROR_STRING_INDEX, SyntaxError) \ - V(JSTaggedValue, EvalErrorString, EVAL_ERROR_STRING_INDEX, EvalError) \ - V(JSTaggedValue, OOMErrorString, OOM_ERROR_STRING_INDEX, OOMError) \ - V(JSTaggedValue, ErrorFuncString, ERROR_FUNC_STRING_INDEX, errorfunc) \ - V(JSTaggedValue, StackString, STACK_STRING_INDEX, stack) \ - V(JSTaggedValue, StackEmptyString, STACK_EMPTY_STRING_INDEX, stackisempty) \ - V(JSTaggedValue, ObjNotCoercibleString, OBJ_NOT_COERCIBLE_STRING_INDEX, objectnotcoercible) \ - /* forIntl. */ \ - V(JSTaggedValue, LanguageString, LANGUAGE_STRING_CLASS_INDEX, language) \ - V(JSTaggedValue, ScriptString, SCRIPT_STRING_CLASS_INDEX, script) \ - V(JSTaggedValue, RegionString, REGION_STRING_CLASS_INDEX, region) \ - V(JSTaggedValue, BaseNameString, BASE_NAME_STRING_CLASS_INDEX, baseName) \ - V(JSTaggedValue, CalendarString, CALENDAR_STRING_CLASS_INDEX, calendar) \ - V(JSTaggedValue, CollationString, COLLATION_STRING_CLASS_INDEX, collation) \ - V(JSTaggedValue, HourCycleString, HOUR_CYCLE_STRING_CLASS_INDEX, hourCycle) \ - V(JSTaggedValue, CaseFirstString, CASE_FIRST_STRING_CLASS_INDEX, caseFirst) \ - V(JSTaggedValue, NumericString, NUMERIC_STRING_CLASS_INDEX, numeric) \ - V(JSTaggedValue, NumberingSystemString, NUMBERING_SYSTEM_STRING_CLASS_INDEX, numberingSystem) \ - V(JSTaggedValue, TypeString, TYPE_STRING_INDEX, type) \ - V(JSTaggedValue, LocaleMatcherString, LOCALE_MATCHER_STRING_INDEX, localeMatcher) \ - V(JSTaggedValue, FormatMatcherString, FORMAT_MATCHER_STRING_INDEX, formatMatcher) \ - V(JSTaggedValue, Hour12String, HOUR12_STRING_INDEX, hour12) \ - V(JSTaggedValue, H11String, H11_STRING_INDEX, h11) \ - V(JSTaggedValue, H12String, H12_STRING_INDEX, h12) \ - V(JSTaggedValue, H23String, H23_STRING_INDEX, h23) \ - V(JSTaggedValue, H24String, H24_STRING_INDEX, h24) \ - V(JSTaggedValue, WeekdayString, WEEK_DAY_STRING_INDEX, weekday) \ - V(JSTaggedValue, EraString, ERA_STRING_INDEX, era) \ - V(JSTaggedValue, YearString, YEAR_STRING_INDEX, year) \ - V(JSTaggedValue, QuarterString, QUARTER_STRING_INDEX, quarter) \ - V(JSTaggedValue, MonthString, MONTH_STRING_INDEX, month) \ - V(JSTaggedValue, DayString, DAY_STRING_INDEX, day) \ - V(JSTaggedValue, HourString, HOUR_STRING_INDEX, hour) \ - V(JSTaggedValue, MinuteString, MINUTE_STRING_INDEX, minute) \ - V(JSTaggedValue, SecondString, SECOND_STRING_INDEX, second) \ - V(JSTaggedValue, YearsString, YEARS_STRING_INDEX, years) \ - V(JSTaggedValue, QuartersString, QUARTERS_STRING_INDEX, quarters) \ - V(JSTaggedValue, MonthsString, MONTHS_STRING_INDEX, months) \ - V(JSTaggedValue, DaysString, DAYS_STRING_INDEX, days) \ - V(JSTaggedValue, HoursString, HOURS_STRING_INDEX, hours) \ - V(JSTaggedValue, MinutesString, MINUTES_STRING_INDEX, minutes) \ - V(JSTaggedValue, SecondsString, SECONDS_STRING_INDEX, seconds) \ - V(JSTaggedValue, TimeZoneNameString, TIME_ZONE_NAME_STRING_INDEX, timeZoneName) \ - V(JSTaggedValue, LocaleString, LOCALE_STRING_INDEX, locale) \ - V(JSTaggedValue, TimeZoneString, TIME_ZONE_STRING_INDEX, timeZone) \ - V(JSTaggedValue, LiteralString, LITERAL_STRING_INDEX, literal) \ - V(JSTaggedValue, YearNameString, YEAR_NAME_STRING_INDEX, yearName) \ - V(JSTaggedValue, DayPeriodString, DAY_PERIOD_STRING_INDEX, dayPeriod) \ - V(JSTaggedValue, FractionalSecondDigitsString, FRACTIONAL_SECOND_DIGITS_STRING_INDEX, fractionalSecondDigits) \ - V(JSTaggedValue, FractionalSecondString, FRACTIONAL_SECOND_STRING_INDEX, fractionalSecond) \ - V(JSTaggedValue, RelatedYearString, RELATED_YEAR_STRING_INDEX, relatedYear) \ - V(JSTaggedValue, LookUpString, LOOK_UP_STRING_INDEX, lookup) \ - V(JSTaggedValue, BestFitString, BEST_FIT_STRING_INDEX, bestfit) \ - V(JSTaggedValue, DateStyleString, DATE_STYLE_STRING_INDEX, dateStyle) \ - V(JSTaggedValue, TimeStyleString, TIME_STYLE_STRING_INDEX, timeStyle) \ - V(JSTaggedValue, UTCString, UTC_STRING_INDEX, UTC) \ - V(JSTaggedValue, WeekString, WEEK_STRING_INDEX, week) \ - V(JSTaggedValue, WeeksString, WEEKS_STRING_INDEX, weeks) \ - V(JSTaggedValue, SourceString, SOURCE_STRING_INDEX, source) \ - V(JSTaggedValue, FormatString, FORMAT_STRING_INDEX, format) \ - V(JSTaggedValue, EnUsString, EN_US_STRING_INDEX, en - US) \ - V(JSTaggedValue, UndString, UND_STRING_INDEX, und) \ - V(JSTaggedValue, LatnString, LATN_STRING_INDEX, latn) \ - V(JSTaggedValue, StyleString, STYLE_STRING_INDEX, style) \ - V(JSTaggedValue, UnitString, UNIT_STRING_INDEX, unit) \ - V(JSTaggedValue, IntegerString, INTEGER_STRING_INDEX, integer) \ - V(JSTaggedValue, NanString, NAN_STRING_INDEX, nan) \ - V(JSTaggedValue, InfinityString, INFINITY_STRING_INDEX, infinity) \ - V(JSTaggedValue, FractionString, FRACTION_STRING_INDEX, fraction) \ - V(JSTaggedValue, DecimalString, DECIMAL_STRING_INDEX, decimal) \ - V(JSTaggedValue, GroupString, GROUP_STRING_INDEX, group) \ - V(JSTaggedValue, GroupsString, GROUPS_STRING_INDEX, groups) \ - V(JSTaggedValue, CurrencyString, CURRENCY_STRING_INDEX, currency) \ - V(JSTaggedValue, CurrencySignString, CURRENCY_SIGN_STRING_INDEX, currencySign) \ - V(JSTaggedValue, CurrencyDisplayString, CURRENCY_DISPLAY_STRING_INDEX, currencyDisplay) \ - V(JSTaggedValue, PercentSignString, PERCENT_SIGN_STRING_INDEX, percentSign) \ - V(JSTaggedValue, PercentString, PERCENT_STRING_INDEX, percent) \ - V(JSTaggedValue, MinusSignString, MINUS_SIGN_STRING_INDEX, minusSign) \ - V(JSTaggedValue, PlusSignString, PLUS_SIGN_STRING_INDEX, plusSign) \ - V(JSTaggedValue, ExponentSeparatorString, EXPONENT_SEPARATOR_STRING_INDEX, exponentSeparator) \ - V(JSTaggedValue, ExponentMinusSignString, EXPONENT_MINUS_SIGN_INDEX, exponentMinusSign) \ - V(JSTaggedValue, ExponentIntegerString, EXPONENT_INTEGER_STRING_INDEX, exponentInteger) \ - V(JSTaggedValue, LongString, LONG_STRING_INDEX, long) \ - V(JSTaggedValue, ShortString, SHORT_STRING_INDEX, short) \ - V(JSTaggedValue, FullString, FULL_STRING_INDEX, full) \ - V(JSTaggedValue, MediumString, MEDIUM_STRING_INDEX, medium) \ - V(JSTaggedValue, NarrowString, NARROW_STRING_INDEX, narrow) \ - V(JSTaggedValue, AlwaysString, ALWAYS_STRING_INDEX, always) \ - V(JSTaggedValue, AutoString, AUTO_STRING_INDEX, auto) \ - V(JSTaggedValue, ThrowString, THROW_STRING_INDEX, throw) \ - V(JSTaggedValue, UnitDisplayString, UNIT_DISPLAY_INDEX, unitDisplay) \ - V(JSTaggedValue, NotationString, NOTATION_INDEX, notation) \ - V(JSTaggedValue, CompactDisplayString, COMPACT_DISPALY_INDEX, compactDisplay) \ - V(JSTaggedValue, UserGroupingString, USER_GROUPING_INDEX, useGrouping) \ - V(JSTaggedValue, SignDisplayString, SIGN_DISPLAY_INDEX, signDisplay) \ - V(JSTaggedValue, CodeString, CODE_INDEX, code) \ - V(JSTaggedValue, NarrowSymbolString, NARROW_SYMBOL_INDEX, narrowSymbol) \ - V(JSTaggedValue, StandardString, STANDARD_INDEX, standard) \ - V(JSTaggedValue, AccountingString, ACCOUNTING_INDEX, accounting) \ - V(JSTaggedValue, ScientificString, SCIENTIFIC_INDEX, scientific) \ - V(JSTaggedValue, EngineeringString, ENGINEERING_INDEX, engineering) \ - V(JSTaggedValue, CompactString, COMPACT_STRING_INDEX, compact) \ - V(JSTaggedValue, NeverString, NEVER_INDEX, never) \ - V(JSTaggedValue, ExceptZeroString, EXPECT_ZERO_INDEX, exceptZero) \ - V(JSTaggedValue, MinimumIntegerDigitsString, MINIMUM_INTEGER_DIGITS_INDEX, minimumIntegerDigits) \ - V(JSTaggedValue, MinimumFractionDigitsString, MINIMUM_FRACTIONDIGITS_INDEX, minimumFractionDigits) \ - V(JSTaggedValue, MaximumFractionDigitsString, MAXIMUM_FRACTIONDIGITS_INDEX, maximumFractionDigits) \ - V(JSTaggedValue, MinimumSignificantDigitsString, MINIMUM_SIGNIFICANTDIGITS_INDEX, minimumSignificantDigits) \ - V(JSTaggedValue, MaximumSignificantDigitsString, MAXIMUM_SIGNIFICANTDIGITS_INDEX, maximumSignificantDigits) \ - V(JSTaggedValue, InvalidDateString, INVALID_DATE_INDEX, InvalidDate) \ - V(JSTaggedValue, UsageString, USAGE_INDEX, usage) \ - V(JSTaggedValue, CompareString, COMPARE_INDEX, compare) \ - V(JSTaggedValue, SensitivityString, SENSITIVITY_INDEX, sensitivity) \ - V(JSTaggedValue, IgnorePunctuationString, IGNORE_PUNCTUATION_INDEX, ignorePunctuation) \ - V(JSTaggedValue, CardinalString, CARDINAL_INDEX, cardinal) \ - V(JSTaggedValue, OrdinalString, ORDINAL_INDEX, ordinal) \ - V(JSTaggedValue, ExecString, EXEC_INDEX, exec) \ - V(JSTaggedValue, LastIndexString, LAST_INDEX_INDEX, lastIndex) \ - V(JSTaggedValue, PluralCategoriesString, PLURAL_CATEGORIES_INDEX, pluralCategories) \ - V(JSTaggedValue, SortString, SORT_INDEX, sort) \ - V(JSTaggedValue, SearchString, SEARCH_INDEX, search) \ - V(JSTaggedValue, BaseString, BASE_INDEX, base) \ - V(JSTaggedValue, AccentString, ACCENT_INDEX, accent) \ - V(JSTaggedValue, CaseString, CASE_INDEX, Case) \ - V(JSTaggedValue, VariantString, VARIANT_INDEX, variant) \ - V(JSTaggedValue, EnUsPosixString, EN_US_POSIX_STRING_INDEX, en - US - POSIX) \ - V(JSTaggedValue, UpperString, UPPER_INDEX, upper) \ - V(JSTaggedValue, LowerString, LOWER_INDEX, lower) \ - V(JSTaggedValue, DefaultString, DEFAULT_INDEX, Default) \ - V(JSTaggedValue, SharedString, SHARED_INDEX, shared) \ - V(JSTaggedValue, StartRangeString, START_RANGE_INDEX, startRange) \ - V(JSTaggedValue, EndRangeString, END_RANGE_INDEX, endRange) \ - V(JSTaggedValue, Iso8601String, ISO8601_INDEX, iso8601) \ - V(JSTaggedValue, GregoryString, GREGORY_INDEX, gregory) \ - V(JSTaggedValue, EthioaaString, ETHIOAA_INDEX, ethioaa) \ - V(JSTaggedValue, StickyString, STICKY_INDEX, sticky) \ - V(JSTaggedValue, HasIndicesString, HAS_INDICES_INDEX, hasIndices) \ - V(JSTaggedValue, IndicesString, INDICES_INDEX, indices) \ - V(JSTaggedValue, UString, U_INDEX, u) \ - V(JSTaggedValue, IndexString, INDEX_INDEX, index) \ - V(JSTaggedValue, InputString, INPUT_INDEX, input) \ - V(JSTaggedValue, UnicodeString, UNICODE_INDEX, unicode) \ - V(JSTaggedValue, ZeroString, ZERO_INDEX, zero) \ - V(JSTaggedValue, ValuesString, VALUES_INDEX, values) \ - V(JSTaggedValue, AddString, ADD_INDEX, add) \ - V(JSTaggedValue, AmbiguousString, AMBIGUOUS_INDEX, ambiguous) \ - V(JSTaggedValue, ModuleString, MODULE_INDEX, module) \ - V(JSTaggedValue, StarString, STAR_INDEX, star) \ - V(JSTaggedValue, DateTimeFieldString, DATETIMEFIELD_INDEX, datetimefield) \ - V(JSTaggedValue, ConjunctionString, CONJUNCTION_INDEX, conjunction) \ - V(JSTaggedValue, NoneString, NONE_INDEX, none) \ - V(JSTaggedValue, FallbackString, FALLBACK_INDEX, fallback) \ - V(JSTaggedValue, DisjunctionString, DISJUNCTION_INDEX, disjunction) \ - V(JSTaggedValue, ElementString, ELEMENT_INDEX, element) \ - V(JSTaggedValue, FlagsString, FLAGS_INDEX, flags) \ - V(JSTaggedValue, GString, G_INDEX, g) \ - V(JSTaggedValue, NotEqualString, NOT_EQUAL_INDEX, notEqual) \ - V(JSTaggedValue, OkString, OK_INDEX, ok) \ - V(JSTaggedValue, TimeoutString, TIMEOUT_INDEX, timedout) \ - V(JSTaggedValue, NfcString, NFC_INDEX, nfc) \ - V(JSTaggedValue, EntriesString, ENTRIES_INDEX, entries) \ - V(JSTaggedValue, LeftSquareBracketString, LEFT_SQUARE_BRACKET_INDEX, leftsquarebracket) \ - V(JSTaggedValue, RightSquareBracketString, RIGHT_SQUARE_BRACKET_INDEX, rightsquarebracket) \ - V(JSTaggedValue, YString, Y_INDEX, y) \ - V(JSTaggedValue, DollarString, DOLLAR_INDEX, dollar) \ - V(JSTaggedValue, CommaString, COMMA_INDEX, comma) \ - V(JSTaggedValue, JoinString, JOIN_INDEX, join) \ - V(JSTaggedValue, CopyWithinString, COPY_WITHIN_INDEX, copywithin) \ - V(JSTaggedValue, FillString, FILL_INDEX, fill) \ - V(JSTaggedValue, FindString, FIND_INDEX, find) \ - V(JSTaggedValue, FindIndexString, FIND_INDEX_INDEX, findindex) \ - V(JSTaggedValue, FlatString, FLAT_INDEX, flat) \ - V(JSTaggedValue, FlatMapString, FLATMAP_INDEX, flatmap) \ - V(JSTaggedValue, IncludesString, INCLUDES_INDEX, includes) \ - V(JSTaggedValue, KeysString, KEYS_INDEX, keys) \ - V(JSTaggedValue, BoundString, BOUND_INDEX, bound) \ - V(JSTaggedValue, BackslashString, BACKSLASH_INDEX, backslash) \ - V(JSTaggedValue, SpaceString, SPACE_INDEX, space) \ - V(JSTaggedValue, NanCapitalString, NAN_INDEX, nan) \ - V(JSTaggedValue, CjsExportsString, CJS_EXPORTS_INDEX, exportsStr) \ - V(JSTaggedValue, CjsCacheString, CJS_CACHE_INDEX, cacheStr) \ - V(JSTaggedValue, NapiWrapperString, NAPI_WRAPPER_INDEX, napiwrapper) \ - /* for require native module */ \ - V(JSTaggedValue, RequireNativeModuleString, REQUIRE_NATIVE_MOUDULE_FUNC_INDEX, requireNativeModule) \ - V(JSTaggedValue, RequireNapiString, REQUIRE_NAPI_FUNC_INDEX, requireNapi) \ - V(JSTaggedValue, DollarStringOne, DOLLAR_STRING_ONE_INDEX, dollarStrOne) \ - V(JSTaggedValue, DollarStringTwo, DOLLAR_STRING_TWO_INDEX, dollarStrTwo) \ - V(JSTaggedValue, DollarStringThree, DOLLAR_STRING_THREE_INDEX, dollarStrThree) \ - V(JSTaggedValue, DollarStringFour, DOLLAR_STRING_FOUR_INDEX, dollarStrFour) \ - V(JSTaggedValue, DollarStringFive, DOLLAR_STRING_FIVE_INDEX, dollarStrFive) \ - V(JSTaggedValue, DollarStringSix, DOLLAR_STRING_SIX_INDEX, dollarStrSix) \ - V(JSTaggedValue, DollarStringSeven, DOLLAR_STRING_SEVEN_INDEX, dollarStrSeven) \ - V(JSTaggedValue, DollarStringEight, DOLLAR_STRING_EIGHT_INDEX, dollarStrEight) \ - V(JSTaggedValue, DollarStringNine, DOLLAR_STRING_NINE_INDEX, dollarStrNine) \ - /* for object to string */ \ - V(JSTaggedValue, UndefinedToString, UNDEFINED_TO_STRING_INDEX, undefinedToString) \ - V(JSTaggedValue, NullToString, NULL_TO_STRING_INDEX, nullToString) \ - V(JSTaggedValue, ObjectToString, OBJECT_TO_STRING_INDEX, objectToString) \ - V(JSTaggedValue, ArrayToString, ARRAY_TO_STRING_INDEX, arrayToString) \ - V(JSTaggedValue, StringToString, STRING_TO_STRING_INDEX, stringToString) \ - V(JSTaggedValue, BooleanToString, BOOLEAN_TO_STRING_INDEX, booleanToString) \ - V(JSTaggedValue, NumberToString, NUMBER_TO_STRING_INDEX, numberToString) \ - V(JSTaggedValue, ArgumentsToString, ARGUMENTS_TO_STRING_INDEX, argumentsToString) \ - V(JSTaggedValue, FunctionToString, FUNCTION_TO_STRING_INDEX, functionToString) \ - V(JSTaggedValue, DateToString, DATE_TO_STRING_INDEX, dateToString) \ - V(JSTaggedValue, ErrorToString, ERROR_TO_STRING_INDEX, errorToString) \ - V(JSTaggedValue, RegExpToString, REGEXP_TO_STRING_INDEX, regExpToString) +#define GLOBAL_ENV_CONSTANT_CONSTANT(V) \ + /* non ECMA standard jsapi containers iterators */ \ + V(JSTaggedValue, ArrayListFunction, ARRAYLIST_FUNCTION_INDEX, ArrayListFunction) \ + V(JSTaggedValue, ArrayListIteratorPrototype, ARRAYLIST_ITERATOR_PROTOTYPE_INDEX, ArrayListIterator) \ + V(JSTaggedValue, HashMapIteratorPrototype, HASHMAP_ITERATOR_PROTOTYPE_INDEX, HashMapIterator) \ + V(JSTaggedValue, HashSetIteratorPrototype, HASHSET_ITERATOR_PROTOTYPE_INDEX, HashSetIterator) \ + V(JSTaggedValue, LightWeightMapIteratorPrototype, \ + LIGHTWEIGHTMAP_ITERATOR_PROTOTYPE_INDEX, LightWeightMapIterator) \ + V(JSTaggedValue, LightWeightSetIteratorPrototype, \ + LIGHTWEIGHTSET_ITERATOR_PROTOTYPE_INDEX, LightWeightSetIterator) \ + V(JSTaggedValue, TreeMapIteratorPrototype, TREEMAP_ITERATOR_PROTOTYPE_INDEX, TreeMapIterator) \ + V(JSTaggedValue, TreeSetIteratorPrototype, TREESET_ITERATOR_PROTOTYPE_INDEX, TreeSetIterator) \ + V(JSTaggedValue, VectorFunction, VECTOR_FUNCTION_INDEX, VectorFunction) \ + V(JSTaggedValue, VectorIteratorPrototype, VECTOR_ITERATOR_PROTOTYPE_INDEX, VectorIterator) \ + V(JSTaggedValue, QueueIteratorPrototype, QUEUE_ITERATOR_PROTOTYPE_INDEX, QueueIterator) \ + V(JSTaggedValue, PlainArrayIteratorPrototype, PLAIN_ARRAY_ITERATOR_PROTOTYPE_INDEX, PlainArrayIterator) \ + V(JSTaggedValue, PlainArrayFunction, PLAIN_ARRAY_FUNCTION_INDEX, PlainArrayFunction) \ + V(JSTaggedValue, DequeIteratorPrototype, DEQUE_ITERATOR_PROTOTYPE_INDEX, DequeIterator) \ + V(JSTaggedValue, StackIteratorPrototype, STACK_ITERATOR_PROTOTYPE_INDEX, StackIterator) \ + V(JSTaggedValue, ListFunction, LIST_FUNCTION_INDEX, ListFunction) \ + V(JSTaggedValue, LinkedListFunction, LINKED_LIST_FUNCTION_INDEX, LinkedListFunction) \ + V(JSTaggedValue, ListIteratorPrototype, LIST_ITERATOR_PROTOTYPE_INDEX, ListIterator) \ + V(JSTaggedValue, UndefinedIterResult, UNDEFINED_INTERATOR_RESULT_INDEX, UndefinedIterResult) \ + V(JSTaggedValue, LinkedListIteratorPrototype, LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, LinkedListIterator) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define GLOBAL_ENV_CONSTANT_ACCESSOR(V) \ @@ -492,19 +497,27 @@ class ObjectFactory; // ConstantIndex used for explicit visit each constant. enum class ConstantIndex : size_t { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define INDEX_FILTER(Type, Name, Index, Desc) Index, - GLOBAL_ENV_CONSTANT_CLASS(INDEX_FILTER) GLOBAL_ENV_CONSTANT_SPECIAL(INDEX_FILTER) - GLOBAL_ENV_CONSTANT_CONSTANT(INDEX_FILTER) GLOBAL_ENV_CONSTANT_ACCESSOR(INDEX_FILTER) - GLOBAL_ENV_CACHES(INDEX_FILTER) +#define INDEX_FILTER_COMMON(Index) Index, +#define INDEX_FILTER_WITH_TYPE(Type, Name, Index, Desc) INDEX_FILTER_COMMON(Index) + GLOBAL_ENV_CONSTANT_CLASS(INDEX_FILTER_WITH_TYPE) + GLOBAL_ENV_CONSTANT_SPECIAL(INDEX_FILTER_WITH_TYPE) + GLOBAL_ENV_CONSTANT_CONSTANT(INDEX_FILTER_WITH_TYPE) + GLOBAL_ENV_CONSTANT_ACCESSOR(INDEX_FILTER_WITH_TYPE) + GLOBAL_ENV_CACHES(INDEX_FILTER_WITH_TYPE) +#undef INDEX_FILTER_WITH_TYPE -#undef INDEX_FILTER - CONSTATNT_COUNT, +#define INDEX_FILTER_STRING(Name, Index, Token) INDEX_FILTER_COMMON(Index) + GLOBAL_ENV_CONSTANT_STRING(INDEX_FILTER_STRING) +#undef INDEX_FILTER_STRING +#undef INDEX_FILTER_COMMON - CONSTATNT_BEGIN = 0, - CONSTATNT_END = CONSTATNT_COUNT, + CONSTANT_COUNT, - READ_ONLY_CONSTATNT_BEGIN = CONSTATNT_BEGIN, - READ_ONLY_CONSTATNT_END = CONSTATNT_END, + CONSTANT_BEGIN = 0, + CONSTANT_END = CONSTANT_COUNT, + + READ_ONLY_CONSTANT_BEGIN = CONSTANT_BEGIN, + READ_ONLY_CONSTANT_END = CONSTANT_END, JSAPI_CONTAINERS_BEGIN = ARRAYLIST_FUNCTION_INDEX, JSAPI_CONTAINERS_END = LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, // ... @@ -547,17 +560,24 @@ public: uintptr_t GetGlobalConstantAddr(ConstantIndex index) const; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECL_GET(Type, Name, Index, Desc) \ - const Type Get##Name() const; \ - const JSHandle GetHandled##Name() const; \ +#define DECL_GET_COMMON(Type, Name) \ + const Type Get##Name() const; \ + const JSHandle GetHandled##Name() const; \ static size_t GetOffsetOf##Name(); - GLOBAL_ENV_CONSTANT_CLASS(DECL_GET) - GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET) - GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET) - GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET) - GLOBAL_ENV_CACHES(DECL_GET) -#undef DECL_GET +#define DECL_GET_WITH_TYPE(Type, Name, Index, Desc) DECL_GET_COMMON(Type, Name) + GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_WITH_TYPE) + GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_WITH_TYPE) + GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_WITH_TYPE) + GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_WITH_TYPE) + GLOBAL_ENV_CACHES(DECL_GET_WITH_TYPE) +#undef DECL_GET_WITH_TYPE + +#define DECL_GET_STRING(Name, Index, Token) DECL_GET_COMMON(JSTaggedValue, Name) + GLOBAL_ENV_CONSTANT_STRING(DECL_GET_STRING) +#undef DECL_GET_STRING + +#undef DECL_GET_COMMON void VisitRangeSlot(const RootRangeVisitor &visitor) { @@ -566,13 +586,13 @@ public: JSTaggedValue GetGlobalConstantObject(size_t index) const { - ASSERT(static_cast(index) < ConstantIndex::CONSTATNT_COUNT); + ASSERT(static_cast(index) < ConstantIndex::CONSTANT_COUNT); return constants_[index]; } size_t GetConstantCount() const { - return static_cast(ConstantIndex::CONSTATNT_COUNT); + return static_cast(ConstantIndex::CONSTANT_COUNT); } size_t GetJSAPIContainersBegin() const @@ -595,12 +615,12 @@ public: } static constexpr size_t SizeArch32 = - JSTaggedValue::TaggedTypeSize() * static_cast(ConstantIndex::CONSTATNT_COUNT); + JSTaggedValue::TaggedTypeSize() * static_cast(ConstantIndex::CONSTANT_COUNT); static constexpr size_t SizeArch64 = - JSTaggedValue::TaggedTypeSize() * static_cast(ConstantIndex::CONSTATNT_COUNT); + JSTaggedValue::TaggedTypeSize() * static_cast(ConstantIndex::CONSTANT_COUNT); private: - JSTaggedValue constants_[static_cast(ConstantIndex::CONSTATNT_COUNT)]; // NOLINT(modernize-avoid-c-arrays) + JSTaggedValue constants_[static_cast(ConstantIndex::CONSTANT_COUNT)]; // NOLINT(modernize-avoid-c-arrays) }; STATIC_ASSERT_EQ_ARCH(sizeof(GlobalEnvConstants), GlobalEnvConstants::SizeArch32, GlobalEnvConstants::SizeArch64); } // namespace panda::ecmascript From 3fa56c9186d08ebaea8a6188946b11212c7f3b50 Mon Sep 17 00:00:00 2001 From: xiongluo Date: Thu, 19 Oct 2023 17:00:09 +0800 Subject: [PATCH 46/50] change props grow step 8 Signed-off-by: xiongluo Change-Id: Ie1f4e7e234e14d317b3ca3204dbe6922421efd70 --- ecmascript/compiler/stub_builder.cpp | 10 +++++++--- ecmascript/compiler/stub_builder.h | 3 ++- ecmascript/ecma_vm.cpp | 7 ++++++- ecmascript/ecma_vm.h | 7 +++++++ ecmascript/ic/ic_runtime_stub-inl.h | 2 +- ecmascript/js_object-inl.h | 4 ++-- ecmascript/js_object.cpp | 5 +++++ ecmascript/js_object.h | 16 ++++++++++++++-- ecmascript/js_thread.h | 19 +++++++++++++++++++ ecmascript/mem/linear_space.cpp | 6 ++++++ ecmascript/object_fast_operator-inl.h | 3 ++- ecmascript/stubs/runtime_stubs.cpp | 3 ++- 12 files changed, 73 insertions(+), 12 deletions(-) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 869298ccf7..01511b7a99 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -536,14 +536,17 @@ void StubBuilder::JSObjectSetProperty( return; } -GateRef StubBuilder::ComputeNonInlinedFastPropsCapacity(GateRef oldLength, GateRef maxNonInlinedFastPropsCapacity) +GateRef StubBuilder::ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength, + GateRef maxNonInlinedFastPropsCapacity) { auto env = GetEnvironment(); Label subEntry(env); env->SubCfgEntry(&subEntry); Label exit(env); DEFVARIABLE(result, VariableType::INT32(), Int32(0)); - GateRef newL = Int32Add(oldLength, Int32(JSObject::PROPERTIES_GROW_SIZE)); + GateRef propertiesStep = Load(VariableType::INT32(), glue, + IntPtr(JSThread::GlueData::GetPropertiesGrowStepOffset(env->Is32Bit()))); + GateRef newL = Int32Add(oldLength, propertiesStep); Label reachMax(env); Label notReachMax(env); Branch(Int32GreaterThan(newL, maxNonInlinedFastPropsCapacity), &reachMax, ¬ReachMax); @@ -884,7 +887,8 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k Jump(&afterDictChangeCon); } Bind(&afterDictChangeCon); - GateRef capacity = ComputeNonInlinedFastPropsCapacity(*length, maxNonInlinedFastPropsCapacity); + GateRef capacity = ComputeNonInlinedFastPropsCapacity(glue, *length, + maxNonInlinedFastPropsCapacity); array = CallRuntime(glue, RTSTUB_ID(CopyArray), { *array, IntToTaggedInt(*length), IntToTaggedInt(capacity) }); SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 4dfd1b3fe8..66820d3bf1 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -467,7 +467,8 @@ public: GateRef IsInternalString(GateRef string); GateRef IsDigit(GateRef ch); GateRef StringToElementIndex(GateRef glue, GateRef string); - GateRef ComputeNonInlinedFastPropsCapacity(GateRef oldLength, GateRef maxNonInlinedFastPropsCapacity); + GateRef ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength, + GateRef maxNonInlinedFastPropsCapacity); GateRef FindTransitions(GateRef glue, GateRef receiver, GateRef hClass, GateRef key, GateRef attr); void TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr); void TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind); diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index e49b921548..54254323f3 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -226,7 +226,7 @@ bool EcmaVM::Initialize() } callTimer_ = new FunctionCallTimer(); - + strategy_ = new ThrouputJSObjectResizingStrategy(); initialized_ = true; return true; } @@ -312,6 +312,11 @@ EcmaVM::~EcmaVM() callTimer_ = nullptr; } + if (strategy_ != nullptr) { + delete strategy_; + strategy_ = nullptr; + } + if (thread_ != nullptr) { delete thread_; thread_ = nullptr; diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 52d7b4e2ac..07b7640d2d 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -85,6 +85,7 @@ class QuickFixManager; class ConstantPool; class FunctionCallTimer; class EcmaStringTable; +class JSObjectResizingStrategy; using NativePtrGetter = void* (*)(void* info); using SourceMapTranslateCallback = std::function; @@ -466,6 +467,11 @@ public: return isProfiling_; } + JSObjectResizingStrategy *GetJSObjectResizingStrategy() + { + return strategy_; + } + protected: void PrintJSErrorInfo(const JSHandle &exceptionInfo) const; @@ -533,6 +539,7 @@ private: CpuProfiler *profiler_ {nullptr}; #endif FunctionCallTimer *callTimer_ {nullptr}; + JSObjectResizingStrategy *strategy_ {nullptr}; // For Native MethodLiteral static void *InternalMethodTable[static_cast(MethodIndex::METHOD_END)]; diff --git a/ecmascript/ic/ic_runtime_stub-inl.h b/ecmascript/ic/ic_runtime_stub-inl.h index 2356b87ff5..33da69f755 100644 --- a/ecmascript/ic/ic_runtime_stub-inl.h +++ b/ecmascript/ic/ic_runtime_stub-inl.h @@ -310,7 +310,7 @@ void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JS } else { auto arrayHandle = JSHandle(thread, array); uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity(); - uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(capacity, + uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity, maxNonInlinedFastPropsCapacity); properties = factory->CopyArray(arrayHandle, capacity, newLen); } diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index d63ba411b7..233c33bdd4 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -366,10 +366,10 @@ inline uint32_t JSObject::ComputeElementCapacityHighGrowth(uint32_t oldCapacity) return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH; } -inline uint32_t JSObject::ComputeNonInlinedFastPropsCapacity(uint32_t oldCapacity, +inline uint32_t JSObject::ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity, uint32_t maxNonInlinedFastPropsCapacity) { - uint32_t newCapacity = static_cast(oldCapacity + PROPERTIES_GROW_SIZE); + uint32_t newCapacity = oldCapacity + thread->GetPropertiesGrowStep(); return newCapacity > maxNonInlinedFastPropsCapacity ? maxNonInlinedFastPropsCapacity : newCapacity; } diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index f5ce1617a2..c645829c22 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -58,6 +58,11 @@ PropertyAttributes::PropertyAttributes(const PropertyDescriptor &desc) } } +void ThrouputJSObjectResizingStrategy::UpdateGrowStep(JSThread *thread, uint32_t step) +{ + thread->SetPropertiesGrowStep(std::min(static_cast(JSThread::PROPERTIES_GROW_SIZE * 2), step)); +} + Method *ECMAObject::GetCallTarget() const { const TaggedObject *obj = this; diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index bd8c15bfbd..2042f13a0a 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -360,11 +360,22 @@ public: } }; +class JSObjectResizingStrategy { +public: + JSObjectResizingStrategy() = default; + virtual ~JSObjectResizingStrategy() = default; + virtual void UpdateGrowStep(JSThread *thread, uint32_t step) = 0; +}; + +class ThrouputJSObjectResizingStrategy : public JSObjectResizingStrategy { +public: + virtual void UpdateGrowStep(JSThread *thread, uint32_t step) override; +}; + class JSObject : public ECMAObject { public: static constexpr int MIN_ELEMENTS_LENGTH = 3; static constexpr int MIN_PROPERTIES_LENGTH = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS; - static constexpr int PROPERTIES_GROW_SIZE = 4; static constexpr int FAST_ELEMENTS_FACTOR = 3; static constexpr int MIN_GAP = 256; static constexpr int MAX_GAP = 1_KB; @@ -665,7 +676,8 @@ private: static uint32_t ComputeElementCapacity(uint32_t oldCapacity, bool isNew = false); static uint32_t ComputeElementCapacityHighGrowth(uint32_t oldCapacity); - static uint32_t ComputeNonInlinedFastPropsCapacity(uint32_t oldCapacity, uint32_t maxNonInlinedFastPropsCapacity); + static uint32_t ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity, + uint32_t maxNonInlinedFastPropsCapacity); static JSTaggedValue ShouldGetValueFromBox(ObjectOperator *op); static std::pair, JSHandle> GetOwnEnumerableNamesInFastMode( diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 719a7a6e0b..3a01dcbd25 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -190,6 +190,7 @@ public: static constexpr int CHECK_SAFEPOINT_BITFIELD_NUM = 8; static constexpr int PGO_PROFILER_BITFIELD_START = 16; static constexpr int BOOL_BITFIELD_NUM = 1; + static constexpr int PROPERTIES_GROW_SIZE = 4; static constexpr uint32_t RESERVE_STACK_SIZE = 128; using MarkStatusBits = BitField; using CheckSafePointBit = BitField; @@ -729,6 +730,16 @@ public: return ++globalNumberCount_; } + void SetPropertiesGrowStep(uint32_t step) + { + glueData_.propertiesGrowStep_ = step; + } + + uint32_t GetPropertiesGrowStep() const + { + return glueData_.propertiesGrowStep_; + } + struct GlueData : public base::AlignedStruct { enum class Index : size_t { BCStubEntriesIndex = 0, @@ -780,6 +792,7 @@ public: IsStartHeapSamplingIndex, IsDebugModeIndex, IsFrameDroppedIndex, + PropertiesGrowStepIndex, EntryFrameDroppedStateIndex, NumOfMembers }; @@ -900,6 +913,11 @@ public: return GetOffset(Index::IsFrameDroppedIndex)>(isArch32); } + static size_t GetPropertiesGrowStepOffset(bool isArch32) + { + return GetOffset(Index::PropertiesGrowStepIndex)>(isArch32); + } + static size_t GetEntryFrameDroppedStateOffset(bool isArch32) { return GetOffset(Index::EntryFrameDroppedStateIndex)>(isArch32); @@ -929,6 +947,7 @@ public: alignas(EAS) JSTaggedValue isStartHeapSampling_ {JSTaggedValue::False()}; alignas(EAS) bool isDebugMode_ {false}; alignas(EAS) bool isFrameDropped_ {false}; + alignas(EAS) uint32_t propertiesGrowStep_ {PROPERTIES_GROW_SIZE}; alignas(EAS) uint64_t entryFrameDroppedState_ {FrameDroppedState::StateFalse}; }; STATIC_ASSERT_EQ_ARCH(sizeof(GlueData), GlueData::SizeArch32, GlueData::SizeArch64); diff --git a/ecmascript/mem/linear_space.cpp b/ecmascript/mem/linear_space.cpp index 21bf97ee68..492ca8f088 100644 --- a/ecmascript/mem/linear_space.cpp +++ b/ecmascript/mem/linear_space.cpp @@ -270,6 +270,10 @@ bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC) } size_t newCapacity = initialCapacity_ * GROWING_FACTOR; SetInitialCapacity(std::min(newCapacity, maximumCapacity_)); + if (newCapacity == maximumCapacity_) { + heap_->GetEcmaVM()->GetJSObjectResizingStrategy()->UpdateGrowStep(heap_->GetJSThread(), + JSThread::PROPERTIES_GROW_SIZE * 2); + } return true; } else if (curObjectSurvivalRate < SHRINK_OBJECT_SURVIVAL_RATE) { if (initialCapacity_ <= minimumCapacity_) { @@ -281,6 +285,8 @@ bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC) } size_t newCapacity = initialCapacity_ / GROWING_FACTOR; SetInitialCapacity(std::max(newCapacity, minimumCapacity_)); + heap_->GetEcmaVM()->GetJSObjectResizingStrategy()->UpdateGrowStep(heap_->GetJSThread(), + JSThread::PROPERTIES_GROW_SIZE); return true; } return false; diff --git a/ecmascript/object_fast_operator-inl.h b/ecmascript/object_fast_operator-inl.h index d67395957b..198c97512f 100644 --- a/ecmascript/object_fast_operator-inl.h +++ b/ecmascript/object_fast_operator-inl.h @@ -566,7 +566,8 @@ PropertyAttributes ObjectFastOperator::AddPropertyByName(JSThread *thread, JSHan return attr; } // Grow properties array size - uint32_t capacity = JSObject::ComputeNonInlinedFastPropsCapacity(length, maxNonInlinedFastPropsCapacity); + uint32_t capacity = JSObject::ComputeNonInlinedFastPropsCapacity(thread, length, + maxNonInlinedFastPropsCapacity); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); array.Update(factory->CopyArray(array, length, capacity).GetTaggedValue()); objHandle->SetProperties(thread, array.GetTaggedValue()); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index e54af254d4..395365227c 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -271,7 +271,8 @@ DEF_RUNTIME_STUBS(PropertiesSetValue) properties = factory->NewTaggedArray(JSObject::MIN_PROPERTIES_LENGTH); } else { uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity(); - uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(capacity, maxNonInlinedFastPropsCapacity); + uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity, + maxNonInlinedFastPropsCapacity); properties = factory->CopyArray(arrayHandle, capacity, newLen); } properties->Set(thread, index, valueHandle); From 7d2fa91e5a7c15dbd7342a79a0e08cc12e6a5e0c Mon Sep 17 00:00:00 2001 From: yang-19970325 Date: Fri, 20 Oct 2023 21:17:35 +0800 Subject: [PATCH 47/50] Fix FA module breakpoint set fail Issue:#I89QXE Signed-off-by: yang-19970325 Change-Id: I09eb20cf6e0844a7bcc4c4efae19406372aa32b2 --- ecmascript/jspandafile/debug_info_extractor.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h index 2594fd3e00..1c854f1456 100644 --- a/ecmascript/jspandafile/debug_info_extractor.h +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -110,10 +110,12 @@ public: panda_file::ClassDataAccessor cda(pandaFile, id); CString recordName = JSPandaFile::ParseEntryPoint(utf::Mutf8AsCString(cda.GetDescriptor())); // the recordName for testcases is empty - if (!debugRecordName.empty()) { - auto iter = debugRecordName.find(std::string(recordName)); - if (iter == debugRecordName.end()) { - continue; + if (!jsPandaFile_->IsBundlePack()) { + if (!debugRecordName.empty()) { + auto iter = debugRecordName.find(std::string(recordName)); + if (iter == debugRecordName.end()) { + continue; + } } } cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { From cd594b181beb816a9301943da909f435adfd60a9 Mon Sep 17 00:00:00 2001 From: rentangyu Date: Sat, 21 Oct 2023 09:48:37 +0800 Subject: [PATCH 48/50] The same bigint type becomes two keys in the map issues:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I89N4V Signed-off-by: rentangyu --- ecmascript/js_api/js_api_lightweightmap.cpp | 4 ++++ ecmascript/linked_hash_table.cpp | 5 ++++- ecmascript/tagged_node.h | 5 ++++- test/moduletest/bigint/bigint.js | 25 ++++++++++++++++++++- test/moduletest/bigint/expect_output.txt | 2 ++ 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/ecmascript/js_api/js_api_lightweightmap.cpp b/ecmascript/js_api/js_api_lightweightmap.cpp index de7c3e669a..3db8f145cb 100644 --- a/ecmascript/js_api/js_api_lightweightmap.cpp +++ b/ecmascript/js_api/js_api_lightweightmap.cpp @@ -475,6 +475,10 @@ int32_t JSAPILightWeightMap::Hash(JSTaggedValue key) int32_t hash = key.GetInt(); return hash; } + if (key.IsBigInt()) { + uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } uint64_t keyValue = key.GetRawData(); return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); } diff --git a/ecmascript/linked_hash_table.cpp b/ecmascript/linked_hash_table.cpp index 2f155dfd69..7e3208fb52 100644 --- a/ecmascript/linked_hash_table.cpp +++ b/ecmascript/linked_hash_table.cpp @@ -248,7 +248,10 @@ int LinkedHash::Hash(JSTaggedValue key) } return hash; } - + if (key.IsBigInt()) { + uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } // Int, Double, Special and HeapObject(except symbol and string) if (key.IsDouble()) { key = JSTaggedValue::TryCastDoubleToInt32(key.GetDouble()); diff --git a/ecmascript/tagged_node.h b/ecmascript/tagged_node.h index 2b982908ee..8657415d21 100644 --- a/ecmascript/tagged_node.h +++ b/ecmascript/tagged_node.h @@ -70,7 +70,10 @@ public: } return hash; } - + if (key.IsBigInt()) { + uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } // Int, Double, Special and HeapObject(except symbol and string) uint64_t keyValue = key.GetRawData(); return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); diff --git a/test/moduletest/bigint/bigint.js b/test/moduletest/bigint/bigint.js index 9fe6825635..ea83f88a98 100644 --- a/test/moduletest/bigint/bigint.js +++ b/test/moduletest/bigint/bigint.js @@ -69,4 +69,27 @@ let v49 = -12n; v49--; const v52 = (v49 >> v49).constructor; const t48 = v52.__defineSetter__; -print(v52(v35)); \ No newline at end of file +print(v52(v35)); + +let map = new Map(); +let a = BigInt(9007199254740991); +let b = BigInt(0x1fffffffffffff); +let c = BigInt(0b11111111111111111111111111111111111111111111111111111); +let d = BigInt(9007199254740991); +map.set(a, '1'); +map.set(b, '2'); +map.set(c, '3'); +map.set(d, '4'); +map.forEach((val,key)=>{ + print("map val:" + val, "key :" + key); +}) + +var HashMap = ArkPrivate.Load(ArkPrivate.HashMap); +let hmap = new HashMap(); +hmap.set(a, '1'); +hmap.set(b, '2'); +hmap.set(c, '3'); +hmap.set(d, '4'); +hmap.forEach((val,key)=>{ + print("hmap val:" + val, "key :" + key); +}) \ No newline at end of file diff --git a/test/moduletest/bigint/expect_output.txt b/test/moduletest/bigint/expect_output.txt index f9b57a4853..bc647eaff6 100644 --- a/test/moduletest/bigint/expect_output.txt +++ b/test/moduletest/bigint/expect_output.txt @@ -21,3 +21,5 @@ RangeError RangeError SyntaxError 0 +map val:4 key :9007199254740991 +hmap val:4 key :9007199254740991 From b50494ca31c75232fcd42147c2608dfb96f40cde Mon Sep 17 00:00:00 2001 From: wupengyong Date: Thu, 19 Oct 2023 19:11:16 +0800 Subject: [PATCH 49/50] Reason:add FindElementWithCache IR Description:add FindElementWithCache IR Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I89F9E?from=project-issue Signed-off-by: wupengyong Change-Id: I357c22e119de8025fd1193a37c90501a7c8b4327 --- ecmascript/compiler/call_signature.cpp | 14 + ecmascript/compiler/call_signature.h | 1 + ecmascript/compiler/mcr_circuit_builder.cpp | 4 +- ecmascript/compiler/stub_builder-inl.h | 69 +++++ ecmascript/compiler/stub_builder.cpp | 306 +++++++++++++++++--- ecmascript/compiler/stub_builder.h | 15 + ecmascript/ecma_context.h | 2 +- ecmascript/ic/properties_cache.h | 49 +++- ecmascript/js_thread.cpp | 26 +- ecmascript/js_thread.h | 15 +- ecmascript/stubs/runtime_stubs.cpp | 15 +- ecmascript/stubs/runtime_stubs.h | 3 +- 12 files changed, 439 insertions(+), 80 deletions(-) diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index be57ca6888..b5995e3905 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -1748,6 +1748,20 @@ DEF_CALL_SIGNATURE(DoubleToLength) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(ComputeHashcode) +{ + // 1 : 1 input parameters + CallSignature index("ComputeHashcode", 0, 1, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32()); + *callSign = index; + // 1 : 1 input parameters + std::array params = { + VariableType::JS_ANY(), + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + DEF_CALL_SIGNATURE(MarkingBarrier) { // 4 : 4 input parameters diff --git a/ecmascript/compiler/call_signature.h b/ecmascript/compiler/call_signature.h index 88cc47e796..a47672a037 100644 --- a/ecmascript/compiler/call_signature.h +++ b/ecmascript/compiler/call_signature.h @@ -427,6 +427,7 @@ private: V(InsertOldToNewRSet) \ V(DoubleToInt) \ V(DoubleToLength) \ + V(ComputeHashcode) \ V(FloatMod) \ V(FloatSqrt) \ V(FloatCos) \ diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 468613540d..7de6413fdd 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -922,8 +922,8 @@ GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value) Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit); Bind(&noRawHashcode); { - hashcode = GetInt32OfTInt( - CallRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, { value }, Circuit::NullGate())); + hashcode = + CallNGCRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, { value }, Circuit::NullGate()); Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode); Jump(&exit); } diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index bfa895f80d..a8b4476d8f 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1689,6 +1689,13 @@ inline GateRef StubBuilder::PropAttrGetOffset(GateRef attr) Int32((1LLU << PropertyAttributes::OffsetField::SIZE) - 1)); } +inline GateRef StubBuilder::GetSortedIndex(GateRef attr) +{ + return Int32And( + Int32LSR(attr, Int32(PropertyAttributes::SortedIndexField::START_BIT)), + Int32((1LLU << PropertyAttributes::SortedIndexField::SIZE) - 1)); +} + // SetDictionaryOrder func in property_attribute.h inline GateRef StubBuilder::SetDictionaryOrderFieldInPropAttr(GateRef attr, GateRef value) { @@ -2781,5 +2788,67 @@ inline GateRef StubBuilder::RemoveTaggedWeakTag(GateRef weak) { return Int64ToTaggedPtr(IntPtrAnd(ChangeTaggedPointerToInt64(weak), IntPtr(~JSTaggedValue::TAG_WEAK))); } + +inline GateRef StubBuilder::GetPropertiesCache(GateRef glue) +{ + GateRef currentContextOffset = IntPtr(JSThread::GlueData::GetCurrentContextOffset(env_->Is32Bit())); + GateRef currentContext = Load(VariableType::NATIVE_POINTER(), glue, currentContextOffset); + return Load(VariableType::NATIVE_POINTER(), currentContext, IntPtr(0)); +} + +inline GateRef StubBuilder::GetSortedKey(GateRef layoutInfo, GateRef index) +{ + GateRef fixedIdx = GetSortedIndex(layoutInfo, index); + return GetKey(layoutInfo, fixedIdx); +} + +inline GateRef StubBuilder::GetSortedIndex(GateRef layoutInfo, GateRef index) +{ + return GetSortedIndex(GetAttr(layoutInfo, index)); +} + +inline GateRef StubBuilder::GetAttrIndex(GateRef index) +{ + return Int32Add(Int32LSL(index, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)), Int32(LayoutInfo::ATTR_INDEX_OFFSET)); +} + +inline GateRef StubBuilder::GetKeyIndex(GateRef index) +{ + return Int32LSL(index, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)); +} + +inline GateRef StubBuilder::GetAttr(GateRef layoutInfo, GateRef index) +{ + GateRef fixedIdx = GetAttrIndex(index); + return GetInt32OfTInt(GetValueFromTaggedArray(layoutInfo, fixedIdx)); +} + +inline GateRef StubBuilder::GetKey(GateRef layoutInfo, GateRef index) +{ + GateRef fixedIdx = GetKeyIndex(index); + return GetValueFromTaggedArray(layoutInfo, fixedIdx); +} + +inline void StubBuilder::SetToPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key, GateRef result) +{ + GateRef hash = HashFromHclassAndKey(glue, cls, key); + GateRef prop = + PtrAdd(cache, PtrMul(ZExtInt32ToPtr(hash), IntPtr(PropertiesCache::PropertyKey::GetPropertyKeySize()))); + StoreWithNoBarrier(VariableType::JS_POINTER(), prop, IntPtr(PropertiesCache::PropertyKey::GetHclassOffset()), cls); + StoreWithNoBarrier(VariableType::JS_ANY(), prop, IntPtr(PropertiesCache::PropertyKey::GetKeyOffset()), key); + StoreWithNoBarrier(VariableType::INT32(), prop, IntPtr(PropertiesCache::PropertyKey::GetResultsOffset()), result); +} + +inline void StubBuilder::StoreWithNoBarrier(VariableType type, GateRef base, GateRef offset, GateRef value) +{ + env_->GetBuilder()->StoreWithNoBarrier(type, base, offset, value); +} + +inline GateRef StubBuilder::HashFromHclassAndKey(GateRef glue, GateRef cls, GateRef key) +{ + GateRef clsHash = Int32LSR(ChangeIntPtrToInt32(TaggedCastToIntPtr(cls)), Int32(3)); // skip 8bytes + GateRef keyHash = GetKeyHashCode(glue, key); + return Int32And(Int32Xor(clsHash, keyHash), Int32(PropertiesCache::CACHE_LENGTH_MASK)); +} } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_STUB_INL_H diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index d18340fedc..4f3344e1aa 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -25,6 +25,7 @@ #include "ecmascript/compiler/rt_call_signature.h" #include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/global_env_constants.h" +#include "ecmascript/ic/properties_cache.h" #include "ecmascript/js_api/js_api_arraylist.h" #include "ecmascript/js_api/js_api_vector.h" #include "ecmascript/js_object.h" @@ -123,52 +124,273 @@ GateRef StubBuilder::FindElementWithCache(GateRef glue, GateRef layoutInfo, Gate Label exit(env); Label notExceedUpper(env); Label exceedUpper(env); - Label afterExceedCon(env); // 9 : Builtins Object properties number is nine Branch(Int32LessThanOrEqual(propsNum, Int32(9)), ¬ExceedUpper, &exceedUpper); + Bind(¬ExceedUpper); { - Bind(¬ExceedUpper); - Label loopHead(env); - Label loopEnd(env); - Label afterLoop(env); - Jump(&loopHead); - LoopBegin(&loopHead); - { - Label propsNumIsZero(env); - Label propsNumNotZero(env); - Branch(Int32Equal(propsNum, Int32(0)), &propsNumIsZero, &propsNumNotZero); - Bind(&propsNumIsZero); - Jump(&afterLoop); - Bind(&propsNumNotZero); - GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo); - GateRef keyInProperty = Load(VariableType::JS_ANY(), - elementAddr, - PtrMul(ZExtInt32ToPtr(*i), - IntPtr(sizeof(panda::ecmascript::Properties)))); - Label equal(env); - Label notEqual(env); - Label afterEqualCon(env); - Branch(Equal(keyInProperty, key), &equal, ¬Equal); - Bind(&equal); - result = *i; - Jump(&exit); - Bind(¬Equal); - Jump(&afterEqualCon); - Bind(&afterEqualCon); - i = Int32Add(*i, Int32(1)); - Branch(Int32UnsignedLessThan(*i, propsNum), &loopEnd, &afterLoop); - Bind(&loopEnd); - LoopEnd(&loopHead); - } - Bind(&afterLoop); - result = Int32(-1); + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label propsNumIsZero(env); + Label propsNumNotZero(env); + Branch(Int32Equal(propsNum, Int32(0)), &propsNumIsZero, &propsNumNotZero); + Bind(&propsNumIsZero); + Jump(&afterLoop); + Bind(&propsNumNotZero); + GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo); + GateRef keyInProperty = Load(VariableType::JS_ANY(), elementAddr, + PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(panda::ecmascript::Properties)))); + Label equal(env); + Label notEqual(env); + Label afterEqualCon(env); + Branch(Equal(keyInProperty, key), &equal, ¬Equal); + Bind(&equal); + result = *i; Jump(&exit); - Bind(&exceedUpper); - Jump(&afterExceedCon); + Bind(¬Equal); + Jump(&afterEqualCon); + Bind(&afterEqualCon); + i = Int32Add(*i, Int32(1)); + Branch(Int32UnsignedLessThan(*i, propsNum), &loopEnd, &afterLoop); + Bind(&loopEnd); + LoopEnd(&loopHead); + } + Bind(&afterLoop); + result = Int32(-1); + Jump(&exit); + } + Bind(&exceedUpper); + Label find(env); + Label notFind(env); + GateRef cache = GetPropertiesCache(glue); + GateRef index = GetIndexFromPropertiesCache(glue, cache, hclass, key); + Branch(Int32Equal(index, Int32(PropertiesCache::NOT_FOUND)), ¬Find, &find); + Bind(¬Find); + { + result = BinarySearch(glue, layoutInfo, key, propsNum); + SetToPropertiesCache(glue, cache, hclass, key, *result); + Jump(&exit); + } + Bind(&find); + { + result = index; + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::GetIndexFromPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key) +{ + auto env = GetEnvironment(); + Label subentry(env); + env->SubCfgEntry(&subentry); + DEFVARIABLE(result, VariableType::INT32(), Int32(PropertiesCache::NOT_FOUND)); + + Label exit(env); + Label find(env); + GateRef hash = HashFromHclassAndKey(glue, cls, key); + GateRef prop = + PtrAdd(cache, PtrMul(ZExtInt32ToPtr(hash), IntPtr(PropertiesCache::PropertyKey::GetPropertyKeySize()))); + GateRef propHclass = + Load(VariableType::JS_POINTER(), prop, IntPtr(PropertiesCache::PropertyKey::GetHclassOffset())); + GateRef propKey = Load(VariableType::JS_ANY(), prop, IntPtr(PropertiesCache::PropertyKey::GetKeyOffset())); + GateRef hclassIsEqual = IntPtrEqual(cls, propHclass); + GateRef keyIsEqual = IntPtrEqual(key, propKey); + Branch(BoolAnd(hclassIsEqual, keyIsEqual), &find, &exit); + Bind(&find); + { + result = Load(VariableType::INT32(), prop, IntPtr(PropertiesCache::PropertyKey::GetResultsOffset())); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::BinarySearch(GateRef glue, GateRef layoutInfo, GateRef key, GateRef propsNum) +{ + auto env = GetEnvironment(); + Label subentry(env); + env->SubCfgEntry(&subentry); + DEFVARIABLE(low, VariableType::INT32(), Int32(0)); + Label exit(env); + GateRef elements = GetExtractLengthOfTaggedArray(layoutInfo); + DEFVARIABLE(high, VariableType::INT32(), Int32Sub(elements, Int32(1))); + DEFVARIABLE(result, VariableType::INT32(), Int32(-1)); + DEFVARIABLE(mid, VariableType::INT32(), Int32(-1)); + + GateRef keyHash = GetKeyHashCode(glue, key); + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Label midGreaterKey(env); + Label midnotGreaterKey(env); + Label midLessKey(env); + Label midEqualKey(env); + Label next(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int32LessThanOrEqual(*low, *high), &next, &exit); + Bind(&next); + mid = Int32Add(*low, Int32Div(Int32Sub(*high, *low), Int32(2))); // 2: half + GateRef midKey = GetSortedKey(layoutInfo, *mid); + GateRef midHash = GetKeyHashCode(glue, midKey); + Branch(Int32UnsignedGreaterThan(midHash, keyHash), &midGreaterKey, &midnotGreaterKey); + Bind(&midGreaterKey); + { + high = Int32Sub(*mid, Int32(1)); + Jump(&loopEnd); + } + Bind(&midnotGreaterKey); + { + Branch(Int32UnsignedLessThan(midHash, keyHash), &midLessKey, &midEqualKey); + Bind(&midLessKey); + { + low = Int32Add(*mid, Int32(1)); + Jump(&loopEnd); + } + Bind(&midEqualKey); + { + Label retIndex(env); + Label nextLoop(env); + DEFVARIABLE(sortIndex, VariableType::INT32(), GetSortedIndex(layoutInfo, *mid)); + DEFVARIABLE(currentKey, VariableType::JS_ANY(), midKey); + Branch(IntPtrEqual(midKey, key), &retIndex, &nextLoop); + Bind(&retIndex); + { + Label retSortIndex(env); + Branch(Int32LessThan(*sortIndex, propsNum), &retSortIndex, &exit); + Bind(&retSortIndex); + { + result = *sortIndex; + Jump(&exit); + } + } + Bind(&nextLoop); + { + DEFVARIABLE(midLeft, VariableType::INT32(), *mid); + DEFVARIABLE(midRight, VariableType::INT32(), *mid); + Label loopHead1(env); + Label loopEnd1(env); + Label afterLoop1(env); + Label nextCount(env); + Jump(&loopHead1); + LoopBegin(&loopHead1); + { + Branch(Int32GreaterThanOrEqual(Int32Sub(*midLeft, Int32(1)), Int32(0)), + &nextCount, &afterLoop1); + Bind(&nextCount); + { + Label hashEqual(env); + midLeft = Int32Sub(*midLeft, Int32(1)); + sortIndex = GetSortedIndex(layoutInfo, *midLeft); + currentKey = GetKey(layoutInfo, *sortIndex); + Branch(Int32Equal(GetKeyHashCode(glue, *currentKey), keyHash), &hashEqual, &afterLoop1); + Bind(&hashEqual); + { + Label retIndex1(env); + Branch(IntPtrEqual(*currentKey, key), &retIndex1, &loopEnd1); + Bind(&retIndex1); + { + Label retSortIndex(env); + Branch(Int32LessThan(*sortIndex, propsNum), &retSortIndex, &exit); + Bind(&retSortIndex); + { + result = *sortIndex; + Jump(&exit); + } + } + } + } + Bind(&loopEnd1); + { + LoopEnd(&loopHead1); + } + } + Bind(&afterLoop1); + { + Label loopHead2(env); + Label loopEnd2(env); + Label nextCount1(env); + Jump(&loopHead2); + LoopBegin(&loopHead2); + { + Branch(Int32LessThan(Int32Add(*midRight, Int32(1)), elements), &nextCount1, &exit); + Bind(&nextCount1); + { + Label hashEqual(env); + midRight = Int32Add(*midRight, Int32(1)); + sortIndex = GetSortedIndex(layoutInfo, *midRight); + currentKey = GetKey(layoutInfo, *sortIndex); + Branch(Int32Equal(GetKeyHashCode(glue, *currentKey), keyHash), &hashEqual, &exit); + Bind(&hashEqual); + { + Label retIndex2(env); + Branch(IntPtrEqual(*currentKey, key), &retIndex2, &loopEnd2); + Bind(&retIndex2); + { + Label retSortIndex(env); + Branch(Int32LessThan(*sortIndex, propsNum), &retSortIndex, &exit); + Bind(&retSortIndex); + { + result = *sortIndex; + Jump(&exit); + } + } + } + } + Bind(&loopEnd2); + { + LoopEnd(&loopHead2); + } + } + } + } + } + } + } + + Bind(&loopEnd); + { + LoopEnd(&loopHead); + } + + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef StubBuilder::GetKeyHashCode(GateRef glue, GateRef key) +{ + auto env = GetEnvironment(); + Label subentry(env); + env->SubCfgEntry(&subentry); + DEFVARIABLE(result, VariableType::INT32(), Int32(-1)); + + Label exit(env); + Label isString(env); + Label isSymblo(env); + Branch(TaggedIsString(key), &isString, &isSymblo); + Bind(&isString); + { + result = GetHashcodeFromString(glue, key); + Jump(&exit); + } + Bind(&isSymblo); + { + result = GetInt32OfTInt(Load(VariableType::INT64(), key, + IntPtr(JSSymbol::HASHFIELD_OFFSET))); + Jump(&exit); } - Bind(&afterExceedCon); - result = CallNGCRuntime(glue, RTSTUB_ID(FindElementWithCache), { glue, hclass, key, propsNum }); - Jump(&exit); Bind(&exit); auto ret = *result; env->SubCfgExit(); @@ -5806,7 +6028,7 @@ GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value) Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit); Bind(&noRawHashcode); { - hashcode = GetInt32OfTInt(CallRuntime(glue, RTSTUB_ID(ComputeHashcode), { value })); + hashcode = CallNGCRuntime(glue, RTSTUB_ID(ComputeHashcode), { value }); Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode); Jump(&exit); } diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 8e71a76d67..84b45130b7 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -146,6 +146,7 @@ public: GateRef Load(VariableType type, GateRef base, GateRef offset); GateRef Load(VariableType type, GateRef base); void Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value); + inline void StoreWithNoBarrier(VariableType type, GateRef base, GateRef offset, GateRef value); // arithmetic GateRef TaggedCastToIntPtr(GateRef x); GateRef Int16Add(GateRef x, GateRef y); @@ -708,6 +709,20 @@ public: GateRef RemoveTaggedWeakTag(GateRef weak); inline GateRef LoadHCIndexFromConstPool(GateRef cachedArray, GateRef cachedLength, GateRef traceId, Label *miss); inline GateRef LoadHCIndexInfosFromConstPool(GateRef jsFunc); + inline GateRef GetPropertiesCache(GateRef glue); + GateRef GetIndexFromPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key); + inline void SetToPropertiesCache(GateRef glue, GateRef cache, GateRef cls, GateRef key, GateRef result); + GateRef HashFromHclassAndKey(GateRef glue, GateRef cls, GateRef key); + GateRef GetKeyHashCode(GateRef glue, GateRef key); + inline GateRef GetSortedKey(GateRef layoutInfo, GateRef index); + inline GateRef GetSortedIndex(GateRef layoutInfo, GateRef index); + inline GateRef GetSortedIndex(GateRef attr); + inline GateRef GetAttrIndex(GateRef index); + inline GateRef GetAttr(GateRef layoutInfo, GateRef index); + inline GateRef GetKey(GateRef layoutInfo, GateRef index); + inline GateRef GetKeyIndex(GateRef index); + GateRef BinarySearch(GateRef glue, GateRef layoutInfo, GateRef key, GateRef propsNum); + private: using BinaryOperation = std::function; GateRef ChangeTaggedPointerToInt64(GateRef x); diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index e4d177d2f6..08a1a41148 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -470,6 +470,7 @@ private: NO_MOVE_SEMANTIC(EcmaContext); NO_COPY_SEMANTIC(EcmaContext); + PropertiesCache *propertiesCache_ {nullptr}; JSThread *thread_ {nullptr}; EcmaVM *vm_ {nullptr}; @@ -538,7 +539,6 @@ private: JSTaggedType *frameBase_ {nullptr}; uint64_t stackStart_ {0}; uint64_t stackLimit_ {0}; - PropertiesCache *propertiesCache_ {nullptr}; GlobalEnvConstants globalConst_; // Join Stack static constexpr uint32_t MIN_JOIN_STACK_SIZE = 2; diff --git a/ecmascript/ic/properties_cache.h b/ecmascript/ic/properties_cache.h index 08acede7ef..b266950963 100644 --- a/ecmascript/ic/properties_cache.h +++ b/ecmascript/ic/properties_cache.h @@ -51,6 +51,45 @@ public: } static const int NOT_FOUND = -1; + static const uint32_t CACHE_LENGTH_BIT = 10; + static const uint32_t CACHE_LENGTH = (1U << CACHE_LENGTH_BIT); + static const uint32_t CACHE_LENGTH_MASK = CACHE_LENGTH - 1; + + struct PropertyKey : public base::AlignedStruct { + enum class Index : size_t { + HclassIndex = 0, + KeyIndex, + ResultsIndex, + NumOfMembers + }; + static size_t GetHclassOffset(bool isArch32 = false) + { + return GetOffset(Index::HclassIndex)>(isArch32); + } + + static size_t GetKeyOffset(bool isArch32 = false) + { + return GetOffset(Index::KeyIndex)>(isArch32); + } + + static size_t GetResultsOffset(bool isArch32 = false) + { + return GetOffset(Index::ResultsIndex)>(isArch32); + } + + static size_t GetPropertyKeySize() + { + return static_cast(Index::NumOfMembers) * static_cast(JSTaggedValue::TaggedTypeSize()); + } + + static_assert(static_cast(Index::NumOfMembers) == NumOfTypes); + alignas(EAS) JSHClass *hclass_ {nullptr}; + alignas(EAS) JSTaggedValue key_ {JSTaggedValue::Hole()}; + alignas(EAS) int results_ {NOT_FOUND}; + }; private: PropertiesCache() @@ -63,11 +102,7 @@ private: } ~PropertiesCache() = default; - struct PropertyKey { - JSHClass *hclass_{nullptr}; - JSTaggedValue key_{JSTaggedValue::Hole()}; - int results_{NOT_FOUND}; - }; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) static inline int Hash(JSHClass *cls, JSTaggedValue key) { @@ -76,10 +111,6 @@ private: return static_cast((clsHash ^ keyHash) & CACHE_LENGTH_MASK); } - static const uint32_t CACHE_LENGTH_BIT = 10; - static const uint32_t CACHE_LENGTH = (1U << CACHE_LENGTH_BIT); - static const uint32_t CACHE_LENGTH_MASK = CACHE_LENGTH - 1; - std::array keys_{}; friend class EcmaContext; diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 6f7fe7a722..325e5a3261 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -219,7 +219,7 @@ void JSThread::Iterate(const RootVisitor &visitor, const RootRangeVisitor &range visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.exception_))); } - EcmaContext *tempContext = currentContext_; + EcmaContext *tempContext = glueData_.currentContext_; for (EcmaContext *context : contexts_) { // visit stack roots SwitchCurrentContext(context, true); @@ -611,9 +611,9 @@ void JSThread::PushContext(EcmaContext *context) const_cast(vm_->GetHeap())->WaitAllTasksFinished(); contexts_.emplace_back(context); - if (!currentContext_) { + if (!glueData_.currentContext_) { // The first context in ecma vm. - currentContext_ = context; + glueData_.currentContext_ = context; context->SetFramePointers(const_cast(GetCurrentSPFrame()), const_cast(GetLastLeaveFrame()), const_cast(GetLastFp())); @@ -637,21 +637,21 @@ void JSThread::PushContext(EcmaContext *context) void JSThread::PopContext() { contexts_.pop_back(); - currentContext_ = contexts_.back(); + glueData_.currentContext_ = contexts_.back(); } void JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate) { ASSERT(std::count(contexts_.begin(), contexts_.end(), currentContext)); - currentContext_->SetFramePointers(const_cast(GetCurrentSPFrame()), + glueData_.currentContext_->SetFramePointers(const_cast(GetCurrentSPFrame()), const_cast(GetLastLeaveFrame()), const_cast(GetLastFp())); - currentContext_->SetFrameBase(glueData_.frameBase_); - currentContext_->SetStackLimit(GetStackLimit()); - currentContext_->SetStackStart(GetStackStart()); - currentContext_->SetGlobalEnv(GetGlueGlobalEnv()); - currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_); + glueData_.currentContext_->SetFrameBase(glueData_.frameBase_); + glueData_.currentContext_->SetStackLimit(GetStackLimit()); + glueData_.currentContext_->SetStackStart(GetStackStart()); + glueData_.currentContext_->SetGlobalEnv(GetGlueGlobalEnv()); + glueData_.currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_); SetCurrentSPFrame(currentContext->GetCurrentFrame()); SetLastLeaveFrame(currentContext->GetLeaveFrame()); @@ -668,7 +668,7 @@ void JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterat glueData_.globalConst_ = const_cast(currentContext->GlobalConstants()); } - currentContext_ = currentContext; + glueData_.currentContext_ = currentContext; } bool JSThread::EraseContext(EcmaContext *context) @@ -677,7 +677,7 @@ bool JSThread::EraseContext(EcmaContext *context) bool isCurrentContext = false; auto iter = std::find(contexts_.begin(), contexts_.end(), context); if (*iter == context) { - if (currentContext_ == context) { + if (glueData_.currentContext_ == context) { isCurrentContext = true; } contexts_.erase(iter); @@ -691,7 +691,7 @@ bool JSThread::EraseContext(EcmaContext *context) PropertiesCache *JSThread::GetPropertiesCache() const { - return currentContext_->GetPropertiesCache(); + return glueData_.currentContext_->GetPropertiesCache(); } const GlobalEnvConstants *JSThread::GetFirstGlobalConst() const diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 7ac51833ca..eadaba88e7 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -656,7 +656,8 @@ public: base::AlignedBool, base::AlignedBool, base::AlignedUint32, - JSTaggedValue> { + JSTaggedValue, + base::AlignedPointer> { enum class Index : size_t { BCStubEntriesIndex = 0, ExceptionIndex, @@ -685,6 +686,7 @@ public: IsFrameDroppedIndex, PropertiesGrowStepIndex, EntryFrameDroppedStateIndex, + CurrentContextIndex, NumOfMembers }; static_assert(static_cast(Index::NumOfMembers) == NumOfTypes); @@ -829,6 +831,11 @@ public: return GetOffset(Index::EntryFrameDroppedStateIndex)>(isArch32); } + static size_t GetCurrentContextOffset(bool isArch32) + { + return GetOffset(Index::CurrentContextIndex)>(isArch32); + } + alignas(EAS) BCStubEntries bcStubEntries_; alignas(EAS) JSTaggedValue exception_ {JSTaggedValue::Hole()}; alignas(EAS) JSTaggedValue globalObject_ {JSTaggedValue::Hole()}; @@ -856,6 +863,7 @@ public: alignas(EAS) bool isFrameDropped_ {false}; alignas(EAS) uint32_t propertiesGrowStep_ {PROPERTIES_GROW_SIZE}; alignas(EAS) uint64_t entryFrameDroppedState_ {FrameDroppedState::StateFalse}; + alignas(EAS) EcmaContext *currentContext_ {nullptr}; }; STATIC_ASSERT_EQ_ARCH(sizeof(GlueData), GlueData::SizeArch32, GlueData::SizeArch64); @@ -864,7 +872,7 @@ public: EcmaContext *GetCurrentEcmaContext() const { - return currentContext_; + return glueData_.currentContext_; } void SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate = false); @@ -888,7 +896,7 @@ private: } void SetCurrentEcmaContext(EcmaContext *context) { - currentContext_ = context; + glueData_.currentContext_ = context; } void SetArrayHClassIndexMap(const CMap &map) @@ -945,7 +953,6 @@ private: CMap arrayHClassIndexMap_; CVector contexts_; - EcmaContext *currentContext_ {nullptr}; friend class GlobalHandleCollection; friend class EcmaVM; friend class EcmaContext; diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 7d5d223818..10d046e9ea 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -152,14 +152,6 @@ DEF_RUNTIME_STUBS(GetHash32) return JSTaggedValue(static_cast(result)).GetRawData(); } -DEF_RUNTIME_STUBS(ComputeHashcode) -{ - JSTaggedType ecmaString = GetTArg(argv, argc, 0); // 0: means the zeroth parameter - auto string = reinterpret_cast(ecmaString); - uint32_t result = EcmaStringAccessor(string).ComputeHashcode(0); - return JSTaggedValue(static_cast(result)).GetRawData(); -} - void RuntimeStubs::PrintHeapReginInfo(uintptr_t argGlue) { auto thread = JSThread::GlueToJSThread(argGlue); @@ -2646,6 +2638,13 @@ void RuntimeStubs::EndCallTimer(uintptr_t argGlue, JSTaggedType func) callTimer->StopCount(method); } +uint32_t RuntimeStubs::ComputeHashcode(JSTaggedType ecmaString) +{ + auto string = reinterpret_cast(ecmaString); + uint32_t result = EcmaStringAccessor(string).ComputeHashcode(0); + return result; +} + DEF_RUNTIME_STUBS(FastStringify) { RUNTIME_STUBS_HEADER(FastStringify); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 7d7b75db91..ab4a504375 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -127,6 +127,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(StartCallTimer) \ V(EndCallTimer) \ V(BigIntSameValueZero) \ + V(ComputeHashcode) \ V(JSHClassFindProtoTransitions) #define RUNTIME_STUB_WITH_GC_LIST(V) \ @@ -137,7 +138,6 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(CallGetPrototype) \ V(ThrowTypeError) \ V(GetHash32) \ - V(ComputeHashcode) \ V(GetTaggedArrayPtrTest) \ V(NewInternalString) \ V(NewTaggedArray) \ @@ -409,6 +409,7 @@ public: static JSTaggedValue RuntimeArraySort(JSThread *thread, JSHandle thisHandle); static JSTaggedValue CallBoundFunction(EcmaRuntimeCallInfo *info); + static uint32_t ComputeHashcode(JSTaggedType ecmaString); private: static void DumpToStreamWithHint(std::ostream &out, std::string_view prompt, JSTaggedValue value); static void PrintHeapReginInfo(uintptr_t argGlue); From 6c330e6ca567aef69f78cf8fd5e30180b445265f Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Fri, 20 Oct 2023 10:30:57 +0800 Subject: [PATCH 50/50] Add Debugger UnitTest framework modify some code lint Issue: https://gitee.com/openharmony/arkcompiler_toolchain/issues/I89IL1 Signed-off-by: wengchangcheng Change-Id: I5add83c69bdce7bcf9d98a810165b429881cf37e --- ecmascript/dfx/hprof/tests/heap_sampling_test.cpp | 2 +- ecmascript/js_object.cpp | 1 + ecmascript/jspandafile/debug_info_extractor.h | 5 +++-- ecmascript/napi/jsnapi.cpp | 3 ++- ecmascript/tests/test_helper.h | 7 ------- test/test_helper.gni | 3 +-- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/ecmascript/dfx/hprof/tests/heap_sampling_test.cpp b/ecmascript/dfx/hprof/tests/heap_sampling_test.cpp index 1e88b11098..e50be1f3d7 100644 --- a/ecmascript/dfx/hprof/tests/heap_sampling_test.cpp +++ b/ecmascript/dfx/hprof/tests/heap_sampling_test.cpp @@ -94,7 +94,7 @@ HWTEST_F_L0(HeapSamplingTest, ImplementSampling) int stackDepth = 128; // default depth std::unique_ptr heapSampling = std::make_unique(instance, const_cast(instance->GetHeap()), samplingInterval, stackDepth); - int size = 1 << 15; // default size + size_t size = 1U << 15U; // default size Address addr = 0; heapSampling->ImplementSampling(addr, size); const SamplingInfo *result = heapSampling->GetAllocationProfile(); diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 3165bd6a47..1163431e95 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -2206,6 +2206,7 @@ JSTaggedValue JSObject::TryGetEnumCache(JSThread *thread, JSTaggedValue obj) break; case EnumCacheKind::PROTOCHAIN: isEnumCacheValid = IsEnumCacheWithProtoChainInfoValid(obj); + break; default: break; } diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h index 1c854f1456..9450ac90c2 100644 --- a/ecmascript/jspandafile/debug_info_extractor.h +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -109,10 +109,11 @@ public: CVector methodIds; panda_file::ClassDataAccessor cda(pandaFile, id); CString recordName = JSPandaFile::ParseEntryPoint(utf::Mutf8AsCString(cda.GetDescriptor())); - // the recordName for testcases is empty + // Check record name in stage mode if (!jsPandaFile_->IsBundlePack()) { + // the recordName for testcases is empty if (!debugRecordName.empty()) { - auto iter = debugRecordName.find(std::string(recordName)); + auto iter = debugRecordName.find(std::string(recordName.c_str())); if (iter == debugRecordName.end()) { continue; } diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 931044a788..1bf5d83f5d 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -443,6 +443,7 @@ bool JSNApi::StartDebugger([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const D } auto handle = panda::os::library_loader::Load(std::string(option.libraryPath)); if (!handle) { + LOG_ECMA(ERROR) << "[StartDebugger] Load library fail: " << option.libraryPath << " " << errno; return false; } @@ -451,7 +452,7 @@ bool JSNApi::StartDebugger([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const D auto sym = panda::os::library_loader::ResolveSymbol(handle.Value(), "StartDebug"); if (!sym) { - LOG_ECMA(ERROR) << sym.Error().ToString(); + LOG_ECMA(ERROR) << "[StartDebugger] Resolve symbol fail: " << sym.Error().ToString(); return false; } diff --git a/ecmascript/tests/test_helper.h b/ecmascript/tests/test_helper.h index 372eb765c2..171f82701c 100644 --- a/ecmascript/tests/test_helper.h +++ b/ecmascript/tests/test_helper.h @@ -117,8 +117,6 @@ public: ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); scope = new EcmaHandleScope(thread); - auto globalEnv = instance->GetGlobalEnv(); - methodFunction_ = instance->GetFactory()->NewJSFunction(globalEnv); } static inline void DestroyEcmaVMWithScope(EcmaVM *instance, EcmaHandleScope *scope) @@ -126,13 +124,8 @@ public: delete scope; scope = nullptr; instance->SetEnableForceGC(false); - auto thread = instance->GetJSThread(); - thread->ClearException(); JSNApi::DestroyJSVM(instance); } - -private: - inline static ecmascript::JSHandle methodFunction_; }; } // namespace panda::test #endif // ECMASCRIPT_TESTS_TEST_HELPER_H diff --git a/test/test_helper.gni b/test/test_helper.gni index 677c52cbf2..3d2ef5aaff 100644 --- a/test/test_helper.gni +++ b/test/test_helper.gni @@ -99,8 +99,7 @@ template("host_unittest_action") { rebase_path("${clang_base_path}/lib/${musl_arch}-linux-ohos", root_build_dir), "--qemu-binary-path", - rebase_path("${QEMU_INSTALLATION_PATH}/bin/qemu-${musl_arch}", - root_build_dir), + "${QEMU_INSTALLATION_PATH}/bin/qemu-${musl_arch}", "--qemu-ld-prefix", rebase_path(musl_linker_so_out_dir, root_build_dir), "--timeout-limit",