From 8e4768226fc4f17061a0f39fb9cae9fd6e7c304a Mon Sep 17 00:00:00 2001 From: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Date: Tue, 7 Nov 2023 10:28:12 +0800 Subject: [PATCH 01/44] speed array.concat() by ir Change-Id: I8f67e1cb7545b3128d3a0ac98bf8ed0f5cca333b Signed-off-by: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue --- .../builtins/builtins_array_stub_builder.cpp | 156 +++++++++++++++--- .../builtins/builtins_array_stub_builder.h | 2 + .../builtins/builtins_string_stub_builder.cpp | 2 +- .../compiler/builtins/builtins_stubs.cpp | 2 +- ecmascript/compiler/stub_builder-inl.h | 19 --- ecmascript/compiler/stub_builder.cpp | 29 ++++ ecmascript/compiler/stub_builder.h | 2 +- ecmascript/stubs/runtime_stubs.cpp | 10 ++ ecmascript/stubs/runtime_stubs.h | 3 +- test/moduletest/arrayConcat/BUILD.gn | 18 ++ test/moduletest/arrayConcat/arrayConcat.js | 18 ++ test/moduletest/arrayConcat/expect_output.txt | 14 ++ 12 files changed, 225 insertions(+), 50 deletions(-) create mode 100644 test/moduletest/arrayConcat/BUILD.gn create mode 100644 test/moduletest/arrayConcat/arrayConcat.js create mode 100644 test/moduletest/arrayConcat/expect_output.txt diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 469bcf6083..deb2414560 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -26,35 +26,98 @@ void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef n Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); - Label thisIsEmpty(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) At most one argument; - // (3) all the arguments (if exists) are empty arrays. - JsArrayRequirements reqThisValue; - reqThisValue.defaultConstructor = true; - Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, reqThisValue), &thisIsEmpty, slowPath); - Bind(&thisIsEmpty); + Label isExtensible(env); + Branch(HasConstructor(thisValue), slowPath, &isExtensible); + Bind(&isExtensible); + Label numArgsOne(env); + Branch(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath); + Bind(&numArgsOne); + GateRef arg0 = GetCallArg0(numArgs); + Label allEcmaObject(env); + Label allStableJsArray(env); + GateRef isThisEcmaObject = IsEcmaObject(thisValue); + GateRef isArgEcmaObject = IsEcmaObject(arg0); + Branch(BoolAnd(isThisEcmaObject, isArgEcmaObject), &allEcmaObject, slowPath); + Bind(&allEcmaObject); + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + GateRef isArgStableJSArray = IsStableJSArray(glue, arg0); + Branch(BoolAnd(isThisStableJSArray, isArgStableJSArray), &allStableJsArray, slowPath); + Bind(&allStableJsArray); + GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX); + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0)); + GateRef sumArrayLen = Int64Add(argLen, thisLen); + Label notOverFlow(env); + Branch(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, ¬OverFlow); + Bind(¬OverFlow); + Label spreadable(env); + Label argspreadable(env); + GateRef isSpreadable = IsConcatSpreadable(glue, thisValue); + Branch(isSpreadable, &spreadable, slowPath); + Bind(&spreadable); + GateRef argisSpreadable = IsConcatSpreadable(glue, arg0); + Branch(argisSpreadable, &argspreadable, slowPath); + Bind(&argspreadable); + // new array + Label setProperties(env); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen); + Branch(TaggedIsException(newArray), exit, &setProperties); + Bind(&setProperties); + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(sumArrayLen)); + GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); + SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); + SetExtensibleToBitfield(glue, newArray, true); + GateRef thisEles = GetElementsArray(thisValue); + GateRef argEles = GetElementsArray(arg0); + GateRef newArrayEles = GetElementsArray(newArray); + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(j, VariableType::INT64(), Int64(0)); + DEFVARIABLE(k, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); { - Label atMostOneArg(env); - Label argValIsEmpty(env); - GateRef numArgsAsInt32 = TruncPtrToInt32(numArgs); - Branch(Int32LessThanOrEqual(numArgsAsInt32, Int32(1)), &atMostOneArg, slowPath); - Bind(&atMostOneArg); - { - Label exactlyOneArg(env); - Branch(Int32Equal(numArgsAsInt32, Int32(0)), &argValIsEmpty, &exactlyOneArg); - Bind(&exactlyOneArg); - GateRef argVal = GetCallArg0(numArgs); - JsArrayRequirements reqArgVal; - Branch(IsJsArrayWithLengthLimit(glue, argVal, MAX_LENGTH_ZERO, reqArgVal), &argValIsEmpty, slowPath); - // Creates an empty array on fast path - Bind(&argValIsEmpty); - NewObjectStubBuilder newBuilder(this); - result->WriteVariable(newBuilder.CreateEmptyArray(glue)); - Jump(exit); - } + Branch(Int64LessThan(*i, thisLen), &next, &loopExit); + Bind(&next); + GateRef ele = GetValueFromTaggedArray(thisEles, *i); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); + Jump(&loopEnd); + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + j = Int64Add(*j, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Label loopHead1(env); + Label loopEnd1(env); + Label next1(env); + Label loopExit1(env); + Jump(&loopHead1); + LoopBegin(&loopHead1); + { + Branch(Int64LessThan(*k, argLen), &next1, &loopExit1); + Bind(&next1); + GateRef ele = GetValueFromTaggedArray(argEles, *k); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); + Jump(&loopEnd1); } + Bind(&loopEnd1); + k = Int64Add(*k, Int64(1)); + j = Int64Add(*j, Int64(1)); + LoopEnd(&loopHead1); + Bind(&loopExit1); + result->WriteVariable(newArray); + Jump(exit); } void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef numArgs, @@ -292,4 +355,43 @@ void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue, result->WriteVariable(IntToTaggedPtr(newLength)); Jump(exit); } + +GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(result, VariableType::BOOL(), False()); + Label exit(env); + Label isEcmaObj(env); + Branch(IsEcmaObject(obj), &isEcmaObj, &exit); + Bind(&isEcmaObj); + { + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + GateRef isConcatsprKey = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX); + GateRef spreadable = FastGetPropertyByValue(glue, obj, isConcatsprKey, ProfileOperation()); + Label isDefined(env); + Label isUnDefined(env); + Branch(TaggedIsUndefined(spreadable), &isUnDefined, &isDefined); + Bind(&isUnDefined); + { + Label IsArray(env); + Branch(IsJsArray(obj), &IsArray, &exit); + Bind(&IsArray); + result = True(); + Jump(&exit); + } + Bind(&isDefined); + { + result = TaggedIsTrue(spreadable); + Jump(&exit); + } + } + Bind(&exit); + auto res = *result; + env->SubCfgExit(); + return res; +} + } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_array_stub_builder.h index e95eaf5f4d..09e2ab0d09 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.h @@ -53,6 +53,8 @@ public: void Push(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); + + GateRef IsConcatSpreadable(GateRef glue, GateRef obj); private: static constexpr uint32_t MAX_LENGTH_ZERO = 0; static constexpr uint32_t MAX_LENGTH_ONE = 1; diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp index 3b75466115..dac63e145b 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp @@ -1866,7 +1866,7 @@ void BuiltinsStringStubBuilder::LocaleCompare([[maybe_unused]] GateRef glue, Gat GateRef options = GetCallArg2(numArgs); GateRef localesIsUndef = TaggedIsUndefined(locales); GateRef optionsIsUndef = TaggedIsUndefined(options); - GateRef cacheable = BoolAnd(BoolOr(localesIsUndef, TaggedObjectIsString(locales)), optionsIsUndef); + GateRef cacheable = BoolAnd(BoolOr(localesIsUndef, TaggedIsString(locales)), optionsIsUndef); Label optionsIsString(env); Label cacheAble(env); Label uncacheable(env); diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index 231c8c65ab..b8d2cc9433 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -278,7 +278,7 @@ DECLARE_BUILTINS(Array##Method) } #define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ - V(Concat, JS_POINTER) \ + V(Concat, JS_ANY) \ V(Filter, JS_POINTER) \ V(ForEach, JS_ANY) \ V(IndexOf, JS_ANY) \ diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 862baa7a87..7437c972bf 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1147,25 +1147,6 @@ inline GateRef StubBuilder::IsString(GateRef obj) return res; } -inline GateRef StubBuilder::TaggedObjectIsString(GateRef obj) -{ - auto env = GetEnvironment(); - Label entryPass(env); - env->SubCfgEntry(&entryPass); - DEFVARIABLE(result, VariableType::BOOL(), False()); - Label heapObj(env); - Label exit(env); - GateRef isHeapObject = TaggedIsHeapObject(obj); - Branch(isHeapObject, &heapObj, &exit); - Bind(&heapObj); - result = env_->GetBuilder()->TaggedObjectIsString(obj); - Jump(&exit); - Bind(&exit); - auto ret = *result; - env->SubCfgExit(); - return ret; -} - inline GateRef StubBuilder::IsLineString(GateRef obj) { GateRef objectType = GetObjectType(LoadHClass(obj)); diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index c081a961f6..86e76f14a4 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -4049,6 +4049,35 @@ GateRef StubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef i return ret; } +GateRef StubBuilder::FastGetPropertyByValue(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback) +{ + 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 = GetPropertyByValue(glue, obj, key, callback); + Label notHole(env); + Branch(TaggedIsHole(*result), &slowPath, &exit); + } + Bind(&slowPath); + { + result = CallRuntime(glue, RTSTUB_ID(LoadICByValue), + { Undefined(), obj, key, IntToTaggedInt(Int32(0)) }); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + void StubBuilder::FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, GateRef value, ProfileOperation callback) { diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 7c095caafe..e6ab87ba1a 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -310,7 +310,6 @@ public: GateRef IsEcmaObject(GateRef obj); GateRef IsSymbol(GateRef obj); GateRef IsString(GateRef obj); - GateRef TaggedObjectIsString(GateRef obj); GateRef IsLineString(GateRef obj); GateRef IsSlicedString(GateRef obj); GateRef IsConstantString(GateRef obj); @@ -576,6 +575,7 @@ public: GateRef GetPropertyByName(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback); GateRef FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback); GateRef FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback); + GateRef FastGetPropertyByValue(GateRef glue, GateRef obj, GateRef key, 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()); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 86efe08050..ea88905adf 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2840,6 +2840,16 @@ DEF_RUNTIME_STUBS(ArrayForEachContinue) return JSTaggedValue::Undefined().GetRawData(); } +DEF_RUNTIME_STUBS(GetConcatSpreadable) +{ + RUNTIME_STUBS_HEADER(GetConcatSpreadable); + JSHandle obj = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + if (ArrayHelper::IsConcatSpreadable(thread, obj)) { + return JSTaggedValue::VALUE_TRUE; + } + return JSTaggedValue::VALUE_FALSE; +} + 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 073aef2e19..a3b15e605c 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -339,7 +339,8 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(JSObjectGrowElementsCapacity) \ V(HClassCloneWithAddProto) \ V(LocaleCompareWithGc) \ - V(ArrayForEachContinue) + V(ArrayForEachContinue) \ + V(GetConcatSpreadable) #define RUNTIME_STUB_LIST(V) \ RUNTIME_ASM_STUB_LIST(V) \ diff --git a/test/moduletest/arrayConcat/BUILD.gn b/test/moduletest/arrayConcat/BUILD.gn new file mode 100644 index 0000000000..6534cb4358 --- /dev/null +++ b/test/moduletest/arrayConcat/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("arrayConcat") { + deps = [] +} diff --git a/test/moduletest/arrayConcat/arrayConcat.js b/test/moduletest/arrayConcat/arrayConcat.js new file mode 100644 index 0000000000..69e492d2d3 --- /dev/null +++ b/test/moduletest/arrayConcat/arrayConcat.js @@ -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. + */ +const array1 = ['a', 'b', 'c']; +const array2 = ['d', 'e', 'f']; +const array3 = array1.concat(array2); +print(array3); diff --git a/test/moduletest/arrayConcat/expect_output.txt b/test/moduletest/arrayConcat/expect_output.txt new file mode 100644 index 0000000000..03d227dd03 --- /dev/null +++ b/test/moduletest/arrayConcat/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. + +a,b,c,d,e,f -- Gitee From c31b1b2a7aa1fb8e1450f981e8404dad240083a1 Mon Sep 17 00:00:00 2001 From: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Date: Thu, 16 Nov 2023 17:26:07 +0800 Subject: [PATCH 02/44] speed Values() and reverse() Signed-off-by: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Change-Id: I15dc813a01e2f2780a592dac384381d1f8df0930 --- ecmascript/builtins/builtins_array.h | 2 +- .../builtins/builtins_array_stub_builder.cpp | 57 ++++++++++++++++--- .../builtins/builtins_array_stub_builder.h | 3 + .../builtins/builtins_call_signature.h | 1 + .../compiler/builtins/builtins_stubs.cpp | 1 + 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/ecmascript/builtins/builtins_array.h b/ecmascript/builtins/builtins_array.h index 82fba75e48..112e03f067 100644 --- a/ecmascript/builtins/builtins_array.h +++ b/ecmascript/builtins/builtins_array.h @@ -107,7 +107,7 @@ /* Array.prototype.unshift ( ...items ) */ \ V("unshift", Unshift, 1, INVALID) \ /* Array.prototype.values ( ) */ \ - V("values", Values, 0, INVALID) \ + V("values", Values, 0, ArrayValues) \ /* Array.prototype.with ( index, value ) */ \ V("with", With, 2, INVALID) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 469bcf6083..28ce940ad4 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -168,17 +168,45 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu } // Note: unused arguments are reserved for further development -void BuiltinsArrayStubBuilder::Reverse([[maybe_unused]] GateRef glue, GateRef thisValue, - [[maybe_unused]] GateRef numArgs, +void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); - Label thisIsEmpty(env); - // Fast path is this is an array of length 0 or 1 - JsArrayRequirements req; - Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ONE, req), &thisIsEmpty, slowPath); - Bind(&thisIsEmpty); - // Returns thisValue on fast path + Label stableJSArray(env); + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + Branch(isThisStableJSArray, &stableJSArray, slowPath); + Bind(&stableJSArray); + + GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef elements = GetElementsArray(thisValue); + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(j, VariableType::INT64(), Int64Sub(thisArrLen, Int64(1))); + + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label arrayValue(env); + Label valueEqual(env); + Branch(Int64LessThan(*i, *j), &next, &loopExit); + Bind(&next); + { + GateRef lower = GetValueFromTaggedArray(elements, *i); + GateRef upper = GetValueFromTaggedArray(elements, *j); + + SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, *i, upper); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, *j, lower); + Jump(&loopEnd); + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + j = Int64Sub(*j, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); result->WriteVariable(thisValue); Jump(exit); } @@ -292,4 +320,17 @@ void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue, result->WriteVariable(IntToTaggedPtr(newLength)); Jump(exit); } + +void BuiltinsArrayStubBuilder::Values(GateRef glue, GateRef thisValue, + [[maybe_unused]] GateRef numArgs, [[maybe_unused]] Variable *result, [[maybe_unused]] Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + GateRef iter = GetIterator(glue, thisValue, ProfileOperation()); + result->WriteVariable(iter); + Jump(exit); +} + } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_array_stub_builder.h index e95eaf5f4d..e3d90d10a4 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.h @@ -53,6 +53,9 @@ public: void Push(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); + + void Values(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath); private: static constexpr uint32_t MAX_LENGTH_ZERO = 0; static constexpr uint32_t MAX_LENGTH_ONE = 1; diff --git a/ecmascript/compiler/builtins/builtins_call_signature.h b/ecmascript/compiler/builtins/builtins_call_signature.h index 82f7ad4160..6bf62ff0b6 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.h +++ b/ecmascript/compiler/builtins/builtins_call_signature.h @@ -65,6 +65,7 @@ namespace panda::ecmascript::kungfu { V(ArrayIndexOf) \ V(ArrayLastIndexOf) \ V(ArraySlice) \ + V(ArrayValues) \ V(ArrayReverse) \ V(ArrayPush) \ V(SetClear) \ diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index 231c8c65ab..9a690b6c7c 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -278,6 +278,7 @@ DECLARE_BUILTINS(Array##Method) } #define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ + V(Values, JS_POINTER) \ V(Concat, JS_POINTER) \ V(Filter, JS_POINTER) \ V(ForEach, JS_ANY) \ -- Gitee From 92d230bc55de2c6f9c540626f28fd2ee7bd45f82 Mon Sep 17 00:00:00 2001 From: yanpeng Date: Tue, 21 Nov 2023 13:51:45 +0800 Subject: [PATCH 03/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8DStringReader::ReadNumbe?= =?UTF-8?q?r()=E5=AF=B9int=E5=80=BC=E7=9A=84=E5=8F=96=E5=80=BC=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E5=88=A4=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I0f6361b3f68d7f6d126230b5103d8d624611eafb Signed-off-by: yanpeng --- ecmascript/date_parse.h | 6 +++--- test/moduletest/regress/expect_output.txt | 9 +++++++++ test/moduletest/regress/regress.js | 12 +++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ecmascript/date_parse.h b/ecmascript/date_parse.h index 86b9fcba55..99e5aab54b 100644 --- a/ecmascript/date_parse.h +++ b/ecmascript/date_parse.h @@ -54,9 +54,9 @@ private: int index = 0; int num = 0; while (IsDigit()) { - // 9 : max decimal of int - if (index < 9) { - num = (value_ - '0') + num * JSDate::TEN; + int n = (value_ - '0') + num * JSDate::TEN; + if (n >= 0 && n < std::numeric_limits::max()) { + num = n; index++; } NextChar(); diff --git a/test/moduletest/regress/expect_output.txt b/test/moduletest/regress/expect_output.txt index 1fe1378d29..2383c312e2 100755 --- a/test/moduletest/regress/expect_output.txt +++ b/test/moduletest/regress/expect_output.txt @@ -132,3 +132,12 @@ true true true true +true +true +true +true +true +true +true +true +true diff --git a/test/moduletest/regress/regress.js b/test/moduletest/regress/regress.js index 8b583e0781..7dbfedbb48 100755 --- a/test/moduletest/regress/regress.js +++ b/test/moduletest/regress/regress.js @@ -304,6 +304,16 @@ print(1283261736000 == Date.parse("2010-08-31T22:35:36+0900")); print(Math.pow(2, 31) == foo(Math.pow(2, 31) - 1)); })(); + // mjsunit/regress/regress-12256.js + const datesList = [{ year: '2021', month: '10', day: '22', hour: '10', minute: '12', second: '32' }, + { year: '2021', month: '8', day: '3', hour: '9', minute: '9', second: '6' }]; + const { year, month, day, hour, minute, second } = datesList[0]; + const s0 = `${year}-${month}-${day} ${hour}:${minute}:${second}Z`; + for (let i = 1; i < 10; i++) { + const s1 = `${'0'.repeat(i) + year}-${month}-${day} ${hour}:${minute}:${second}Z`; + print(new Date(s0).getTime() == new Date(s1).getTime()); + } + // mjsunit/regress/regress-crbug-1262007.js function foo(...args) { class C {} @@ -315,4 +325,4 @@ print(1283261736000 == Date.parse("2010-08-31T22:35:36+0900")); foo() } catch(e) { print(e instanceof TypeError) - } \ No newline at end of file + } -- Gitee From e9bbe9714309d419013185bbca105b03b321ae64 Mon Sep 17 00:00:00 2001 From: yang-19970325 Date: Wed, 8 Nov 2023 10:17:27 +0800 Subject: [PATCH 04/44] Fix router and startability Inconsistent jump behavior Issue:#I87P2Y Signed-off-by: yang-19970325 Change-Id: I47897b5b026f771fd8830d112bdafafe476ddee9 --- ecmascript/napi/include/jsnapi.h | 1 + ecmascript/napi/jsnapi.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 1108186869..2e96c914ce 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -1408,6 +1408,7 @@ public: static bool IsMixedDebugEnabled(const EcmaVM *vm); static void NotifyNativeCalling(const EcmaVM *vm, const void *nativeAddress); static void NotifyNativeReturnJS(const EcmaVM *vm); + static void NotifyLoadModule(const EcmaVM *vm); static void SetDeviceDisconnectCallback(EcmaVM *vm, DeviceDisconnectCallback cb); // Serialize & Deserialize. static void* SerializeValue(const EcmaVM *vm, Local data, Local transfer); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4e6180958d..5e3d5b1665 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -556,6 +556,17 @@ void JSNApi::NotifyNativeReturnJS([[maybe_unused]] const EcmaVM *vm) #endif } +void JSNApi::NotifyLoadModule([[maybe_unused]] const EcmaVM *vm) +{ +#if defined(ECMASCRIPT_SUPPORT_DEBUGGER) + CHECK_HAS_PENDING_EXCEPTION_WITHOUT_RETURN(vm); + // if load module, it needs to check whether clear singlestepper_ + vm->GetJsDebuggerManager()->ClearSingleStepper(); +#else + LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; +#endif +} + void JSNApi::SetDeviceDisconnectCallback(EcmaVM *vm, DeviceDisconnectCallback cb) { vm->SetDeviceDisconnectCallback(cb); -- Gitee From 948ea6b40baa73c4a4a756dc6c72e0592496fbb3 Mon Sep 17 00:00:00 2001 From: lukai Date: Wed, 22 Nov 2023 17:19:19 +0800 Subject: [PATCH 05/44] Register ArkNativeFunctionCallBack directly Remove the middle-level call named "registerCallback" for napi. Issue:https://gitee.com/openharmony/arkui_napi/issues/I8IN1S?from=project-issue Signed-off-by: lukai Change-Id: Icc195388f09a84a3911c80bf30a87bcabc7830e9 --- ecmascript/napi/include/jsnapi.h | 6 ++- ecmascript/napi/jsnapi.cpp | 62 +++++++++++++++++++++------ ecmascript/napi/test/jsnapi_tests.cpp | 2 +- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 1a01f3e0c4..10eb294987 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -772,13 +772,17 @@ public: }; using FunctionCallback = Local(*)(JsiRuntimeCallInfo*); +using InternalFunctionCallback = JSValueRef(*)(JsiRuntimeCallInfo*); class ECMA_PUBLIC_API FunctionRef : public ObjectRef { public: static Local New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter = nullptr, void *data = nullptr, bool callNapi = false, size_t nativeBindingsize = 0); + static Local New(EcmaVM *vm, InternalFunctionCallback nativeFunc, Deleter deleter, + void *data = nullptr, bool callNapi = false, size_t nativeBindingsize = 0); static Local NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi = false, size_t nativeBindingsize = 0); - + static Local NewClassFunction(EcmaVM *vm, InternalFunctionCallback nativeFunc, Deleter deleter, + void *data, bool callNapi = false, size_t nativeBindingsize = 0); Local Call(const EcmaVM *vm, Local thisObj, const Local argv[], int32_t length); Local Constructor(const EcmaVM *vm, const Local argv[], int32_t length); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4e6180958d..6e5d927d99 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -1738,6 +1738,36 @@ Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, return JSNApiHelper::ToLocal(JSHandle(current)); } +Local FunctionRef::New(EcmaVM *vm, InternalFunctionCallback nativeFunc, + Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) +{ + CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); + JSThread *thread = vm->GetJSThread(); + ObjectFactory *factory = vm->GetFactory(); + JSHandle env = vm->GetGlobalEnv(); + JSHandle current(factory->NewJSFunction(env, reinterpret_cast(nativeFunc))); + current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); + current->SetCallNapi(callNapi); + return JSNApiHelper::ToLocal(JSHandle(current)); +} + +static void InitClassFunction(EcmaVM *vm, JSHandle &func, bool callNapi) +{ + JSThread *thread = vm->GetJSThread(); + JSHandle env = vm->GetGlobalEnv(); + auto globalConst = thread->GlobalConstants(); + JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); + func->SetPropertyInlinedProps(thread, JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX, + accessor.GetTaggedValue()); + JSHandle clsPrototype = JSFunction::NewJSFunctionPrototype(thread, func); + clsPrototype->GetClass()->SetClassPrototype(true); + func->SetClassConstructor(true); + JSHandle parent = env->GetFunctionPrototype(); + JSObject::SetPrototype(thread, JSHandle::Cast(func), parent); + func->SetHomeObject(thread, clsPrototype); + func->SetCallNapi(callNapi); +} + Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { @@ -1750,22 +1780,26 @@ Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback na JSHandle current = factory->NewJSFunctionByHClass(reinterpret_cast(Callback::RegisterCallback), hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); - - auto globalConst = thread->GlobalConstants(); - JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); - current->SetPropertyInlinedProps(thread, JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX, - accessor.GetTaggedValue()); - + InitClassFunction(vm, current, callNapi); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize); + Local result = JSNApiHelper::ToLocal(JSHandle(current)); + return scope.Escape(result); +} - JSHandle clsPrototype = JSFunction::NewJSFunctionPrototype(thread, current); - clsPrototype.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassPrototype(true); - JSHandle::Cast(current)->GetTaggedObject()->GetClass()->SetClassConstructor(true); - current->SetClassConstructor(true); - JSHandle parent = env->GetFunctionPrototype(); - JSObject::SetPrototype(thread, JSHandle::Cast(current), parent); - current->SetHomeObject(thread, clsPrototype); - current->SetCallNapi(callNapi); +Local FunctionRef::NewClassFunction(EcmaVM *vm, InternalFunctionCallback nativeFunc, + Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) +{ + CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm); + EscapeLocalScope scope(vm); + JSThread *thread = vm->GetJSThread(); + ObjectFactory *factory = vm->GetFactory(); + JSHandle env = vm->GetGlobalEnv(); + JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); + JSHandle current = + factory->NewJSFunctionByHClass(reinterpret_cast(nativeFunc), + hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); + InitClassFunction(vm, current, callNapi); + current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); Local result = JSNApiHelper::ToLocal(JSHandle(current)); return scope.Escape(result); } diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index f3a4704b38..a624f4a2fa 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -985,7 +985,7 @@ HWTEST_F_L0(JSNApiTests, InheritPrototype_004) HWTEST_F_L0(JSNApiTests, ClassFunction) { LocalScope scope(vm_); - Local cls = FunctionRef::NewClassFunction(vm_, nullptr, nullptr, nullptr); + Local cls = FunctionRef::NewClassFunction(vm_, FunctionCallback, nullptr, nullptr); JSHandle clsObj = JSNApiHelper::ToJSHandle(Local(cls)); ASSERT_TRUE(clsObj->IsClassConstructor()); -- Gitee From ca2538116e8d0b556554f84a2358033d0f147976 Mon Sep 17 00:00:00 2001 From: wupengyong Date: Thu, 23 Nov 2023 16:32:20 +0800 Subject: [PATCH 06/44] Reason:optimize GetRawStringFromStringTable Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8IXVF?from=project-issue Signed-off-by: wupengyong Change-Id: Id2f57c9dab6dcfe7a7321de3e65813a7bb5b763d --- ecmascript/ecma_string-inl.h | 29 +++++++++ ecmascript/ecma_string.h | 10 ++- ecmascript/ecma_string_table.cpp | 102 +++++++++++++++++-------------- ecmascript/ecma_string_table.h | 9 +-- ecmascript/object_factory.cpp | 5 +- 5 files changed, 99 insertions(+), 56 deletions(-) diff --git a/ecmascript/ecma_string-inl.h b/ecmascript/ecma_string-inl.h index c1d82ca8e9..2a255834af 100644 --- a/ecmascript/ecma_string-inl.h +++ b/ecmascript/ecma_string-inl.h @@ -68,6 +68,35 @@ inline EcmaString *EcmaString::CreateFromUtf8(const EcmaVM *vm, const uint8_t *u return string; } +inline EcmaString *EcmaString::CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, + MemSpaceType type) +{ + if (utf16Len == 0) { + return vm->GetFactory()->GetEmptyString().GetObject(); + } + auto string = CreateLineStringWithSpaceType(vm, utf16Len, false, type); + ASSERT(string != nullptr); + auto len = utf::ConvertRegionMUtf8ToUtf16( + utf8Data, string->GetDataUtf16Writable(), utf::Mutf8Size(utf8Data), utf16Len, 0); + if (len < utf16Len) { + string->TrimLineString(vm->GetJSThread(), len); + } + ASSERT_PRINT(false == CanBeCompressed(string), "Bad input canBeCompress!"); + return string; +} + +inline void EcmaString::TrimLineString(const JSThread *thread, uint32_t newLength) +{ + ASSERT(IsLineString()); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + uint32_t oldLength = GetLength(); + ASSERT(oldLength > newLength); + size_t trimBytes = (oldLength - newLength) * (IsUtf8() ? sizeof(uint8_t) : sizeof(uint16_t)); + size_t size = IsUtf8() ? LineEcmaString::ComputeSizeUtf8(newLength) : LineEcmaString::ComputeSizeUtf16(newLength); + factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this)); + SetLength(newLength, CanBeCompressed(this)); +} + inline EcmaString *EcmaString::CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress, MemSpaceType type) { diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index f046900ab0..32906c91b2 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -103,6 +103,8 @@ private: static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE, bool isConstantString = false, uint32_t idOffset = 0); + static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, + MemSpaceType type = MemSpaceType::SEMI_SPACE); static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE); static SlicedString *CreateSlicedString(const EcmaVM *vm, MemSpaceType type = MemSpaceType::SEMI_SPACE); @@ -132,7 +134,7 @@ private: // not change src data structure static inline EcmaString *FastSubUtf16String(const EcmaVM *vm, const JSHandle &src, uint32_t start, uint32_t length); - + inline void TrimLineString(const JSThread *thread, uint32_t newLength); inline bool IsUtf8() const { return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_COMPRESSED; @@ -1030,6 +1032,12 @@ public: return EcmaString::CreateConstantString(vm, utf8Data, length, compressed, type, idOffset); } + static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, + MemSpaceType type = MemSpaceType::SEMI_SPACE) + { + return EcmaString::CreateUtf16StringFromUtf8(vm, utf8Data, utf8Len, type); + } + static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE) { diff --git a/ecmascript/ecma_string_table.cpp b/ecmascript/ecma_string_table.cpp index a468b4ceef..35750327d8 100644 --- a/ecmascript/ecma_string_table.cpp +++ b/ecmascript/ecma_string_table.cpp @@ -25,8 +25,8 @@ namespace panda::ecmascript { EcmaStringTable::EcmaStringTable(const EcmaVM *vm) : vm_(vm) {} -EcmaString *EcmaStringTable::GetString(const JSHandle &firstString, - const JSHandle &secondString) const +std::pair EcmaStringTable::GetString(const JSHandle &firstString, + const JSHandle &secondString) const { ASSERT(EcmaStringAccessor(firstString).NotTreeString()); ASSERT(EcmaStringAccessor(secondString).NotTreeString()); @@ -37,41 +37,41 @@ EcmaString *EcmaStringTable::GetString(const JSHandle &firstString, for (auto item = range.first; item != range.second; ++item) { auto foundString = item->second; if (EcmaStringAccessor(foundString).EqualToSplicedString(*firstString, *secondString)) { - return foundString; + return std::make_pair(foundString, hashCode); } } - return nullptr; + return std::make_pair(nullptr, hashCode); } -EcmaString *EcmaStringTable::GetString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const +std::pair EcmaStringTable::GetString(const uint8_t *utf8Data, + uint32_t utf8Len, bool canBeCompress) const { uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); auto range = table_.equal_range(hashCode); for (auto item = range.first; item != range.second; ++item) { auto foundString = item->second; if (EcmaStringAccessor::StringIsEqualUint8Data(foundString, utf8Data, utf8Len, canBeCompress)) { - return foundString; + return std::make_pair(foundString, hashCode); } } - return nullptr; + return std::make_pair(nullptr, hashCode); } -EcmaString *EcmaStringTable::GetString(const uint16_t *utf16Data, uint32_t utf16Len) const +std::pair EcmaStringTable::GetString(const uint16_t *utf16Data, uint32_t utf16Len) const { uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast(utf16Data), utf16Len); auto range = table_.equal_range(hashCode); for (auto item = range.first; item != range.second; ++item) { auto foundString = item->second; if (EcmaStringAccessor::StringsAreEqualUtf16(foundString, utf16Data, utf16Len)) { - return foundString; + return std::make_pair(foundString, hashCode); } } - return nullptr; + return std::make_pair(nullptr, hashCode); } EcmaString *EcmaStringTable::GetString(EcmaString *string) const { - ASSERT(EcmaStringAccessor(string).NotTreeString()); auto hashcode = EcmaStringAccessor(string).GetHashcode(); auto range = table_.equal_range(hashcode); for (auto item = range.first; item != range.second; ++item) { @@ -106,27 +106,30 @@ EcmaString *EcmaStringTable::GetOrInternString(const JSHandle &first { auto firstFlat = JSHandle(vm_->GetJSThread(), EcmaStringAccessor::Flatten(vm_, firstString)); auto secondFlat = JSHandle(vm_->GetJSThread(), EcmaStringAccessor::Flatten(vm_, secondString)); - EcmaString *concatString = GetString(firstFlat, secondFlat); - if (concatString != nullptr) { - return concatString; + std::pair result = GetString(firstFlat, secondFlat); + if (result.first != nullptr) { + return result.first; } JSHandle concatHandle(vm_->GetJSThread(), EcmaStringAccessor::Concat(vm_, firstFlat, secondFlat, MemSpaceType::OLD_SPACE)); - concatString = EcmaStringAccessor::Flatten(vm_, concatHandle, MemSpaceType::OLD_SPACE); + EcmaString *concatString = EcmaStringAccessor::Flatten(vm_, concatHandle, MemSpaceType::OLD_SPACE); + concatString->SetMixHashcode(result.second); InternString(concatString); return concatString; } EcmaString *EcmaStringTable::GetOrInternString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) { - EcmaString *result = GetString(utf8Data, utf8Len, canBeCompress); - if (result != nullptr) { - return result; + std::pair result = GetString(utf8Data, utf8Len, canBeCompress); + if (result.first != nullptr) { + return result.first; } - result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, MemSpaceType::OLD_SPACE); - InternString(result); - return result; + EcmaString *str = + EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, MemSpaceType::OLD_SPACE); + str->SetMixHashcode(result.second); + InternString(str); + return str; } /* @@ -135,26 +138,29 @@ EcmaString *EcmaStringTable::GetOrInternString(const uint8_t *utf8Data, uint32_t */ EcmaString *EcmaStringTable::CreateAndInternStringNonMovable(const uint8_t *utf8Data, uint32_t utf8Len) { - EcmaString *result = GetString(utf8Data, utf8Len, true); - if (result != nullptr) { - return result; + std::pair result = GetString(utf8Data, utf8Len, true); + if (result.first != nullptr) { + return result.first; } - result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, true, MemSpaceType::NON_MOVABLE); - InternString(result); - return result; + EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, true, MemSpaceType::NON_MOVABLE); + str->SetMixHashcode(result.second); + InternString(str); + return str; } EcmaString *EcmaStringTable::GetOrInternString(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) { - EcmaString *result = GetString(utf16Data, utf16Len); - if (result != nullptr) { - return result; + std::pair result = GetString(utf16Data, utf16Len); + if (result.first != nullptr) { + return result.first; } - result = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, MemSpaceType::OLD_SPACE); - InternString(result); - return result; + EcmaString *str = + EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, MemSpaceType::OLD_SPACE); + str->SetMixHashcode(result.second); + InternString(str); + return str; } EcmaString *EcmaStringTable::GetOrInternString(EcmaString *string) @@ -194,33 +200,35 @@ EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint8_t *utf8D bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset) { - EcmaString *result = GetString(utf8Data, utf8Len, canBeCompress); - if (result != nullptr) { - return result; + std::pair result = GetString(utf8Data, utf8Len, canBeCompress); + if (result.first != nullptr) { + return result.first; } type = type == MemSpaceType::NON_MOVABLE ? MemSpaceType::NON_MOVABLE : MemSpaceType::OLD_SPACE; + EcmaString *str; if (canBeCompress) { // Constant string will be created in this branch. - result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type, isConstantString, + str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type, isConstantString, idOffset); } else { - result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type); + str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type); } - InternString(result); - return result; + str->SetMixHashcode(result.second); + InternString(str); + return str; } -EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint16_t *utf16Data, uint32_t utf16Len, - bool canBeCompress, MemSpaceType type) +EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf16Len, + MemSpaceType type) { - EcmaString *result = GetString(utf16Data, utf16Len); + type = type == MemSpaceType::NON_MOVABLE ? MemSpaceType::NON_MOVABLE : MemSpaceType::OLD_SPACE; + EcmaString *str = EcmaStringAccessor::CreateUtf16StringFromUtf8(vm_, utf8Data, utf16Len, type); + EcmaString *result = GetString(str); if (result != nullptr) { return result; } - type = type == MemSpaceType::NON_MOVABLE ? MemSpaceType::NON_MOVABLE : MemSpaceType::OLD_SPACE; - result = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, type); - InternString(result); - return result; + InternString(str); + return str; } void EcmaStringTable::SweepWeakReference(const WeakRootVisitor &visitor) diff --git a/ecmascript/ecma_string_table.h b/ecmascript/ecma_string_table.h index 3feae6ab77..2d3ae10c16 100644 --- a/ecmascript/ecma_string_table.h +++ b/ecmascript/ecma_string_table.h @@ -41,7 +41,7 @@ public: EcmaString *GetOrInternString(EcmaString *string); EcmaString *GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset); - EcmaString *GetOrInternStringWithSpaceType(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress, + EcmaString *GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type); EcmaString *TryGetInternString(EcmaString *string); @@ -52,9 +52,10 @@ private: NO_COPY_SEMANTIC(EcmaStringTable); NO_MOVE_SEMANTIC(EcmaStringTable); - EcmaString *GetString(const JSHandle &firstString, const JSHandle &secondString) const; - EcmaString *GetString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const; - EcmaString *GetString(const uint16_t *utf16Data, uint32_t utf16Len) const; + std::pair GetString( + const JSHandle &firstString, const JSHandle &secondString) const; + std::pair GetString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const; + std::pair GetString(const uint16_t *utf16Data, uint32_t utf16Len) const; EcmaString *GetString(EcmaString *string) const; void InternString(EcmaString *string); diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 8b4e819389..feeafe6e73 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -2672,10 +2672,7 @@ EcmaString *ObjectFactory::GetRawStringFromStringTable(StringData sd, MemSpaceTy return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(mutf8Data, utf16Len, true, type, isConstantString, idOffset); } - - CVector utf16Data(utf16Len); - auto len = utf::ConvertRegionMUtf8ToUtf16(mutf8Data, utf16Data.data(), utf::Mutf8Size(mutf8Data), utf16Len, 0); - return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(utf16Data.data(), len, false, type); + return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(mutf8Data, utf16Len, type); } JSHandle ObjectFactory::NewPropertyBox(const JSHandle &value) -- Gitee From 538a718a410eb554e9c7e5c964b2411483cb3228 Mon Sep 17 00:00:00 2001 From: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Date: Wed, 15 Nov 2023 09:43:33 +0800 Subject: [PATCH 07/44] speed find() and findIndex() Signed-off-by: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Change-Id: Idddaed1e409a20df17eb3888577095fa304ae5ee --- ecmascript/builtins/builtins_array.h | 4 +- .../builtins/builtins_array_stub_builder.cpp | 192 ++++++++++++++++++ .../builtins/builtins_array_stub_builder.h | 7 + .../builtins/builtins_call_signature.h | 2 + .../compiler/builtins/builtins_stubs.cpp | 2 + test/moduletest/arrayfind/BUILD.gn | 18 ++ test/moduletest/arrayfind/arrayfind.js | 41 ++++ test/moduletest/arrayfind/expect_output.txt | 16 ++ test/moduletest/arrayfindIndex/BUILD.gn | 18 ++ .../arrayfindIndex/arrayfindIndex.js | 28 +++ .../arrayfindIndex/expect_output.txt | 14 ++ 11 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 test/moduletest/arrayfind/BUILD.gn create mode 100644 test/moduletest/arrayfind/arrayfind.js create mode 100644 test/moduletest/arrayfind/expect_output.txt create mode 100644 test/moduletest/arrayfindIndex/BUILD.gn create mode 100644 test/moduletest/arrayfindIndex/arrayfindIndex.js create mode 100644 test/moduletest/arrayfindIndex/expect_output.txt diff --git a/ecmascript/builtins/builtins_array.h b/ecmascript/builtins/builtins_array.h index 18cf335c2c..d54be63100 100644 --- a/ecmascript/builtins/builtins_array.h +++ b/ecmascript/builtins/builtins_array.h @@ -49,9 +49,9 @@ /* Array.prototype.filter ( callbackfn [ , thisArg ] ) */ \ V("filter", Filter, 1, ArrayFilter) \ /* Array.prototype.find ( predicate [ , thisArg ] ) */ \ - V("find", Find, 1, INVALID) \ + V("find", Find, 1, ArrayFind) \ /* Array.prototype.findIndex ( predicate [ , thisArg ] ) */ \ - V("findIndex", FindIndex, 1, INVALID) \ + V("findIndex", FindIndex, 1, ArrayFindIndex) \ /* Array.prototype.findLast ( predicate [ , thisArg ] ) */ \ V("findLast", FindLast, 1, INVALID) \ /* Array.prototype.findLastIndex ( predicate [ , thisArg ] ) */ \ diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index c848dbb884..01bb52b92e 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -221,6 +221,198 @@ GateRef BuiltinsArrayStubBuilder::IsJsArrayWithLengthLimit(GateRef glue, GateRef return ret; } +void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label stableJSArray(env); + + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + Branch(isThisStableJSArray, &stableJSArray, slowPath); + Bind(&stableJSArray); + + GateRef callbackFnHandle = GetCallArg0(numArgs); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObject, slowPath); + Bind(&isHeapObject); + Label callable(env); + Branch(IsCallable(callbackFnHandle), &callable, slowPath); + Bind(&callable); + GateRef argHandle = GetCallArg1(numArgs); + GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + + + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*i, thisArrLen), &next, &loopExit); + Bind(&next); + GateRef thisEles = GetElementsArray(thisValue); + GateRef kValue = GetValueFromTaggedArray(thisEles, *i); + GateRef key = Int64ToTaggedInt(*i); + Label hasException(env); + Label notHasException(env); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { argHandle, kValue, key, thisValue }); + Branch(HasPendingException(glue), &hasException, ¬HasException); + Bind(&hasException); + { + result->WriteVariable(retValue); + Jump(exit); + } + Bind(¬HasException); + { + Label find(env); + Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd); + Bind(&find); + { + result->WriteVariable(kValue); + Jump(exit); + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(exit); +} + + +void BuiltinsArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label stableJSArray(env); + Label notStableJSArray(env); + GateRef callbackFnHandle = GetCallArg0(numArgs); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObject, slowPath); + Bind(&isHeapObject); + Label callable(env); + Branch(IsCallable(callbackFnHandle), &callable, slowPath); + Bind(&callable); + result->WriteVariable(IntToTaggedPtr(Int32(-1))); + GateRef argHandle = GetCallArg1(numArgs); + GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + Branch(isThisStableJSArray, &stableJSArray, ¬StableJSArray); + Bind(&stableJSArray); + { + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*i, thisArrLen), &next, &loopExit); + Bind(&next); + DebugPrint(glue, {thisArrLen}); + GateRef thisEles = GetElementsArray(thisValue); + kValue = GetValueFromTaggedArray(thisEles, *i); + Label isHole(env); + Label notHole(env); + Branch(TaggedIsHole(*kValue), &isHole, ¬Hole); + Bind(&isHole); + { + GateRef res = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + Label resIsHole(env); + Label resNotHole(env); + Branch(TaggedIsHole(res), &resIsHole, &resNotHole); + Bind(&resIsHole); + kValue = Undefined(); + Jump(¬Hole); + Bind(&resNotHole); + kValue = res; + Jump(¬Hole); + } + Bind(¬Hole); + GateRef key = IntToTaggedPtr(*i); + Label hasException(env); + Label notHasException(env); + Label checkStable(env); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { argHandle, *kValue, key, thisValue }); + Branch(TaggedIsException(retValue), &hasException, ¬HasException); + Bind(&hasException); + { + result->WriteVariable(retValue); + Jump(exit); + } + Bind(¬HasException); + { + Label find(env); + Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkStable); + Bind(&find); + { + result->WriteVariable(key); + Jump(exit); + } + } + + Bind(&checkStable); + i = Int64Add(*i, Int64(1)); + Branch(IsStableJSArray(glue, thisValue), &loopEnd, ¬StableJSArray); + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(exit); + } + Bind(¬StableJSArray); + { + DebugPrint(glue, {Int64(999)}); + DEFVARIABLE(j, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*j, thisArrLen), &next, &loopExit); + Bind(&next); + + GateRef thisEles = GetElementsArray(thisValue); + GateRef kValue = GetValueFromTaggedArray(thisEles, *j); + GateRef key = IntToTaggedPtr(*j); + Label hasException(env); + Label notHasException(env); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { argHandle, kValue, key, thisValue }); + Branch(TaggedIsException(retValue), &hasException, ¬HasException); + Bind(&hasException); + { + result->WriteVariable(retValue); + Jump(exit); + } + Bind(¬HasException); + { + Label find(env); + Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd); + Bind(&find); + { + result->WriteVariable(key); + Jump(exit); + } + } + } + Bind(&loopEnd); + j = Int64Add(*j, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(exit); + } +} + void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_array_stub_builder.h index c25fa4444a..6fd330eefb 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.h @@ -36,6 +36,12 @@ public: void Filter(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); + void Find(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath); + + void FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath); + void ForEach(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); @@ -55,6 +61,7 @@ public: Variable *result, Label *exit, Label *slowPath); void Includes(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); + private: static constexpr uint32_t MAX_LENGTH_ZERO = 0; static constexpr uint32_t MAX_LENGTH_ONE = 1; diff --git a/ecmascript/compiler/builtins/builtins_call_signature.h b/ecmascript/compiler/builtins/builtins_call_signature.h index f3ea44e217..d81c90d75e 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.h +++ b/ecmascript/compiler/builtins/builtins_call_signature.h @@ -62,6 +62,8 @@ namespace panda::ecmascript::kungfu { V(FunctionPrototypeApply) \ V(ArrayConcat) \ V(ArrayFilter) \ + V(ArrayFind) \ + V(ArrayFindIndex) \ V(ArrayForEach) \ V(ArrayIndexOf) \ V(ArrayLastIndexOf) \ diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index 5d1beb8981..9ab897f8a9 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -280,6 +280,8 @@ DECLARE_BUILTINS(Array##Method) #define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ V(Concat, JS_POINTER) \ V(Filter, JS_POINTER) \ + V(Find, JS_ANY) \ + V(FindIndex, JS_ANY) \ V(ForEach, JS_ANY) \ V(IndexOf, JS_ANY) \ V(LastIndexOf, JS_ANY) \ diff --git a/test/moduletest/arrayfind/BUILD.gn b/test/moduletest/arrayfind/BUILD.gn new file mode 100644 index 0000000000..004ca2e948 --- /dev/null +++ b/test/moduletest/arrayfind/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("arrayfind") { + deps = [] +} diff --git a/test/moduletest/arrayfind/arrayfind.js b/test/moduletest/arrayfind/arrayfind.js new file mode 100644 index 0000000000..ea26a65d5a --- /dev/null +++ b/test/moduletest/arrayfind/arrayfind.js @@ -0,0 +1,41 @@ +/* + * 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:stringSlice + * @tc.desc:test String.slice + * @tc.type: FUNC + * @tc.require: issueI5NO8G + */ + + +const array1 = [5, 12, 8, 130, 44]; + +const found = array1.find((element) => element > 10); +print(found); + + +function isPrime(element, index, array) { + let start = 2; + while (start <= Math.sqrt(element)) { + if (element % start++ < 1) { + return false; + } + } + return element > 1; +} + +print([4, 6, 8, 12].find(isPrime)); // undefined,未找到 +print([4, 5, 8, 12].find(isPrime)); // 5 diff --git a/test/moduletest/arrayfind/expect_output.txt b/test/moduletest/arrayfind/expect_output.txt new file mode 100644 index 0000000000..8189d7b9bb --- /dev/null +++ b/test/moduletest/arrayfind/expect_output.txt @@ -0,0 +1,16 @@ +# 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. + +12 +undefined +5 diff --git a/test/moduletest/arrayfindIndex/BUILD.gn b/test/moduletest/arrayfindIndex/BUILD.gn new file mode 100644 index 0000000000..0deb202b3b --- /dev/null +++ b/test/moduletest/arrayfindIndex/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("arrayfindIndex") { + deps = [] +} diff --git a/test/moduletest/arrayfindIndex/arrayfindIndex.js b/test/moduletest/arrayfindIndex/arrayfindIndex.js new file mode 100644 index 0000000000..1f84c15f64 --- /dev/null +++ b/test/moduletest/arrayfindIndex/arrayfindIndex.js @@ -0,0 +1,28 @@ +/* + * 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:stringSlice + * @tc.desc:test String.slice + * @tc.type: FUNC + * @tc.require: issueI5NO8G + */ + + +const array1 = [5, 12, 8, 130, 44]; + +const isLargeNumber = (element) => element > 13; + +print(array1.findIndex(isLargeNumber)); diff --git a/test/moduletest/arrayfindIndex/expect_output.txt b/test/moduletest/arrayfindIndex/expect_output.txt new file mode 100644 index 0000000000..d0698dcfa5 --- /dev/null +++ b/test/moduletest/arrayfindIndex/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. + +3 -- Gitee From de3b2e409aefd2999ae5a4e0dd2a10dee42e27a9 Mon Sep 17 00:00:00 2001 From: yaoyuan Date: Thu, 23 Nov 2023 20:56:24 +0800 Subject: [PATCH 08/44] Enable fetching ArrayLiteral from AOTArrayInfos Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8IZY5 Signed-off-by: yaoyuan Change-Id: I194b095556e97ef783829ff1de5f7e1bc52a7e2e --- .../compiler/aot_file/aot_file_manager.h | 41 ++++++++++++++----- .../snapshot_constantpool_data.cpp | 11 ++++- .../aot_snapshot/snapshot_constantpool_data.h | 5 ++- ecmascript/jspandafile/program_object.h | 29 ++++++++++++- 4 files changed, 70 insertions(+), 16 deletions(-) diff --git a/ecmascript/compiler/aot_file/aot_file_manager.h b/ecmascript/compiler/aot_file/aot_file_manager.h index f355341432..e2200788d3 100644 --- a/ecmascript/compiler/aot_file/aot_file_manager.h +++ b/ecmascript/compiler/aot_file/aot_file_manager.h @@ -21,6 +21,7 @@ #include "ecmascript/base/file_header.h" #include "ecmascript/compiler/aot_file/an_file_info.h" #include "ecmascript/compiler/aot_file/aot_file_info.h" +#include "ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h" #include "ecmascript/compiler/aot_file/binary_buffer_parser.h" #include "ecmascript/compiler/aot_file/module_section_des.h" #include "ecmascript/compiler/aot_file/stub_file_info.h" @@ -37,23 +38,25 @@ class JSpandafile; class JSThread; /* AOTLiteralInfo - * +--------------------------------+---- - * | cache | ^ - * | ... | | - * | -1 (No AOT Function Entry) | | - * | AOT Function Entry Index | | - * | AOT Function Entry Index | | - * +--------------------------------+---- - * | AOT Instance Hclass (IHC) | - * | AOT Constructor Hclass (CHC) | - * +--------------------------------+ + * +-----------------------------------+---- + * | cache | ^ + * | ... | | + * | -1 (No AOT Function Entry) | | + * | AOT Function Entry Index | | + * | AOT Function Entry Index | | + * +-----------------------------------+---- + * | AOT Instance Hclass (IHC) | + * | AOT Constructor Hclass (CHC) | + * | AOT ElementIndex (ElementIndex) | + * +-----------------------------------+ */ class AOTLiteralInfo : public TaggedArray { public: static constexpr size_t NO_FUNC_ENTRY_VALUE = -1; static constexpr size_t AOT_CHC_INDEX = 1; static constexpr size_t AOT_IHC_INDEX = 2; - static constexpr size_t RESERVED_LENGTH = AOT_IHC_INDEX; + static constexpr size_t AOT_ELEMENT_INDEX = 3; + static constexpr size_t RESERVED_LENGTH = AOT_ELEMENT_INDEX; static AOTLiteralInfo *Cast(TaggedObject *object) { @@ -71,6 +74,7 @@ public: TaggedArray::InitializeWithSpecialValue(initValue, capacity + RESERVED_LENGTH, extraLength); SetIhc(JSTaggedValue::Undefined()); SetChc(JSTaggedValue::Undefined()); + SetElementIndex(JSTaggedValue(kungfu::BaseSnapshotInfo::AOT_ELEMENT_INDEX_DEFAULT_VALUE)); } inline uint32_t GetCacheLength() const @@ -98,6 +102,16 @@ public: return JSTaggedValue(Barriers::GetValue(GetData(), GetChcOffset())); } + inline void SetElementIndex(JSTaggedValue value) + { + Barriers::SetPrimitive(GetData(), GetElementIndexOffset(), value.GetRawData()); + } + + inline int GetElementIndex() const + { + return JSTaggedValue(Barriers::GetValue(GetData(), GetElementIndexOffset())).GetInt(); + } + inline void SetObjectToCache(JSThread *thread, uint32_t index, JSTaggedValue value) { Set(thread, index, value); @@ -118,6 +132,11 @@ private: { return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_CHC_INDEX); } + + inline size_t GetElementIndexOffset() const + { + return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_ELEMENT_INDEX); + } }; class AOTFileManager { diff --git a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp index 3d2d4c12b6..da1ea881a1 100644 --- a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp +++ b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp @@ -39,7 +39,8 @@ void BaseSnapshotInfo::Record(ItemData &data) void BaseSnapshotInfo::CollectLiteralInfo(EcmaVM *vm, JSHandle array, uint32_t constantPoolIndex, JSHandle snapshotConstantPool, const std::set &skippedMethods, - JSHandle ihc, JSHandle chc) + JSHandle ihc, JSHandle chc, + int32_t elementIndex) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); @@ -73,6 +74,10 @@ void BaseSnapshotInfo::CollectLiteralInfo(EcmaVM *vm, JSHandle arra aotLiteralInfo->SetChc(chc.GetTaggedValue()); } + if (elementIndex != AOT_ELEMENT_INDEX_DEFAULT_VALUE) { + aotLiteralInfo->SetElementIndex(JSTaggedValue(elementIndex)); + } + snapshotConstantPool->SetObjectToCache(thread, constantPoolIndex, aotLiteralInfo.GetTaggedValue()); } @@ -197,6 +202,7 @@ void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFi const std::set &skippedMethods) { JSThread *thread = vm->GetJSThread(); + PGOTypeManager *ptManager = thread->GetCurrentEcmaContext()->GetPTManager(); for (auto item : info_) { const ItemData &data = item.second; JSHandle cp(thread, @@ -204,13 +210,14 @@ void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFi panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType( thread, jsPandaFile, id, cp, data.recordName_); + int32_t elementIndex = ptManager->GetElementsIndexByEntityId(id); uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_); JSHandle snapshotCpArr(thread, globalData.GetCurSnapshotCpArray()); JSHandle snapshotCp(thread, snapshotCpArr->Get(snapshotCpArrIdx)); JSHandle ihc = thread->GlobalConstants()->GetHandledUndefined(); JSHandle chc = thread->GlobalConstants()->GetHandledUndefined(); - CollectLiteralInfo(vm, literal, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc); + CollectLiteralInfo(vm, literal, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc, elementIndex); globalData.RecordReviseData( ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_}); } diff --git a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h index 67b46a5d28..c756e9b040 100644 --- a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h +++ b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h @@ -29,6 +29,8 @@ namespace panda::ecmascript::kungfu { class BaseSnapshotInfo { public: + static constexpr int32_t AOT_ELEMENT_INDEX_DEFAULT_VALUE = -1; + struct ItemData { CString recordName_; int32_t constantPoolId_ {0}; @@ -54,7 +56,8 @@ protected: void CollectLiteralInfo(EcmaVM *vm, JSHandle array, uint32_t constantPoolIndex, JSHandle snapshotConstantPool, const std::set &skippedMethods, - JSHandle ihc, JSHandle chc); + JSHandle ihc, JSHandle chc, + int32_t elementIndex = AOT_ELEMENT_INDEX_DEFAULT_VALUE); CUnorderedMap info_; }; diff --git a/ecmascript/jspandafile/program_object.h b/ecmascript/jspandafile/program_object.h index 2bb3ca6f05..3dbb47997d 100644 --- a/ecmascript/jspandafile/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -197,6 +197,11 @@ public: Barriers::SetPrimitive(GetData(), GetAotArrayInfoOffset(), info.GetRawData()); } + inline JSTaggedValue GetAotArrayInfo() + { + return JSTaggedValue(Barriers::GetValue(GetData(), GetAotArrayInfoOffset())); + } + inline void SetAotHClassInfo(JSTaggedValue info) { Barriers::SetPrimitive(GetData(), GetAotHClassInfoOffset(), info.GetRawData()); @@ -339,8 +344,13 @@ public: break; } case ConstPoolType::ARRAY_LITERAL: { - JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType(thread, jsPandaFile, id, - constpoolHandle, entry, needSetAotFlag, entryIndexes); + // literal fetching from AOT ArrayInfos + JSMutableHandle literal(thread, JSTaggedValue::Undefined()); + if (!constpoolHandle->TryGetAOTArrayLiteral(thread, needSetAotFlag, entryIndexes, literal)) { + literal.Update(LiteralDataExtractor::GetDatasIgnoreType(thread, jsPandaFile, id, + constpoolHandle, entry, + needSetAotFlag, entryIndexes)); + } uint32_t length = literal->GetLength(); JSHandle arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length), ArrayMode::LITERAL)); arr->SetElements(thread, literal); @@ -360,6 +370,21 @@ public: return val; } + bool TryGetAOTArrayLiteral(JSThread *thread, bool loadAOT, JSHandle entryIndexes, + JSMutableHandle literal) + { + if (loadAOT) { + int elementIndex = entryIndexes->GetElementIndex(); + if (elementIndex != kungfu::BaseSnapshotInfo::AOT_ELEMENT_INDEX_DEFAULT_VALUE) { + JSTaggedValue arrayInfos = GetAotArrayInfo(); + JSHandle aotArrayInfos(thread, arrayInfos); + literal.Update(aotArrayInfos->Get(elementIndex)); + return true; + } + } + return false; + } + static panda_file::File::EntityId GetIdFromCache(JSTaggedValue constpool, uint32_t index) { const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); -- Gitee From 00a3bfa3ffe722b8f771ffdf6cf36767d4a9ff49 Mon Sep 17 00:00:00 2001 From: yanpeng Date: Tue, 21 Nov 2023 15:37:13 +0800 Subject: [PATCH 09/44] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=83=A8=E5=88=86regre?= =?UTF-8?q?sstest=E9=9C=80=E8=A6=81=E7=9A=84=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yanpeng Change-Id: I027006bbed2637ef408e9ccc389c46cb266b995c Signed-off-by: yanpeng --- ecmascript/builtins/builtins_ark_tools.cpp | 153 +++++++++++++++++++++ ecmascript/builtins/builtins_ark_tools.h | 50 +++++-- 2 files changed, 190 insertions(+), 13 deletions(-) diff --git a/ecmascript/builtins/builtins_ark_tools.cpp b/ecmascript/builtins/builtins_ark_tools.cpp index 509de41350..1bcdc1942f 100644 --- a/ecmascript/builtins/builtins_ark_tools.cpp +++ b/ecmascript/builtins/builtins_ark_tools.cpp @@ -25,6 +25,9 @@ #include "ecmascript/napi/include/dfx_jsnapi.h" #include "ecmascript/mem/clock_scope.h" #include "ecmascript/property_detector-inl.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "builtins_typedarray.h" namespace panda::ecmascript::builtins { using StringHelper = base::StringHelper; @@ -470,4 +473,154 @@ JSTaggedValue BuiltinsArkTools::PGOAssertType([[maybe_unused]] EcmaRuntimeCallIn LOG_ECMA(INFO) << "Enter PGOAssertType"; return JSTaggedValue::Undefined(); } + +JSTaggedValue BuiltinsArkTools::ToLength([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter ToLength()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + JSHandle key = GetCallArg(info, 0); + return JSTaggedValue::ToLength(thread, key); +} + +JSTaggedValue BuiltinsArkTools::HasHoleyElements([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HasHoleyElements()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle array = GetCallArg(info, 0); + if (!array->IsJSArray()) { + return JSTaggedValue::False(); + } + JSHandle elements(thread, JSHandle::Cast(array)->GetElements()); + uint32_t len = JSHandle::Cast(array)->GetArrayLength(); + for (uint32_t i = 0; i < len; i++) { + if (elements->Get(i).IsHole()) { + return JSTaggedValue::True(); + } + } + return JSTaggedValue::False(); +} + +JSTaggedValue BuiltinsArkTools::HasDictionaryElements([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HasDictionaryElements()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle objValue = GetCallArg(info, 0); + JSHandle obj = JSHandle::Cast(objValue); + return JSTaggedValue(obj->GetJSHClass()->IsDictionaryMode()); +} + +JSTaggedValue BuiltinsArkTools::HasSmiElements([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HasSmiElements()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle array = GetCallArg(info, 0); + if (!array->IsJSArray()) { + return JSTaggedValue::False(); + } + JSHandle elements(thread, JSHandle::Cast(array)->GetElements()); + uint32_t len = JSHandle::Cast(array)->GetArrayLength(); + for (uint32_t i = 0; i < len; i++) { + if (elements->Get(i).IsInt()) { + return JSTaggedValue::True(); + } + } + return JSTaggedValue::False(); +} + +JSTaggedValue BuiltinsArkTools::HasDoubleElements([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HasDoubleElements()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + JSHandle array = GetCallArg(info, 0); + if (!array->IsJSArray()) { + return JSTaggedValue::False(); + } + JSHandle elements(thread, JSHandle::Cast(array)->GetElements()); + uint32_t len = JSHandle::Cast(array)->GetArrayLength(); + for (uint32_t i = 0; i < len; i++) { + if (elements->Get(i).IsDouble() && !elements->Get(i).IsZero()) { + return JSTaggedValue::True(); + } + } + return JSTaggedValue::False(); +} + +JSTaggedValue BuiltinsArkTools::HasObjectElements([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HasObjectElements()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + JSHandle array = GetCallArg(info, 0); + if (!array->IsJSArray()) { + return JSTaggedValue::False(); + } + JSHandle elements(thread, JSHandle::Cast(array)->GetElements()); + uint32_t len = JSHandle::Cast(array)->GetArrayLength(); + for (uint32_t i = 0; i < len; i++) { + if (elements->Get(i).IsObject()) { + return JSTaggedValue::True(); + } + } + return JSTaggedValue::False(); +} + +JSTaggedValue BuiltinsArkTools::ArrayBufferDetach([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter ArrayBufferDetach()"; + ASSERT(info); + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle obj1 = GetCallArg(info, 0); + JSHandle arrBuf = JSHandle::Cast(obj1); + arrBuf->Detach(thread); + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsArkTools::HaveSameMap([[maybe_unused]] EcmaRuntimeCallInfo *info) +{ + LOG_ECMA(INFO) << "Enter HaveSameMap()"; + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle obj1 = GetCallArg(info, 0); + JSHandle obj2 = GetCallArg(info, 1); + JSHClass *obj1Hclass = obj1->GetTaggedObject()->GetClass(); + JSHClass *obj2Hclass = obj2->GetTaggedObject()->GetClass(); + bool res = (obj1Hclass == obj2Hclass); + if (!res) { + return JSTaggedValue::False(); + } + JSHandle jsobj1(obj1); + JSHandle jsobj2(obj2); + JSHandle nameList1 = JSObject::EnumerableOwnNames(thread, jsobj1); + JSHandle nameList2 = JSObject::EnumerableOwnNames(thread, jsobj2); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint32_t len1 = nameList1->GetLength(); + uint32_t len2 = nameList2->GetLength(); + if (len1 != len2) { + return JSTaggedValue::False(); + } + for (uint32_t i = 0; i < len1; i++) { + if (obj1->IsJSArray()) { + JSTaggedValue objTagged1 = JSObject::GetProperty(thread, obj1, i).GetValue().GetTaggedValue(); + JSTaggedValue objTagged2 = JSObject::GetProperty(thread, obj2, i).GetValue().GetTaggedValue(); + if (FastRuntimeStub::FastTypeOf(thread, objTagged1) != + FastRuntimeStub::FastTypeOf(thread, objTagged2)) { + return JSTaggedValue::False(); + } + } else if (JSObject::GetProperty(thread, obj1, i).GetValue() != + JSObject::GetProperty(thread, obj2, i).GetValue()) { + return JSTaggedValue::False(); + } + } + return JSTaggedValue::True(); +} + } // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_ark_tools.h b/ecmascript/builtins/builtins_ark_tools.h index 105b57de2c..ef0fbc5411 100644 --- a/ecmascript/builtins/builtins_ark_tools.h +++ b/ecmascript/builtins/builtins_ark_tools.h @@ -44,19 +44,27 @@ V("timeInUs", TimeInUs, 0, INVALID) \ V("isAOTCompiled", IsAOTCompiled, 1, INVALID) -#define BUILTIN_ARK_TOOLS_FUNCTIONS_REGRESS(V) \ - V("prepareFunctionForOptimization", PrepareFunctionForOptimization, 1, INVALID) \ - V("optimizeFunctionOnNextCall", OptimizeFunctionOnNextCall, 1, INVALID) \ - V("optimizeMaglevOnNextCall", OptimizeMaglevOnNextCall, 1, INVALID) \ - V("deoptimizeFunction", DeoptimizeFunction, 1, INVALID) \ - V("optimizeOsr", OptimizeOsr, 1, INVALID) \ - V("neverOptimizeFunction", NeverOptimizeFunction, 1, INVALID) \ - V("heapObjectVerify", HeapObjectVerify, 1, INVALID) \ - V("disableOptimizationFinalization", DisableOptimizationFinalization, 0, INVALID) \ - V("deoptimizeNow", DeoptimizeNow, 0, INVALID) \ - V("deoptimize_now", DeoptimizeNow, 0, INVALID) \ - V("waitForBackgroundOptimization", WaitForBackgroundOptimization, 0, INVALID) \ - V("gc", Gc, 0, INVALID) +#define BUILTIN_ARK_TOOLS_FUNCTIONS_REGRESS(V) \ + V("prepareFunctionForOptimization", PrepareFunctionForOptimization, 1, INVALID) \ + V("optimizeFunctionOnNextCall", OptimizeFunctionOnNextCall, 1, INVALID) \ + V("optimizeMaglevOnNextCall", OptimizeMaglevOnNextCall, 1, INVALID) \ + V("deoptimizeFunction", DeoptimizeFunction, 1, INVALID) \ + V("optimizeOsr", OptimizeOsr, 1, INVALID) \ + V("neverOptimizeFunction", NeverOptimizeFunction, 1, INVALID) \ + V("heapObjectVerify", HeapObjectVerify, 1, INVALID) \ + V("disableOptimizationFinalization", DisableOptimizationFinalization, 0, INVALID) \ + V("deoptimizeNow", DeoptimizeNow, 0, INVALID) \ + V("deoptimize_now", DeoptimizeNow, 0, INVALID) \ + V("waitForBackgroundOptimization", WaitForBackgroundOptimization, 0, INVALID) \ + V("gc", Gc, 0, INVALID) \ + V("toLength", ToLength, 1, INVALID) \ + V("hasHoleyElements", HasHoleyElements, 1, INVALID) \ + V("hasDictionaryElements", HasDictionaryElements, 1, INVALID) \ + V("hasSmiElements", HasSmiElements, 1, INVALID) \ + V("hasDoubleElements", HasDoubleElements, 1, INVALID) \ + V("hasObjectElements", HasObjectElements, 1, INVALID) \ + V("arrayBufferDetach", ArrayBufferDetach, 1, INVALID) \ + V("haveSameMap", HaveSameMap, 2, INVALID) #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER #define BUILTIN_ARK_TOOLS_FUNCTIONS_CPUPROFILER(V) \ @@ -148,6 +156,22 @@ public: static JSTaggedValue PGOAssertType(EcmaRuntimeCallInfo *info); + static JSTaggedValue ToLength(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HasHoleyElements(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HasDictionaryElements(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HasSmiElements(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HasDoubleElements(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HasObjectElements(EcmaRuntimeCallInfo *info); + + static JSTaggedValue ArrayBufferDetach(EcmaRuntimeCallInfo *info); + + static JSTaggedValue HaveSameMap(EcmaRuntimeCallInfo *info); + static Span GetArkToolsFunctions() { return Span(ARK_TOOLS_FUNCTIONS); -- Gitee From c48127bca8664c3a90ca139666d9268a5c3008ea Mon Sep 17 00:00:00 2001 From: liuzhijie Date: Fri, 17 Nov 2023 09:53:05 +0800 Subject: [PATCH 10/44] Global IndexMap Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8HA58?from=project-issue Signed-off-by: liuzhijie Change-Id: Ie3c1682f86b43e6ae8e759ad89ed57343f89db8c --- BUILD.gn | 1 + ecmascript/ecma_context.cpp | 3 + ecmascript/ecma_context.h | 3 + ecmascript/global_index_map.cpp | 123 ++++++++++++++++ ecmascript/global_index_map.h | 130 +++++++++++++++++ ecmascript/js_handle.h | 4 +- ecmascript/js_thread.h | 5 + ecmascript/tagged_dictionary.cpp | 27 ++++ ecmascript/tagged_dictionary.h | 51 +++++++ ecmascript/tests/BUILD.gn | 1 + ecmascript/tests/global_index_map_test.cpp | 157 +++++++++++++++++++++ script/run_ark_executable.py | 12 +- 12 files changed, 510 insertions(+), 7 deletions(-) create mode 100644 ecmascript/global_index_map.cpp create mode 100644 ecmascript/global_index_map.h create mode 100644 ecmascript/tests/global_index_map_test.cpp diff --git a/BUILD.gn b/BUILD.gn index 171ee2eaf8..f748f49647 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -801,6 +801,7 @@ ecma_source = [ "ecmascript/regexp/regexp_opcode.cpp", "ecmascript/regexp/regexp_parser.cpp", "ecmascript/regexp/regexp_parser_cache.cpp", + "ecmascript/global_index_map.cpp", "ecmascript/shared_mm/shared_mm.cpp", "ecmascript/tagged_dictionary.cpp", "ecmascript/tagged_hash_array.cpp", diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index f2ab099bd8..5b75361b40 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -42,6 +42,7 @@ #include "ecmascript/require/js_require_manager.h" #include "ecmascript/snapshot/mem/snapshot.h" #include "ecmascript/platform/log.h" +#include "ecmascript/global_index_map.h" namespace panda::ecmascript { using PathHelper = base::PathHelper; @@ -748,6 +749,8 @@ void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&numberToStringResultCache_))); v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&stringSplitResultCache_))); v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(µJobQueue_))); + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&pointerToIndexDictionary_))); + if (moduleManager_) { moduleManager_->Iterate(v); } diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index b2804ce55f..faa01aa883 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -47,6 +47,7 @@ class ConstantPool; class JSPromise; class RegExpExecResultCache; class EcmaHandleScope; +class GlobalIndexMap; enum class PromiseRejectionEvent : uint8_t; template @@ -516,6 +517,7 @@ private: JSTaggedValue numberToStringResultCache_ {JSTaggedValue::Hole()}; JSTaggedValue stringSplitResultCache_ {JSTaggedValue::Hole()}; JSTaggedValue globalEnv_ {JSTaggedValue::Hole()}; + JSTaggedValue pointerToIndexDictionary_ {JSTaggedValue::Hole()}; JSTaggedValue regexpCache_ {JSTaggedValue::Hole()}; JSTaggedValue regexpGlobal_ {JSTaggedValue::Hole()}; JSTaggedValue microJobQueue_ {JSTaggedValue::Hole()}; @@ -587,6 +589,7 @@ private: friend class ObjectFactory; friend class panda::JSNApi; friend class AOTFileManager; + friend class GlobalIndexMap; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/global_index_map.cpp b/ecmascript/global_index_map.cpp new file mode 100644 index 0000000000..ab4cde05a9 --- /dev/null +++ b/ecmascript/global_index_map.cpp @@ -0,0 +1,123 @@ +/* + * 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/global_env.h" +#include "ecmascript/global_index_map.h" + +namespace panda::ecmascript { +void GlobalIndexMap::Initialize(const JSThread *thread, + JSMutableHandle globalIndexMap) +{ + // GlobalIndex map should be created when it is first used. + InitGlobalIndexMap(thread, globalIndexMap); + + // Init GlobalIndex map + InitGlobalConst(thread, globalIndexMap); + InitGlobalEnv(thread, globalIndexMap); + InitBuiltinEntries(thread, globalIndexMap); +} + +void GlobalIndexMap::InitGlobalIndexMap(const JSThread *thread, + JSMutableHandle globalIndexMap) +{ + if (globalIndexMap.GetTaggedValue().IsHeapObject()) { + return ; + } + globalIndexMap.Update(PointerToIndexDictionary::Create(thread)); +} + +void GlobalIndexMap::InitGlobalConst(const JSThread *thread, + JSMutableHandle globalIndexMap) +{ + ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed."); + auto globalConst = const_cast(thread->GlobalConstants()); + uint32_t constantCount = globalConst->GetConstantCount(); + JSMutableHandle globalIndexMapHandle(thread, globalIndexMap); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); + for (uint32_t index = 0; index < constantCount; index++) { + JSTaggedValue objectValue = globalConst->GetGlobalConstantObject(index); + if (objectValue.IsHeapObject() && !objectValue.IsString()) { + keyHandle.Update(objectValue); + + GlobalIndex globalIndex; + globalIndex.UpdateGlobalConstId(index); + valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex())); + JSHandle newDict = + PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle); + globalIndexMapHandle.Update(newDict); + } + } + globalIndexMap.Update(globalIndexMapHandle); +} + +void GlobalIndexMap::InitGlobalEnv(const JSThread *thread, + JSMutableHandle globalIndexMap) +{ + ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed."); + auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); + uint32_t globalEnvFieldSize = globalEnv->GetGlobalEnvFieldSize(); + JSMutableHandle globalIndexMapHandle(thread, globalIndexMap); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); + for (uint32_t index = 0; index < globalEnvFieldSize; index++) { + JSTaggedValue objectValue = globalEnv->GetGlobalEnvObjectByIndex(index).GetTaggedValue(); + if (objectValue.IsHeapObject()) { + keyHandle.Update(objectValue); + + GlobalIndex globalIndex; + globalIndex.UpdateGlobalEnvId(index); + valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex())); + JSHandle newDict = + PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle); + globalIndexMapHandle.Update(newDict); + } + } + globalIndexMap.Update(globalIndexMapHandle); +} + +void GlobalIndexMap::InitBuiltinEntries(const JSThread *thread, + JSMutableHandle globalIndexMap) +{ + ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed."); + auto builtinEntries = thread->GetBuiltinEntries(); + uint32_t builtinEntriesCount = BuiltinEntries::COUNT; + JSMutableHandle globalIndexMapHandle(thread, globalIndexMap); + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); + for (uint32_t index = 0; index < builtinEntriesCount; index++) { + JSTaggedValue objectValue = builtinEntries.builtin_[index].hClass_; + keyHandle.Update(objectValue); + if (objectValue.IsHeapObject()) { + GlobalIndex globalIndex; + globalIndex.UpdateBuiltinEntriesId(index); + valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex())); + JSHandle newDict = + PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle); + globalIndexMapHandle.Update(newDict); + } + } + globalIndexMap.Update(globalIndexMapHandle); +} + +void GlobalIndexMap::FindGlobalIndex(JSHandle globalIndexMap, + JSTaggedValue objAddress, GlobalIndex *globalIndex) +{ + int entry = globalIndexMap->FindEntry(objAddress); + if (entry != -1) { + *globalIndex = GlobalIndex(globalIndexMap->GetValue(entry).GetInt()); + } +} +} // namespace panda::ecmascript diff --git a/ecmascript/global_index_map.h b/ecmascript/global_index_map.h new file mode 100644 index 0000000000..116796351d --- /dev/null +++ b/ecmascript/global_index_map.h @@ -0,0 +1,130 @@ +/* + * 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_INDEX_MAP_H +#define ECMASCRIPT_GLOBAL_INDEX_MAP_H + +#include "ecmascript/tagged_dictionary.h" +#include "utils/bit_field.h" + +namespace panda::ecmascript { +class GlobalIndex { +public: + static constexpr uint32_t GLOBAL_CONST_BITFILED_NUM = 10; + static constexpr uint32_t GLOBAL_ENV_BITFILED_NUM = 10; + static constexpr uint32_t BUILTIN_ENTRIES_BITFILED_NUM = 10; + using GlobalConstBits = BitField; + using GlobalEnvBits = GlobalConstBits::NextField; + using BuiltinEntriesBits = GlobalEnvBits::NextField; + + GlobalIndex() = default; + explicit GlobalIndex(uint32_t index) : index_(index) {} + explicit GlobalIndex(int32_t index) : index_(static_cast(index)) {} + + int GetGlobalConstId() const + { + int id = GlobalConstBits::Decode(index_); + return id - 1; + } + + void UpdateGlobalConstId(size_t id) + { + index_ = GlobalConstBits::Update(index_, id + 1); + } + + bool IsGlobalConstId() const + { + return GlobalConstBits::Decode(index_); + } + + int GetGlobalEnvId() const + { + int id = GlobalEnvBits::Decode(index_); + return id - 1; + } + + void UpdateGlobalEnvId(size_t id) + { + index_ = GlobalEnvBits::Update(index_, id + 1); + } + + bool IsGlobalEnvId() const + { + return GlobalEnvBits::Decode(index_); + } + + int GetBuiltinEntriesId() const + { + int id = BuiltinEntriesBits::Decode(index_); + return id - 1; + } + + void UpdateBuiltinEntriesId(size_t id) + { + index_ = BuiltinEntriesBits::Update(index_, id + 1); + } + + bool IsBuiltinEntriesId() const + { + return BuiltinEntriesBits::Decode(index_); + } + + uint32_t GetGlobalIndex() const + { + return index_; + } + + void UpdateGlobalIndex(size_t index) + { + index_ = index; + } + + bool operator!=(const GlobalIndex &right) const + { + return index_ != right.index_; + } + + bool operator==(const GlobalIndex &right) const + { + return index_ == right.index_; + } + +private: + uint32_t index_ {0}; +}; + +// HeapObject's Pointer To IndexHashmap +class GlobalIndexMap { +public: + static void Initialize(const JSThread *thread, + JSMutableHandle globalIndexMap); + static void InitGlobalIndexMap(const JSThread *thread, + JSMutableHandle globalIndexMap); + static void InitGlobalConst(const JSThread *thread, + JSMutableHandle globalIndexMap); + static void InitGlobalEnv(const JSThread *thread, + JSMutableHandle globalIndexMap); + static void InitBuiltinEntries(const JSThread *thread, + JSMutableHandle globalIndexMap); + static void FindGlobalIndex(JSHandle globalIndexMap, + JSTaggedValue obj, GlobalIndex *globalIndex); + static inline JSHandle GetGlobalIndexMap(EcmaContext *context) + { + return JSHandle(reinterpret_cast(&context->pointerToIndexDictionary_)); + } +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_GLOBAL_INDEX_MAP_H \ No newline at end of file diff --git a/ecmascript/js_handle.h b/ecmascript/js_handle.h index a07caf2262..81fcee1efd 100644 --- a/ecmascript/js_handle.h +++ b/ecmascript/js_handle.h @@ -156,7 +156,9 @@ public: { if (!std::is_convertible::value) { ASSERT(slot != 0); - T::Cast((*reinterpret_cast(slot)).GetTaggedObject()); + if ((*reinterpret_cast(slot)).IsHeapObject()) { + T::Cast((*reinterpret_cast(slot)).GetTaggedObject()); + } } } diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 958f471443..13b98b38e9 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -204,6 +204,11 @@ public: return glueData_.globalConst_; } + const BuiltinEntries GetBuiltinEntries() const + { + return glueData_.builtinEntries_; + } + const CMap &GetArrayHClassIndexMap() const { return arrayHClassIndexMap_; diff --git a/ecmascript/tagged_dictionary.cpp b/ecmascript/tagged_dictionary.cpp index 1aabbbf1fa..86b55a7c3f 100644 --- a/ecmascript/tagged_dictionary.cpp +++ b/ecmascript/tagged_dictionary.cpp @@ -407,4 +407,31 @@ void NumberDictionary::ClearEntry(const JSThread *thread, int entry) PropertyAttributes metaData; SetEntry(thread, entry, hole, hole, metaData); } + +JSHandle PointerToIndexDictionary::Create(const JSThread *thread, int numberOfElements) +{ + return OrderHashTableT::Create(thread, numberOfElements); +} + +JSHandle PointerToIndexDictionary::PutIfAbsent( + const JSThread *thread, + const JSHandle &dictionary, + const JSHandle &key, + const JSHandle &value) +{ + /* no need to add key if exist */ + int entry = dictionary->FindEntry(key.GetTaggedValue()); + if (entry != -1) { + return dictionary; + } + // Check whether the table should be growed + JSHandle newDictionary = HashTableT::GrowHashTable(thread, dictionary); + + // Compute the key object + int32_t hash = PointerToIndexDictionary::Hash(key.GetTaggedValue()); + entry = newDictionary->FindInsertIndex(hash); + newDictionary->SetEntry(thread, entry, key.GetTaggedValue(), value.GetTaggedValue()); + newDictionary->IncreaseEntries(thread); + return newDictionary; +} } // namespace panda::ecmascript diff --git a/ecmascript/tagged_dictionary.h b/ecmascript/tagged_dictionary.h index 62ef433e65..40184b9340 100644 --- a/ecmascript/tagged_dictionary.h +++ b/ecmascript/tagged_dictionary.h @@ -140,5 +140,56 @@ public: static constexpr int ENTRY_DETAILS_INDEX = 2; static constexpr int ENTRY_SIZE = 3; }; + +class PointerToIndexDictionary : public OrderTaggedHashTable { +public: + using OrderHashTableT = OrderTaggedHashTable; + inline static int GetKeyIndex(int entry) + { + return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; + } + + inline static int GetValueIndex(int entry) + { + return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; + } + + inline static int GetEntryIndex(int entry) + { + return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize(); + } + + inline static int GetEntrySize() + { + return ENTRY_SIZE; + } + + inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value) + { + SetKey(thread, entry, key); + SetValue(thread, entry, value); + } + + static int32_t Hash(const JSTaggedValue &key) + { + return static_cast(key.GetRawData()); + } + + static bool IsMatch(const JSTaggedValue &key, const JSTaggedValue &other) + { + return key == other; + } + static JSHandle Create(const JSThread *thread, + int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); + static JSHandle PutIfAbsent( + const JSThread *thread, const JSHandle &dictionary, + const JSHandle &key, const JSHandle &value); + + // DECL_DUMP() + + static constexpr int ENTRY_KEY_INDEX = 0; + static constexpr int ENTRY_VALUE_INDEX = 1; + static constexpr int ENTRY_SIZE = 2; +}; } // namespace panda::ecmascript #endif // ECMASCRIPT_NEW_DICTIONARY_H diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn index 3000fd552a..31b3d3d6ca 100644 --- a/ecmascript/tests/BUILD.gn +++ b/ecmascript/tests/BUILD.gn @@ -38,6 +38,7 @@ host_unittest_action("EcmaVm_001_Test") { "frame_test.cpp", "gc_test.cpp", "global_dictionary_test.cpp", + "global_index_map_test.cpp", "glue_regs_test.cpp", "handle_leak_test.cpp", "huge_object_test.cpp", diff --git a/ecmascript/tests/global_index_map_test.cpp b/ecmascript/tests/global_index_map_test.cpp new file mode 100644 index 0000000000..73a4c1a7d6 --- /dev/null +++ b/ecmascript/tests/global_index_map_test.cpp @@ -0,0 +1,157 @@ +/* + * 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/builtin_entries.h" +#include "ecmascript/global_env.h" +#include "ecmascript/global_env_constants.h" +#include "ecmascript/global_index_map.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class GlobalIndexMapTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(instance, scope); + } + + EcmaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +/** + * @tc.name: InitGlobalIndexMap + * @tc.desc: Check whether InitGlobalIndexMap can initialize dictionary. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(GlobalIndexMapTest, GlobalIndexMap_initGlobalIndexMap) +{ + JSMutableHandle globalIndexMap( + GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext()).GetAddress()); + EXPECT_NE(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + GlobalIndexMap::InitGlobalIndexMap(thread, globalIndexMap); + globalIndexMap.Update(GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext())); + EXPECT_EQ(globalIndexMap.GetTaggedValue().IsHeapObject(), true); +} + +/** + * @tc.name: InitGlobalConst + * @tc.desc: Check whether GlobalConst can be find in the GlobalMap. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(GlobalIndexMapTest, GlobalIndexMap_initGlobalConst) +{ + JSMutableHandle globalIndexMap( + GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext()).GetAddress()); + EXPECT_NE(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + GlobalIndexMap::InitGlobalIndexMap(thread, globalIndexMap); + GlobalIndexMap::InitGlobalConst(thread, globalIndexMap); + globalIndexMap.Update(GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext())); + EXPECT_EQ(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + auto globalConst = const_cast(thread->GlobalConstants()); + uint32_t constantCount = globalConst->GetConstantCount(); + for (uint32_t index = 0; index < constantCount; index++) { + JSTaggedValue objectValue = globalConst->GetGlobalConstantObject(index); + if (objectValue.IsHeapObject() && !objectValue.IsString()) { + GlobalIndex rootIndex; + GlobalIndexMap::FindGlobalIndex(globalIndexMap, objectValue, &rootIndex); + EXPECT_EQ(static_cast(index), rootIndex.GetGlobalConstId()); + GlobalIndex globalConstGlobalIndex; + globalConstGlobalIndex.UpdateGlobalConstId(index); + EXPECT_EQ(globalConstGlobalIndex, rootIndex); + } + } +} + +/** + * @tc.name: InitGlobalEnv + * @tc.desc: Check whether GlobalEnv can be find in the GlobalMap. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(GlobalIndexMapTest, GlobalIndexMap_initGlobalEnv) +{ + JSMutableHandle globalIndexMap( + GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext()).GetAddress()); + EXPECT_NE(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + GlobalIndexMap::InitGlobalIndexMap(thread, globalIndexMap); + GlobalIndexMap::InitGlobalEnv(thread, globalIndexMap); + globalIndexMap.Update(GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext())); + EXPECT_EQ(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); + uint32_t globalEnvFieldSize = globalEnv->GetGlobalEnvFieldSize(); + for (uint32_t index = 0; index < globalEnvFieldSize; index++) { + JSTaggedValue objectValue = globalEnv->GetGlobalEnvObjectByIndex(index).GetTaggedValue(); + if (objectValue.IsHeapObject()) { + GlobalIndex rootIndex; + GlobalIndexMap::FindGlobalIndex(globalIndexMap, objectValue, &rootIndex); + EXPECT_EQ(static_cast(index), rootIndex.GetGlobalEnvId()); + GlobalIndex globalEnvGlobalIndex; + globalEnvGlobalIndex.UpdateGlobalEnvId(index); + EXPECT_EQ(globalEnvGlobalIndex, rootIndex); + } + } +} + +/** + * @tc.name: InitBuiltinEntries + * @tc.desc: Check whether BuiltinEntries can be find in the GlobalMap. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(GlobalIndexMapTest, GlobalIndexMap_initBuiltinEntries) +{ + JSMutableHandle globalIndexMap( + GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext()).GetAddress()); + EXPECT_NE(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + GlobalIndexMap::InitGlobalIndexMap(thread, globalIndexMap); + GlobalIndexMap::InitBuiltinEntries(thread, globalIndexMap); + globalIndexMap.Update(GlobalIndexMap::GetGlobalIndexMap(thread->GetCurrentEcmaContext())); + EXPECT_EQ(globalIndexMap.GetTaggedValue().IsHeapObject(), true); + auto builtinEntries = thread->GetBuiltinEntries(); + uint32_t builtinEntriesCount = BuiltinEntries::COUNT; + for (uint32_t index = 0; index < builtinEntriesCount; index++) { + JSTaggedValue objectValue = builtinEntries.builtin_[index].hClass_; + if (objectValue.IsHeapObject()) { + GlobalIndex rootIndex; + GlobalIndexMap::FindGlobalIndex(globalIndexMap, objectValue, &rootIndex); + EXPECT_EQ(static_cast(index), rootIndex.GetBuiltinEntriesId()); + GlobalIndex builtinEntriesIndex; + builtinEntriesIndex.UpdateBuiltinEntriesId(index); + EXPECT_EQ(builtinEntriesIndex, rootIndex); + } + } +} +} // namespace panda::test \ No newline at end of file diff --git a/script/run_ark_executable.py b/script/run_ark_executable.py index c2dc61c5c7..1012ad29ee 100755 --- a/script/run_ark_executable.py +++ b/script/run_ark_executable.py @@ -132,17 +132,17 @@ def judge_output(args: object): if args.expect_output: returncode = str(subp.returncode) if returncode != args.expect_output: - out_str = out.decode('UTF-8') - err_str = err.decode('UTF-8') + out_str = out.decode('UTF-8', errors="ignore") + err_str = err.decode('UTF-8', errors="ignore") print(out_str) print(err_str) print(">>>>> Expect return: [" + args.expect_output \ + "]\n>>>>> But got: [" + returncode + "]") raise RuntimeError("Run [" + cmd + "] failed!") elif args.expect_sub_output: - out_str = out.decode('UTF-8') + out_str = out.decode('UTF-8', errors="ignore") if out_str.find(args.expect_sub_output) == -1: - out_str = out.decode('UTF-8') + out_str = out.decode('UTF-8', errors="ignore") print(out_str) print(">>>>> Expect contain: [" + args.expect_sub_output \ + "]\n>>>>> But got: [" + out_str + "]") @@ -152,9 +152,9 @@ def judge_output(args: object): # skip license header expect_output = ''.join(file.readlines()[13:]) file.close() - out_str = out.decode('UTF-8') + out_str = out.decode('UTF-8', errors="ignore") if out_str != expect_output: - err_str = err.decode('UTF-8') + err_str = err.decode('UTF-8', errors="ignore") print(err_str) print(">>>>> Expect : [" + expect_output \ + "]\n>>>>> But got: [" + out_str + "]") -- Gitee From 905fe24f9bb5c32665176841418fbbbe86d0e9fc Mon Sep 17 00:00:00 2001 From: h30044958 Date: Wed, 22 Nov 2023 15:33:05 +0800 Subject: [PATCH 11/44] AOT adaptation to the code owner mechanism Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8IKU6 Signed-off-by: h30044958 Change-Id: Ic5853fd7515278befaaf48daa5df4176dfcaf1d2 --- ecmascript/compiler/aot_compiler.cpp | 3 ++- ecmascript/compiler/aot_compiler_preprocessor.cpp | 5 +++++ ecmascript/compiler/aot_compiler_preprocessor.h | 2 ++ ecmascript/compiler/file_generators.cpp | 4 ++-- ecmascript/compiler/file_generators.h | 2 +- ecmascript/ohos/ohos_pkg_args.h | 12 +++++++++++- ecmascript/platform/code_sign.h | 2 +- ecmascript/platform/unix/code_sign.cpp | 3 ++- ecmascript/platform/unix/ohos/code_sign.cpp | 4 ++-- ecmascript/platform/windows/code_sign.cpp | 3 ++- 10 files changed, 30 insertions(+), 10 deletions(-) diff --git a/ecmascript/compiler/aot_compiler.cpp b/ecmascript/compiler/aot_compiler.cpp index 0ad7e61e2d..59dbd4c669 100644 --- a/ecmascript/compiler/aot_compiler.cpp +++ b/ecmascript/compiler/aot_compiler.cpp @@ -152,7 +152,8 @@ int Main(const int argc, const char **argv) AOTFileGenerator generator(&log, &logList, vm, cOptions.triple_); const auto &fileInfos = cPreprocessor.GetAbcFileInfo(); CompileValidFiles(passManager, generator, ret, fileInfos); - generator.SaveAOTFile(cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN); + std::string appSignature = cPreprocessor.GetMainPkgArgsAppSignature(); + generator.SaveAOTFile(cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN, appSignature); generator.SaveSnapshotFile(); log.Print(); } diff --git a/ecmascript/compiler/aot_compiler_preprocessor.cpp b/ecmascript/compiler/aot_compiler_preprocessor.cpp index 79dce24409..868bbc1eb7 100644 --- a/ecmascript/compiler/aot_compiler_preprocessor.cpp +++ b/ecmascript/compiler/aot_compiler_preprocessor.cpp @@ -253,4 +253,9 @@ void AotCompilerPreprocessor::SnapshotInitialize() PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager(); ptManager->InitAOTSnapshot(fileInfos_.size()); } + +std::string AotCompilerPreprocessor::GetMainPkgArgsAppSignature() const +{ + return GetMainPkgArgs() == nullptr ? "" : GetMainPkgArgs()->GetAppSignature(); +} } // namespace panda::ecmascript::kungfu \ No newline at end of file diff --git a/ecmascript/compiler/aot_compiler_preprocessor.h b/ecmascript/compiler/aot_compiler_preprocessor.h index 85e3be7020..8a1db060e4 100644 --- a/ecmascript/compiler/aot_compiler_preprocessor.h +++ b/ecmascript/compiler/aot_compiler_preprocessor.h @@ -95,6 +95,8 @@ public: void GeneratePGOTypes(const CompilationOptions &cOptions); void SnapshotInitialize(); + + std::string GetMainPkgArgsAppSignature() const; bool GetCompilerResult() { diff --git a/ecmascript/compiler/file_generators.cpp b/ecmascript/compiler/file_generators.cpp index e7dd1898d3..6ebe21474c 100644 --- a/ecmascript/compiler/file_generators.cpp +++ b/ecmascript/compiler/file_generators.cpp @@ -417,7 +417,7 @@ bool AOTFileGenerator::CreateDirIfNotExist(const std::string &filename) return panda::ecmascript::SetDirModeAsDefault(path); } -void AOTFileGenerator::SaveAOTFile(const std::string &filename) +void AOTFileGenerator::SaveAOTFile(const std::string &filename, const std::string &appSignature) { if (aotInfo_.GetTotalCodeSize() == 0) { LOG_COMPILER(WARN) << "error: code size of generated an file is empty!"; @@ -434,7 +434,7 @@ void AOTFileGenerator::SaveAOTFile(const std::string &filename) if (!panda::ecmascript::SetFileModeAsDefault(filename)) { LOG_COMPILER(ERROR) << "Fail to set an file mode:" << filename; } - panda::ecmascript::CodeSignForAOTFile(filename); + panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature); } void AOTFileGenerator::SaveSnapshotFile() diff --git a/ecmascript/compiler/file_generators.h b/ecmascript/compiler/file_generators.h index 9f01046d06..4789f606c2 100644 --- a/ecmascript/compiler/file_generators.h +++ b/ecmascript/compiler/file_generators.h @@ -187,7 +187,7 @@ public: bool SetFileModeAsDefault(const std::string &filename); // save function for aot files containing normal func translated from JS/TS - void SaveAOTFile(const std::string &filename); + void SaveAOTFile(const std::string &filename, const std::string &appSignature); void SaveSnapshotFile(); diff --git a/ecmascript/ohos/ohos_pkg_args.h b/ecmascript/ohos/ohos_pkg_args.h index 46cab2c3ab..e5614e7160 100644 --- a/ecmascript/ohos/ohos_pkg_args.h +++ b/ecmascript/ohos/ohos_pkg_args.h @@ -54,6 +54,7 @@ public: constexpr static const char *const KEY_PROCESS_UID = "processUid"; constexpr static const char *const KEY_BUNDLE_UID = "bundleUid"; constexpr static const char *const IS_ENCRYPTED_BUNDLE = "isEncryptedBundle"; + constexpr static const char *const APP_IDENTIFIER = "appIdentifier"; OhosPkgArgs() = default; @@ -259,6 +260,8 @@ public: } else if (strcmp(key, IS_ENCRYPTED_BUNDLE) == 0) { char *str = nullptr; IsEncryptedBundle_ = static_cast(strtol(value, &str, 0)); + } else if (strcmp(key, APP_IDENTIFIER) == 0) { + appSignature_ = value; } else { LOG_COMPILER(ERROR) << "Unknown keyword when parse pkg info. key: " << key << ", value: " << value; } @@ -285,7 +288,8 @@ public: << KEY_PGO_DIR << ": " << pgoDir_ << ", " << KEY_BUNDLE_UID << ": " << bundleUid_ << ", " << KEY_PROCESS_UID << ": " << processUid_ << ", " - << IS_ENCRYPTED_BUNDLE << ": " << IsEncryptedBundle_ ; + << IS_ENCRYPTED_BUNDLE << ": " << IsEncryptedBundle_ + << APP_IDENTIFIER << ": " << appSignature_; } const std::string &GetBundleName() const @@ -303,6 +307,11 @@ public: return pkgPath_; } + const std::string &GetAppSignature() const + { + return appSignature_; + } + std::string GetFullName() const { return pkgPath_ + GetPathSeparator() + moduleName_ + GetPathSeparator() + abcName_; @@ -445,6 +454,7 @@ private: std::string pkgPath_{""}; std::string abcName_{""}; std::string pgoDir_{""}; + std::string appSignature_{""}; uint32_t abcOffset_ {INVALID_VALUE}; uint32_t abcSize_ {INVALID_VALUE}; uint32_t bundleUid_ {INVALID_VALUE}; diff --git a/ecmascript/platform/code_sign.h b/ecmascript/platform/code_sign.h index 8a3be1b253..d819fe3186 100644 --- a/ecmascript/platform/code_sign.h +++ b/ecmascript/platform/code_sign.h @@ -19,6 +19,6 @@ #include namespace panda::ecmascript { -void CodeSignForAOTFile(const std::string &filename); +void CodeSignatureForAOTFile(const std::string &filename, const std::string &appSignature); } // namespace panda::ecmascript #endif // ECMASCRIPT_PLATFORM_CODE_SIGN_H diff --git a/ecmascript/platform/unix/code_sign.cpp b/ecmascript/platform/unix/code_sign.cpp index c82cfbb5ba..ab06a14351 100644 --- a/ecmascript/platform/unix/code_sign.cpp +++ b/ecmascript/platform/unix/code_sign.cpp @@ -16,8 +16,9 @@ #include "ecmascript/platform/code_sign.h" namespace panda::ecmascript { -void CodeSignForAOTFile(const std::string &filename) +void CodeSignatureForAOTFile(const std::string &filename, const std::string &appSignature) { (void)filename; + (void)appSignature; } } // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/platform/unix/ohos/code_sign.cpp b/ecmascript/platform/unix/ohos/code_sign.cpp index 1a7fdaad03..d34a296088 100644 --- a/ecmascript/platform/unix/ohos/code_sign.cpp +++ b/ecmascript/platform/unix/ohos/code_sign.cpp @@ -22,11 +22,11 @@ using namespace OHOS::Security::CodeSign; namespace panda::ecmascript { -void CodeSignForAOTFile(const std::string &filename) +void CodeSignatureForAOTFile(const std::string &filename, const std::string &appSignature) { LOG_ECMA(DEBUG) << "start to sign the aot file!"; ByteBuffer sig; - if (LocalCodeSignKit::SignLocalCode(filename, sig) != CommonErrCode::CS_SUCCESS) { + if (LocalCodeSignKit::SignLocalCode(appSignature, filename, sig) != CommonErrCode::CS_SUCCESS) { LOG_ECMA(ERROR) << "Failed to sign the aot file!"; return; } diff --git a/ecmascript/platform/windows/code_sign.cpp b/ecmascript/platform/windows/code_sign.cpp index c82cfbb5ba..ab06a14351 100644 --- a/ecmascript/platform/windows/code_sign.cpp +++ b/ecmascript/platform/windows/code_sign.cpp @@ -16,8 +16,9 @@ #include "ecmascript/platform/code_sign.h" namespace panda::ecmascript { -void CodeSignForAOTFile(const std::string &filename) +void CodeSignatureForAOTFile(const std::string &filename, const std::string &appSignature) { (void)filename; + (void)appSignature; } } // namespace panda::ecmascript \ No newline at end of file -- Gitee From bbdd384184468f9e820360bbec20ab8904e052f1 Mon Sep 17 00:00:00 2001 From: gwl Date: Fri, 24 Nov 2023 14:50:40 +0800 Subject: [PATCH 12/44] [add test case] Change-Id: Ie98950ff1d5829a0cf7e66d6349b54a1ee1a7c97 Signed-off-by: gwl --- .../builtins/builtins_array_stub_builder.cpp | 3 ++ test/moduletest/arrayConcat/arrayConcat.js | 34 +++++++++++++++++++ test/moduletest/arrayConcat/expect_output.txt | 5 +++ 3 files changed, 42 insertions(+) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 38508331cd..404ffc7de5 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -26,6 +26,9 @@ void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef n Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); Label isExtensible(env); Branch(HasConstructor(thisValue), slowPath, &isExtensible); Bind(&isExtensible); diff --git a/test/moduletest/arrayConcat/arrayConcat.js b/test/moduletest/arrayConcat/arrayConcat.js index 69e492d2d3..377a03e144 100644 --- a/test/moduletest/arrayConcat/arrayConcat.js +++ b/test/moduletest/arrayConcat/arrayConcat.js @@ -16,3 +16,37 @@ const array1 = ['a', 'b', 'c']; const array2 = ['d', 'e', 'f']; const array3 = array1.concat(array2); print(array3); + +const letters = ["a", "b", "c"]; +const numbers = [1, 2, 3]; + +const alphaNumeric = letters.concat(numbers); +print(alphaNumeric); + +const num1 = [1, 2, 3]; +const num2 = [4, 5, 6]; +const num3 = [7, 8, 9]; + +const numbers1 = num1.concat(num2, num3); + +print(numbers1); + + +const letters1 = ["a", "b", "c"]; + +const alphaNumeric1 = letters1.concat(1, [2, 3]); + +print(alphaNumeric1); + +const num11 = [[1]]; +const num22 = [2, [3]]; + +const numbers2 = num1.concat(num22); + +print(numbers2); +// [[1], 2, [3]] + +num11[0].push(4); + +print(numbers2); + diff --git a/test/moduletest/arrayConcat/expect_output.txt b/test/moduletest/arrayConcat/expect_output.txt index 03d227dd03..4139bcfab6 100644 --- a/test/moduletest/arrayConcat/expect_output.txt +++ b/test/moduletest/arrayConcat/expect_output.txt @@ -12,3 +12,8 @@ # limitations under the License. a,b,c,d,e,f +a,b,c,1,2,3 +1,2,3,4,5,6,7,8,9 +a,b,c,1,2,3 +1,2,3,2,3 +1,2,3,2,3 -- Gitee From 2e1c797e857993d224ee4f7103629ae7d57dce53 Mon Sep 17 00:00:00 2001 From: yaoyuan Date: Fri, 24 Nov 2023 11:35:15 +0800 Subject: [PATCH 13/44] Instanceof Stub FastPath && AOT Instanceof bugfix Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8J4X8 Signed-off-by: yaoyuan Change-Id: I220725e5b71ff6b4c5528b5cc3fcb2177beb58aa --- ecmascript/compiler/stub_builder.cpp | 63 ++++++++++++++++++++--- ecmascript/compiler/stub_builder.h | 1 + ecmascript/compiler/type_hcr_lowering.cpp | 43 ++++++++++++++-- ecmascript/stubs/runtime_stubs.cpp | 8 +++ ecmascript/stubs/runtime_stubs.h | 1 + test/aottest/instanceof/expect_output.txt | 3 ++ test/aottest/instanceof/instanceof.ts | 10 ++++ 7 files changed, 118 insertions(+), 11 deletions(-) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 0bfe9e9ea5..c554d52de8 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -4408,6 +4408,35 @@ void StubBuilder::FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef inde env->SubCfgExit(); } +GateRef StubBuilder::GetCtorPrototype(GateRef ctor) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined()); + Label exit(env); + Label isHClass(env); + Label isPrototype(env); + + GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), ctor, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + Branch(IsJSHClass(ctorProtoOrHC), &isHClass, &isPrototype); + Bind(&isHClass); + { + constructorPrototype = Load(VariableType::JS_POINTER(), ctorProtoOrHC, IntPtr(JSHClass::PROTOTYPE_OFFSET)); + Jump(&exit); + } + Bind(&isPrototype); + { + constructorPrototype = ctorProtoOrHC; + Jump(&exit); + } + + Bind(&exit); + auto ret = *constructorPrototype; + env->SubCfgExit(); + return ret; +} + GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj) { auto env = GetEnvironment(); @@ -4457,10 +4486,32 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Bind(&objIsEcmaObject); { // 4. Let P be Get(C, "prototype"). - auto prototypeString = GetGlobalConstantValue( - VariableType::JS_POINTER(), glue, ConstantIndex::PROTOTYPE_STRING_INDEX); + Label getCtorProtoSlowPath(env); + Label ctorIsJSFunction(env); + Label gotCtorPrototype(env); + DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined()); + Branch(IsJSFunction(target), &ctorIsJSFunction, &getCtorProtoSlowPath); + Bind(&ctorIsJSFunction); + { + Label getCtorProtoFastPath(env); + GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), target, + IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - GateRef constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation()); + Branch(TaggedIsHole(ctorProtoOrHC), &getCtorProtoSlowPath, &getCtorProtoFastPath); + Bind(&getCtorProtoFastPath); + { + constructorPrototype = GetCtorPrototype(target); + Jump(&gotCtorPrototype); + } + } + Bind(&getCtorProtoSlowPath); + { + auto prototypeString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, + ConstantIndex::PROTOTYPE_STRING_INDEX); + constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation()); + Jump(&gotCtorPrototype); + } + Bind(&gotCtorPrototype); // 5. ReturnIfAbrupt(P). // no throw exception, so needn't return @@ -4478,10 +4529,10 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Label constructorPrototypeIsHeapObject(env); Label constructorPrototypeIsEcmaObject(env); Label constructorPrototypeNotEcmaObject(env); - Branch(TaggedIsHeapObject(constructorPrototype), &constructorPrototypeIsHeapObject, + Branch(TaggedIsHeapObject(*constructorPrototype), &constructorPrototypeIsHeapObject, &constructorPrototypeNotEcmaObject); Bind(&constructorPrototypeIsHeapObject); - Branch(TaggedObjectIsEcmaObject(constructorPrototype), &constructorPrototypeIsEcmaObject, + Branch(TaggedObjectIsEcmaObject(*constructorPrototype), &constructorPrototypeIsEcmaObject, &constructorPrototypeNotEcmaObject); Bind(&constructorPrototypeNotEcmaObject); { @@ -4508,7 +4559,7 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Branch(TaggedIsNull(*object), &afterLoop, &loopHead); LoopBegin(&loopHead); { - GateRef isEqual = SameValue(glue, *object, constructorPrototype); + GateRef isEqual = SameValue(glue, *object, *constructorPrototype); Branch(isEqual, &strictEqual1, ¬StrictEqual1); Bind(&strictEqual1); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 9fd812e3b2..607fef69e2 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -389,6 +389,7 @@ public: GateRef HclassIsTransitionHandler(GateRef hClass); GateRef HclassIsPropertyBox(GateRef hClass); GateRef PropAttrGetOffset(GateRef attr); + GateRef GetCtorPrototype(GateRef ctor); GateRef InstanceOf(GateRef glue, GateRef object, GateRef target, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback); GateRef OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj); diff --git a/ecmascript/compiler/type_hcr_lowering.cpp b/ecmascript/compiler/type_hcr_lowering.cpp index 1c73a99c73..3aa05ec9fd 100644 --- a/ecmascript/compiler/type_hcr_lowering.cpp +++ b/ecmascript/compiler/type_hcr_lowering.cpp @@ -2182,11 +2182,44 @@ void TypeHCRLowering::LowerOrdinaryHasInstance(GateRef gate, GateRef glue) builder_.Bind(&objIsEcmaObject); { // 4. Let P be Get(C, "prototype"). - // target must be a builtin function - GateRef ctorHClass = builder_.LoadConstOffset(VariableType::JS_POINTER(), target, - JSFunction::PROTO_OR_DYNCLASS_OFFSET); - GateRef constructorPrototype = builder_.LoadPrototype(ctorHClass); + Label getCtorProtoSlowPath(&builder_); + Label ctorIsJSFunction(&builder_); + Label gotCtorPrototype(&builder_); + DEFVALUE(constructorPrototype, (&builder_), VariableType::JS_ANY(), builder_.Undefined()); + builder_.Branch(builder_.IsJSFunction(target), &ctorIsJSFunction, &getCtorProtoSlowPath); + builder_.Bind(&ctorIsJSFunction); + { + Label getCtorProtoFastPath(&builder_); + GateRef ctorProtoOrHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), target, + JSFunction::PROTO_OR_DYNCLASS_OFFSET); + builder_.Branch(builder_.TaggedIsHole(ctorProtoOrHC), &getCtorProtoSlowPath, &getCtorProtoFastPath); + builder_.Bind(&getCtorProtoFastPath); + { + Label isHClass(&builder_); + Label isPrototype(&builder_); + builder_.Branch(builder_.IsJSHClass(ctorProtoOrHC), &isHClass, &isPrototype); + builder_.Bind(&isHClass); + { + constructorPrototype = builder_.LoadConstOffset(VariableType::JS_POINTER(), ctorProtoOrHC, + JSHClass::PROTOTYPE_OFFSET); + builder_.Jump(&gotCtorPrototype); + } + builder_.Bind(&isPrototype); + { + constructorPrototype = ctorProtoOrHC; + builder_.Jump(&gotCtorPrototype); + } + } + } + builder_.Bind(&getCtorProtoSlowPath); + { + auto prototypeString = builder_.GetGlobalConstantValue(ConstantIndex::PROTOTYPE_STRING_INDEX); + constructorPrototype = builder_.CallRuntime(glue, RTSTUB_ID(GetPropertyByName), Gate::InvalidGateRef, + { target, prototypeString }, gate); + builder_.Jump(&gotCtorPrototype); + } + builder_.Bind(&gotCtorPrototype); // 7. Repeat // a.Let O be O.[[GetPrototypeOf]](). // b.ReturnIfAbrupt(O). @@ -2203,7 +2236,7 @@ void TypeHCRLowering::LowerOrdinaryHasInstance(GateRef gate, GateRef glue) builder_.Branch(builder_.TaggedIsNull(*object), &afterLoop, &loopHead); builder_.LoopBegin(&loopHead); { - GateRef isEqual = builder_.Equal(*object, constructorPrototype); + GateRef isEqual = builder_.Equal(*object, *constructorPrototype); builder_.Branch(isEqual, &strictEqual1, ¬StrictEqual1); builder_.Bind(&strictEqual1); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 38449f0d2d..67e2ed1cb1 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2251,6 +2251,14 @@ DEF_RUNTIME_STUBS(FastCopyElementToArray) return JSTaggedValue(JSTypedArray::FastCopyElementToArray(thread, typedArray, array)).GetRawData(); } +DEF_RUNTIME_STUBS(GetPropertyByName) +{ + RUNTIME_STUBS_HEADER(GetPropertyByName); + JSHandle target = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSHandle key = GetHArg(argv, argc, 1); // 1: means the first parameter + return JSTaggedValue::GetProperty(thread, target, key).GetValue()->GetRawData(); +} + DEF_RUNTIME_STUBS(DebugAOTPrint) { RUNTIME_STUBS_HEADER(DebugAOTPrint); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 19fdd642d6..9c8204bcec 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -316,6 +316,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(GetTypeArrayPropertyByIndex) \ V(SetTypeArrayPropertyByIndex) \ V(FastCopyElementToArray) \ + V(GetPropertyByName) \ V(JSObjectGetMethod) \ V(DebugAOTPrint) \ V(ProfileOptimizedCode) \ diff --git a/test/aottest/instanceof/expect_output.txt b/test/aottest/instanceof/expect_output.txt index bedb3fa1dd..0bb3008073 100644 --- a/test/aottest/instanceof/expect_output.txt +++ b/test/aottest/instanceof/expect_output.txt @@ -22,6 +22,9 @@ true false true true +false +true +true true true true diff --git a/test/aottest/instanceof/instanceof.ts b/test/aottest/instanceof/instanceof.ts index 7a313e98bc..42e91d58c3 100644 --- a/test/aottest/instanceof/instanceof.ts +++ b/test/aottest/instanceof/instanceof.ts @@ -67,6 +67,16 @@ function test5() { } test5(); +function foo() {}; +function bar() {}; +const proxy = new Proxy(foo, {}); + +let f = new foo(); + +print(f instanceof foo); // true +print(f instanceof proxy); // true +print(f instanceof bar); // false + print(ArkTools.isAOTCompiled(test1)); print(ArkTools.isAOTCompiled(test2)); print(ArkTools.isAOTCompiled(test3)); -- Gitee From fed086b8dfd33c9b5c7fc4c8fabeefaae9f495d6 Mon Sep 17 00:00:00 2001 From: liuzhijie Date: Wed, 15 Nov 2023 17:09:56 +0800 Subject: [PATCH 14/44] StrictNotEq fastpath Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8GQOL?from=project-issue Signed-off-by: liuzhijie Change-Id: I7dfeecec59f49cfe1dd0ee3a44570d7f023a8a75 --- ecmascript/compiler/bytecodes.cpp | 1 + ecmascript/compiler/circuit_builder.h | 1 + ecmascript/compiler/mcr_circuit_builder.h | 10 ++++ ecmascript/compiler/mcr_gate_meta_data.h | 1 + .../compiler/number_speculative_lowering.cpp | 55 ++++++++++++++----- .../compiler/number_speculative_lowering.h | 8 +-- .../compiler/number_speculative_retype.cpp | 19 ++++--- .../compiler/number_speculative_retype.h | 4 +- .../compiler/type_bytecode_lowering.cpp | 15 +++-- ecmascript/compiler/type_bytecode_lowering.h | 2 +- test/aottest/BUILD.gn | 1 + .../binaryop_special_value.ts | 19 +++++++ .../binaryop_special_value/expect_output.txt | 19 +++++++ test/aottest/not_equal/BUILD.gn | 18 ++++++ test/aottest/not_equal/expect_output.txt | 37 +++++++++++++ test/aottest/not_equal/not_equal.js | 50 +++++++++++++++++ 16 files changed, 226 insertions(+), 34 deletions(-) create mode 100644 test/aottest/not_equal/BUILD.gn create mode 100644 test/aottest/not_equal/expect_output.txt create mode 100644 test/aottest/not_equal/not_equal.js diff --git a/ecmascript/compiler/bytecodes.cpp b/ecmascript/compiler/bytecodes.cpp index b4bdc73596..7b0a094e33 100644 --- a/ecmascript/compiler/bytecodes.cpp +++ b/ecmascript/compiler/bytecodes.cpp @@ -210,6 +210,7 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc) case EcmaOpcode::GREATER_IMM8_V8: case EcmaOpcode::GREATEREQ_IMM8_V8: case EcmaOpcode::STRICTEQ_IMM8_V8: + case EcmaOpcode::STRICTNOTEQ_IMM8_V8: case EcmaOpcode::TONUMERIC_IMM8: case EcmaOpcode::ISTRUE: case EcmaOpcode::ISFALSE: diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 399b66fdc2..28a8f7246e 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -580,6 +580,7 @@ public: inline GateRef TaggedIsStoreTSHandler(GateRef x); inline GateRef TaggedIsTransWithProtoHandler(GateRef x); inline GateRef TaggedIsUndefinedOrNull(GateRef x); + inline GateRef TaggedIsNotUndefinedAndNull(GateRef x); inline GateRef TaggedIsTrue(GateRef x); inline GateRef TaggedIsFalse(GateRef x); inline GateRef TaggedIsNull(GateRef x); diff --git a/ecmascript/compiler/mcr_circuit_builder.h b/ecmascript/compiler/mcr_circuit_builder.h index 3b7ded3ecc..e0077bba38 100644 --- a/ecmascript/compiler/mcr_circuit_builder.h +++ b/ecmascript/compiler/mcr_circuit_builder.h @@ -389,6 +389,16 @@ GateRef CircuitBuilder::TaggedIsUndefinedOrNull(GateRef x) return result; } +GateRef CircuitBuilder::TaggedIsNotUndefinedAndNull(GateRef x) +{ + x = ChangeTaggedPointerToInt64(x); + GateRef heapObjMask = Int64(JSTaggedValue::TAG_HEAPOBJECT_MASK); + GateRef tagSpecial = Int64(JSTaggedValue::TAG_SPECIAL); + GateRef andGate = Int64And(x, heapObjMask); + GateRef result = NotEqual(andGate, tagSpecial); + return result; +} + GateRef CircuitBuilder::TaggedTrue() { return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_TRUE, GateType::TaggedValue()); diff --git a/ecmascript/compiler/mcr_gate_meta_data.h b/ecmascript/compiler/mcr_gate_meta_data.h index 440660e9b7..6e68ff88d2 100644 --- a/ecmascript/compiler/mcr_gate_meta_data.h +++ b/ecmascript/compiler/mcr_gate_meta_data.h @@ -44,6 +44,7 @@ namespace panda::ecmascript::kungfu { V(TYPED_EQ) \ V(TYPED_NOTEQ) \ V(TYPED_STRICTEQ) \ + V(TYPED_STRICTNOTEQ) \ V(TYPED_SHL) \ V(TYPED_SHR) \ V(TYPED_ASHR) \ diff --git a/ecmascript/compiler/number_speculative_lowering.cpp b/ecmascript/compiler/number_speculative_lowering.cpp index 74434b50d0..3d04bf6834 100644 --- a/ecmascript/compiler/number_speculative_lowering.cpp +++ b/ecmascript/compiler/number_speculative_lowering.cpp @@ -116,12 +116,14 @@ void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate) } auto op = acc_.GetTypedBinaryOp(gate); switch (op) { - case TypedBinOp::TYPED_STRICTEQ: { - VisitStrictEqual(gate); + case TypedBinOp::TYPED_STRICTEQ: + case TypedBinOp::TYPED_STRICTNOTEQ: { + VisitStrictEqualOrStrictNotEqual(gate); break; } - case TypedBinOp::TYPED_EQ: { - VisitEqual(gate); + case TypedBinOp::TYPED_EQ: + case TypedBinOp::TYPED_NOTEQ: { + VisitEqualOrNotEqual(gate); break; } default: { @@ -133,21 +135,21 @@ void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate) } } -void NumberSpeculativeLowering::VisitEqual(GateRef gate) +void NumberSpeculativeLowering::VisitEqualOrNotEqual(GateRef gate) { if (acc_.HasNumberType(gate)) { VisitNumberBinaryOp(gate); } else { - VisitUndefinedEq(gate); + VisitUndefinedEqOrUndefinedNotEq(gate); } } -void NumberSpeculativeLowering::VisitStrictEqual(GateRef gate) +void NumberSpeculativeLowering::VisitStrictEqualOrStrictNotEqual(GateRef gate) { if (acc_.HasNumberType(gate)) { VisitNumberBinaryOp(gate); } else { - VisitUndefinedStrictEq(gate); + VisitUndefinedStrictEqOrUndefinedStrictNotEq(gate); } } @@ -195,6 +197,10 @@ void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate) VisitNumberCompare(gate); break; } + case TypedBinOp::TYPED_STRICTNOTEQ: { + VisitNumberCompare(gate); + break; + } case TypedBinOp::TYPED_SHL: { VisitNumberShift(gate); break; @@ -476,26 +482,39 @@ void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate) acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate()); } -void NumberSpeculativeLowering::VisitUndefinedStrictEq(GateRef gate) +void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate) { - ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ); + ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ); GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); ASSERT(acc_.IsUndefinedOrNull(left) || acc_.IsUndefinedOrNull(right)); - GateRef result = builder_.Equal(left, right); + GateRef result = Circuit::NullGate(); + if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) { + result = builder_.Equal(left, right); + } else { + result = builder_.NotEqual(left, right); + } + ASSERT(result != Circuit::NullGate()); acc_.SetMachineType(gate, MachineType::I1); acc_.SetGateType(gate, GateType::NJSValue()); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } -void NumberSpeculativeLowering::VisitUndefinedEq(GateRef gate) +void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate) { - ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ); + ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ); GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); ASSERT(acc_.IsUndefinedOrNull(left) || acc_.IsUndefinedOrNull(right)); GateRef valueGate = acc_.IsUndefinedOrNull(left) ? right : left; - GateRef result = builder_.TaggedIsUndefinedOrNull(valueGate); + GateRef result = Circuit::NullGate(); + if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) { + result = builder_.TaggedIsUndefinedOrNull(valueGate); + } else { + result = builder_.TaggedIsNotUndefinedAndNull(valueGate); + } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } @@ -730,6 +749,7 @@ GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right) condition = builder_.Int32Equal(left, right); break; case TypedBinOp::TYPED_NOTEQ: + case TypedBinOp::TYPED_STRICTNOTEQ: condition = builder_.Int32NotEqual(left, right); break; default: @@ -768,6 +788,13 @@ GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right) condition = builder_.BoolAnd(builder_.BoolAnd(leftNotNan, rightNotNan), doubleEqual); break; } + case TypedBinOp::TYPED_STRICTNOTEQ: { + GateRef leftNotNan = builder_.BoolNot(builder_.DoubleIsNAN(left)); + GateRef rightNotNan = builder_.BoolNot(builder_.DoubleIsNAN(right)); + GateRef doubleEqual = builder_.DoubleNotEqual(left, right); + condition = builder_.BoolAnd(builder_.BoolAnd(leftNotNan, rightNotNan), doubleEqual); + break; + } default: break; } diff --git a/ecmascript/compiler/number_speculative_lowering.h b/ecmascript/compiler/number_speculative_lowering.h index fe5e1cebdf..28b3c3c556 100644 --- a/ecmascript/compiler/number_speculative_lowering.h +++ b/ecmascript/compiler/number_speculative_lowering.h @@ -43,9 +43,9 @@ private: void VisitTypedConditionJump(GateRef gate); void VisitConstant(GateRef gate); void VisitPhi(GateRef gate); - void VisitUndefinedStrictEq(GateRef gate); - void VisitUndefinedEq(GateRef gate); - void VisitEqual(GateRef gate); + void VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate); + void VisitUndefinedEqOrUndefinedNotEq(GateRef gate); + void VisitEqualOrNotEqual(GateRef gate); void VisitCallBuiltins(GateRef gate); void VisitRangeGuard(GateRef gate); void VisitRangeCheckPredicate(GateRef gate); @@ -70,7 +70,7 @@ private: void VisitNumberMod(GateRef gate); void VisitBooleanJump(GateRef gate); void VisitIsTrueOrFalse(GateRef gate, bool flag); - void VisitStrictEqual(GateRef gate); + void VisitStrictEqualOrStrictNotEqual(GateRef gate); template void VisitStringCompare(GateRef gate); diff --git a/ecmascript/compiler/number_speculative_retype.cpp b/ecmascript/compiler/number_speculative_retype.cpp index ad1e498b0f..62974d3431 100644 --- a/ecmascript/compiler/number_speculative_retype.cpp +++ b/ecmascript/compiler/number_speculative_retype.cpp @@ -160,28 +160,32 @@ GateRef NumberSpeculativeRetype::VisitTypedBinaryOp(GateRef gate) } if (acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_STRICTEQ && - acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_EQ) { + acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_STRICTNOTEQ && + acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_EQ && + acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_NOTEQ) { if (acc_.HasPrimitiveNumberType(gate)) { return VisitNumberBinaryOp(gate); } } - return VisitEqualOrStrictEqual(gate); + return VisitEqualCompareOrNotEqualCompare(gate); } -GateRef NumberSpeculativeRetype::VisitEqualOrStrictEqual(GateRef gate) +GateRef NumberSpeculativeRetype::VisitEqualCompareOrNotEqualCompare(GateRef gate) { if (acc_.HasNumberType(gate)) { return VisitNumberBinaryOp(gate); } else { - return VisitUndefinedEqOrStrictEq(gate); + return VisitUndefinedEqualCompareOrUndefinedNotEqualCompare(gate); } } -GateRef NumberSpeculativeRetype::VisitUndefinedEqOrStrictEq(GateRef gate) +GateRef NumberSpeculativeRetype::VisitUndefinedEqualCompareOrUndefinedNotEqualCompare(GateRef gate) { ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ || - acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ); + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ); GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); ASSERT((acc_.IsUndefinedOrNull(left)) || (acc_.IsUndefinedOrNull(right))); @@ -361,7 +365,8 @@ GateRef NumberSpeculativeRetype::VisitNumberBinaryOp(GateRef gate) case TypedBinOp::TYPED_GREATEREQ: case TypedBinOp::TYPED_EQ: case TypedBinOp::TYPED_NOTEQ: - case TypedBinOp::TYPED_STRICTEQ: { + case TypedBinOp::TYPED_STRICTEQ: + case TypedBinOp::TYPED_STRICTNOTEQ: { return VisitNumberCompare(gate); } case TypedBinOp::TYPED_SHL: diff --git a/ecmascript/compiler/number_speculative_retype.h b/ecmascript/compiler/number_speculative_retype.h index 6d83be0b49..b42a05ee8a 100644 --- a/ecmascript/compiler/number_speculative_retype.h +++ b/ecmascript/compiler/number_speculative_retype.h @@ -64,7 +64,7 @@ private: GateRef VisitTypedBinaryOp(GateRef gate); GateRef VisitNumberBinaryOp(GateRef gate); GateRef VisitStringBinaryOp(GateRef gate); - GateRef VisitUndefinedEqOrStrictEq(GateRef gate); + GateRef VisitUndefinedEqualCompareOrUndefinedNotEqualCompare(GateRef gate); GateRef VisitTypedUnaryOp(GateRef gate); GateRef VisitNumberMonocular(GateRef gate); @@ -95,7 +95,7 @@ private: GateRef VisitIsTrueOrFalse(GateRef gate); GateRef VisitWithConstantValue(GateRef gate, size_t ignoreIndex); GateRef VisitIntermediateValue(GateRef gate); - GateRef VisitEqualOrStrictEqual(GateRef gate); + GateRef VisitEqualCompareOrNotEqualCompare(GateRef gate); GateRef VisitStringCompare(GateRef gate); GateRef VisitStringAdd(GateRef gate); diff --git a/ecmascript/compiler/type_bytecode_lowering.cpp b/ecmascript/compiler/type_bytecode_lowering.cpp index 46399a44ef..18c3d908eb 100644 --- a/ecmascript/compiler/type_bytecode_lowering.cpp +++ b/ecmascript/compiler/type_bytecode_lowering.cpp @@ -185,13 +185,16 @@ void TypeBytecodeLowering::Lower(GateRef gate) LowerTypedBinOp(gate); break; case EcmaOpcode::EQ_IMM8_V8: - LowerTypedEqOrStrictEq(gate); + LowerTypedEqOrNotEq(gate); break; case EcmaOpcode::STRICTEQ_IMM8_V8: - LowerTypedEqOrStrictEq(gate); + LowerTypedEqOrNotEq(gate); break; case EcmaOpcode::NOTEQ_IMM8_V8: - LowerTypedBinOp(gate, false); + LowerTypedEqOrNotEq(gate); + break; + case EcmaOpcode::STRICTNOTEQ_IMM8_V8: + LowerTypedEqOrNotEq(gate); break; case EcmaOpcode::SHL2_IMM8_V8: LowerTypedBinOp(gate); @@ -371,7 +374,7 @@ void TypeBytecodeLowering::LowerTypedUnOp(GateRef gate) } template -void TypeBytecodeLowering::LowerTypedEqOrStrictEq(GateRef gate) +void TypeBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate) { GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); @@ -1600,7 +1603,7 @@ void TypeBytecodeLowering::LowerTypedSuperCall(GateRef gate) } void TypeBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector &args, - BuiltinsStubCSigns::ID id, bool isThrow) + BuiltinsStubCSigns::ID id, bool isThrow) { if (!Uncheck()) { builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast(id)), args[0]); @@ -1828,7 +1831,7 @@ bool TypeBytecodeLowering::CanOptimizeAsFastCall(GateRef func) } void TypeBytecodeLowering::CheckFastCallThisCallTarget(GateRef gate, GateRef func, GlobalTSTypeRef funcGt, - GateType funcType, bool isNoGC) + GateType funcType, bool isNoGC) { if (noCheck_) { return; diff --git a/ecmascript/compiler/type_bytecode_lowering.h b/ecmascript/compiler/type_bytecode_lowering.h index 1f1b509edd..ab78538887 100644 --- a/ecmascript/compiler/type_bytecode_lowering.h +++ b/ecmascript/compiler/type_bytecode_lowering.h @@ -101,7 +101,7 @@ private: template void LowerTypedUnOp(GateRef gate); template - void LowerTypedEqOrStrictEq(GateRef gate); + void LowerTypedEqOrNotEq(GateRef gate); void LowerTypeToNumeric(GateRef gate); void LowerPrimitiveTypeToNumber(GateRef gate); void LowerConditionJump(GateRef gate, bool flag); diff --git a/test/aottest/BUILD.gn b/test/aottest/BUILD.gn index b3050b7ed5..9f42e82c6e 100644 --- a/test/aottest/BUILD.gn +++ b/test/aottest/BUILD.gn @@ -177,6 +177,7 @@ group("ark_aot_ts_test") { "newobjrange", "newobjspread", "not", + "not_equal", "numberspeculativeretype", "operations_stub_test", "optimization", diff --git a/test/aottest/binaryop_special_value/binaryop_special_value.ts b/test/aottest/binaryop_special_value/binaryop_special_value.ts index 0314c044b6..3d8a9ae6a6 100644 --- a/test/aottest/binaryop_special_value/binaryop_special_value.ts +++ b/test/aottest/binaryop_special_value/binaryop_special_value.ts @@ -36,6 +36,7 @@ print(intNum >= undf); print(intNum == undf); print(intNum === undf); print(intNum != undf); +print(intNum !== undf); print(intNum << undf); print(intNum >> undf); print(intNum >>> undf); @@ -56,6 +57,7 @@ print(doubleNum >= undf); print(doubleNum == undf); print(doubleNum === undf); print(doubleNum != undf); +print(doubleNum !== undf); print(doubleNum << undf); print(doubleNum >> undf); print(doubleNum >>> undf); @@ -76,6 +78,7 @@ print(falseValue >= undf); print(falseValue == undf); print(falseValue === undf); print(falseValue != undf); +print(falseValue !== undf); print(falseValue << undf); print(falseValue >> undf); print(falseValue >>> undf); @@ -96,6 +99,7 @@ print(trueValue >= undf); print(trueValue == undf); print(trueValue === undf); print(trueValue != undf); +print(trueValue !== undf); print(trueValue << undf); print(trueValue >> undf); print(trueValue >>> undf); @@ -116,6 +120,7 @@ print(nullValue >= undf); print(nullValue == undf); print(nullValue === undf); print(nullValue != undf); +print(nullValue !== undf); print(nullValue << undf); print(nullValue >> undf); print(nullValue >>> undf); @@ -136,6 +141,7 @@ print(intNum >= nullValue); print(intNum == nullValue); print(intNum === nullValue); print(intNum != nullValue); +print(intNum !== nullValue); print(intNum << nullValue); print(intNum >> nullValue); print(intNum >>> nullValue); @@ -156,6 +162,7 @@ print(doubleNum >= nullValue); print(doubleNum == nullValue); print(doubleNum === nullValue); print(doubleNum != nullValue); +print(doubleNum !== nullValue); print(doubleNum << nullValue); print(doubleNum >> nullValue); print(doubleNum >>> nullValue); @@ -176,6 +183,7 @@ print(falseValue >= nullValue); print(falseValue == nullValue); print(falseValue === nullValue); print(falseValue != nullValue); +print(falseValue !== nullValue); print(falseValue << nullValue); print(falseValue >> nullValue); print(falseValue >>> nullValue); @@ -196,6 +204,7 @@ print(trueValue >= nullValue); print(trueValue == nullValue); print(trueValue === nullValue); print(trueValue != nullValue); +print(trueValue !== nullValue); print(trueValue << nullValue); print(trueValue >> nullValue); print(trueValue >>> nullValue); @@ -216,6 +225,7 @@ print(intNum >= falseValue); print(intNum == falseValue); print(intNum === falseValue); print(intNum != falseValue); +print(intNum !== falseValue); print(intNum << falseValue); print(intNum >> falseValue); print(intNum >>> falseValue); @@ -236,6 +246,7 @@ print(doubleNum >= falseValue); print(doubleNum == falseValue); print(doubleNum === falseValue); print(doubleNum != falseValue); +print(doubleNum !== falseValue); print(doubleNum << falseValue); print(doubleNum >> falseValue); print(doubleNum >>> falseValue); @@ -256,6 +267,7 @@ print(trueValue >= falseValue); print(trueValue == falseValue); print(trueValue === falseValue); print(trueValue != falseValue); +print(trueValue !== falseValue); print(trueValue << falseValue); print(trueValue >> falseValue); print(trueValue >>> falseValue); @@ -276,6 +288,7 @@ print(intNum >= trueValue); print(intNum == trueValue); print(intNum === trueValue); print(intNum != trueValue); +print(intNum !== trueValue); print(intNum << trueValue); print(intNum >> trueValue); print(intNum >>> trueValue); @@ -296,6 +309,7 @@ print(doubleNum >= trueValue); print(doubleNum == trueValue); print(doubleNum === trueValue); print(doubleNum != trueValue); +print(doubleNum !== trueValue); print(doubleNum << trueValue); print(doubleNum >> trueValue); print(doubleNum >>> trueValue); @@ -316,6 +330,7 @@ print(trueValue >= falseValue); print(trueValue == falseValue); print(trueValue === falseValue); print(trueValue != falseValue); +print(trueValue !== falseValue); print(trueValue << falseValue); print(trueValue >> falseValue); print(trueValue >>> falseValue); @@ -336,6 +351,7 @@ print(undf >= undf); print(undf == undf); print(undf === undf); print(undf != undf); +print(undf !== undf); print(undf << undf); print(undf >> undf); print(undf >>> undf); @@ -356,6 +372,7 @@ print(nullValue >= nullValue); print(nullValue == nullValue); print(nullValue === nullValue); print(nullValue != nullValue); +print(nullValue !== nullValue); print(nullValue << nullValue); print(nullValue >> nullValue); print(nullValue >>> nullValue); @@ -376,6 +393,7 @@ print(trueValue >= trueValue); print(trueValue == trueValue); print(trueValue === trueValue); print(trueValue != trueValue); +print(trueValue !== trueValue); print(trueValue << trueValue); print(trueValue >> trueValue); print(trueValue >>> trueValue); @@ -396,6 +414,7 @@ print(falseValue >= falseValue); print(falseValue == falseValue); print(falseValue === falseValue); print(falseValue != falseValue); +print(falseValue !== falseValue); print(falseValue << falseValue); print(falseValue >> falseValue); print(falseValue >>> falseValue); diff --git a/test/aottest/binaryop_special_value/expect_output.txt b/test/aottest/binaryop_special_value/expect_output.txt index d9c4fc4348..80806963d8 100644 --- a/test/aottest/binaryop_special_value/expect_output.txt +++ b/test/aottest/binaryop_special_value/expect_output.txt @@ -24,6 +24,7 @@ false false false true +true 5 5 5 @@ -42,6 +43,7 @@ false false false true +true 1 1 1 @@ -60,6 +62,7 @@ false false false true +true 0 0 0 @@ -78,6 +81,7 @@ false false false true +true 1 1 1 @@ -96,6 +100,7 @@ false true false false +true 0 0 0 @@ -114,6 +119,7 @@ true false false true +true 5 5 5 @@ -132,6 +138,7 @@ true false false true +true 1 1 1 @@ -150,6 +157,7 @@ true false false true +true 0 0 0 @@ -168,6 +176,7 @@ true false false true +true 1 1 1 @@ -186,6 +195,7 @@ true false false true +true 5 5 5 @@ -204,6 +214,7 @@ true false false true +true 1 1 1 @@ -222,6 +233,7 @@ true false false true +true 1 1 1 @@ -240,6 +252,7 @@ true false false true +true 10 2 2 @@ -258,6 +271,7 @@ true false false true +true 2 0 0 @@ -276,6 +290,7 @@ true false false true +true 1 1 1 @@ -294,6 +309,7 @@ false true true false +false 0 0 0 @@ -312,6 +328,7 @@ true true true false +false 0 0 0 @@ -330,6 +347,7 @@ true true true false +false 2 0 0 @@ -348,6 +366,7 @@ true true true false +false 0 0 0 diff --git a/test/aottest/not_equal/BUILD.gn b/test/aottest/not_equal/BUILD.gn new file mode 100644 index 0000000000..1c035d43b8 --- /dev/null +++ b/test/aottest/not_equal/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_js_test_action("not_equal") { + deps = [] +} diff --git a/test/aottest/not_equal/expect_output.txt b/test/aottest/not_equal/expect_output.txt new file mode 100644 index 0000000000..866e77b029 --- /dev/null +++ b/test/aottest/not_equal/expect_output.txt @@ -0,0 +1,37 @@ +# 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. + +true +true +true +true +false +false +false +false +false +false +false +false +true +true +true +true +false +false +true +true +true +true +false +false diff --git a/test/aottest/not_equal/not_equal.js b/test/aottest/not_equal/not_equal.js new file mode 100644 index 0000000000..e81d3634f8 --- /dev/null +++ b/test/aottest/not_equal/not_equal.js @@ -0,0 +1,50 @@ +/* + * 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. + */ + +var a = 2; +print(a != null); +print(null != a); +print(a != undefined); +print(undefined != a); + +var b = null; +print(b != null); +print(null != b); +print(b != undefined); +print(undefined != b); + +var c = undefined; +print(c != null); +print(null != c); +print(c != undefined); +print(undefined != c); + +var d = 2; +print(d !== null); +print(null !== d); +print(d !== undefined); +print(undefined !== d); + +var e = null; +print(e !== null); +print(null !== e); +print(e !== undefined); +print(undefined !== e); + +var f = undefined; +print(f !== null); +print(null !== f); +print(f !== undefined); +print(undefined !== f); \ No newline at end of file -- Gitee From c6058f098315f554f60d066b889d435bae168829 Mon Sep 17 00:00:00 2001 From: yycc Date: Thu, 23 Nov 2023 16:08:28 +0800 Subject: [PATCH 15/44] PGO surport StringAdd Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8IXBO Description: add profileOpType for stringadd Signed-off-by: yycc Change-Id: I94500bb91a14c11321d4e88bccc8e6f674e9f6a1 --- .../compiler/number_speculative_retype.cpp | 13 +++++ ecmascript/compiler/stub_builder.cpp | 1 + test/aottest/BUILD.gn | 1 + test/aottest/js_string_add/BUILD.gn | 19 ++++++++ test/aottest/js_string_add/expect_output.txt | 23 +++++++++ test/aottest/js_string_add/js_string_add.js | 47 +++++++++++++++++++ .../js_string_add/pgo_expect_output.txt | 23 +++++++++ test/aottest/js_string_equal/BUILD.gn | 1 + .../js_string_equal/pgo_expect_output.txt | 21 +++++++++ 9 files changed, 149 insertions(+) create mode 100644 test/aottest/js_string_add/BUILD.gn create mode 100644 test/aottest/js_string_add/expect_output.txt create mode 100644 test/aottest/js_string_add/js_string_add.js create mode 100644 test/aottest/js_string_add/pgo_expect_output.txt create mode 100644 test/aottest/js_string_equal/pgo_expect_output.txt diff --git a/ecmascript/compiler/number_speculative_retype.cpp b/ecmascript/compiler/number_speculative_retype.cpp index ad1e498b0f..fa4d50e67e 100644 --- a/ecmascript/compiler/number_speculative_retype.cpp +++ b/ecmascript/compiler/number_speculative_retype.cpp @@ -259,6 +259,19 @@ GateRef NumberSpeculativeRetype::VisitStringAdd(GateRef gate) if (IsRetype()) { return SetOutputType(gate, GateType::StringType()); } + if (IsConvert()) { + Environment env(gate, circuit_, &builder_); + size_t valueNum = acc_.GetNumValueIn(gate); + for (size_t i = 0; i < valueNum; ++i) { + GateRef input = acc_.GetValueIn(gate, i); + TypeInfo inputInfo = GetOutputTypeInfo(input); + if (inputInfo == TypeInfo::CHAR) { + GateRef glue = acc_.GetGlueFromArgList(); + input = builder_.CallStub(glue, gate, CommonStubCSigns::CreateStringBySingleCharCode, { glue, input }); + } + acc_.ReplaceValueIn(gate, input, i); + } + } return Circuit::NullGate(); } diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index e81404c85e..a6320e83aa 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -5480,6 +5480,7 @@ GateRef StubBuilder::FastBinaryOp(GateRef glue, GateRef left, GateRef right, Branch(bothString, &stringAdd, &exit); Bind(&stringAdd); { + callback.ProfileOpType(Int32(PGOSampleType::StringType())); BuiltinsStringStubBuilder builtinsStringStubBuilder(this); result = builtinsStringStubBuilder.StringConcat(glue, left, right); Branch(HasPendingException(glue), &hasPendingException, &exit); diff --git a/test/aottest/BUILD.gn b/test/aottest/BUILD.gn index b3050b7ed5..98953aa7d1 100644 --- a/test/aottest/BUILD.gn +++ b/test/aottest/BUILD.gn @@ -29,6 +29,7 @@ group("ark_aot_js_test") { "dead_code_elimination", "equal", "js_string_equal", + "js_string_add", ] deps = [] diff --git a/test/aottest/js_string_add/BUILD.gn b/test/aottest/js_string_add/BUILD.gn new file mode 100644 index 0000000000..4153c71ad0 --- /dev/null +++ b/test/aottest/js_string_add/BUILD.gn @@ -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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_aot_js_test_action("js_string_add") { + deps = [] + is_enable_pgo = true +} diff --git a/test/aottest/js_string_add/expect_output.txt b/test/aottest/js_string_add/expect_output.txt new file mode 100644 index 0000000000..9b05ecd62e --- /dev/null +++ b/test/aottest/js_string_add/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. + +HelloWorld +Hello WorldHello +123 +Hello, OD +Hello, Huawei +Hello, +BUGBUG +BUGfull of bug +full of bugfull of bug +%F0 diff --git a/test/aottest/js_string_add/js_string_add.js b/test/aottest/js_string_add/js_string_add.js new file mode 100644 index 0000000000..c2b9aff45b --- /dev/null +++ b/test/aottest/js_string_add/js_string_add.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. + */ + +let str = "Hello World"; + +// two const +print("Hello" + "World"); +print(str + "Hello"); +print("" + "" + "123" + ""); + +// one const +let strs = ["OD", "Huawei", ""]; +for (let i = 0; i<3; ++i) { + let m = strs[i]; + print("Hello, " + m); +} + +// no const +function foo(flag) { + let str = ["BUG", "full of bug"]; + if (flag) { + return str[0]; + } else { + return str[1]; + } +} +let left = foo(true); +let right1 = foo(true); +let right2 = foo(false); +print(left + right1); +print(left + right2); +print(right2 + right2); + +var hex = "0123456789ABCDEF"; +print("%" + hex[(0xF0 >> 4) & 0xf] + hex[0xF0 & 0xf]); \ No newline at end of file diff --git a/test/aottest/js_string_add/pgo_expect_output.txt b/test/aottest/js_string_add/pgo_expect_output.txt new file mode 100644 index 0000000000..9b05ecd62e --- /dev/null +++ b/test/aottest/js_string_add/pgo_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. + +HelloWorld +Hello WorldHello +123 +Hello, OD +Hello, Huawei +Hello, +BUGBUG +BUGfull of bug +full of bugfull of bug +%F0 diff --git a/test/aottest/js_string_equal/BUILD.gn b/test/aottest/js_string_equal/BUILD.gn index 6ecf3f70f5..801765f9cf 100644 --- a/test/aottest/js_string_equal/BUILD.gn +++ b/test/aottest/js_string_equal/BUILD.gn @@ -15,4 +15,5 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") host_aot_js_test_action("js_string_equal") { deps = [] + is_enable_pgo = true } diff --git a/test/aottest/js_string_equal/pgo_expect_output.txt b/test/aottest/js_string_equal/pgo_expect_output.txt new file mode 100644 index 0000000000..a51946ab51 --- /dev/null +++ b/test/aottest/js_string_equal/pgo_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. + +true +true +false +false +true +false +false +true -- Gitee From b41ec68832a16b16b58c9cfff086257147d819e2 Mon Sep 17 00:00:00 2001 From: ginxu Date: Thu, 23 Nov 2023 14:37:51 +0800 Subject: [PATCH 16/44] JSON Parse Refactor 1. Recursive framework changed to loop framework. 2. Optimize json Array and Object creation. Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8IXV8 Signed-off-by: ginxu Change-Id: I5e369babad6ad0a3f710e1616cc48f9d1dd7158d --- ecmascript/base/json_parser.h | 362 +++++++++++------- ecmascript/base/tests/json_parser_test.cpp | 2 +- ecmascript/object_factory.cpp | 26 ++ ecmascript/object_factory.h | 3 + .../aottest/exception_case1/expect_output.txt | 2 +- .../exception_case11/expect_output.txt | 2 +- .../exception_case12/expect_output.txt | 2 +- .../aottest/exception_case8/expect_output.txt | 2 +- .../ts_inline_exception3/expect_output.txt | 2 +- .../ts_inline_exception7/expect_output.txt | 2 +- 10 files changed, 261 insertions(+), 144 deletions(-) diff --git a/ecmascript/base/json_parser.h b/ecmascript/base/json_parser.h index bf21ab47b7..c280d0a265 100644 --- a/ecmascript/base/json_parser.h +++ b/ecmascript/base/json_parser.h @@ -53,10 +53,23 @@ enum class Tokens : uint8_t { TOKEN_ILLEGAL, }; +struct JsonContinuation { + enum class ContinuationType : uint8_t { + RETURN = 0, + ARRAY, + OBJECT, + }; + JsonContinuation(ContinuationType type, size_t index) : type_(type), index_(index) {} + + ContinuationType type_ {ContinuationType::RETURN}; + size_t index_ {0}; +}; + template class JsonParser { protected: using Text = const T *; + using ContType = JsonContinuation::ContinuationType; // Instantiation of the class is prohibited JsonParser() = default; explicit JsonParser(JSThread *thread) : thread_(thread) {} @@ -78,6 +91,11 @@ protected: auto vm = thread_->GetEcmaVM(); factory_ = vm->GetFactory(); env_ = *vm->GetGlobalEnv(); + JSHandle arrayFunc(env_->GetArrayFunction()); + initialJSArrayClass_ = JSHandle(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, arrayFunc)); + JSHandle objectFunc(env_->GetObjectFunction()); + initialJSObjectClass_ = + JSHandle(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, objectFunc)); SkipEndWhiteSpace(); range_ = end_; @@ -85,28 +103,195 @@ protected: return JSHandle(thread_, result); } - JSTaggedValue ParseJSONText(bool inObjorArr = false) + inline bool IsInObjOrArray(ContType type) + { + return type == ContType::ARRAY || type == ContType::OBJECT; + } + + inline bool EmptyArrayCheck() + { + GetNextNonSpaceChar(); + return *current_ == ']'; + } + + inline bool EmptyObjectCheck() + { + GetNextNonSpaceChar(); + return *current_ == '}'; + } + + JSTaggedValue ParseJSONText() + { + JSHandle parseValue; + std::vector continuationList; + std::vector> elementsList; + std::vector> propertyList; + continuationList.reserve(16); // 16: initial capacity + elementsList.reserve(16); // 16: initial capacity + propertyList.reserve(16); // 16: initial capacity + JsonContinuation continuation(ContType::RETURN, 0); + while (true) { + while (true) { + SkipStartWhiteSpace(); + Tokens token = ParseToken(); + switch (token) { + case Tokens::OBJECT: + if (EmptyObjectCheck()) { + parseValue = JSHandle(factory_->NewJSObject(initialJSObjectClass_)); + GetNextNonSpaceChar(); + break; + } + continuationList.emplace_back(std::move(continuation)); + continuation = JsonContinuation(ContType::OBJECT, propertyList.size()); + + SkipStartWhiteSpace(); + if (*current_ == '"') { + propertyList.emplace_back(JSHandle(thread_, ParseString(true))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON", + JSTaggedValue::Exception()); + } + SkipStartWhiteSpace(); + if (*current_ == ':') { + Advance(); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", + JSTaggedValue::Exception()); + } + continue; + case Tokens::ARRAY: + if (EmptyArrayCheck()) { + parseValue = JSHandle(factory_->NewJSArray(0, initialJSArrayClass_)); + GetNextNonSpaceChar(); + break; + } + continuationList.emplace_back(std::move(continuation)); + continuation = JsonContinuation(ContType::ARRAY, elementsList.size()); + continue; + case Tokens::LITERAL_TRUE: + parseValue = JSHandle(thread_, ParseLiteralTrue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + break; + case Tokens::LITERAL_FALSE: + parseValue = JSHandle(thread_, ParseLiteralFalse()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + break; + case Tokens::LITERAL_NULL: + parseValue = JSHandle(thread_, ParseLiteralNull()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + break; + case Tokens::NUMBER: + parseValue = JSHandle(thread_, ParseNumber(IsInObjOrArray(continuation.type_))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + break; + case Tokens::STRING: + parseValue = JSHandle(thread_, ParseString(IsInObjOrArray(continuation.type_))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + break; + default: + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); + } + break; + } + + while (true) { + switch (continuation.type_) { + case ContType::RETURN: + ASSERT(continuationList.empty()); + ASSERT(elementsList.empty()); + ASSERT(propertyList.empty()); + if (current_ <= range_) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", + JSTaggedValue::Exception()); + } + return parseValue.GetTaggedValue(); + case ContType::ARRAY: { + elementsList.emplace_back(parseValue); + SkipStartWhiteSpace(); + if (*current_ == ',') { + Advance(); + break; + } + parseValue = CreateJsonArray(continuation, elementsList); + if (*current_ != ']') { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", + JSTaggedValue::Exception()); + } + GetNextNonSpaceChar(); + elementsList.resize(continuation.index_); + continuation = std::move(continuationList.back()); + continuationList.pop_back(); + continue; + } + case ContType::OBJECT: { + propertyList.emplace_back(parseValue); + SkipStartWhiteSpace(); + if (*current_ == ',') { + GetNextNonSpaceChar(); + if (*current_ == '"') { + propertyList.emplace_back(JSHandle(thread_, ParseString(true))); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON", + JSTaggedValue::Exception()); + } + SkipStartWhiteSpace(); + if (*current_ == ':') { + Advance(); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", + JSTaggedValue::Exception()); + } + break; + } + + parseValue = CreateJsonObject(continuation, propertyList); + if (*current_ == '}') { + GetNextNonSpaceChar(); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", + JSTaggedValue::Exception()); + } + propertyList.resize(continuation.index_); + continuation = std::move(continuationList.back()); + continuationList.pop_back(); + continue; + } + } + break; + } + } + } + + JSHandle CreateJsonArray(JsonContinuation continuation, + std::vector> &elementsList) { - SkipStartWhiteSpace(); - Tokens token = ParseToken(); - switch (token) { - case Tokens::OBJECT: - return ParseObject(inObjorArr); - case Tokens::ARRAY: - return ParseArray(inObjorArr); - case Tokens::LITERAL_TRUE: - return ParseLiteralTrue(); - case Tokens::LITERAL_FALSE: - return ParseLiteralFalse(); - case Tokens::LITERAL_NULL: - return ParseLiteralNull(); - case Tokens::NUMBER: - return ParseNumber(inObjorArr); - case Tokens::STRING: - return ParseString(inObjorArr); - default: - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); + size_t start = continuation.index_; + size_t size = elementsList.size() - start; + JSHandle array = factory_->NewJSArray(size, initialJSArrayClass_); + JSHandle elements = factory_->NewJsonFixedArray(start, size, elementsList); + JSHandle obj(array); + obj->SetElements(thread_, elements); + return JSHandle(array); + } + + JSHandle CreateJsonObject(JsonContinuation continuation, + std::vector> &propertyList) + { + size_t start = continuation.index_; + size_t size = propertyList.size() - start; + JSHandle obj = factory_->NewJSObject(initialJSObjectClass_); + for (size_t i = 0; i < size; i += 2) { // 2: prop name and value + JSTaggedValue res = ObjectFastOperator::SetPropertyByValue(thread_, obj.GetTaggedValue(), + propertyList[start + i].GetTaggedValue(), propertyList[start + i + 1].GetTaggedValue()); + if (res.IsHole()) { + // slow path + JSTaggedValue::SetProperty(thread_, JSHandle(obj), propertyList[start + i], + propertyList[start + i + 1], true); + } } + return JSHandle(obj); } JSTaggedValue ParseNumber(bool inObjorArr = false) @@ -116,7 +301,8 @@ protected: int32_t fastInteger = 0; bool isNumber = ReadNumberRange(isFast, fastInteger); if (!isNumber) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON Array Or Object", + JSTaggedValue::Exception()); } if (isFast) { return JSTaggedValue(fastInteger); @@ -143,7 +329,7 @@ protected: } std::string strNum(current, end_ + 1); - current_ = end_; + current_ = end_ + 1; errno = 0; // reset errno to 0 to avoid errno has been changed double v = std::strtod(strNum.c_str(), nullptr); if (errno == ERANGE) { @@ -221,6 +407,7 @@ protected: } } ASSERT(res.size() <= static_cast(UINT32_MAX)); + Advance(); return factory_->NewFromUtf8Literal(reinterpret_cast(res.c_str()), res.size()) .GetTaggedValue(); } @@ -229,111 +416,6 @@ protected: virtual JSTaggedValue ParseString(bool inObjorArr = false) = 0; - JSTaggedValue ParseArray(bool inObjorArr = false) - { - if (UNLIKELY(*range_ != ']' && !inObjorArr)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); - } - - Advance(); - SkipStartWhiteSpace(); - - if (*current_ == ']') { - JSHandle arr = factory_->NewJSArray(); - return arr.GetTaggedValue(); - } - - JSTaggedValue value; - std::vector> vec; - while (current_ <= range_) { - value = ParseJSONText(true); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - vec.emplace_back(JSHandle(thread_, value)); - GetNextNonSpaceChar(); - if (*current_ == ',') { - Advance(); - } else if (*current_ == ']') { - if (inObjorArr || current_ == range_) { - return CreateJsonArray(vec); - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); - } - } - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); - } - - inline JSTaggedValue CreateJsonArray(std::vector> &vec) - { - JSHandle array = factory_->NewJSArray(); - size_t arrayLength = vec.size(); - array->SetArrayLength(thread_, arrayLength); - JSHandle newElements = factory_->NewTaggedArray(arrayLength); - for (size_t i = 0; i < arrayLength; i++) { - newElements->Set(thread_, i, vec[i]); - } - JSHandle obj(array); - obj->SetElements(thread_, newElements); - return array.GetTaggedValue(); - } - - JSTaggedValue ParseObject(bool inObjorArr = false) - { - if (UNLIKELY(*range_ != '}' && !inObjorArr)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - - JSHandle proto(env_->GetObjectFunction()); - JSHandle result = factory_->NewJSObjectByConstructor(proto); - Advance(); - if (*current_ == '}') { - return result.GetTaggedValue(); - } - - JSMutableHandle keyHandle(thread_, JSTaggedValue::Undefined()); - JSTaggedValue value; - while (current_ <= range_) { - SkipStartWhiteSpace(); - if (*current_ == '"') { - keyHandle.Update(ParseString(true)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - } else { - if (*current_ == '}' && (inObjorArr || current_ == range_)) { - return result.GetTaggedValue(); - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - GetNextNonSpaceChar(); - if (*current_ == ':') { - Advance(); - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - value = ParseJSONText(true); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - // fast path - JSTaggedValue res = ObjectFastOperator::SetPropertyByValue(thread_, result.GetTaggedValue(), - keyHandle.GetTaggedValue(), value); - if (res.IsHole()) { - // slow path - JSTaggedValue::SetProperty(thread_, JSHandle(result), keyHandle, - JSHandle(thread_, value), true); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - } - GetNextNonSpaceChar(); - if (*current_ == ',') { - Advance(); - } else if (*current_ == '}') { - if (inObjorArr || current_ == range_) { - return result.GetTaggedValue(); - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - } - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - void SkipEndWhiteSpace() { while (current_ != end_) { @@ -401,7 +483,7 @@ protected: if (UNLIKELY(remainingLength < 3)) { // 3: literalTrue length - 1 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); } - bool isMatch = MatchText(literalTrue, 3); // 3: literalTrue length - 1 + bool isMatch = MatchText(literalTrue, 4); // 4: literalTrue length if (LIKELY(isMatch)) { return JSTaggedValue::True(); } @@ -415,7 +497,7 @@ protected: if (UNLIKELY(remainingLength < 4)) { // 4: literalFalse length - 1 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); } - bool isMatch = MatchText(literalFalse, 4); // 4: literalFalse length - 1 + bool isMatch = MatchText(literalFalse, 5); // 5: literalFalse length if (LIKELY(isMatch)) { return JSTaggedValue::False(); } @@ -429,7 +511,7 @@ protected: if (UNLIKELY(remainingLength < 3)) { // 3: literalNull length - 1 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); } - bool isMatch = MatchText(literalNull, 3); // 3: literalNull length - 1 + bool isMatch = MatchText(literalNull, 4); // 4: literalNull length if (LIKELY(isMatch)) { return JSTaggedValue::Null(); } @@ -439,7 +521,7 @@ protected: bool MatchText(const char *str, uint32_t matchLen) { // first char is already matched - for (uint32_t pos = 1; pos <= matchLen; ++pos) { + for (uint32_t pos = 1; pos < matchLen; ++pos) { if (current_[pos] != str[pos]) { return false; } @@ -472,7 +554,7 @@ protected: i = (i * 10) + ((*current) - '0'); } fastInteger = i * sign; - current_ = advance - 1; + current_ = advance; return true; } isFast = false; @@ -679,6 +761,8 @@ protected: JSThread *thread_ {nullptr}; ObjectFactory *factory_ {nullptr}; GlobalEnv *env_ {nullptr}; + JSHandle initialJSArrayClass_; + JSHandle initialJSObjectClass_; }; class Utf8JsonParser : public JsonParser { @@ -692,10 +776,11 @@ public: JSHandle Parse(EcmaString *str) { ASSERT(str != nullptr); - uint32_t len = EcmaStringAccessor(str).GetLength(); + auto stringAccessor = EcmaStringAccessor(str); + uint32_t len = stringAccessor.GetLength(); ASSERT(len != UINT32_MAX); CVector buf(len + 1); - EcmaStringAccessor(str).WriteToFlatUtf8(buf.data(), len); + stringAccessor.WriteToFlatUtf8(buf.data(), len); Text begin = buf.data(); return Launch(begin, begin + len); } @@ -720,7 +805,7 @@ private: ASSERT(strLength <= static_cast(UINT32_MAX)); JSTaggedValue res = factory_->NewCompressedUtf8( reinterpret_cast(current_), strLength).GetTaggedValue(); - current_ = end_; + current_ = end_ + 1; return res; } } else { @@ -733,6 +818,7 @@ private: } if (LIKELY(isFastString)) { std::string_view value(reinterpret_cast(current_), end_ - current_); + current_ = end_ + 1; ASSERT(value.size() <= static_cast(UINT32_MAX)); return factory_->NewFromUtf8LiteralCompress( reinterpret_cast(value.data()), value.size()).GetTaggedValue(); @@ -812,13 +898,13 @@ private: if (isFastString) { if (isAscii) { std::string value(current_, end_); // from uint16_t* to std::string, can't use std::string_view - current_ = end_; + current_ = end_ + 1; ASSERT(value.size() <= static_cast(UINT32_MAX)); return factory_->NewFromUtf8LiteralCompress( reinterpret_cast(value.c_str()), value.size()).GetTaggedValue(); } std::u16string_view value(reinterpret_cast(current_), end_ - current_); - current_ = end_; + current_ = end_ + 1; ASSERT(value.size() <= static_cast(UINT32_MAX)); return factory_->NewFromUtf16LiteralNotCompress( reinterpret_cast(value.data()), value.size()).GetTaggedValue(); @@ -835,11 +921,13 @@ private: if (isAscii) { std::string value(current_, end_); // from uint16_t* to std::string, can't use std::string_view ASSERT(value.size() <= static_cast(UINT32_MAX)); + current_ = end_ + 1; return factory_->NewFromUtf8LiteralCompress( reinterpret_cast(value.c_str()), value.size()).GetTaggedValue(); } std::u16string_view value(reinterpret_cast(current_), end_ - current_); ASSERT(value.size() <= static_cast(UINT32_MAX)); + current_ = end_ + 1; return factory_->NewFromUtf16LiteralNotCompress( reinterpret_cast(value.data()), value.size()).GetTaggedValue(); } diff --git a/ecmascript/base/tests/json_parser_test.cpp b/ecmascript/base/tests/json_parser_test.cpp index 6a0a03f837..c29fd60f6c 100644 --- a/ecmascript/base/tests/json_parser_test.cpp +++ b/ecmascript/base/tests/json_parser_test.cpp @@ -125,7 +125,7 @@ HWTEST_F_L0(JsonParserTest, Parser_003) JSHandle handleMsg(factory->NewFromASCII( "\t\r \n{\t\r \n \"json\"\t\r\n:\t\r \n{\t\r \n}\t\r \n,\t\r \n \"prop2\"\t\r \n:\t\r \n [\t\r \nfalse\t\r" - "\n,\t\r \nnull\t\r \ntrue\t\r,123.456\t\r \n]\t\r \n}\t\r \n")); + "\n,\t\r \nnull\t\r, \ntrue\t\r,123.456\t\r \n]\t\r \n}\t\r \n")); JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Object JSHandle result = parser.Parse(*handleStr); EXPECT_TRUE(result->IsECMAObject()); diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index d8088453e1..9443fa7c37 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -671,6 +671,32 @@ JSHandle ObjectFactory::NewJSArray() return JSHandle(NewJSObjectByConstructor(function)); } +JSHandle ObjectFactory::NewJSArray(size_t length, JSHandle &hclass) +{ + JSHandle obj = NewJSObject(hclass); + JSArray::Cast(*obj)->SetLength(length); + JSArray::Cast(*obj)->SetTrackInfo(thread_, JSTaggedValue::Undefined()); + auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor(); + JSArray::Cast(*obj)->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor); + return JSHandle(obj); +} + +JSHandle ObjectFactory::NewJsonFixedArray(size_t start, size_t length, + const std::vector> &vec) +{ + if (length == 0) { + return EmptyArray(); + } + + MemSpaceType spaceType = length < LENGTH_THRESHOLD ? MemSpaceType::SEMI_SPACE : MemSpaceType::OLD_SPACE; + JSHandle array = NewTaggedArrayWithoutInit(length, spaceType); + array->SetExtraLength(0); + for (size_t i = 0; i < length; i++) { + array->Set(thread_, i, vec[start + i]); + } + return array; +} + JSHandle ObjectFactory::NewJSForinIterator(const JSHandle &obj, const JSHandle keys, const JSHandle cachedHclass) diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 9525803d0b..f2174dfc2d 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -317,6 +317,9 @@ public: JSHandle NewPendingJob(const JSHandle &func, const JSHandle &argv); JSHandle NewJSArray(); + JSHandle NewJSArray(size_t length, JSHandle &hclass); + JSHandle NewJsonFixedArray(size_t start, size_t length, + const std::vector> &vec); JSHandle NewJSProxy(const JSHandle &target, const JSHandle &handler); JSHandle NewJSRealm(); diff --git a/test/aottest/exception_case1/expect_output.txt b/test/aottest/exception_case1/expect_output.txt index aef6644542..562ec280e5 100644 --- a/test/aottest/exception_case1/expect_output.txt +++ b/test/aottest/exception_case1/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object exception_case1.js:18:18 exception_case1.js:20:1 diff --git a/test/aottest/exception_case11/expect_output.txt b/test/aottest/exception_case11/expect_output.txt index 866a932dd3..76321182d6 100644 --- a/test/aottest/exception_case11/expect_output.txt +++ b/test/aottest/exception_case11/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object exception_case11.ts:22:22 exception_case11.ts:25:1 diff --git a/test/aottest/exception_case12/expect_output.txt b/test/aottest/exception_case12/expect_output.txt index 7ab54e8b31..e42f38d42d 100644 --- a/test/aottest/exception_case12/expect_output.txt +++ b/test/aottest/exception_case12/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object exception_case12.ts:21:21 exception_case12.ts:24:1 diff --git a/test/aottest/exception_case8/expect_output.txt b/test/aottest/exception_case8/expect_output.txt index 6e1b8a23ff..1908e04e0a 100644 --- a/test/aottest/exception_case8/expect_output.txt +++ b/test/aottest/exception_case8/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object exception_case8.js:18:18 exception_case8.js:22:22 exception_case8.js:24:1 diff --git a/test/aottest/ts_inline_exception3/expect_output.txt b/test/aottest/ts_inline_exception3/expect_output.txt index ab3ea75305..c884d9eb72 100644 --- a/test/aottest/ts_inline_exception3/expect_output.txt +++ b/test/aottest/ts_inline_exception3/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object at foo1 (maybe inlined). depth: 2 at foo3 (maybe inlined). depth: 1 at foo4 (maybe inlined). depth: 0 diff --git a/test/aottest/ts_inline_exception7/expect_output.txt b/test/aottest/ts_inline_exception7/expect_output.txt index 8ebf2e2d6f..b880a9c4fc 100644 --- a/test/aottest/ts_inline_exception7/expect_output.txt +++ b/test/aottest/ts_inline_exception7/expect_output.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SyntaxError: Unexpected Array in JSON +SyntaxError: Unexpected Number in JSON Array Or Object at Student (hidden:26:26) at foo1 (maybe inlined). depth: 1 at foo2 (maybe inlined). depth: 0 -- Gitee From e9b1dcc3f08cee821049108b1559835a315f4cc4 Mon Sep 17 00:00:00 2001 From: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue Date: Fri, 24 Nov 2023 16:58:58 +0800 Subject: [PATCH 17/44] code style Change-Id: I6047a8e53f1827695b7ece16644de957550316d6 Signed-off-by: repo sync -c -j8 repo forall -c 'git lfs pull'wangyue --- .../builtins/builtins_array_stub_builder.cpp | 198 ++++++++++-------- 1 file changed, 108 insertions(+), 90 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 404ffc7de5..5383b28c09 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -29,98 +29,116 @@ void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef n Label isHeapObject(env); Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); Bind(&isHeapObject); - Label isExtensible(env); - Branch(HasConstructor(thisValue), slowPath, &isExtensible); - Bind(&isExtensible); - Label numArgsOne(env); - Branch(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath); - Bind(&numArgsOne); - GateRef arg0 = GetCallArg0(numArgs); - Label allEcmaObject(env); - Label allStableJsArray(env); - GateRef isThisEcmaObject = IsEcmaObject(thisValue); - GateRef isArgEcmaObject = IsEcmaObject(arg0); - Branch(BoolAnd(isThisEcmaObject, isArgEcmaObject), &allEcmaObject, slowPath); - Bind(&allEcmaObject); - GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); - GateRef isArgStableJSArray = IsStableJSArray(glue, arg0); - Branch(BoolAnd(isThisStableJSArray, isArgStableJSArray), &allStableJsArray, slowPath); - Bind(&allStableJsArray); - GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX); - GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); - GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0)); - GateRef sumArrayLen = Int64Add(argLen, thisLen); - Label notOverFlow(env); - Branch(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, ¬OverFlow); - Bind(¬OverFlow); - Label spreadable(env); - Label argspreadable(env); - GateRef isSpreadable = IsConcatSpreadable(glue, thisValue); - Branch(isSpreadable, &spreadable, slowPath); - Bind(&spreadable); - GateRef argisSpreadable = IsConcatSpreadable(glue, arg0); - Branch(argisSpreadable, &argspreadable, slowPath); - Bind(&argspreadable); - // new array - Label setProperties(env); - GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); - GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); - auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); - GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - NewObjectStubBuilder newBuilder(this); - newBuilder.SetParameters(glue, 0); - GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen); - Branch(TaggedIsException(newArray), exit, &setProperties); - Bind(&setProperties); - GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); - Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(sumArrayLen)); - GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); - SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); - SetExtensibleToBitfield(glue, newArray, true); - GateRef thisEles = GetElementsArray(thisValue); - GateRef argEles = GetElementsArray(arg0); - GateRef newArrayEles = GetElementsArray(newArray); - DEFVARIABLE(i, VariableType::INT64(), Int64(0)); - DEFVARIABLE(j, VariableType::INT64(), Int64(0)); - DEFVARIABLE(k, VariableType::INT64(), Int64(0)); - Label loopHead(env); - Label loopEnd(env); - Label next(env); - Label loopExit(env); - Jump(&loopHead); - LoopBegin(&loopHead); { - Branch(Int64LessThan(*i, thisLen), &next, &loopExit); - Bind(&next); - GateRef ele = GetValueFromTaggedArray(thisEles, *i); - SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); - Jump(&loopEnd); - } - Bind(&loopEnd); - i = Int64Add(*i, Int64(1)); - j = Int64Add(*j, Int64(1)); - LoopEnd(&loopHead); - Bind(&loopExit); - Label loopHead1(env); - Label loopEnd1(env); - Label next1(env); - Label loopExit1(env); - Jump(&loopHead1); - LoopBegin(&loopHead1); - { - Branch(Int64LessThan(*k, argLen), &next1, &loopExit1); - Bind(&next1); - GateRef ele = GetValueFromTaggedArray(argEles, *k); - SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); - Jump(&loopEnd1); + Label isExtensible(env); + Branch(HasConstructor(thisValue), slowPath, &isExtensible); + Bind(&isExtensible); + { + Label numArgsOne(env); + Branch(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath); + Bind(&numArgsOne); + { + GateRef arg0 = GetCallArg0(numArgs); + Label allEcmaObject(env); + Label allStableJsArray(env); + GateRef isThisEcmaObject = IsEcmaObject(thisValue); + GateRef isArgEcmaObject = IsEcmaObject(arg0); + Branch(BoolAnd(isThisEcmaObject, isArgEcmaObject), &allEcmaObject, slowPath); + Bind(&allEcmaObject); + { + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + GateRef isArgStableJSArray = IsStableJSArray(glue, arg0); + Branch(BoolAnd(isThisStableJSArray, isArgStableJSArray), &allStableJsArray, slowPath); + Bind(&allStableJsArray); + { + GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX); + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0)); + GateRef sumArrayLen = Int64Add(argLen, thisLen); + Label notOverFlow(env); + Branch(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, ¬OverFlow); + Bind(¬OverFlow); + { + Label spreadable(env); + GateRef isSpreadable = IsConcatSpreadable(glue, thisValue); + GateRef argisSpreadable = IsConcatSpreadable(glue, arg0); + Branch(BoolAnd(isSpreadable, argisSpreadable), &spreadable, slowPath); + Bind(&spreadable); + { + Label setProperties(env); + GateRef glueGlobalEnvOffset = + IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc =GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, + IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen); + Branch(TaggedIsException(newArray), exit, &setProperties); + Bind(&setProperties); + { + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, newArray, lengthOffset, + TruncInt64ToInt32(sumArrayLen)); + GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, + ConstantIndex::ARRAY_LENGTH_ACCESSOR); + SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, + Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); + SetExtensibleToBitfield(glue, newArray, true); + GateRef thisEles = GetElementsArray(thisValue); + GateRef argEles = GetElementsArray(arg0); + GateRef newArrayEles = GetElementsArray(newArray); + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(j, VariableType::INT64(), Int64(0)); + DEFVARIABLE(k, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*i, thisLen), &next, &loopExit); + Bind(&next); + GateRef ele = GetValueFromTaggedArray(thisEles, *i); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); + Jump(&loopEnd); + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + j = Int64Add(*j, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Label loopHead1(env); + Label loopEnd1(env); + Label next1(env); + Label loopExit1(env); + Jump(&loopHead1); + LoopBegin(&loopHead1); + { + Branch(Int64LessThan(*k, argLen), &next1, &loopExit1); + Bind(&next1); + GateRef ele = GetValueFromTaggedArray(argEles, *k); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *j, ele); + Jump(&loopEnd1); + } + Bind(&loopEnd1); + k = Int64Add(*k, Int64(1)); + j = Int64Add(*j, Int64(1)); + LoopEnd(&loopHead1); + Bind(&loopExit1); + result->WriteVariable(newArray); + Jump(exit); + } + } + } + } + } + } + } } - Bind(&loopEnd1); - k = Int64Add(*k, Int64(1)); - j = Int64Add(*j, Int64(1)); - LoopEnd(&loopHead1); - Bind(&loopExit1); - result->WriteVariable(newArray); - Jump(exit); } void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef numArgs, -- Gitee From 4b10692cb9cff06d103cf842e1686da1d86836e5 Mon Sep 17 00:00:00 2001 From: gwl Date: Thu, 9 Nov 2023 18:32:35 +0800 Subject: [PATCH 18/44] array.slice Change-Id: Iff7b918ee0012e3f50d2d992ac526f318b0d090d Signed-off-by: gwl --- .../builtins/builtins_array_stub_builder.cpp | 220 +++++++++++++++++- test/moduletest/arraySlice/BUILD.gn | 18 ++ test/moduletest/arraySlice/arraySlice.js | 60 +++++ test/moduletest/arraySlice/expect_output.txt | 22 ++ 4 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 test/moduletest/arraySlice/BUILD.gn create mode 100644 test/moduletest/arraySlice/arraySlice.js create mode 100644 test/moduletest/arraySlice/expect_output.txt diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 13a7e4335c..1a5770a31e 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -147,13 +147,20 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + Label noConstructor(env); + Branch(HasConstructor(thisValue), slowPath, &noConstructor); + Bind(&noConstructor); Label thisIsEmpty(env); + Label thisNotEmpty(env); // Fast path if: // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details); // (2) no arguments exist JsArrayRequirements req; req.defaultConstructor = true; - Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath); + Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, &thisNotEmpty); Bind(&thisIsEmpty); { Label noArgs(env); @@ -165,6 +172,217 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu result->WriteVariable(newBuilder.CreateEmptyArray(glue)); Jump(exit); } + Bind(&thisNotEmpty); + { + Label stableJSArray(env); + Label arrayLenNotZero(env); + + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + Branch(isThisStableJSArray, &stableJSArray, slowPath); + Bind(&stableJSArray); + + GateRef msg0 = GetCallArg0(numArgs); + GateRef msg1 = GetCallArg1(numArgs); + + GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + Label msg0Int(env); + Branch(TaggedIsInt(msg0), &msg0Int, slowPath); + Bind(&msg0Int); + DEFVARIABLE(start, VariableType::INT64(), Int64(0)); + DEFVARIABLE(end, VariableType::INT64(), thisArrLen); + + GateRef argStart = SExtInt32ToInt64(TaggedGetInt(msg0)); + Label arg0LessZero(env); + Label arg0NotLessZero(env); + Label startDone(env); + Branch(Int64LessThan(argStart, Int64(0)), &arg0LessZero, &arg0NotLessZero); + Bind(&arg0LessZero); + { + Label tempGreaterZero(env); + Label tempNotGreaterZero(env); + GateRef tempStart = Int64Add(argStart, thisArrLen); + Branch(Int64GreaterThan(tempStart, Int64(0)), &tempGreaterZero, &tempNotGreaterZero); + Bind(&tempGreaterZero); + { + start = tempStart; + Jump(&startDone); + } + Bind(&tempNotGreaterZero); + { + Jump(&startDone); + } + } + Bind(&arg0NotLessZero); + { + Label argLessLen(env); + Label argNotLessLen(env); + Branch(Int64LessThan(argStart, thisArrLen), &argLessLen, &argNotLessLen); + Bind(&argLessLen); + { + start = argStart; + Jump(&startDone); + } + Bind(&argNotLessLen); + { + start = thisArrLen; + Jump(&startDone); + } + } + Bind(&startDone); + + Label endDone(env); + Label msg1Def(env); + Branch(TaggedIsUndefined(msg1), &endDone, &msg1Def); + Bind(&msg1Def); + { + Label msg1Int(env); + Branch(TaggedIsInt(msg1), &msg1Int, slowPath); + Bind(&msg1Int); + { + GateRef argEnd = SExtInt32ToInt64(TaggedGetInt(msg1)); + Label arg1LessZero(env); + Label arg1NotLessZero(env); + Branch(Int64LessThan(argEnd, Int64(0)), &arg1LessZero, &arg1NotLessZero); + Bind(&arg1LessZero); + { + Label tempGreaterZero(env); + Label tempNotGreaterZero(env); + GateRef tempEnd = Int64Add(argEnd, thisArrLen); + Branch(Int64GreaterThan(tempEnd, Int64(0)), &tempGreaterZero, &tempNotGreaterZero); + Bind(&tempGreaterZero); + { + end = tempEnd; + Jump(&endDone); + } + Bind(&tempNotGreaterZero); + { + end = Int64(0); + Jump(&endDone); + } + } + Bind(&arg1NotLessZero); + { + Label argLessLen(env); + Label argNotLessLen(env); + Branch(Int64LessThan(argEnd, thisArrLen), &argLessLen, &argNotLessLen); + Bind(&argLessLen); + { + end = argEnd; + Jump(&endDone); + } + Bind(&argNotLessLen); + { + end = thisArrLen; + Jump(&endDone); + } + } + } + } + + Bind(&endDone); + + DEFVARIABLE(count, VariableType::INT64(), Int64(0)); + GateRef tempCnt = Int64Sub(*end, *start); + Label tempCntGreaterOrEqualZero(env); + Label tempCntDone(env); + Branch(Int64LessThan(tempCnt, Int64(0)), &tempCntDone, &tempCntGreaterOrEqualZero); + Bind(&tempCntGreaterOrEqualZero); + { + count = tempCnt; + Jump(&tempCntDone); + } + Bind(&tempCntDone); + + // new array + Label setProperties(env); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, *count); + Branch(TaggedIsException(newArray), exit, &setProperties); + Bind(&setProperties); + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(*count)); + GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); + SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); + SetExtensibleToBitfield(glue, newArray, true); + + GateRef thisEles = GetElementsArray(thisValue); + GateRef thisElesLen = ZExtInt32ToInt64(GetLengthOfTaggedArray(thisEles)); + GateRef newArrayEles = GetElementsArray(newArray); + + Label inThisEles(env); + Label outThisEles(env); + Branch(Int64GreaterThan(thisElesLen, Int64Add(*start, *count)), &inThisEles, &outThisEles); + Bind(&inThisEles); + { + DEFVARIABLE(idx, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*idx, *count), &next, &loopExit); + Bind(&next); + + GateRef ele = GetValueFromTaggedArray(thisEles, Int64Add(*idx, *start)); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *idx, ele); + Jump(&loopEnd); + } + Bind(&loopEnd); + idx = Int64Add(*idx, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(newArray); + Jump(exit); + } + Bind(&outThisEles); + { + DEFVARIABLE(idx, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Branch(Int64LessThan(*idx, *count), &next, &loopExit); + Bind(&next); + GateRef index = Int64Add(*idx, *start); + DEFVARIABLE(ele, VariableType::JS_ANY(), Hole()); + + Label indexOutRange(env); + Label indexInRange(env); + Label setEle(env); + Branch(Int64GreaterThan(thisElesLen, index), &indexInRange, &indexOutRange); + Bind(&indexInRange); + { + ele = GetValueFromTaggedArray(thisEles, index); + Jump(&setEle); + } + Bind(&indexOutRange); + { + ele = Hole(); + Jump(&setEle); + } + Bind(&setEle); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *idx, *ele); + Jump(&loopEnd); + } + + Bind(&loopEnd); + idx = Int64Add(*idx, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(newArray); + Jump(exit); + } + } } // Note: unused arguments are reserved for further development diff --git a/test/moduletest/arraySlice/BUILD.gn b/test/moduletest/arraySlice/BUILD.gn new file mode 100644 index 0000000000..20a83f1990 --- /dev/null +++ b/test/moduletest/arraySlice/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("arraySlice") { + deps = [] +} diff --git a/test/moduletest/arraySlice/arraySlice.js b/test/moduletest/arraySlice/arraySlice.js new file mode 100644 index 0000000000..1f3b6fa65f --- /dev/null +++ b/test/moduletest/arraySlice/arraySlice.js @@ -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. + */ + +/* + * @tc.name:stringSlice + * @tc.desc:test String.slice + * @tc.type: FUNC + * @tc.require: issueI5NO8G + */ + +const animals = ['ant', 'bison', 'camel', 'duck', 'elephant']; + +print(animals.slice(2)); +// Expected output: Array ["camel", "duck", "elephant"] + +print(animals.slice(2, 4)); +// Expected output: Array ["camel", "duck"] + +print(animals.slice(1, 5)); +// Expected output: Array ["bison", "camel", "duck", "elephant"] + +print(animals.slice(-2)); +// Expected output: Array ["duck", "elephant"] + +print(animals.slice(2, -1)); +// Expected output: Array ["camel", "duck"] + +print(animals.slice()); +// Expected output: Array ["ant", "bison", "camel", "duck", "elephant"] + +print([1, 2, , 4, 5].slice(1, 4)); // [2, empty, 4] +const arrayLike = { + length: 3, + 0: 2, + 1: 3, + 2: 4, +}; +print(Array.prototype.slice.call(arrayLike, 1, 3)); + +const slice = Function.prototype.call.bind(Array.prototype.slice); + +function list() { + return slice(arguments); +} + +const list1 = list(1, 2, 3); // [1, 2, 3] + +print(list1); diff --git a/test/moduletest/arraySlice/expect_output.txt b/test/moduletest/arraySlice/expect_output.txt new file mode 100644 index 0000000000..41082dd1bd --- /dev/null +++ b/test/moduletest/arraySlice/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. + +camel,duck,elephant +camel,duck +bison,camel,duck,elephant +duck,elephant +camel,duck +ant,bison,camel,duck,elephant +2,,4 +3,4 +1,2,3 -- Gitee From 3cc0bc22f6ddd3f03cc6b4011a15ad857cd064dd Mon Sep 17 00:00:00 2001 From: yanpeng Date: Fri, 24 Nov 2023 15:09:21 +0800 Subject: [PATCH 19/44] fix defineProperty array length not throw typeerror Signed-off-by: yanpeng Change-Id: I1a35a3a002be0e4ded98d2a5e638072a3fe3a777 Signed-off-by: yanpeng --- ecmascript/builtins/builtins_array.cpp | 5 ++-- test/moduletest/BUILD.gn | 1 + .../moduletest/regressdefineproperty/BUILD.gn | 18 ++++++++++++++ .../regressdefineproperty/expect_output.txt | 14 +++++++++++ .../regressdefineproperty.js | 24 +++++++++++++++++++ 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100755 test/moduletest/regressdefineproperty/BUILD.gn create mode 100755 test/moduletest/regressdefineproperty/expect_output.txt create mode 100755 test/moduletest/regressdefineproperty/regressdefineproperty.js diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index efe225bdf1..df49e25577 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -1515,10 +1515,11 @@ JSTaggedValue BuiltinsArray::Pop(EcmaRuntimeCallInfo *argv) // 1. Let O be ToObject(this value). JSHandle thisHandle = GetThis(argv); - if (thisHandle->IsStableJSArray(thread)) { + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { return JSStableArray::Pop(JSHandle::Cast(thisHandle), argv); } - JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index d251202364..5e938dac31 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -113,6 +113,7 @@ group("ark_js_moduletest") { "regexpcallthrow", "regexpflagd", "regress", + "regressdefineproperty", "require", "setobjectwithproto", "spreadoperator", diff --git a/test/moduletest/regressdefineproperty/BUILD.gn b/test/moduletest/regressdefineproperty/BUILD.gn new file mode 100755 index 0000000000..99fe717091 --- /dev/null +++ b/test/moduletest/regressdefineproperty/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("regressdefineproperty") { + deps = [] +} diff --git a/test/moduletest/regressdefineproperty/expect_output.txt b/test/moduletest/regressdefineproperty/expect_output.txt new file mode 100755 index 0000000000..9dc1ee02d8 --- /dev/null +++ b/test/moduletest/regressdefineproperty/expect_output.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +true diff --git a/test/moduletest/regressdefineproperty/regressdefineproperty.js b/test/moduletest/regressdefineproperty/regressdefineproperty.js new file mode 100755 index 0000000000..9150337a2f --- /dev/null +++ b/test/moduletest/regressdefineproperty/regressdefineproperty.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. + */ +let a = []; +Object.defineProperty(a, "length", {writable: false}); +function f() { + return a.pop(); +} +try{ + f(); +} catch (e) { + print(e instanceof TypeError) +} -- Gitee From 69be933473a31f94df04548c84c29a2f0130a599 Mon Sep 17 00:00:00 2001 From: yqhan Date: Fri, 24 Nov 2023 18:22:01 +0800 Subject: [PATCH 20/44] Modify the name of thread issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8JB9B Signed-off-by: yqhan --- ecmascript/dfx/cpu_profiler/sampling_processor.cpp | 2 +- ecmascript/taskpool/runner.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ecmascript/dfx/cpu_profiler/sampling_processor.cpp b/ecmascript/dfx/cpu_profiler/sampling_processor.cpp index 9d427b0b79..288a3b453a 100644 --- a/ecmascript/dfx/cpu_profiler/sampling_processor.cpp +++ b/ecmascript/dfx/cpu_profiler/sampling_processor.cpp @@ -71,7 +71,7 @@ void *SamplingProcessor::Run(void *arg) } } generator->SetThreadStopTime(); - pthread_setname_np(tid, "GC_WorkerThread"); + pthread_setname_np(tid, "OS_GC_WorkerThread"); if (generator->SemPost(1) != 0) { LOG_ECMA(ERROR) << "sem_[1] post failed"; return nullptr; diff --git a/ecmascript/taskpool/runner.cpp b/ecmascript/taskpool/runner.cpp index 26a05a6533..52c94bb38b 100644 --- a/ecmascript/taskpool/runner.cpp +++ b/ecmascript/taskpool/runner.cpp @@ -95,7 +95,7 @@ void Runner::SetRunTask(uint32_t threadId, Task *task) void Runner::Run(uint32_t threadId) { os::thread::native_handle_type thread = os::thread::GetNativeHandle(); - os::thread::SetThreadName(thread, "GC_WorkerThread"); + os::thread::SetThreadName(thread, "OS_GC_WorkerThread"); RecordThreadId(); while (std::unique_ptr task = taskQueue_.PopTask()) { SetRunTask(threadId, task.get()); -- Gitee From 8d9f113f582ebe07da4a084f4fa148bf2a326e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Fri, 24 Nov 2023 18:30:41 +0800 Subject: [PATCH 21/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dslice=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=95=B0=E5=AD=97=E8=8E=B7=E5=8F=96=E5=B1=9E=E6=80=A7=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- ecmascript/js_object.cpp | 14 ++++++++++++++ ecmascript/js_stable_array.cpp | 9 --------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 43fdd2ac5c..926a497cbd 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -1121,6 +1121,20 @@ bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle const JSHandle &key, PropertyDescriptor &desc) { ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); + JSHandle thisObjVal(obj); + bool isArray = obj->IsJSArray(); + if (isArray) { + JSHandle srcElements(thread, obj->GetElements()); + int64_t len = static_cast(srcElements->GetLength()); + for (int i = 0; i < len; i++) { + JSTaggedValue value = srcElements->Get(thread, i); + if (value.IsHole() && JSTaggedValue::HasProperty(thread, thisObjVal, i)) { + value = JSArray::FastGetPropertyByValue(thread, thisObjVal, i).GetTaggedValue(); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + srcElements->Set(thread, i, value); + } + } + } ObjectOperator op(thread, JSHandle(obj), key, OperatorType::OWN); if (!op.IsFound()) { diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 4ea959655d..ed5602e012 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -1063,7 +1063,6 @@ JSTaggedValue JSStableArray::Slice(JSThread *thread, JSHandle thisObjH { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle srcElements(thread, thisObjHandle->GetElements()); - JSHandle thisObjVal(thisObjHandle); int64_t len = static_cast(srcElements->GetLength()); int64_t oldLen; if (len > k + count) { @@ -1072,14 +1071,6 @@ JSTaggedValue JSStableArray::Slice(JSThread *thread, JSHandle thisObjH oldLen = len - k; } JSHandle dstElements = factory->NewAndCopyTaggedArray(srcElements, count, oldLen, k); - for (int i = 0; i < count; i++) { - JSTaggedValue value = dstElements->Get(thread, i); - if (value.IsHole() && JSTaggedValue::HasProperty(thread, thisObjVal, i)) { - value = JSArray::FastGetPropertyByValue(thread, thisObjVal, i).GetTaggedValue(); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - dstElements->Set(thread, i, value); - } - } return factory->NewJSStableArrayWithElements(dstElements).GetTaggedValue(); } -- Gitee From 03b5bacc3b502ffba6c9abe3f1e5727bbeadb556 Mon Sep 17 00:00:00 2001 From: gwl Date: Fri, 24 Nov 2023 20:23:37 +0800 Subject: [PATCH 22/44] add testcase Signed-off-by: gwl Change-Id: Ib910f9baf40513cce0decf86008d0f2f154fe3a3 Signed-off-by: gwl --- .../builtins/builtins_array_stub_builder.cpp | 14 +++--- test/moduletest/arrayfind/arrayfind.js | 44 ++++++++++++++----- test/moduletest/arrayfind/expect_output.txt | 16 +++++++ .../arrayfindIndex/arrayfindIndex.js | 29 ++++++++++-- .../arrayfindIndex/expect_output.txt | 4 ++ 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 01bb52b92e..c7b75d4ef3 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -225,23 +225,24 @@ void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef num Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); Label stableJSArray(env); - GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); Branch(isThisStableJSArray, &stableJSArray, slowPath); Bind(&stableJSArray); GateRef callbackFnHandle = GetCallArg0(numArgs); - Label isHeapObject(env); - Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObject, slowPath); - Bind(&isHeapObject); + Label arg0HeapObject(env); + Branch(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath); + Bind(&arg0HeapObject); Label callable(env); Branch(IsCallable(callbackFnHandle), &callable, slowPath); Bind(&callable); GateRef argHandle = GetCallArg1(numArgs); GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); - DEFVARIABLE(i, VariableType::INT64(), Int64(0)); Label loopHead(env); Label loopEnd(env); @@ -252,8 +253,7 @@ void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef num { Branch(Int64LessThan(*i, thisArrLen), &next, &loopExit); Bind(&next); - GateRef thisEles = GetElementsArray(thisValue); - GateRef kValue = GetValueFromTaggedArray(thisEles, *i); + GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); GateRef key = Int64ToTaggedInt(*i); Label hasException(env); Label notHasException(env); diff --git a/test/moduletest/arrayfind/arrayfind.js b/test/moduletest/arrayfind/arrayfind.js index ea26a65d5a..4d4fdb2857 100644 --- a/test/moduletest/arrayfind/arrayfind.js +++ b/test/moduletest/arrayfind/arrayfind.js @@ -20,22 +20,42 @@ * @tc.require: issueI5NO8G */ - const array1 = [5, 12, 8, 130, 44]; - const found = array1.find((element) => element > 10); -print(found); +console.log(found); + +const arrayLike = { + length: 3, + 0: 2, + 1: 7.3, + 2: 4, +}; +console.log(Array.prototype.find.call(arrayLike, (x) => !Number.isInteger(x))); +const array = [0, 1, , , , 5, 6]; + +array.find((value, index) => { + console.log(`${index},${value}`); +}); + +array.find((value, index) => { + if (index === 0) { + console.log(`array[5]${array[5]}`); + delete array[5]; + } + console.log(`${index},${value}`); +}); function isPrime(element, index, array) { - let start = 2; - while (start <= Math.sqrt(element)) { - if (element % start++ < 1) { - return false; - } - } - return element > 1; + let start = 2; + while (start <= Math.sqrt(element)) { + if (element % start++ < 1) { + return false; + } + } + return element > 1; } -print([4, 6, 8, 12].find(isPrime)); // undefined,未找到 -print([4, 5, 8, 12].find(isPrime)); // 5 +console.log([4, 6, 8, 12].find(isPrime)); // undefined,未找到 +console.log([4, 5, 8, 12].find(isPrime)); // 5 + diff --git a/test/moduletest/arrayfind/expect_output.txt b/test/moduletest/arrayfind/expect_output.txt index 8189d7b9bb..6bbc994cc1 100644 --- a/test/moduletest/arrayfind/expect_output.txt +++ b/test/moduletest/arrayfind/expect_output.txt @@ -12,5 +12,21 @@ # limitations under the License. 12 +7.3 +0,0 +1,1 +2,undefined +3,undefined +4,undefined +5,5 +6,6 +array[5]5 +0,0 +1,1 +2,undefined +3,undefined +4,undefined +5,undefined +6,6 undefined 5 diff --git a/test/moduletest/arrayfindIndex/arrayfindIndex.js b/test/moduletest/arrayfindIndex/arrayfindIndex.js index 1f84c15f64..4f5a51da9f 100644 --- a/test/moduletest/arrayfindIndex/arrayfindIndex.js +++ b/test/moduletest/arrayfindIndex/arrayfindIndex.js @@ -20,9 +20,30 @@ * @tc.require: issueI5NO8G */ - -const array1 = [5, 12, 8, 130, 44]; - +t array1 = [5, 12, 8, 130, 44]; const isLargeNumber = (element) => element > 13; - print(array1.findIndex(isLargeNumber)); + +const arrayLike = { + length: 3, + 0: 2, + 1: 7.3, + 2: 4, +}; +print( + Array.prototype.findIndex.call(arrayLike, (x) => !Number.isInteger(x)), +); +print([1, , 3].findIndex((x) => x === undefined)); +function isPrime(element) { + if (element % 2 === 0 || element < 2) { + return false; + } + for (let factor = 3; factor <= Math.sqrt(element); factor += 2) { + if (element % factor === 0) { + return false; + } + } + return true; +} +print([4, 6, 8, 9, 12].findIndex(isPrime)); +print([4, 6, 7, 9, 12].findIndex(isPrime)); diff --git a/test/moduletest/arrayfindIndex/expect_output.txt b/test/moduletest/arrayfindIndex/expect_output.txt index d0698dcfa5..eb22b1c779 100644 --- a/test/moduletest/arrayfindIndex/expect_output.txt +++ b/test/moduletest/arrayfindIndex/expect_output.txt @@ -12,3 +12,7 @@ # limitations under the License. 3 +1 +1 +-1 +2 -- Gitee From e85ea344a50fb91a760edff8fe3ba401c9cdddd2 Mon Sep 17 00:00:00 2001 From: hwx1163501 Date: Tue, 21 Nov 2023 12:38:41 +0800 Subject: [PATCH 23/44] =?UTF-8?q?array.map=E6=B2=A1=E6=9C=89=E7=88=AC?= =?UTF-8?q?=E5=8F=96=E5=8E=9F=E5=9E=8B=E9=93=BE=E4=B8=8A=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= 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/I8I5ZZ --- ecmascript/js_stable_array.cpp | 7 +++++- test/moduletest/BUILD.gn | 3 +++ test/moduletest/arraymap/BUILD.gn | 18 ++++++++++++++ test/moduletest/arraymap/arraymap.js | 29 ++++++++++++++++++++++ test/moduletest/arraymap/expect_output.txt | 15 +++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/moduletest/arraymap/BUILD.gn create mode 100644 test/moduletest/arraymap/arraymap.js create mode 100644 test/moduletest/arraymap/expect_output.txt diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index ed5602e012..578392f288 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -761,7 +761,12 @@ JSTaggedValue JSStableArray::Map(JSHandle newArrayHandle, JSHandleGetElements()); - kValue.Update(array->Get(k)); + JSTaggedValue value = array->Get(k); + if (value.IsHole() && JSTaggedValue::HasProperty(thread, thisObjVal, k)) { + value = JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + kValue.Update(value); if (!kValue.GetTaggedValue().IsHole()) { key.Update(JSTaggedValue(k)); EcmaRuntimeCallInfo *info = diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 7c9387703d..901f61fc90 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -25,6 +25,7 @@ group("ark_js_moduletest") { "arrayfindlastindex", "arrayforeach", "arrayjoin", + "arraymap", "arraypop", "arraytoreversed", "arraytospliced", @@ -179,6 +180,7 @@ group("ark_asm_test") { "arrayfindindex", "arrayforeach", "arrayjoin", + "arraymap", "arraypop", "arraysort", "arrayprotochange", @@ -309,6 +311,7 @@ group("ark_asm_single_step_test") { "arrayfindlastindex", "arrayforeach", "arrayjoin", + "arraymap", "arraypop", "arrayprotochange", "arrayshift", diff --git a/test/moduletest/arraymap/BUILD.gn b/test/moduletest/arraymap/BUILD.gn new file mode 100644 index 0000000000..e48a6ae563 --- /dev/null +++ b/test/moduletest/arraymap/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("arraymap") { + deps = [] +} diff --git a/test/moduletest/arraymap/arraymap.js b/test/moduletest/arraymap/arraymap.js new file mode 100644 index 0000000000..eb83050db7 --- /dev/null +++ b/test/moduletest/arraymap/arraymap.js @@ -0,0 +1,29 @@ +/* + * 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:async + * @tc.desc:test async function + * @tc.type: FUNC + * @tc.require: issueI5NO8G issueI8FBM3 + */ +var array = [,]; +function map() { + return array.map(x => x + 1); +} +array.__proto__.push(5); +var narr = map(); +print(JSON.stringify(Object.getOwnPropertyDescriptor(narr, 0))); +print(narr[0], 6); \ No newline at end of file diff --git a/test/moduletest/arraymap/expect_output.txt b/test/moduletest/arraymap/expect_output.txt new file mode 100644 index 0000000000..d4969415c5 --- /dev/null +++ b/test/moduletest/arraymap/expect_output.txt @@ -0,0 +1,15 @@ +# 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. + +{"value":6,"writable":true,"enumerable":true,"configurable":true} +6 6 -- Gitee From 1e736754e3ce0779d74958b35128cae361f8332e Mon Sep 17 00:00:00 2001 From: gwl Date: Sat, 25 Nov 2023 11:59:37 +0800 Subject: [PATCH 24/44] Extract method Signed-off-by: gwl Change-Id: I4f0108875bd5c9d706818889d033ea110937c3b2 --- .../builtins/builtins_array_stub_builder.cpp | 57 ++++++++++++------- .../builtins/builtins_array_stub_builder.h | 2 + 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 4a0a191a21..9cccbd9356 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -69,7 +69,7 @@ void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef n GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); - auto arrayFunc =GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); @@ -313,7 +313,6 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu } } Bind(&startDone); - Label endDone(env); Label msg1Def(env); Branch(TaggedIsUndefined(msg1), &endDone, &msg1Def); @@ -364,7 +363,6 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu } Bind(&endDone); - DEFVARIABLE(count, VariableType::INT64(), Int64(0)); GateRef tempCnt = Int64Sub(*end, *start); Label tempCntGreaterOrEqualZero(env); @@ -376,24 +374,7 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu Jump(&tempCntDone); } Bind(&tempCntDone); - - // new array - Label setProperties(env); - GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); - GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); - auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); - GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - NewObjectStubBuilder newBuilder(this); - newBuilder.SetParameters(glue, 0); - GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, *count); - Branch(TaggedIsException(newArray), exit, &setProperties); - Bind(&setProperties); - GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); - Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(*count)); - GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); - SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); - SetExtensibleToBitfield(glue, newArray, true); - + GateRef newArray = NewArray(glue, *count); GateRef thisEles = GetElementsArray(thisValue); GateRef thisElesLen = ZExtInt32ToInt64(GetLengthOfTaggedArray(thisEles)); GateRef newArrayEles = GetElementsArray(newArray); @@ -608,7 +589,8 @@ GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj) { GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); - GateRef isConcatsprKey = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX); + GateRef isConcatsprKey = + GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX); GateRef spreadable = FastGetPropertyByValue(glue, obj, isConcatsprKey, ProfileOperation()); Label isDefined(env); Label isUnDefined(env); @@ -633,6 +615,37 @@ GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj) return res; } +GateRef BuiltinsArrayStubBuilder::NewArray(GateRef glue, GateRef count) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined()); + Label exit(env); + Label setProperties(env); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + result = newBuilder.NewJSArrayWithSize(intialHClass, count); + Branch(TaggedIsException(*result), &exit, &setProperties); + Bind(&setProperties); + { + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, *result, lengthOffset, TruncInt64ToInt32(count)); + GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); + SetPropertyInlinedProps(glue, *result, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); + SetExtensibleToBitfield(glue, *result, true); + Jump(&exit); + } + Bind(&exit); + auto res = *result; + env->SubCfgExit(); + return res; +} + void BuiltinsArrayStubBuilder::Includes(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_array_stub_builder.h index ba89a681bd..1593ee2090 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.h @@ -57,6 +57,8 @@ public: void Includes(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); GateRef IsConcatSpreadable(GateRef glue, GateRef obj); + + GateRef NewArray(GateRef glue, GateRef count); private: static constexpr uint32_t MAX_LENGTH_ZERO = 0; static constexpr uint32_t MAX_LENGTH_ONE = 1; -- Gitee From 639ac41c96f16b4b7d98f7d05f286412741d24d8 Mon Sep 17 00:00:00 2001 From: shaoyijiang Date: Wed, 22 Nov 2023 08:58:55 +0000 Subject: [PATCH 25/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86crash=E6=B7=B7?= =?UTF-8?q?=E5=90=88=E6=A0=88=E6=89=93=E5=8D=B0=EF=BC=8C=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E8=AF=BB=E5=8F=96hap=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: shaoyijiang Change-Id: I80bb2f02f5105ae58bba2de59338b4f17ee94526 --- ecmascript/dfx/stackinfo/js_stackinfo.cpp | 318 +++++++++++------- ecmascript/dfx/stackinfo/js_stackinfo.h | 2 +- ecmascript/extractortool/src/zip_file.cpp | 8 +- .../extractortool/src/zip_file_reader.cpp | 6 +- 4 files changed, 202 insertions(+), 132 deletions(-) diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.cpp b/ecmascript/dfx/stackinfo/js_stackinfo.cpp index 593a1dc53c..966fcf46aa 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.cpp +++ b/ecmascript/dfx/stackinfo/js_stackinfo.cpp @@ -529,6 +529,21 @@ bool ArkGetMethodIdandJSPandaFileAddr(int pid, uintptr_t method, uintptr_t &meth return true; } +uint32_t ArkGetOffsetFromMethod(int pid, uintptr_t currentPtr, uintptr_t method) +{ + uintptr_t pc = 0; + if (!ReadUintptrFromAddr(pid, currentPtr, pc, true)) { + return 0; + } + uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET; + uintptr_t byteCodeArray = 0; + if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, true)) { + return 0; + } + uintptr_t offset = pc - byteCodeArray; + return static_cast(offset); +} + uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, uintptr_t currentPtr) { FrameType type = static_cast(frameType); @@ -537,33 +552,13 @@ uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, ui case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { currentPtr -= AsmInterpretedFrame::GetTypeOffset(); currentPtr += AsmInterpretedFrame::GetPcOffset(false); - uintptr_t pc = 0; - if (!ReadUintptrFromAddr(pid, currentPtr, pc, true)) { - return 0; - } - uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET; - uintptr_t byteCodeArray = 0; - if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, true)) { - return 0; - } - uintptr_t offset = pc - byteCodeArray; - return static_cast(offset); + return ArkGetOffsetFromMethod(pid, currentPtr, method); } case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME: { currentPtr -= InterpretedFrame::GetTypeOffset(); currentPtr += InterpretedFrame::GetPcOffset(false); - uintptr_t pc = 0; - if (!ReadUintptrFromAddr(pid, currentPtr, pc, true)) { - return 0; - } - uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET; - uintptr_t byteCodeArray = 0; - if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, true)) { - return 0; - } - uintptr_t offset = pc - byteCodeArray; - return static_cast(offset); + return ArkGetOffsetFromMethod(pid, currentPtr, method); } // ato need stackmaps case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: @@ -598,22 +593,24 @@ bool ArkReadData(const std::string &hapPath, const std::string &sourceMapPath, c } *data = (char*)malloc(sizeof(char)*dataSize); if (memcpy_s(*data, dataSize, dataPtr.get(), dataSize) != EOK) { - LOG_COMPILER(FATAL) << "memcpy_s failed"; + LOG_ECMA(FATAL) << "memcpy_s failed"; UNREACHABLE(); } return true; } -std::string ArkGetHapName(int pid, std::string filename) +std::string ArkGetHapName(int pid, std::string &fileName) { - auto found = filename.find(JSPandaFile::BUNDLE_INSTALL_PATH); + auto found = fileName.find(JSPandaFile::BUNDLE_INSTALL_PATH); if (found == std::string::npos) { + LOG_ECMA(ERROR) << "ArkGetHapName can't find BUNDLE_INSTALL_PATH: " << fileName; return ""; } - std::string subPath = filename.substr(sizeof(JSPandaFile::BUNDLE_INSTALL_PATH) - 1); + std::string subPath = fileName.substr(sizeof(JSPandaFile::BUNDLE_INSTALL_PATH) - 1); auto endPos = subPath.find("/"); if (endPos == std::string::npos) { + LOG_ECMA(ERROR) << "ArkGetHapName can't find /: " << fileName; return ""; } @@ -623,7 +620,135 @@ std::string ArkGetHapName(int pid, std::string filename) return hapSource; } -bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrameList) +std::string ArkGetMapPath(std::string &fileName) +{ + auto lastSlash = fileName.rfind("/"); + if (lastSlash == std::string::npos) { + LOG_ECMA(ERROR) << "ArkGetMapPath can't find fisrt /: " << fileName; + return ""; + } + + auto secondLastSlash = fileName.rfind("/", lastSlash - 1); + if (secondLastSlash == std::string::npos) { + LOG_ECMA(ERROR) << "ArkGetMapPath can't second fisrt /: " << fileName; + return ""; + } + + std::string mapPath = fileName.substr(secondLastSlash + 1); + return mapPath; +} + +bool ArkIsNativeWithCallField(int pid, uintptr_t method) +{ + uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET; + uintptr_t callField = 0; + if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, true)) { + return true; + } + return Method::IsNativeBit::Decode(callField); +} + +std::string ArkReadFileName(int pid, uintptr_t descAddr) +{ + std::string fileName; + while(true) { + uintptr_t desc = 0; + ReadUintptrFromAddr(pid, descAddr, desc, true); + bool key = 1; + size_t shiftAmount = 8; + for (size_t i = 0; i < sizeof(long); i++) { + char bottomEightBits = desc; + desc = desc >> shiftAmount; + if (!bottomEightBits) { + key = 0; + break; + } + fileName += bottomEightBits; + } + if (!key) { + break; + } + descAddr += sizeof(long); + } + return fileName; +} + +std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr) +{ + size_t size = sizeof(JSPandaFile) / sizeof(long); + uintptr_t *jsPandaFilePart = new uintptr_t[size](); + for (size_t i = 0; i < size; i++) { + if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], true)) { + LOG_ECMA(ERROR) << "ArkGetFileName failed, jsPandaFileAddr: " << jsPandaFileAddr; + return ""; + } + jsPandaFileAddr += sizeof(long); + } + JSPandaFile *jsPandaFile = reinterpret_cast(jsPandaFilePart); + uintptr_t descAddr = reinterpret_cast(const_cast(jsPandaFile->GetJSPandaFileDesc().c_str())); + delete []jsPandaFilePart; + return ArkReadFileName(pid, descAddr); +} + +JsFrame ArkParseJsFrameInfo(const panda_file::File *pf, std::string &fileName, + uintptr_t preMethodId, uintptr_t offset) +{ + std::shared_ptr newJsPandaFile = + JSPandaFileManager::GetInstance()->NewJSPandaFile(pf, fileName.c_str()); + auto debugExtractor = std::make_unique(newJsPandaFile.get()); + auto methodId = EntityId(preMethodId); + std::string name = MethodLiteral::ParseFunctionName(newJsPandaFile.get(), methodId); + name = name.size() ? name : "?"; + std::string url = debugExtractor->GetSourceFile(methodId); + + // line number and column number + int lineNumber = 0; + int columnNumber = 0; + auto callbackLineFunc = [&lineNumber](int32_t line) -> bool { + lineNumber = line + 1; + return true; + }; + auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool { + columnNumber = column + 1; + return true; + }; + if (offset > 0) { + if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || + !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { + lineNumber = 0; + columnNumber = 0; + } + } + JsFrame jsFrame; + size_t urlSize = url.size() + 1; + size_t nameSize = name.size() + 1; + if (strcpy_s(jsFrame.url, urlSize, url.c_str()) != EOK || + strcpy_s(jsFrame.functionName, nameSize, name.c_str()) != EOK) { + LOG_FULL(FATAL) << "strcpy_s failed"; + UNREACHABLE(); + } + jsFrame.line = lineNumber; + jsFrame.column = columnNumber; + return jsFrame; +} + +bool ArkGetNextFrame(uintptr_t ¤tPtr, uintptr_t typeOffset, + uintptr_t prevOffset, int pid) +{ + currentPtr -= typeOffset; + currentPtr += prevOffset; + if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, true)) { + return false; + } + if (currentPtr == 0) { + LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!"; + return false; + } + return true; +} + +bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, + size_t &size, panda::ecmascript::JsFrame **jsFrameList) { constexpr size_t FP_SIZE = 8; constexpr size_t LR_SIZE = 8; @@ -637,6 +762,7 @@ bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, LOG_ECMA(ERROR) << "invalid pc in GetArkNativeFrameInfo()!"; return false; } + std::vector jsFrames; while (true) { currentPtr -= sizeof(FrameType); uintptr_t frameType = 0; @@ -655,100 +781,43 @@ bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, break; } uintptr_t function = ArkGetFunction(pid, currentPtr, frameType); - if (function != 0) { - uintptr_t method = ArkCheckAndGetMethod(pid, function); - uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET; - uintptr_t callField = 0; - if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, true)) { + if (!function) { + if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) { return false; } - - bool isNativeWithCallField = Method::IsNativeBit::Decode(callField); - if (!isNativeWithCallField) { - uintptr_t jsPandaFileAddr = 0; - uintptr_t preMethodId = 0; - ArkGetMethodIdandJSPandaFileAddr(pid, method, preMethodId, jsPandaFileAddr); - uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr); - if (offset) { - size_t count = sizeof(JSPandaFile) / sizeof(long); - uintptr_t *jsPandaFilePart = new uintptr_t[count]; - for (size_t i = 0; i < count; i++) { - ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], true); - jsPandaFileAddr += sizeof(long); - } - JSPandaFile *jsPandaFile = reinterpret_cast(jsPandaFilePart); - uintptr_t desc = 0; - uintptr_t descAddr = reinterpret_cast(const_cast(jsPandaFile->GetJSPandaFileDesc().c_str())); - std::string fileName = {}; - while(true) { - ReadUintptrFromAddr(pid, descAddr, desc, true); - bool key = 1; - size_t shiftAmount = 8; - for (size_t i = 0; i < sizeof(long); i++) { - char bottomEightBits = desc; - desc = desc >> shiftAmount; - if (!bottomEightBits) { - key = 0; - break; - } - fileName += bottomEightBits; - } - if (!key) { - break; - } - descAddr += sizeof(long); - } - std::string hapPath = ArkGetHapName(pid, fileName); - std::string sourceMapPath = "ets/modules.abc"; - char *data = nullptr; - size_t dataSize = 0; - ArkReadData(hapPath, sourceMapPath, &data, dataSize); - auto pf = panda_file::OpenPandaFileFromMemory(data, dataSize); - std::shared_ptr newJsPandaFile = - JSPandaFileManager::GetInstance()->NewJSPandaFile(pf.get(), fileName.c_str()); - auto extractorPtr = std::make_unique(newJsPandaFile.get()); - DebugInfoExtractor *debugExtractor = extractorPtr.get(); - auto methodId = EntityId(preMethodId); - std::string name = MethodLiteral::ParseFunctionName(newJsPandaFile.get(), methodId); - name = name.size() ? name : "?"; - std::string url = debugExtractor->GetSourceFile(methodId); - // line number and column number - int lineNumber = 0; - int columnNumber = 0; - auto callbackLineFunc = [&lineNumber](int32_t line) -> bool { - lineNumber = line + 1; - return true; - }; - auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool { - columnNumber = column + 1; - return true; - }; - if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || - !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { - lineNumber = 0; - columnNumber = 0; - } - JsFrame jsFrame; - if (strcpy_s(jsFrame.url, url.size(), url.c_str()) != EOK && - strcpy_s(jsFrame.functionName, name.size(), name.c_str()) != EOK) { - LOG_FULL(FATAL) << "strcpy_s failed"; - UNREACHABLE(); - } - jsFrame.line = lineNumber; - jsFrame.column = columnNumber; - *jsFrameList++ = jsFrame; - delete []jsPandaFilePart; - free(data); - } + continue; + } + uintptr_t method = ArkCheckAndGetMethod(pid, function); + if (!method) { + if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) { + return false; } + continue; } - currentPtr -= typeOffset; - currentPtr += prevOffset; - if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, true)) { - return false; + if (!ArkIsNativeWithCallField(pid, method)) { + uintptr_t jsPandaFileAddr = 0; + uintptr_t preMethodId = 0; + if (!ArkGetMethodIdandJSPandaFileAddr(pid, method, preMethodId, jsPandaFileAddr)) { + LOG_ECMA(ERROR) << "Method ERROR, method: " << method; + return false; + } + uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr); + std::string fileName = ArkGetFileName(pid, jsPandaFileAddr); + std::string hapPath = ArkGetHapName(pid, fileName); + std::string MapPath = ArkGetMapPath(fileName); + char *data = nullptr; + size_t dataSize = 0; + ArkReadData(hapPath, MapPath, &data, dataSize); + auto pf = panda_file::OpenPandaFileFromMemory(data, dataSize); + if (!pf.get()) { + LOG_ECMA(ERROR) << "OpenPandaFileFromMemory ERROR, hapPath: " << hapPath + << ", MapPath: " << MapPath; + return false; + } + JsFrame jsFrame = ArkParseJsFrameInfo(pf.get(), fileName, preMethodId, offset); + jsFrames.push_back(jsFrame); } - if (currentPtr == 0) { - LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!"; + if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) { return false; } } @@ -760,6 +829,17 @@ bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, } currentPtr += LR_SIZE; *sp = currentPtr; + + size = jsFrames.size(); + if (!size) { + return true; + } + size_t jsFramesSize = sizeof(JsFrame) * size; + *jsFrameList = (JsFrame*)malloc(jsFramesSize); + if (memcpy_s(*jsFrameList, jsFramesSize, jsFrames.data(), jsFramesSize) != EOK) { + LOG_ECMA(FATAL) << "JsFrame memcpy_s failed, jsFramesSize: " << jsFramesSize; + UNREACHABLE(); + } return true; } #endif @@ -937,10 +1017,10 @@ __attribute__((visibility("default"))) int get_ark_js_heap_crash_info( } #if defined(PANDA_TARGET_OHOS) -__attribute__((visibility("default"))) int get_ark_native_frame_info( - int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrameList) +__attribute__((visibility("default"))) int get_ark_native_frame_info(int pid, uintptr_t *pc, + uintptr_t *fp, uintptr_t *sp, size_t &size, panda::ecmascript::JsFrame **jsFrameList) { - if (GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrameList)) { + if (GetArkNativeFrameInfo(pid, pc, fp, sp, size, jsFrameList)) { return 1; } return -1; diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.h b/ecmascript/dfx/stackinfo/js_stackinfo.h index a7fac64e9e..73421d8280 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.h +++ b/ecmascript/dfx/stackinfo/js_stackinfo.h @@ -65,7 +65,7 @@ extern "C" int get_ark_js_heap_crash_info( int pid, uintptr_t *x20, uintptr_t *fp, int out_js_info, char *buf, size_t buf_sz); #if defined(PANDA_TARGET_OHOS) extern "C" int get_ark_native_frame_info( - int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrameList); + int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, size_t &size, panda::ecmascript::JsFrame **jsFrameList); #endif // define in dfx_signal_handler.h typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext); diff --git a/ecmascript/extractortool/src/zip_file.cpp b/ecmascript/extractortool/src/zip_file.cpp index 58648a9b78..df8d9b2e3d 100644 --- a/ecmascript/extractortool/src/zip_file.cpp +++ b/ecmascript/extractortool/src/zip_file.cpp @@ -186,14 +186,8 @@ bool ZipFile::Open() if (pathName_.length() > PATH_MAX) { return false; } - std::string realPath; - realPath.reserve(PATH_MAX); - realPath.resize(PATH_MAX - 1); - if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) { - return false; - } - zipFileReader_ = ZipFileReader::CreateZipFileReader(realPath); + zipFileReader_ = ZipFileReader::CreateZipFileReader(pathName_); if (!zipFileReader_) { return false; } diff --git a/ecmascript/extractortool/src/zip_file_reader.cpp b/ecmascript/extractortool/src/zip_file_reader.cpp index 6b0f1aae52..0b94b8d39d 100644 --- a/ecmascript/extractortool/src/zip_file_reader.cpp +++ b/ecmascript/extractortool/src/zip_file_reader.cpp @@ -76,11 +76,7 @@ bool ZipFileReader::init() if (filePath_.empty()) { return false; } - char resolvePath[PATH_MAX] = {0}; - if (realpath(filePath_.c_str(), resolvePath) == nullptr) { - return false; - } - fd_ = open(resolvePath, O_RDONLY); + fd_ = open(filePath_.c_str(), O_RDONLY); if (fd_ < 0) { return false; } -- Gitee From 66bf26a731b5eae2179c1e19f374b891ddfd9637 Mon Sep 17 00:00:00 2001 From: lukai Date: Fri, 24 Nov 2023 14:36:47 +0800 Subject: [PATCH 26/44] Use hintSize to calaculate growing capacity HintSize collected by pgo is used to calaculate growing capacity. TrackInfo filed of jsarray will be used as hintSize(taggedInt) in aot compiling. Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8J6TX?from=project-issue Signed-off-by: lukai Change-Id: I706fb19ff5d00e8db324b0c55986fedf18538c10 --- ecmascript/compiler/gate_accessor.cpp | 2 +- ecmascript/compiler/ntype_hcr_lowering.cpp | 23 +++++++++++----------- ecmascript/compiler/ntype_hcr_lowering.h | 4 ++-- ecmascript/js_array.h | 10 ++++++++++ ecmascript/js_object-inl.h | 12 +++++++++++ ecmascript/js_object.cpp | 13 +++++++----- ecmascript/js_object.h | 4 ++++ 7 files changed, 49 insertions(+), 19 deletions(-) diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index d96a8f6ce1..81c820cff4 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -607,7 +607,7 @@ void GateAccessor::TrySetArrayElementsLength(GateRef gate, uint32_t length) Gate *gatePtr = circuit_->LoadGatePtr(gate); OpCode op = GetOpCode(gate); if (op == OpCode::JS_BYTECODE) { - const_cast(gatePtr->GetJSBytecodeMetaData())->SetElementsLength(length); + const_cast(gatePtr->GetJSBytecodeMetaData())->SetElementsLength(length); } } diff --git a/ecmascript/compiler/ntype_hcr_lowering.cpp b/ecmascript/compiler/ntype_hcr_lowering.cpp index 0ad57b78af..9cc2d73de3 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.cpp +++ b/ecmascript/compiler/ntype_hcr_lowering.cpp @@ -46,24 +46,20 @@ void NTypeHCRLowering::LowerCreateArray(GateRef gate, GateRef glue) { Environment env(gate, circuit_, &builder_); if (acc_.GetArraySize(gate) == 0) { - LowerCreateEmptyArray(gate, glue); + LowerCreateEmptyArray(gate); } else { LowerCreateArrayWithOwn(gate, glue); } } -void NTypeHCRLowering::LowerCreateEmptyArray(GateRef gate, GateRef glue) +void NTypeHCRLowering::LowerCreateEmptyArray(GateRef gate) { GateRef length = builder_.Int32(0); GateRef elements = Circuit::NullGate(); GateRef value = acc_.GetValueIn(gate, 0); - auto elementsLength = static_cast(acc_.GetConstantValue(value)); - if (elementsLength > 0) { - elements = CreateElementsWithLength(gate, glue, elementsLength); - } else { - elements = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); - } - auto array = NewJSArrayLiteral(gate, elements, length); + auto hintLength = static_cast(acc_.GetConstantValue(value)); + elements = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); + auto array = NewJSArrayLiteral(gate, elements, length, hintLength); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array); } @@ -137,7 +133,7 @@ GateRef NTypeHCRLowering::CreateElementsWithLength(GateRef gate, GateRef glue, s return elements; } -GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef gate, GateRef elements, GateRef length) +GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef gate, GateRef elements, GateRef length, uint32_t hintLength) { ElementsKind kind = acc_.GetArrayMetaDataAccessor(gate).GetElementsKind(); GateRef hclass = Circuit::NullGate(); @@ -172,7 +168,12 @@ GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef gate, GateRef elements, Gate builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::PROPERTIES_OFFSET, emptyArray); builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::ELEMENTS_OFFSET, elements); builder_.StoreConstOffset(VariableType::INT32(), array, JSArray::LENGTH_OFFSET, length); - builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET, builder_.Undefined()); + if (hintLength > 0) { + builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET, + builder_.Int64(JSTaggedValue(hintLength).GetRawData())); + } else { + builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET, builder_.Undefined()); + } builder_.StoreConstOffset(VariableType::JS_POINTER(), array, lengthAccessorOffset, accessor); builder_.FinishAllocate(); return array; diff --git a/ecmascript/compiler/ntype_hcr_lowering.h b/ecmascript/compiler/ntype_hcr_lowering.h index 04af7abc73..0fc6d19c8e 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.h +++ b/ecmascript/compiler/ntype_hcr_lowering.h @@ -44,13 +44,13 @@ private: void Lower(GateRef gate); void LowerCreateArray(GateRef gate, GateRef glue); void LowerCreateArrayWithBuffer(GateRef gate, GateRef glue); - void LowerCreateEmptyArray(GateRef gate, GateRef glue); + void LowerCreateEmptyArray(GateRef gate); void LowerCreateArrayWithOwn(GateRef gate, GateRef glue); void LowerStoreModuleVar(GateRef gate, GateRef glue); void LowerLdLocalModuleVar(GateRef gate); GateRef LoadFromConstPool(GateRef jsFunc, size_t index, size_t valVecType); - GateRef NewJSArrayLiteral(GateRef gate, GateRef elements, GateRef length); + GateRef NewJSArrayLiteral(GateRef gate, GateRef elements, GateRef length, uint32_t hintLength = 0); GateRef NewTaggedArray(size_t length); GateRef NewTaggedArray(GateRef length); GateRef CreateElementsWithLength(GateRef gate, GateRef glue, size_t arrayLength); diff --git a/ecmascript/js_array.h b/ecmascript/js_array.h index 6c4b9e09c9..ad5c94e7bb 100644 --- a/ecmascript/js_array.h +++ b/ecmascript/js_array.h @@ -57,6 +57,16 @@ public: SetLength(length); } + inline uint32_t GetHintLength() const + { + auto trackInfo = GetTrackInfo(); + if (trackInfo.IsInt()) { + int hint = trackInfo.GetInt(); + return hint > 0 ? hint : 0; + } + return 0; + } + static constexpr size_t LENGTH_OFFSET = JSObject::SIZE; ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, TRACE_INDEX_OFFSET) ACCESSORS_PRIMITIVE_FIELD(TraceIndex, uint32_t, TRACE_INDEX_OFFSET, TRACK_INFO_OFFSET) diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index 98876e1b50..1882197fcc 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -372,6 +372,18 @@ inline uint32_t JSObject::ComputeElementCapacityHighGrowth(uint32_t oldCapacity) return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH; } +inline uint32_t JSObject::ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint) +{ + uint32_t newCapacity = 0; + if ((oldCapacity >= hint) || (hint < MIN_ELEMENTS_HINT_LENGTH) || (hint >= MAX_ELEMENTS_HINT_LENGTH)) { + return newCapacity; + } + if ((hint / oldCapacity) <= ELEMENTS_HINT_FACTOR) { + newCapacity = hint; + } + return newCapacity; +} + inline uint32_t JSObject::ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity, uint32_t maxNonInlinedFastPropsCapacity) { diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 43fdd2ac5c..69fd261428 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -86,11 +86,14 @@ Method *ECMAObject::GetCallTarget() const JSHandle JSObject::GrowElementsCapacity(const JSThread *thread, const JSHandle &obj, uint32_t capacity, bool highGrowth, bool isNew) { - uint32_t newCapacity; - if (highGrowth) { - newCapacity = ComputeElementCapacityHighGrowth(capacity); - } else { - newCapacity = ComputeElementCapacity(capacity, isNew); + uint32_t newCapacity = 0; + if (obj->IsJSArray()) { + uint32_t hint = JSHandle(obj)->GetHintLength(); + newCapacity = ComputeElementCapacityWithHint(capacity, hint); + } + if (newCapacity == 0) { + newCapacity = highGrowth ? ComputeElementCapacityHighGrowth(capacity) : + ComputeElementCapacity(capacity, isNew); } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle oldElements(thread, obj->GetElements()); diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 27ac614193..cee6de3c89 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -371,6 +371,9 @@ public: static constexpr int MIN_GAP = 256; static constexpr int MAX_GAP = 1_KB; static constexpr uint32_t MAX_ELEMENT_INDEX = std::numeric_limits::max(); + static constexpr int MIN_ELEMENTS_HINT_LENGTH = 1_KB; + static constexpr int MAX_ELEMENTS_HINT_LENGTH = 2_MB; + static constexpr int ELEMENTS_HINT_FACTOR = 8; CAST_CHECK(JSObject, IsECMAObject); @@ -701,6 +704,7 @@ private: static uint32_t ComputeElementCapacity(uint32_t oldCapacity, bool isNew = false); static uint32_t ComputeElementCapacityHighGrowth(uint32_t oldCapacity); + static uint32_t ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint); static uint32_t ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity, uint32_t maxNonInlinedFastPropsCapacity); -- Gitee From 49e0f0c7aa27784fe203401a81b413f18503bbdd Mon Sep 17 00:00:00 2001 From: chenjx-huawei Date: Sat, 25 Nov 2023 17:37:35 +0800 Subject: [PATCH 27/44] Bugfix on NewJSError when recursively execute the function Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8JGBS?from=project-issue Signed-off-by: chenjx-huawei Change-Id: I2564a9393abd0e657b3f9d64dded9d9d35b8f641 --- ecmascript/base/error_helper.cpp | 15 +++++++++------ ecmascript/base/error_helper.h | 4 ++-- ecmascript/object_factory.cpp | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index 58197f6ac7..18b32e6f95 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -131,7 +131,7 @@ JSHandle ErrorHelper::GetErrorName(JSThread *thread, const JSHand } JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, - const ErrorType &errorType) + [[maybe_unused]] const ErrorType &errorType) { JSThread *thread = argv->GetThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); @@ -195,8 +195,7 @@ JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, ASSERT_PRINT(status == true, "return result exception!"); } - bool isOOMError = errorType == ErrorType::OOM_ERROR; - JSHandle handleStack = BuildEcmaStackTrace(thread, isOOMError); + JSHandle handleStack = BuildEcmaStackTrace(thread); JSHandle stackkey = globalConst->GetHandledStackString(); PropertyDescriptor stackDesc(thread, JSHandle::Cast(handleStack), true, false, true); [[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread, nativeInstanceObj, stackkey, stackDesc); @@ -225,11 +224,15 @@ JSHandle ErrorHelper::GetErrorJSFunction(JSThread *thread) return thread->GlobalConstants()->GetHandledUndefined(); } -JSHandle ErrorHelper::BuildEcmaStackTrace(JSThread *thread, bool isOOMError) +JSHandle ErrorHelper::BuildEcmaStackTrace(JSThread *thread) { std::string data = JsStackInfo::BuildJsStackTrace(thread, false); - if (isOOMError) { - data = data.substr(0, MAX_ERROR_SIZE); + if (data.size() > MAX_ERROR_SIZE) { + // find last line break from 0 to MAX_ERROR_SIZE + size_t pos = data.rfind('\n', MAX_ERROR_SIZE); + if (pos != std::string::npos) { + data = data.substr(0, pos); + } } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); LOG_ECMA(DEBUG) << data; diff --git a/ecmascript/base/error_helper.h b/ecmascript/base/error_helper.h index aedf378e64..c2917c265c 100644 --- a/ecmascript/base/error_helper.h +++ b/ecmascript/base/error_helper.h @@ -35,11 +35,11 @@ public: private: static JSHandle GetErrorJSFunction(JSThread *thread); - static JSHandle BuildEcmaStackTrace(JSThread *thread, bool isOOMError); + static JSHandle BuildEcmaStackTrace(JSThread *thread); static JSHandle GetErrorName(JSThread *thread, const JSHandle &name, const ErrorType &errorType); - static constexpr uint32_t MAX_ERROR_SIZE = 128_KB; + static constexpr uint32_t MAX_ERROR_SIZE = 10_KB; }; } // namespace panda::ecmascript::base diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 2377950cff..d047ec995b 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -907,6 +907,7 @@ JSHandle ObjectFactory::NewJSError(const ErrorType &errorType, const J info->SetCallArg(message.GetTaggedValue()); Method *method = JSHandle::Cast(ctor)->GetCallTarget(); JSTaggedValue obj = reinterpret_cast(const_cast(method->GetNativePointer()))(info); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread_); JSHandle handleNativeInstanceObj(thread_, obj); auto sp = const_cast(thread_->GetCurrentSPFrame()); ASSERT(FrameHandler::GetFrameType(sp) == FrameType::INTERPRETER_ENTRY_FRAME); -- Gitee From 2ceaf6714a56df079038342cd80b40be7cbb1f4b Mon Sep 17 00:00:00 2001 From: rentangyu Date: Tue, 21 Nov 2023 10:34:25 +0800 Subject: [PATCH 28/44] CpuProfiler code optimization issues:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8I403 Signed-off-by: rentangyu --- ecmascript/dfx/cpu_profiler/cpu_profiler.cpp | 9 ++++--- ecmascript/dfx/cpu_profiler/cpu_profiler.h | 2 ++ ecmascript/napi/include/jsnapi.h | 4 +++- ecmascript/napi/jsnapi.cpp | 25 +++++++++++++++++++- ecmascript/napi/test/jsnapi_tests.cpp | 2 +- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp index b90bace335..411db2efd1 100644 --- a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp +++ b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp @@ -21,7 +21,6 @@ #include #include "ecmascript/compiler/assembler/assembler.h" -#include "ecmascript/dfx/cpu_profiler/sampling_processor.h" #include "ecmascript/frames.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" @@ -84,8 +83,8 @@ void CpuProfiler::StartCpuProfilerForInfo() generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT); generator_->SetIsStart(true); - RunParams *params = new RunParams(generator_, static_cast(interval_), pthread_self()); - if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params) != 0) { + params_ = new RunParams(generator_, static_cast(interval_), pthread_self()); + if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) { LOG_ECMA(ERROR) << "pthread_create fail!"; return; } @@ -147,8 +146,8 @@ void CpuProfiler::StartCpuProfilerForFile(const std::string &fileName) generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT); generator_->SetIsStart(true); - RunParams *params = new RunParams(generator_, static_cast(interval_), pthread_self()); - if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params) != 0) { + params_ = new RunParams(generator_, static_cast(interval_), pthread_self()); + if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) { LOG_ECMA(ERROR) << "pthread_create fail!"; return; } diff --git a/ecmascript/dfx/cpu_profiler/cpu_profiler.h b/ecmascript/dfx/cpu_profiler/cpu_profiler.h index c50153da8c..c4653c2515 100644 --- a/ecmascript/dfx/cpu_profiler/cpu_profiler.h +++ b/ecmascript/dfx/cpu_profiler/cpu_profiler.h @@ -19,6 +19,7 @@ #include #include "ecmascript/dfx/cpu_profiler/samples_record.h" +#include "ecmascript/dfx/cpu_profiler/sampling_processor.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/js_thread.h" @@ -118,6 +119,7 @@ private: uint64_t beforeCallNapiTimeStamp_ = 0; std::atomic_bool isBuildNapiStack_ {false}; bool enableVMTag_ {false}; + RunParams *params_ = nullptr; }; class CallNapiScope { diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 1a01f3e0c4..658eafc94b 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -1452,8 +1452,10 @@ public: static EcmaVM* CreateEcmaVM(const ecmascript::JSRuntimeOptions &options); static void PreFork(EcmaVM *vm); static void PostFork(EcmaVM *vm, const RuntimeOption &option); - static void addWorker(EcmaVM *hostVm, EcmaVM *workerVm); + static void AddWorker(EcmaVM *hostVm, EcmaVM *workerVm); static bool DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm); + static void GetStackBeforeCallNapiSuccess(EcmaVM *vm, bool &getStackBeforeCallNapiSuccess); + static void GetStackAfterCallNapi(EcmaVM *vm); static PatchErrorCode LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName); static PatchErrorCode LoadPatch(EcmaVM *vm, diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4c0aa74277..95d3f4e900 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -689,7 +689,7 @@ void JSNApi::PostFork(EcmaVM *vm, const RuntimeOption &option) vm->PostFork(); } -void JSNApi::addWorker(EcmaVM *hostVm, EcmaVM *workerVm) +void JSNApi::AddWorker(EcmaVM *hostVm, EcmaVM *workerVm) { if (hostVm != nullptr && workerVm != nullptr) { hostVm->WorkersetInfo(workerVm); @@ -3824,6 +3824,29 @@ void JSNApi::SetSourceMapTranslateCallback(EcmaVM *vm, SourceMapTranslateCallbac vm->SetSourceMapTranslateCallback(callback); } + +void JSNApi::GetStackBeforeCallNapiSuccess([[maybe_unused]] EcmaVM *vm, + [[maybe_unused]] bool &getStackBeforeCallNapiSuccess) +{ +#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) + JSThread *thread = vm->GetJSThread(); + if (thread->GetIsProfiling()) { + getStackBeforeCallNapiSuccess = vm->GetProfiler()->GetStackBeforeCallNapi(thread); + } +#endif +} + +void JSNApi::GetStackAfterCallNapi([[maybe_unused]] EcmaVM *vm) +{ +#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) + JSThread *thread = vm->GetJSThread(); + if (thread->GetIsProfiling()) { + vm->GetProfiler()->GetStackAfterCallNapi(thread); + } +#endif +} + + TryCatch::~TryCatch() { if (!rethrow_) { diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index f3a4704b38..5dc0087435 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -1073,7 +1073,7 @@ HWTEST_F_L0(JSNApiTests, addWorker_DeleteWorker) { JSRuntimeOptions option; EcmaVM *workerVm = JSNApi::CreateEcmaVM(option); - JSNApi::addWorker(vm_, workerVm); + JSNApi::AddWorker(vm_, workerVm); bool hasDeleted = JSNApi::DeleteWorker(vm_, workerVm); EXPECT_TRUE(hasDeleted); -- Gitee From c0fbf3aebdd6ae6d88eaeeeb05d5c8098f84633f Mon Sep 17 00:00:00 2001 From: lijiamin2019 Date: Wed, 8 Nov 2023 17:16:13 +0800 Subject: [PATCH 29/44] Refactor debugger process Signed-off-by: lijiamin2019 Change-Id: I8c6f5c6274946adb4157b9a06ebebdfa77b057cf --- ecmascript/napi/dfx_jsnapi.cpp | 11 +- ecmascript/napi/include/dfx_jsnapi.h | 5 +- ecmascript/napi/include/jsnapi.h | 17 ++- ecmascript/napi/jsnapi.cpp | 209 ++++++++++++++++++++++++++- 4 files changed, 234 insertions(+), 8 deletions(-) diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index cc9ab9afba..a78732fd9b 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -612,14 +612,16 @@ void DFXJSNApi::StopSampling([[maybe_unused]] const EcmaVM *vm) #endif } -bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int32_t instanceId, - const DebuggerPostTask &debuggerPostTask) +// old process. +bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, uint32_t tid, + int32_t instanceId, const DebuggerPostTask &debuggerPostTask) { JSNApi::DebugOption debugOption; debugOption.libraryPath = option.libraryPath; if (option.profilerType == ProfilerType::CPU_PROFILER) { debugOption.isDebugMode = false; - if (JSNApi::StartDebugger(vm, debugOption, instanceId, debuggerPostTask)) { + if (JSNApi::NotifyDebugMode( + tid, vm, option.libraryPath, debugOption, instanceId, debuggerPostTask, false, false)) { StartCpuProfilerForInfo(vm, option.interval); return true; } else { @@ -628,7 +630,8 @@ bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int32_t } } else { debugOption.isDebugMode = true; - return JSNApi::StartDebugger(vm, debugOption, instanceId, debuggerPostTask); + return JSNApi::JSNApi::NotifyDebugMode( + tid, vm, option.libraryPath, debugOption, instanceId, debuggerPostTask, true, true); } } diff --git a/ecmascript/napi/include/dfx_jsnapi.h b/ecmascript/napi/include/dfx_jsnapi.h index 01c22a0836..74249ce3e6 100644 --- a/ecmascript/napi/include/dfx_jsnapi.h +++ b/ecmascript/napi/include/dfx_jsnapi.h @@ -100,8 +100,9 @@ public: int interval = 500; // 500:Default Sampling interval 500 microseconds ProfilerType profilerType = ProfilerType::CPU_PROFILER; }; - static bool StartProfiler(EcmaVM *vm, const ProfilerOption &option, int32_t instanceId, - const DebuggerPostTask &debuggerPostTask); + // To be compatible with old process. + static bool StartProfiler(EcmaVM *vm, const ProfilerOption &option, uint32_t tid, + int32_t instanceId, const DebuggerPostTask &debuggerPostTask); static void SetCpuSamplingInterval(const EcmaVM *vm, int interval); static bool StartSampling(const EcmaVM *vm, uint64_t samplingInterval); static const SamplingInfo *GetAllocationProfile(const EcmaVM *vm); diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index bbcd3054c7..1483be6327 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1312,7 +1313,7 @@ class PUBLIC_API JSNApi { public: struct DebugOption { const char *libraryPath; - bool isDebugMode; + bool isDebugMode = false; int port = -1; }; using DebuggerPostTask = std::function&&)>; @@ -1393,9 +1394,20 @@ public: static bool HasPendingException(const EcmaVM *vm); static bool HasPendingJob(const EcmaVM *vm); static void EnableUserUncaughtErrorHandler(EcmaVM *vm); + // prevewer debugger. static bool StartDebugger(EcmaVM *vm, const DebugOption &option, int32_t instanceId = 0, const DebuggerPostTask &debuggerPostTask = {}); + // To be compatible with the old process. + static bool StartDebuggerForOldProcess(EcmaVM *vm, const DebugOption &option, int32_t instanceId = 0, + const DebuggerPostTask &debuggerPostTask = {}); + // socketpair process in ohos platform. + static bool StartDebuggerForSocketPair(uint32_t tid, const DebugOption &option, int socketfd = -1, + const DebuggerPostTask &debuggerPostTask = {}); static bool StopDebugger(EcmaVM *vm); + static bool StopDebugger(uint32_t tid); + static bool NotifyDebugMode(uint32_t tid, EcmaVM *vm, const char *libraryPath, const DebugOption &option, + int32_t instanceId = 0, const DebuggerPostTask &debuggerPostTask = {}, + bool debugApp = false, bool debugMode = false); static bool IsMixedDebugEnabled(const EcmaVM *vm); static void NotifyNativeCalling(const EcmaVM *vm, const void *nativeAddress); static void NotifyNativeReturnJS(const EcmaVM *vm); @@ -1459,9 +1471,12 @@ public: private: static int vmCount_; static bool initialize_; + static std::unordered_map> debugInfo_; static bool CreateRuntime(const RuntimeOption &option); static bool DestroyRuntime(); + static EcmaVM *GetEcmaVMByTid(uint32_t tid); + static const DebuggerPostTask &GetDebuggerTaskByTid(uint32_t tid); static uintptr_t GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress); static uintptr_t GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress); static uintptr_t SetWeak(const EcmaVM *vm, uintptr_t localAddress); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 62412ad9cd..79cdcaea72 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "dfx_jsnapi.h" #include "jsnapi_helper.h" #include @@ -20,6 +21,7 @@ #include #include #include +#include #include "ecmascript/base/builtins_base.h" #include "ecmascript/base/json_parser.h" @@ -99,9 +101,10 @@ namespace OHOS::ArkCompiler::Toolchain { using DebuggerPostTask = std::function &&)>; extern "C" { - bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId, + bool StartDebug(const std::string& componentName, void* vm, int32_t instanceId, const DebuggerPostTask& debuggerPostTask, int port); void StopDebug(const std::string& componentName); + void WaitForDebugger(void* vm); } } // namespace OHOS::ArkCompiler::Toolchain const std::string DEBUGGER_NAME = "PandaDebugger"; @@ -200,6 +203,7 @@ constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; } int JSNApi::vmCount_ = 0; bool JSNApi::initialize_ = false; +std::unordered_map> JSNApi::debugInfo_ {}; static Mutex *mutex = new panda::Mutex(); #define XPM_PROC_PREFIX "/proc/" #define XPM_PROC_SUFFIX "/xpm_region" @@ -423,6 +427,7 @@ void JSNApi::PrintExceptionInfo(const EcmaVM *vm) ThrowException(vm, exception); } +// for prevewer debugger. bool JSNApi::StartDebugger([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, [[maybe_unused]] int32_t instanceId, [[maybe_unused]] const DebuggerPostTask &debuggerPostTask) @@ -487,6 +492,168 @@ bool JSNApi::StartDebugger([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const D #endif // ECMASCRIPT_SUPPORT_DEBUGGER } +// for old process. +bool JSNApi::StartDebuggerForOldProcess([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, + [[maybe_unused]] int32_t instanceId, + [[maybe_unused]] const DebuggerPostTask &debuggerPostTask) +{ +#if defined(ECMASCRIPT_SUPPORT_DEBUGGER) +#if !defined(PANDA_TARGET_IOS) + if (vm == nullptr) { + return false; + } + CHECK_HAS_PENDING_EXCEPTION(vm, false); + const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); + if (!handle.IsValid()) { + LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] Get library handle fail: " << option.libraryPath; + return false; + } + + using StartDebugger = bool (*)( + const std::string &, EcmaVM *, int32_t, const DebuggerPostTask &, int); + + auto sym = panda::os::library_loader::ResolveSymbol(handle, "StartDebug"); + if (!sym) { + LOG_ECMA(ERROR) << "[StartDebugger] Resolve symbol fail: " << sym.Error().ToString(); + return false; + } + + bool ret = reinterpret_cast(sym.Value())( + "PandaDebugger", vm, instanceId, debuggerPostTask, option.port); + if (!ret) { + // Reset the config + vm->GetJsDebuggerManager()->SetDebugMode(false); + panda::os::library_loader::LibraryHandle libraryHandle(nullptr); + vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(libraryHandle)); + } + return ret; +#else + if (vm == nullptr) { + return false; + } + CHECK_HAS_PENDING_EXCEPTION(vm, false); + vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode); + bool ret = OHOS::ArkCompiler::Toolchain::StartDebug( + DEBUGGER_NAME, vm, option.isDebugMode, instanceId, debuggerPostTask, option.port); + if (!ret) { + // Reset the config + vm->GetJsDebuggerManager()->SetDebugMode(false); + } + return ret; +#endif // PANDA_TARGET_IOS +#else + LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; + return false; +#endif // ECMASCRIPT_SUPPORT_DEBUGGER +} + +// for socketpair process in ohos platform. +bool JSNApi::StartDebuggerForSocketPair([[maybe_unused]] uint32_t tid, + [[maybe_unused]] const DebugOption &option, + [[maybe_unused]] int socketfd, + [[maybe_unused]] const DebuggerPostTask &debuggerPostTask) +{ +#if defined(ECMASCRIPT_SUPPORT_DEBUGGER) + EcmaVM *vm = GetEcmaVMByTid(tid); + const DebuggerPostTask &realDebuggerPostTask = GetDebuggerTaskByTid(tid); + if (vm == nullptr) { + return false; + } + CHECK_HAS_PENDING_EXCEPTION(vm, false); + const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); + if (!handle.IsValid()) { + LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] Get library handle fail: " << option.libraryPath; + return false; + } + + using StartDebuggerForSocketPair = bool (*)(EcmaVM *, uint32_t, const DebuggerPostTask &, int); + + auto sym = panda::os::library_loader::ResolveSymbol(handle, "StartDebugForSocketpair"); + if (!sym) { + LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] Resolve symbol fail: " << sym.Error().ToString(); + return false; + } + + bool ret = reinterpret_cast(sym.Value())(vm, tid, realDebuggerPostTask, socketfd); + if (!ret) { + // Reset the config + vm->GetJsDebuggerManager()->SetDebugMode(false); + panda::os::library_loader::LibraryHandle libraryHandle(nullptr); + vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(libraryHandle)); + } + return ret; +#else + LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; + return false; +#endif // ECMASCRIPT_SUPPORT_DEBUGGER +} + +EcmaVM *JSNApi::GetEcmaVMByTid(uint32_t tid) +{ + if (debugInfo_.find(tid) == debugInfo_.end()) { + return nullptr; + } + return debugInfo_[tid].first; +} + +const DebuggerPostTask &JSNApi::GetDebuggerTaskByTid(uint32_t tid) +{ + if (debugInfo_.find(tid) == debugInfo_.end()) { + return {}; + } + return debugInfo_[tid].second; +} + +bool JSNApi::NotifyDebugMode([[maybe_unused]] uint32_t tid, + [[maybe_unused]] EcmaVM *vm, + [[maybe_unused]] const char *libraryPath, + [[maybe_unused]] const DebugOption &option, + [[maybe_unused]] int32_t instanceId, + [[maybe_unused]] const DebuggerPostTask &debuggerPostTask, + [[maybe_unused]] bool debugApp, [[maybe_unused]] bool debugMode) +{ +#if defined(ECMASCRIPT_SUPPORT_DEBUGGER) + // debug app & -D; heap profile + if (vm == nullptr) { + return false; + } + if (debugInfo_.find(tid) == debugInfo_.end()) { + debugInfo_.emplace(tid, std::make_pair(vm, debuggerPostTask)); + } + + CHECK_HAS_PENDING_EXCEPTION(vm, false); + const auto &handler = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); + if (handler.IsValid()) { + return false; + } + + auto handle = panda::os::library_loader::Load(std::string(libraryPath)); + if (!handle) { + LOG_ECMA(ERROR) << "[NotifyDebugMode] Load library fail: " << libraryPath << " " << errno; + return false; + } + vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(handle.Value())); + vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode && debugApp); + bool ret = StartDebuggerForOldProcess(vm, option, instanceId, debuggerPostTask); + + if (debugApp && debugMode) { + using WaitForDebugger = bool (*)(EcmaVM *); + + auto sym = panda::os::library_loader::ResolveSymbol( + vm->GetJsDebuggerManager()->GetDebugLibraryHandle(), "WaitForDebugger"); + if (!sym) { + LOG_ECMA(ERROR) << "[NotifyDebugMode] Resolve symbol fail: " << sym.Error().ToString(); + return false; + } + reinterpret_cast(sym.Value())(vm); + } + return ret; +#else + LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; + return false; +#endif // ECMASCRIPT_SUPPORT_DEBUGGER +} + bool JSNApi::StopDebugger([[maybe_unused]] EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) @@ -526,6 +693,46 @@ bool JSNApi::StopDebugger([[maybe_unused]] EcmaVM *vm) #endif // ECMASCRIPT_SUPPORT_DEBUGGER } +bool JSNApi::StopDebugger(uint32_t tid) +{ +#if defined(ECMASCRIPT_SUPPORT_DEBUGGER) +#if !defined(PANDA_TARGET_IOS) + EcmaVM *vm = GetEcmaVMByTid(tid); + if (vm == nullptr) { + return false; + } + CHECK_HAS_PENDING_EXCEPTION(vm, false); + + const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); + + using StopOldDebug = void (*)(void *, const std::string &); + + auto sym = panda::os::library_loader::ResolveSymbol(handle, "StopOldDebug"); + if (!sym) { + LOG_ECMA(ERROR) << sym.Error().ToString(); + return false; + } + + reinterpret_cast(sym.Value())(vm, "PandaDebugger"); + + vm->GetJsDebuggerManager()->SetDebugMode(false); + return true; +#else + if (vm == nullptr) { + return false; + } + CHECK_HAS_PENDING_EXCEPTION(vm, false); + + OHOS::ArkCompiler::Toolchain::StopDebug(DEBUGGER_NAME); + vm->GetJsDebuggerManager()->SetDebugMode(false); + return true; +#endif // PANDA_TARGET_IOS +#else + LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; + return false; +#endif // ECMASCRIPT_SUPPORT_DEBUGGER +} + bool JSNApi::IsMixedDebugEnabled([[maybe_unused]] const EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) -- Gitee From b76ca786c91fd7c8f8fffb2ae12ad57d4a54ad41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Mon, 27 Nov 2023 09:12:19 +0800 Subject: [PATCH 30/44] =?UTF-8?q?=E5=9B=9E=E9=80=80=E2=80=98pull=20requwst?= =?UTF-8?q?=EF=BC=815204=EF=BC=9Aflat=E4=B8=8Eflatmap=E2=80=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- test/moduletest/BUILD.gn | 3 -- test/moduletest/arrayflat/arrayflat.js | 10 ------ test/moduletest/arrayflat/expect_output.txt | 2 +- test/moduletest/arrayflatmap/BUILD.gn | 18 ----------- test/moduletest/arrayflatmap/arrayflatmap.js | 31 ------------------- .../moduletest/arrayflatmap/expect_output.txt | 14 --------- 6 files changed, 1 insertion(+), 77 deletions(-) delete mode 100644 test/moduletest/arrayflatmap/BUILD.gn delete mode 100644 test/moduletest/arrayflatmap/arrayflatmap.js delete mode 100644 test/moduletest/arrayflatmap/expect_output.txt diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 91db49456c..24c7e03066 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -20,7 +20,6 @@ group("ark_js_moduletest") { "array", "arrayfindlast", "arrayflat", - "arrayflatmap", "arrayfindindex", "arrayfindlastindex", "arrayforeach", @@ -182,7 +181,6 @@ group("ark_asm_test") { "arrayfindindex", "arrayforeach", "arrayjoin", - "arraymap", "arraypop", "arraysort", "arrayprotochange", @@ -311,7 +309,6 @@ group("ark_asm_single_step_test") { "arrayfindindex", "arrayfindlast", "arrayflat", - "arrayflatmap", "arrayfindlastindex", "arrayforeach", "arrayjoin", diff --git a/test/moduletest/arrayflat/arrayflat.js b/test/moduletest/arrayflat/arrayflat.js index ad8dc59334..22fb4c7cbb 100644 --- a/test/moduletest/arrayflat/arrayflat.js +++ b/test/moduletest/arrayflat/arrayflat.js @@ -22,13 +22,3 @@ const input = [1, [2], [[3]]]; print(input.flat(undefined)); -{ - class MyArray extends Array { - static get [Symbol.species]() { - return this; - } - } - const wannabe = new MyArray(); - const flattened = wannabe.flat(Infinity); - print(flattened instanceof MyArray); -} diff --git a/test/moduletest/arrayflat/expect_output.txt b/test/moduletest/arrayflat/expect_output.txt index 53aae57749..2636bda9fc 100644 --- a/test/moduletest/arrayflat/expect_output.txt +++ b/test/moduletest/arrayflat/expect_output.txt @@ -12,4 +12,4 @@ # limitations under the License. 1,2,3 -true + diff --git a/test/moduletest/arrayflatmap/BUILD.gn b/test/moduletest/arrayflatmap/BUILD.gn deleted file mode 100644 index 1bcef0c2c3..0000000000 --- a/test/moduletest/arrayflatmap/BUILD.gn +++ /dev/null @@ -1,18 +0,0 @@ -# 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("arrayflatmap") { - deps = [] -} diff --git a/test/moduletest/arrayflatmap/arrayflatmap.js b/test/moduletest/arrayflatmap/arrayflatmap.js deleted file mode 100644 index 9a27ec63b4..0000000000 --- a/test/moduletest/arrayflatmap/arrayflatmap.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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:async - * @tc.desc:array.flatmap - * @tc.type: FUNC - * @tc.require:issueI8FBM3 - */ -{ - class MyArray extends Array { - static get [Symbol.species]() { - return this; - } - } - const wannabe = new MyArray(); - const result = wannabe.flatMap(x => [x, x]); - print(result instanceof MyArray);//t -} diff --git a/test/moduletest/arrayflatmap/expect_output.txt b/test/moduletest/arrayflatmap/expect_output.txt deleted file mode 100644 index ce415d321a..0000000000 --- a/test/moduletest/arrayflatmap/expect_output.txt +++ /dev/null @@ -1,14 +0,0 @@ -# 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. - -true -- Gitee From 78d413cbecf6671c020d90a5727995ebae465a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Mon, 27 Nov 2023 09:23:31 +0800 Subject: [PATCH 31/44] =?UTF-8?q?=E5=9B=9E=E9=80=80pr5204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- ecmascript/js_array.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index 6ef5c2bf9b..87f951d481 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -115,6 +115,10 @@ JSTaggedValue JSArray::ArraySpeciesCreate(JSThread *thread, const JSHandle constructor(thread, JSTaggedValue::Undefined()); if (isArray) { // Let C be Get(originalArray, "constructor"). + auto *hclass = originalArray->GetJSHClass(); + if (hclass->IsJSArray() && !hclass->HasConstructor()) { + return JSArray::ArrayCreate(thread, length, ArrayMode::LITERAL).GetTaggedValue(); + } JSHandle constructorKey = globalConst->GetHandledConstructorString(); constructor = JSTaggedValue::GetProperty(thread, originalValue, constructorKey).GetValue(); // ReturnIfAbrupt(C). -- Gitee From 99f3e742500430368bbb73f9e64ba30eb2c73d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Mon, 27 Nov 2023 09:49:47 +0800 Subject: [PATCH 32/44] =?UTF-8?q?=E5=9B=9E=E9=80=80pr5204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- test/moduletest/BUILD.gn | 2 +- test/moduletest/arrayflat/expect_output.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 24c7e03066..8794016f19 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -176,11 +176,11 @@ group("ark_asm_test") { "array", "arrayfindlast", "arrayflat", - "arrayflatmap", "arrayfindlastindex", "arrayfindindex", "arrayforeach", "arrayjoin", + "arraymap", "arraypop", "arraysort", "arrayprotochange", diff --git a/test/moduletest/arrayflat/expect_output.txt b/test/moduletest/arrayflat/expect_output.txt index 2636bda9fc..c2f8381c3b 100644 --- a/test/moduletest/arrayflat/expect_output.txt +++ b/test/moduletest/arrayflat/expect_output.txt @@ -12,4 +12,3 @@ # limitations under the License. 1,2,3 - -- Gitee From 8e347722287880dab9bb21f1631a0ccd1562f56c Mon Sep 17 00:00:00 2001 From: gwl Date: Sat, 25 Nov 2023 15:01:52 +0800 Subject: [PATCH 33/44] fixbug in concat Signed-off-by: gwl Change-Id: Ib0888475fd99a669a33fa8c925b589d27a7512ee Signed-off-by: gwl --- .../compiler/builtins/builtins_array_stub_builder.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 9cccbd9356..301cefd555 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -20,6 +20,8 @@ #include "ecmascript/compiler/profiler_operation.h" #include "ecmascript/compiler/rt_call_signature.h" #include "ecmascript/runtime_call_id.h" +#include "ecmascript/compiler/access_object_stub_builder.h" + namespace panda::ecmascript::kungfu { void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs, @@ -591,7 +593,9 @@ GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj) GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); GateRef isConcatsprKey = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX); - GateRef spreadable = FastGetPropertyByValue(glue, obj, isConcatsprKey, ProfileOperation()); + AccessObjectStubBuilder builder(this); + GateRef spreadable = + builder.LoadObjByValue(glue, obj, isConcatsprKey, Undefined(), Int32(0), ProfileOperation()); Label isDefined(env); Label isUnDefined(env); Branch(TaggedIsUndefined(spreadable), &isUnDefined, &isDefined); -- Gitee From d5660a4a23ce378c20d602b51c4c54e2850c9c56 Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 27 Nov 2023 10:21:10 +0800 Subject: [PATCH 34/44] fixbug in findindex case Signed-off-by: gwl Change-Id: I52620c1207c364f44a078fe0f3e9a3cd882193c9 --- test/moduletest/{arrayfindIndex => arrayFindIndexCase}/BUILD.gn | 0 .../{arrayfindIndex => arrayFindIndexCase}/arrayfindIndex.js | 0 .../{arrayfindIndex => arrayFindIndexCase}/expect_output.txt | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/moduletest/{arrayfindIndex => arrayFindIndexCase}/BUILD.gn (100%) rename test/moduletest/{arrayfindIndex => arrayFindIndexCase}/arrayfindIndex.js (100%) rename test/moduletest/{arrayfindIndex => arrayFindIndexCase}/expect_output.txt (100%) diff --git a/test/moduletest/arrayfindIndex/BUILD.gn b/test/moduletest/arrayFindIndexCase/BUILD.gn similarity index 100% rename from test/moduletest/arrayfindIndex/BUILD.gn rename to test/moduletest/arrayFindIndexCase/BUILD.gn diff --git a/test/moduletest/arrayfindIndex/arrayfindIndex.js b/test/moduletest/arrayFindIndexCase/arrayfindIndex.js similarity index 100% rename from test/moduletest/arrayfindIndex/arrayfindIndex.js rename to test/moduletest/arrayFindIndexCase/arrayfindIndex.js diff --git a/test/moduletest/arrayfindIndex/expect_output.txt b/test/moduletest/arrayFindIndexCase/expect_output.txt similarity index 100% rename from test/moduletest/arrayfindIndex/expect_output.txt rename to test/moduletest/arrayFindIndexCase/expect_output.txt -- Gitee From 750bb7f9700d5feb269cc84b8c4ba5a20d9033c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Mon, 27 Nov 2023 10:54:00 +0800 Subject: [PATCH 35/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dslices=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=85=83=E7=B4=A0=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- test/moduletest/arrayslice/arrayslice.js | 3 +++ test/moduletest/arrayslice/expect_output.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/test/moduletest/arrayslice/arrayslice.js b/test/moduletest/arrayslice/arrayslice.js index 9c099983ca..5492dfb84a 100644 --- a/test/moduletest/arrayslice/arrayslice.js +++ b/test/moduletest/arrayslice/arrayslice.js @@ -12,6 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +var holey_array = [1, 2, 3, 4, 5,,,,,,]; +print(holey_array.slice(6, 7)[0]); +print(holey_array.slice(2, 3)[0]); (function() { var array = [,]; diff --git a/test/moduletest/arrayslice/expect_output.txt b/test/moduletest/arrayslice/expect_output.txt index 6a9bc8b453..c5b432b3e6 100644 --- a/test/moduletest/arrayslice/expect_output.txt +++ b/test/moduletest/arrayslice/expect_output.txt @@ -11,4 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. +undefined +3 [object Object] -- Gitee From dc7e60d32bc5f91e13aee5fc9a0db65f0ee23d43 Mon Sep 17 00:00:00 2001 From: liuzhijie Date: Thu, 23 Nov 2023 20:53:24 +0800 Subject: [PATCH 36/44] Optimize As Fast Elements Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8J0UD?from=project-issue Signed-off-by: liuzhijie Change-Id: I62c6a83348914e65b12ee0fdc64d587621b4ace7 --- ecmascript/js_object-inl.h | 15 +++++++++++++++ ecmascript/js_object.cpp | 18 +++++++++++++++--- ecmascript/js_object.h | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index 1882197fcc..4089ef5d99 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -24,6 +24,7 @@ #include "ecmascript/js_typed_array.h" #include "ecmascript/tagged_array-inl.h" #include "ecmascript/tagged_queue.h" +#include "ecmascript/tagged_dictionary.h" namespace panda::ecmascript { inline void ECMAObject::SetCallable(bool flag) @@ -360,6 +361,20 @@ inline bool JSObject::ShouldTransToDict(uint32_t capacity, uint32_t index) return false; } +inline bool JSObject::ShouldTransToFastElements(JSHandle dictionary, + uint32_t capacity, uint32_t index) +{ + if (index >= static_cast(INT32_MAX)) { + return false; + } + uint32_t dictionarySize = static_cast(dictionary->GetLength()); + // Turn fast if only saves 50% space. + if (dictionarySize * SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR >= capacity) { + return true; + } + return false; +} + inline uint32_t JSObject::ComputeElementCapacity(uint32_t oldCapacity, bool isNew) { uint32_t newCapacity = isNew ? oldCapacity : (oldCapacity + (oldCapacity >> 1U)); diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 69fd261428..89d3372e28 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -333,10 +333,10 @@ bool JSObject::IsArrayLengthWritable(JSThread *thread, const JSHandle return op.GetAttr().IsWritable(); } -bool JSObject::AddElementInternal(JSThread *thread, const JSHandle &receiver, uint32_t index, - const JSHandle &value, PropertyAttributes attr) +bool JSObject::AddElementInternal(JSThread *thread, const JSHandle &receiver, + uint32_t index, const JSHandle &value, + PropertyAttributes attr) { - bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement(); ElementsKind kind = ElementsKind::NONE; if (receiver->IsJSArray()) { DISALLOW_GARBAGE_COLLECTION; @@ -354,6 +354,18 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle &re } thread->NotifyStableArrayElementsGuardians(receiver, StableArrayChangeKind::NOT_PROTO); + // check whether to convert to dictionary + if (receiver->GetJSHClass()->IsDictionaryElement() && receiver->IsJSArray()) { + JSArray *arr = JSArray::Cast(*receiver); + uint32_t capacity = arr->GetArrayLength(); + TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); + ASSERT(elements->IsDictionaryMode()); + if (ShouldTransToFastElements(JSHandle(thread, elements), capacity, index)) { + JSObject::TryOptimizeAsFastElements(thread, receiver); + } + } + + bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement(); TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); if (isDictionary) { ASSERT(elements->IsDictionaryMode()); diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index cee6de3c89..de365cd7a8 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -41,6 +41,7 @@ class JSForInIterator; class LexicalEnv; class GlobalEnv; class TaggedQueue; +class NumberDictionary; using EnumCacheKind = EnumCache::EnumCacheKind; // Integrity level for objects @@ -374,6 +375,7 @@ public: static constexpr int MIN_ELEMENTS_HINT_LENGTH = 1_KB; static constexpr int MAX_ELEMENTS_HINT_LENGTH = 2_MB; static constexpr int ELEMENTS_HINT_FACTOR = 8; + static constexpr int SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR = 2; CAST_CHECK(JSObject, IsECMAObject); @@ -659,6 +661,7 @@ public: static bool IsArrayLengthWritable(JSThread *thread, const JSHandle &receiver); bool UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value); static bool ShouldTransToDict(uint32_t capacity, uint32_t index); + static bool ShouldTransToFastElements(JSHandle dictionary, uint32_t capacity, uint32_t index); static bool ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle obj); static JSHandle GrowElementsCapacity(const JSThread *thread, const JSHandle &obj, uint32_t capacity, bool highGrowth = false, bool isNew = false); -- Gitee From 22ea3221ac6aa0a0007bc242f76e923229e50c79 Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 27 Nov 2023 11:17:41 +0800 Subject: [PATCH 37/44] chang case name Change-Id: I6d81bad50bb6836365c42b4b1f9cee2958985d1e Signed-off-by: gwl --- test/moduletest/arrayFindIndexCase/BUILD.gn | 2 +- .../{arrayfindIndex.js => findIndex.js} | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename test/moduletest/arrayFindIndexCase/{arrayfindIndex.js => findIndex.js} (91%) diff --git a/test/moduletest/arrayFindIndexCase/BUILD.gn b/test/moduletest/arrayFindIndexCase/BUILD.gn index 0deb202b3b..db14fd79d8 100644 --- a/test/moduletest/arrayFindIndexCase/BUILD.gn +++ b/test/moduletest/arrayFindIndexCase/BUILD.gn @@ -13,6 +13,6 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") -host_moduletest_action("arrayfindIndex") { +host_moduletest_action("findIndex") { deps = [] } diff --git a/test/moduletest/arrayFindIndexCase/arrayfindIndex.js b/test/moduletest/arrayFindIndexCase/findIndex.js similarity index 91% rename from test/moduletest/arrayFindIndexCase/arrayfindIndex.js rename to test/moduletest/arrayFindIndexCase/findIndex.js index 4f5a51da9f..0fc4ffd389 100644 --- a/test/moduletest/arrayFindIndexCase/arrayfindIndex.js +++ b/test/moduletest/arrayFindIndexCase/findIndex.js @@ -14,13 +14,13 @@ */ /* - * @tc.name:stringSlice - * @tc.desc:test String.slice + * @tc.name:findIndex + * @tc.desc:test array.findIndex * @tc.type: FUNC - * @tc.require: issueI5NO8G + * @tc.require: */ -t array1 = [5, 12, 8, 130, 44]; +const array1 = [5, 12, 8, 130, 44]; const isLargeNumber = (element) => element > 13; print(array1.findIndex(isLargeNumber)); -- Gitee From 283d95cdc14707f705edfe9771add16ec9c1a0d1 Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 27 Nov 2023 10:25:45 +0800 Subject: [PATCH 38/44] change testcase name Signed-off-by: gwl Change-Id: Ie1b2f8e1c9e0b207ed348ec8d52f1d28f21a2e4e Signed-off-by: gwl --- test/moduletest/{arraySlice => arraySliceCase}/BUILD.gn | 2 +- .../arraySlice.js => arraySliceCase/arraySliceCase.js} | 6 +++--- .../{arraySlice => arraySliceCase}/expect_output.txt | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename test/moduletest/{arraySlice => arraySliceCase}/BUILD.gn (93%) rename test/moduletest/{arraySlice/arraySlice.js => arraySliceCase/arraySliceCase.js} (94%) rename test/moduletest/{arraySlice => arraySliceCase}/expect_output.txt (100%) diff --git a/test/moduletest/arraySlice/BUILD.gn b/test/moduletest/arraySliceCase/BUILD.gn similarity index 93% rename from test/moduletest/arraySlice/BUILD.gn rename to test/moduletest/arraySliceCase/BUILD.gn index 20a83f1990..aa7aac7462 100644 --- a/test/moduletest/arraySlice/BUILD.gn +++ b/test/moduletest/arraySliceCase/BUILD.gn @@ -13,6 +13,6 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") -host_moduletest_action("arraySlice") { +host_moduletest_action("arraySliceCase") { deps = [] } diff --git a/test/moduletest/arraySlice/arraySlice.js b/test/moduletest/arraySliceCase/arraySliceCase.js similarity index 94% rename from test/moduletest/arraySlice/arraySlice.js rename to test/moduletest/arraySliceCase/arraySliceCase.js index 1f3b6fa65f..b2faf75060 100644 --- a/test/moduletest/arraySlice/arraySlice.js +++ b/test/moduletest/arraySliceCase/arraySliceCase.js @@ -14,10 +14,10 @@ */ /* - * @tc.name:stringSlice - * @tc.desc:test String.slice + * @tc.name:arraySlice + * @tc.desc:test array.slice * @tc.type: FUNC - * @tc.require: issueI5NO8G + * @tc.require: */ const animals = ['ant', 'bison', 'camel', 'duck', 'elephant']; diff --git a/test/moduletest/arraySlice/expect_output.txt b/test/moduletest/arraySliceCase/expect_output.txt similarity index 100% rename from test/moduletest/arraySlice/expect_output.txt rename to test/moduletest/arraySliceCase/expect_output.txt -- Gitee From be9d1d134c509214ec8430b93fbb7b26e4e6d4e0 Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 27 Nov 2023 10:30:34 +0800 Subject: [PATCH 39/44] change testcase name Signed-off-by: gwl Change-Id: If1f5e0819de58aa6391728b4c6654a54806e650a Signed-off-by: gwl --- .../{arrayReverse => arrayReverseCase}/BUILD.gn | 2 +- .../arrayReverseCase.js} | 15 +++++++++++++++ .../expect_output.txt | 0 .../{arrayValues => arrayValuesCase}/BUILD.gn | 2 +- .../arrayValuesCase.js} | 0 .../expect_output.txt | 0 6 files changed, 17 insertions(+), 2 deletions(-) rename test/moduletest/{arrayReverse => arrayReverseCase}/BUILD.gn (93%) rename test/moduletest/{arrayReverse/arrayReverse.js => arrayReverseCase/arrayReverseCase.js} (59%) rename test/moduletest/{arrayReverse => arrayReverseCase}/expect_output.txt (100%) rename test/moduletest/{arrayValues => arrayValuesCase}/BUILD.gn (93%) rename test/moduletest/{arrayValues/arrayValues.js => arrayValuesCase/arrayValuesCase.js} (100%) rename test/moduletest/{arrayValues => arrayValuesCase}/expect_output.txt (100%) diff --git a/test/moduletest/arrayReverse/BUILD.gn b/test/moduletest/arrayReverseCase/BUILD.gn similarity index 93% rename from test/moduletest/arrayReverse/BUILD.gn rename to test/moduletest/arrayReverseCase/BUILD.gn index 1b63c3434e..471ede6d01 100644 --- a/test/moduletest/arrayReverse/BUILD.gn +++ b/test/moduletest/arrayReverseCase/BUILD.gn @@ -13,6 +13,6 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") -host_moduletest_action("arrayReverse") { +host_moduletest_action("arrayReverseCase") { deps = [] } diff --git a/test/moduletest/arrayReverse/arrayReverse.js b/test/moduletest/arrayReverseCase/arrayReverseCase.js similarity index 59% rename from test/moduletest/arrayReverse/arrayReverse.js rename to test/moduletest/arrayReverseCase/arrayReverseCase.js index 2cb901a862..1768080e2e 100644 --- a/test/moduletest/arrayReverse/arrayReverse.js +++ b/test/moduletest/arrayReverseCase/arrayReverseCase.js @@ -1,3 +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. + */ + const array1 = ['one', 'two', 'three']; print('array1:', array1); // Expected output: "array1:" Array ["one", "two", "three"] diff --git a/test/moduletest/arrayReverse/expect_output.txt b/test/moduletest/arrayReverseCase/expect_output.txt similarity index 100% rename from test/moduletest/arrayReverse/expect_output.txt rename to test/moduletest/arrayReverseCase/expect_output.txt diff --git a/test/moduletest/arrayValues/BUILD.gn b/test/moduletest/arrayValuesCase/BUILD.gn similarity index 93% rename from test/moduletest/arrayValues/BUILD.gn rename to test/moduletest/arrayValuesCase/BUILD.gn index 9442dcc5ad..2509f350b4 100644 --- a/test/moduletest/arrayValues/BUILD.gn +++ b/test/moduletest/arrayValuesCase/BUILD.gn @@ -13,6 +13,6 @@ import("//arkcompiler/ets_runtime/test/test_helper.gni") -host_moduletest_action("arrayValues") { +host_moduletest_action("arrayValuesCase") { deps = [] } diff --git a/test/moduletest/arrayValues/arrayValues.js b/test/moduletest/arrayValuesCase/arrayValuesCase.js similarity index 100% rename from test/moduletest/arrayValues/arrayValues.js rename to test/moduletest/arrayValuesCase/arrayValuesCase.js diff --git a/test/moduletest/arrayValues/expect_output.txt b/test/moduletest/arrayValuesCase/expect_output.txt similarity index 100% rename from test/moduletest/arrayValues/expect_output.txt rename to test/moduletest/arrayValuesCase/expect_output.txt -- Gitee From ececdbe31e70bcefc1a6b1e5e349f7261aca3043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=BA=91=E9=A3=9E?= Date: Mon, 27 Nov 2023 15:32:52 +0800 Subject: [PATCH 40/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dslices=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=8E=B7=E5=8F=96=E5=B1=9E=E6=80=A7=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨云飞 --- ecmascript/js_object.cpp | 14 -------------- ecmascript/js_stable_array.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 926a497cbd..43fdd2ac5c 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -1121,20 +1121,6 @@ bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle const JSHandle &key, PropertyDescriptor &desc) { ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); - JSHandle thisObjVal(obj); - bool isArray = obj->IsJSArray(); - if (isArray) { - JSHandle srcElements(thread, obj->GetElements()); - int64_t len = static_cast(srcElements->GetLength()); - for (int i = 0; i < len; i++) { - JSTaggedValue value = srcElements->Get(thread, i); - if (value.IsHole() && JSTaggedValue::HasProperty(thread, thisObjVal, i)) { - value = JSArray::FastGetPropertyByValue(thread, thisObjVal, i).GetTaggedValue(); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); - srcElements->Set(thread, i, value); - } - } - } ObjectOperator op(thread, JSHandle(obj), key, OperatorType::OWN); if (!op.IsFound()) { diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index ed5602e012..2e970d8143 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -1063,6 +1063,7 @@ JSTaggedValue JSStableArray::Slice(JSThread *thread, JSHandle thisObjH { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle srcElements(thread, thisObjHandle->GetElements()); + JSHandle thisObjVal(thisObjHandle); int64_t len = static_cast(srcElements->GetLength()); int64_t oldLen; if (len > k + count) { @@ -1071,6 +1072,14 @@ JSTaggedValue JSStableArray::Slice(JSThread *thread, JSHandle thisObjH oldLen = len - k; } JSHandle dstElements = factory->NewAndCopyTaggedArray(srcElements, count, oldLen, k); + for (int i = 0; i < count; i++) { + JSTaggedValue value = dstElements->Get(thread, i); + if (value.IsHole() && JSTaggedValue::HasProperty(thread, thisObjVal, i + k)) { + value = JSArray::FastGetPropertyByValue(thread, thisObjVal, i + k).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + dstElements->Set(thread, i, value); + } + } return factory->NewJSStableArrayWithElements(dstElements).GetTaggedValue(); } -- Gitee From f05aed29cc2cd43646c7445af8d957680002680d Mon Sep 17 00:00:00 2001 From: liuzhijie Date: Mon, 27 Nov 2023 15:44:02 +0800 Subject: [PATCH 41/44] Nan !== Nan Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8JRZP?from=project-issue Signed-off-by: liuzhijie Change-Id: I28e3c043ea2b60312d844eab0f48e7e2967469dc --- ecmascript/compiler/number_speculative_lowering.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ecmascript/compiler/number_speculative_lowering.cpp b/ecmascript/compiler/number_speculative_lowering.cpp index 3d04bf6834..d88ca31d17 100644 --- a/ecmascript/compiler/number_speculative_lowering.cpp +++ b/ecmascript/compiler/number_speculative_lowering.cpp @@ -789,10 +789,10 @@ GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right) break; } case TypedBinOp::TYPED_STRICTNOTEQ: { - GateRef leftNotNan = builder_.BoolNot(builder_.DoubleIsNAN(left)); - GateRef rightNotNan = builder_.BoolNot(builder_.DoubleIsNAN(right)); - GateRef doubleEqual = builder_.DoubleNotEqual(left, right); - condition = builder_.BoolAnd(builder_.BoolAnd(leftNotNan, rightNotNan), doubleEqual); + GateRef leftNotNan = builder_.DoubleIsNAN(left); + GateRef rightNotNan = builder_.DoubleIsNAN(right); + GateRef doubleNotEqual = builder_.DoubleNotEqual(left, right); + condition = builder_.BoolOr(builder_.BoolOr(leftNotNan, rightNotNan), doubleNotEqual); break; } default: -- Gitee From 03eed9f4b95e5ebf6fce692571bb004d89666dbc Mon Sep 17 00:00:00 2001 From: zhangyouyou Date: Mon, 27 Nov 2023 20:28:00 +0800 Subject: [PATCH 42/44] fix deleteobj ToPropertyKey bug Signed-off-by: zhangyouyou --- ecmascript/compiler/stub_builder.cpp | 3 ++- ecmascript/stubs/runtime_stubs.cpp | 8 ++++++++ ecmascript/stubs/runtime_stubs.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 2e2f19a05b..5d303f2402 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -6186,7 +6186,8 @@ GateRef StubBuilder::DeletePropertyOrThrow(GateRef glue, GateRef obj, GateRef va Branch(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &isException); Bind(&objectIsEcmaObject); { - result = DeleteProperty(glue, obj, value); + GateRef keyValue = CallRuntime(glue, RTSTUB_ID(ToPropertyKey), {value}); + result = DeleteProperty(glue, obj, keyValue); Jump(&exit); } Bind(&isException); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 67e2ed1cb1..4f6c3ecd8a 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -691,6 +691,14 @@ DEF_RUNTIME_STUBS(CallJSObjDeletePrototype) return JSTaggedValue::True().GetRawData(); } +DEF_RUNTIME_STUBS(ToPropertyKey) +{ + RUNTIME_STUBS_HEADER(ToPropertyKey); + JSHandle key = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSTaggedValue res = JSTaggedValue::ToPropertyKey(thread, key).GetTaggedValue(); + return res.GetRawData(); +} + DEF_RUNTIME_STUBS(Exp) { RUNTIME_STUBS_HEADER(Exp); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 9c8204bcec..f82c010da8 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -144,6 +144,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(CallModuleNamespaceDeletePrototype) \ V(CallTypedArrayDeletePrototype) \ V(CallJSObjDeletePrototype) \ + V(ToPropertyKey) \ V(NewJSPrimitiveRef) \ V(ThrowTypeError) \ V(GetHash32) \ -- Gitee From f25571689da712ba19d95b01b2cc8bad9099c649 Mon Sep 17 00:00:00 2001 From: yang-19970325 Date: Mon, 27 Nov 2023 19:53:58 +0800 Subject: [PATCH 43/44] Fix invalid files in release application when loadModuleEvent Issue:#I8JVMW Signed-off-by: yang-19970325 Change-Id: Ic43f5f89876984730335d1f65598463a15323824 --- ecmascript/debugger/js_debugger_manager.h | 11 +++++++++++ ecmascript/napi/jsnapi.cpp | 1 + 2 files changed, 12 insertions(+) diff --git a/ecmascript/debugger/js_debugger_manager.h b/ecmascript/debugger/js_debugger_manager.h index 9bdf555dd2..68b1b173e9 100644 --- a/ecmascript/debugger/js_debugger_manager.h +++ b/ecmascript/debugger/js_debugger_manager.h @@ -76,6 +76,16 @@ public: return isDebugMode_; } + void SetIsDebugApp(bool isDebugApp) + { + isDebugApp_ = isDebugApp; + } + + bool IsDebugApp() const + { + return isDebugApp_; + } + void SetMixedDebugEnabled(bool enabled) { isMixedDebugEnabled_ = enabled; @@ -174,6 +184,7 @@ public: private: bool isDebugMode_ {false}; + bool isDebugApp_ {false}; bool isMixedDebugEnabled_ { false }; ProtocolHandler *debuggerHandler_ {nullptr}; LibraryHandle debuggerLibraryHandle_ {nullptr}; diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 640003938b..6c589a6c5b 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -634,6 +634,7 @@ bool JSNApi::NotifyDebugMode([[maybe_unused]] uint32_t tid, } vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(handle.Value())); vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode && debugApp); + vm->GetJsDebuggerManager()->SetIsDebugApp(debugApp); bool ret = StartDebuggerForOldProcess(vm, option, instanceId, debuggerPostTask); if (debugApp && debugMode) { -- Gitee From 548558c3509b53e080087680553cb9e76ed1843a Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 27 Nov 2023 22:02:23 +0800 Subject: [PATCH 44/44] fix confilct Signed-off-by: gwl Change-Id: I4ed05266b5a869cfa99b976b1930a9268aaa087e --- .../builtins/builtins_array_stub_builder.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index e8c12ccb6c..724a30b4f8 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -457,6 +457,9 @@ void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_ Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); Label isJSArray(env); GateRef jsCOWArray = IsJsCOWArray(thisValue); GateRef jsJSArray = IsJsArray(thisValue); @@ -631,12 +634,15 @@ void BuiltinsArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, GateRe Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); Label stableJSArray(env); Label notStableJSArray(env); GateRef callbackFnHandle = GetCallArg0(numArgs); - Label isHeapObject(env); - Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObject, slowPath); - Bind(&isHeapObject); + Label arg0HeapObject(env); + Branch(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath); + Bind(&arg0HeapObject); Label callable(env); Branch(IsCallable(callbackFnHandle), &callable, slowPath); Bind(&callable); -- Gitee