1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_JS_STABLE_ARRAY_H 17 #define ECMASCRIPT_JS_STABLE_ARRAY_H 18 19 #include "ecmascript/base/array_helper.h" 20 #include "ecmascript/base/typed_array_helper.h" 21 #include "ecmascript/js_array.h" 22 #include "ecmascript/js_dataview.h" 23 #include "ecmascript/js_hclass.h" 24 #include "ecmascript/js_typed_array.h" 25 #include "ecmascript/js_tagged_value.h" 26 27 namespace panda::ecmascript { 28 class JSStableArray { 29 public: 30 enum class ComparisonType: uint8_t { 31 STRICT_EQUAL, 32 SAME_VALUE_ZERO, 33 }; 34 35 enum class IndexOfReturnType: uint8_t { 36 TAGGED_FOUND_INDEX, 37 TAGGED_FOUND_OR_NOT, 38 UNTAGGED_FOUND_INDEX, 39 UNTAGGED_FOUND_OR_NOT, 40 }; 41 42 struct IndexOfOptions { 43 ComparisonType compType = ComparisonType::STRICT_EQUAL; 44 IndexOfReturnType returnType = IndexOfReturnType::TAGGED_FOUND_INDEX; 45 bool reversedOrder = false; 46 bool holeAsUndefined = false; 47 }; 48 49 #if !ENABLE_NEXT_OPTIMIZATION 50 enum SeparatorFlag : int { MINUS_ONE = -1, MINUS_TWO = -2 }; 51 #endif 52 static JSTaggedValue Push(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv); 53 static JSTaggedValue Push(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv); 54 static JSTaggedValue Pop(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv); 55 static JSTaggedValue Pop(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv); 56 static JSTaggedValue Splice(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv, uint32_t start, 57 uint32_t insertCount, uint32_t actualDeleteCount, 58 JSHandle<JSObject> newArrayHandle, uint32_t len); 59 static JSTaggedValue Splice(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv, uint32_t start, 60 uint32_t insertCount, uint32_t actualDeleteCount, 61 JSHandle<JSObject> newArrayHandle, uint32_t len); 62 static JSTaggedValue Shift(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv); 63 static JSTaggedValue Shift(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv); 64 static JSTaggedValue Join(JSHandle<JSTaggedValue> receiver, EcmaRuntimeCallInfo *argv); 65 static JSTaggedValue HandleFindIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 66 JSHandle<JSTaggedValue> callbackFnHandle, 67 JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k); 68 static JSTaggedValue HandleFindLastIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 69 JSHandle<JSTaggedValue> callbackFnHandle, 70 JSHandle<JSTaggedValue> thisArgHandle, int64_t &k); 71 static JSTaggedValue HandleEveryOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 72 JSHandle<JSTaggedValue> callbackFnHandle, 73 JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k); 74 static JSTaggedValue HandleSomeOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 75 JSHandle<JSTaggedValue> callbackFnHandle, 76 JSHandle<JSTaggedValue> thisArgHandle, uint32_t &k); 77 static JSTaggedValue HandleforEachOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 78 JSHandle<JSTaggedValue> callbackFnHandle, 79 JSHandle<JSTaggedValue> thisArgHandle, uint32_t len, uint32_t &k); 80 static JSTaggedValue Includes(JSThread *thread, JSHandle<JSTaggedValue> receiver, 81 JSHandle<JSTaggedValue> searchElement, uint32_t from, uint32_t len); 82 static JSTaggedValue IndexOf(JSThread *thread, JSHandle<JSTaggedValue> receiver, 83 JSHandle<JSTaggedValue> searchElement, uint32_t from, uint32_t len); 84 static JSTaggedValue LastIndexOf(JSThread *thread, JSHandle<JSTaggedValue> receiver, 85 JSHandle<JSTaggedValue> searchElement, uint32_t from, uint32_t len); 86 static JSTaggedValue Filter(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle, 87 EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t &toIndex); 88 static JSTaggedValue Map(JSHandle<JSObject> newArrayHandle, JSHandle<JSObject> thisObjHandle, 89 EcmaRuntimeCallInfo *argv, uint32_t &k, uint32_t len); 90 static JSTaggedValue Reverse(JSThread *thread, JSHandle<JSObject> thisObjHandle, 91 int64_t &lower, uint32_t len); 92 static JSTaggedValue FastReverse(JSThread *thread, JSHandle<TaggedArray> elements, 93 int64_t &lower, uint32_t len, ElementsKind kind); 94 static JSTaggedValue Concat(JSThread *thread, JSHandle<JSObject> newArrayHandle, 95 JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &n); 96 template<base::TypedArrayKind typedArrayKind = base::TypedArrayKind::NON_SHARED> 97 static JSTaggedValue FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle<JSTypedArray> &target, 98 DataViewType targetType, uint64_t targetOffset, 99 uint32_t srcLength, JSHandle<JSObject> &obj); 100 static JSTaggedValue At(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv); 101 static JSTaggedValue At(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv); 102 static JSTaggedValue With(JSThread *thread, JSHandle<JSArray> receiver, 103 int64_t insertCount, int64_t index, JSHandle<JSTaggedValue> value); 104 static JSTaggedValue ToSpliced(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv, 105 int64_t argc, int64_t actualStart, int64_t actualSkipCount, int64_t insertCount); 106 static JSTaggedValue ToReversed(JSThread *thread, JSHandle<JSArray> receiver, int64_t insertCount); 107 static JSTaggedValue Reduce(JSThread *thread, JSHandle<JSObject> thisObjHandle, 108 JSHandle<JSTaggedValue> callbackFnHandle, 109 JSMutableHandle<JSTaggedValue> accumulator, int64_t &k, int64_t &len); 110 static JSTaggedValue Slice(JSThread *thread, JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &count); 111 static JSHandle<TaggedArray> SortIndexedProperties(JSThread *thread, const JSHandle<JSTaggedValue> &thisObj, 112 int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle, 113 base::HolesType holes); 114 static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal, 115 const JSHandle<JSTaggedValue> &callbackFnHandle); 116 static JSTaggedValue CopySortedListToReceiver(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal, 117 JSHandle<TaggedArray> sortedList, uint32_t len); 118 static JSTaggedValue Fill(JSThread *thread, const JSHandle<JSObject> &thisObj, 119 const JSHandle<JSTaggedValue> &value, 120 int64_t start, int64_t end); 121 static JSTaggedValue HandleFindLastOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 122 JSHandle<JSTaggedValue> callbackFnHandle, 123 JSHandle<JSTaggedValue> thisArgHandle, 124 JSMutableHandle<JSTaggedValue> &kValue, int64_t &k); 125 static JSTaggedValue HandleReduceRightOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle, 126 JSHandle<JSTaggedValue> callbackFnHandle, 127 JSMutableHandle<JSTaggedValue> &accumulator, 128 JSHandle<JSTaggedValue> thisArgHandle, int64_t &k); 129 130 private: 131 template <class Predicate> 132 static const JSTaggedType* IndexOfElements(Span<const TaggedType> rawElements, IndexOfOptions options, 133 Predicate predicate); 134 static const JSTaggedType* IndexOfUndefined(Span<const JSTaggedType> elements, IndexOfOptions options, 135 bool isMutant); 136 static const JSTaggedType* IndexOfTaggedZero(Span<const JSTaggedType> taggedElements, IndexOfOptions options); 137 static const JSTaggedType* IndexOfInt(Span<const JSTaggedType> elements, JSTaggedValue searchElement, 138 IndexOfOptions options, bool isMutantInt32Array); 139 static const JSTaggedType* IndexOfDouble(Span<const JSTaggedType> elements, JSTaggedValue searchElement, 140 IndexOfOptions options, bool isMutantDoubleArray); 141 static const JSTaggedType* IndexOfObjectAddress(Span<const JSTaggedType> elements, JSTaggedValue searchElement, 142 IndexOfOptions options); 143 static const JSTaggedType* IndexOfString(Span<const JSTaggedType> elements, JSTaggedValue searchElement, 144 IndexOfOptions options); 145 static const JSTaggedType* IndexOfBigInt(Span<const JSTaggedType> elements, JSTaggedValue searchElement, 146 IndexOfOptions options); 147 static JSTaggedValue IndexOfDispatch(JSThread *thread, JSHandle<JSTaggedValue> receiver, 148 JSHandle<JSTaggedValue> searchElementHandle, uint32_t from, uint32_t len, 149 IndexOfOptions options); 150 151 static JSTaggedValue UpdateArrayCapacity(JSHandle<JSObject> &thisObjHandle, uint32_t &len, 152 uint32_t &insertCount, uint32_t &actualDeleteCount, 153 JSHandle<JSArray> &receiver, uint32_t &start, 154 JSThread *thread, bool &needTransition, 155 JSHandle<JSTaggedValue> &holeHandle, 156 EcmaRuntimeCallInfo *argv, JSHandle<JSTaggedValue> &thisObjVal, 157 JSHandle<JSTaggedValue> &lengthKey); 158 static void HandleArray(JSHandle<JSObject> &newArrayHandle, uint32_t &actualDeleteCount, 159 JSThread *thread, uint32_t &start, JSHandle<JSObject> &thisObjHandle, 160 JSHandle<JSTaggedValue> &holeHandle); 161 162 #if !ENABLE_NEXT_OPTIMIZATION 163 static void SetSepValue(JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength); 164 static JSTaggedValue JoinUseTreeString(const JSThread *thread, 165 const JSHandle<JSTaggedValue> receiverValue, 166 const JSHandle<EcmaString> sepStringHandle, const int sep, 167 CVector<JSHandle<EcmaString>> &vec); 168 inline static bool WorthUseTreeString(int sep, size_t allocateLength, uint32_t len); 169 #endif 170 171 // Allocate object larger than 256 need liner search in the free object list, 172 // so try to use tree string when the join result is larger than 256. 173 static constexpr size_t TREE_STRING_THRESHOLD = 256; 174 static constexpr size_t NUM_2 = 2; 175 176 #if ENABLE_NEXT_OPTIMIZATION 177 // When Array length is no more than 64, use array (stack memory) instead of vector to store the elements. 178 static constexpr int64_t USE_STACK_MEMORY_THRESHOLD = 64; 179 inline static bool WorthUseTreeString(uint32_t sepLength, size_t allocateLength, uint32_t len); 180 template <typename Container> 181 static void ProcessElements(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len, 182 Container &arrElements, bool &isOneByte, uint64_t &allocateLength); 183 template <typename Container> 184 static JSTaggedValue DoStableArrayJoin(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len, 185 Container &arrElements, bool &isOneByte, uint32_t sep, 186 uint32_t sepLength, JSHandle<EcmaString> sepStringHandle); 187 template <typename Container> 188 static JSTaggedValue JoinUseTreeString(const JSThread *thread, JSHandle<JSTaggedValue> receiverValue, 189 JSHandle<EcmaString> sepStringHandle, uint32_t sepLength, 190 Container &arrElements, uint32_t elemNum); 191 #endif 192 }; 193 } // namespace panda::ecmascript 194 #endif // ECMASCRIPT_JS_STABLE_ARRAY_H 195