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 <RBMode mode = RBMode::DEFAULT_RB, class Predicate> 132 static const JSTaggedType *IndexOfElements(JSThread *thread, Span<const TaggedType> rawElements, 133 IndexOfOptions options, Predicate predicate); 134 static const JSTaggedType *IndexOfUndefined(JSThread *thread, Span<const JSTaggedType> elements, 135 IndexOfOptions options, bool isMutant); 136 static const JSTaggedType *IndexOfTaggedZero(JSThread *thread, Span<const JSTaggedType> taggedElements, 137 IndexOfOptions options); 138 static const JSTaggedType *IndexOfInt(JSThread *thread, Span<const JSTaggedType> elements, 139 JSTaggedValue searchElement, IndexOfOptions options, bool isMutantInt32Array); 140 static const JSTaggedType *IndexOfDouble(JSThread *thread, Span<const JSTaggedType> elements, 141 JSTaggedValue searchElement, IndexOfOptions options, 142 bool isMutantDoubleArray); 143 static const JSTaggedType *IndexOfObjectAddress(JSThread *thread, Span<const JSTaggedType> elements, 144 JSTaggedValue searchElement, IndexOfOptions options); 145 static const JSTaggedType *IndexOfString(JSThread *thread, Span<const JSTaggedType> elements, 146 JSTaggedValue searchElement, IndexOfOptions options); 147 static const JSTaggedType *IndexOfBigInt(JSThread *thread, Span<const JSTaggedType> elements, 148 JSTaggedValue searchElement, IndexOfOptions options); 149 static JSTaggedValue IndexOfDispatch(JSThread *thread, JSHandle<JSTaggedValue> receiver, 150 JSHandle<JSTaggedValue> searchElementHandle, uint32_t from, uint32_t len, 151 IndexOfOptions options); 152 153 static JSTaggedValue UpdateArrayCapacity(JSHandle<JSObject> &thisObjHandle, uint32_t &len, 154 uint32_t &insertCount, uint32_t &actualDeleteCount, 155 JSHandle<JSArray> &receiver, uint32_t &start, 156 JSThread *thread, bool &needTransition, 157 JSHandle<JSTaggedValue> &holeHandle, 158 EcmaRuntimeCallInfo *argv, JSHandle<JSTaggedValue> &thisObjVal, 159 JSHandle<JSTaggedValue> &lengthKey); 160 static void HandleArray(JSHandle<JSObject> &newArrayHandle, uint32_t &actualDeleteCount, 161 JSThread *thread, uint32_t &start, JSHandle<JSObject> &thisObjHandle, 162 JSHandle<JSTaggedValue> &holeHandle); 163 164 #if !ENABLE_NEXT_OPTIMIZATION 165 static void SetSepValue(JSThread *thread, JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength); 166 static JSTaggedValue JoinUseTreeString(const JSThread *thread, 167 const JSHandle<JSTaggedValue> receiverValue, 168 const JSHandle<EcmaString> sepStringHandle, const int sep, 169 CVector<JSHandle<EcmaString>> &vec); 170 inline static bool WorthUseTreeString(int sep, size_t allocateLength, uint32_t len); 171 #endif 172 173 // Allocate object larger than 256 need liner search in the free object list, 174 // so try to use tree string when the join result is larger than 256. 175 static constexpr size_t TREE_STRING_THRESHOLD = 256; 176 static constexpr size_t NUM_2 = 2; 177 178 #if ENABLE_NEXT_OPTIMIZATION 179 // When Array length is no more than 64, use array (stack memory) instead of vector to store the elements. 180 static constexpr int64_t USE_STACK_MEMORY_THRESHOLD = 64; 181 inline static bool WorthUseTreeString(uint32_t sepLength, size_t allocateLength, uint32_t len); 182 template <typename Container> 183 static void ProcessElements(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len, 184 Container &arrElements, bool &isOneByte, uint64_t &allocateLength); 185 template <typename Container> 186 static JSTaggedValue DoStableArrayJoin(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len, 187 Container &arrElements, bool &isOneByte, uint32_t sep, 188 uint32_t sepLength, JSHandle<EcmaString> sepStringHandle); 189 template <typename Container> 190 static JSTaggedValue JoinUseTreeString(const JSThread *thread, JSHandle<JSTaggedValue> receiverValue, 191 JSHandle<EcmaString> sepStringHandle, uint32_t sepLength, 192 Container &arrElements, uint32_t elemNum); 193 #endif 194 }; 195 } // namespace panda::ecmascript 196 #endif // ECMASCRIPT_JS_STABLE_ARRAY_H 197