1/*
2 * Copyright (c) 2021-2022 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_BUILTINS_BUILTINS_ARRAY_H
17#define ECMASCRIPT_BUILTINS_BUILTINS_ARRAY_H
18
19#include "ecmascript/base/builtins_base.h"
20
21// List of functions in Array, excluding the '@@' properties.
22// V(name, func, length, stubIndex)
23// where BuiltinsArray::func refers to the native implementation of Array[name].
24//       kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
25#define BUILTIN_ARRAY_FUNCTIONS(V)                          \
26    /* Array.from ( items [ , mapfn [ , thisArg ] ] ) */    \
27    V("from",    From,    1, ArrayFrom)                     \
28    /* Array.isArray ( arg ) */                             \
29    V("isArray", IsArray, 1, ArrayIsArray)                  \
30    /* Array.of ( ...items ) */                             \
31    V("of",      Of,      0, INVALID)
32
33// List of functions in Array.prototype, excluding the constructor and '@@' properties.
34// V(name, func, length, stubIndex)
35// where BuiltinsArray::func refers to the native implementation of Array.prototype[name].
36#define BUILTIN_ARRAY_PROTOTYPE_FUNCTIONS(V)                                \
37    /* Array.prototype.at ( index ) */                                      \
38    V("at",             At,               1, INVALID)                       \
39    /* Array.prototype.concat ( ...items ) */                               \
40    V("concat",         Concat,           1, ArrayConcat)                   \
41    /* Array.prototype.copyWithin ( target, start [ , end ] ) */            \
42    V("copyWithin",     CopyWithin,       2, ArrayCopyWithin)               \
43    /* Array.prototype.entries ( ) */                                       \
44    V("entries",        Entries,          0, ArrayEntries)                  \
45    /* Array.prototype.every ( callbackfn [ , thisArg ] ) */                \
46    V("every",          Every,            1, ArrayEvery)                    \
47    /* Array.prototype.fill ( value [ , start [ , end ] ] ) */              \
48    V("fill",           Fill,             1, ArrayFill)                     \
49    /* Array.prototype.filter ( callbackfn [ , thisArg ] ) */               \
50    V("filter",         Filter,           1, ArrayFilter)                   \
51    /* Array.prototype.find ( predicate [ , thisArg ] ) */                  \
52    V("find",           Find,             1, ArrayFind)                     \
53    /* Array.prototype.findIndex ( predicate [ , thisArg ] ) */             \
54    V("findIndex",      FindIndex,        1, ArrayFindIndex)                \
55    /* Array.prototype.findLast ( predicate [ , thisArg ] ) */              \
56    V("findLast",       FindLast,         1, ArrayFindLast)                 \
57    /* Array.prototype.findLastIndex ( predicate [ , thisArg ] ) */         \
58    V("findLastIndex",  FindLastIndex,    1, ArrayFindLastIndex)            \
59    /* Array.prototype.flat ( [ depth ] ) */                                \
60    V("flat",           Flat,             0, INVALID)                       \
61    /* Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) */          \
62    V("flatMap",        FlatMap,          1, ArrayFlatMap)                  \
63    /* Array.prototype.forEach ( callbackfn [ , thisArg ] ) */              \
64    V("forEach",        ForEach,          1, ArrayForEach)                  \
65    /* Array.prototype.includes ( searchElement [ , fromIndex ] ) */        \
66    V("includes",       Includes,         1, ArrayIncludes)                 \
67    /* Array.prototype.indexOf ( searchElement [ , fromIndex ] ) */         \
68    V("indexOf",        IndexOf,          1, ArrayIndexOf)                  \
69    /* Array.prototype.join ( separator ) */                                \
70    V("join",           Join,             1, INVALID)                       \
71    /* Array.prototype.keys ( ) */                                          \
72    V("keys",           Keys,             0, ArrayKeys)                     \
73    /* Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) */     \
74    V("lastIndexOf",    LastIndexOf,      1, ArrayLastIndexOf)              \
75    /* Array.prototype.map ( callbackfn [ , thisArg ] ) */                  \
76    V("map",            Map,              1, ArrayMap)                      \
77    /* Array.prototype.pop ( ) */                                           \
78    V("pop",            Pop,              0, ArrayPop)                      \
79    /* Array.prototype.push ( ...items ) */                                 \
80    V("push",           Push,             1, ArrayPush)                     \
81    /* Array.prototype.reduce ( callbackfn [ , initialValue ] ) */          \
82    V("reduce",         Reduce,           1, ArrayReduce)                   \
83    /* Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) */     \
84    V("reduceRight",    ReduceRight,      1, ArrayReduceRight)              \
85    /* Array.prototype.reverse ( ) */                                       \
86    V("reverse",        Reverse,          0, ArrayReverse)                  \
87    /* Array.prototype.shift ( ) */                                         \
88    V("shift",          Shift,            0, ArrayShift)                    \
89    /* Array.prototype.slice ( start, end ) */                              \
90    V("slice",          Slice,            2, ArraySlice)                    \
91    /* Array.prototype.some ( callbackfn [ , thisArg ] ) */                 \
92    V("some",           Some,             1, ArraySome)                     \
93    /* Array.prototype.sort ( comparefn ) */                                \
94    V("sort",           Sort,             1, ArraySort)                     \
95    /* Array.prototype.splice ( start, deleteCount, ...items ) */           \
96    V("splice",         Splice,           2, ArraySplice)                   \
97    /* Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) */  \
98    V("toLocaleString", ToLocaleString,   0, INVALID)                       \
99    /* Array.prototype.toReversed ( ) */                                    \
100    V("toReversed",     ToReversed,       0, ArrayToReversed)               \
101    /* Array.prototype.toSorted ( comparefn ) */                            \
102    V("toSorted",       ToSorted,         1, ArrayToSorted)                 \
103    /* Array.prototype.toSpliced ( start, skipCount, ...items ) */          \
104    V("toSpliced",      ToSpliced,        2, ArrayToSpliced)                \
105    /* Array.prototype.toString ( ) */                                      \
106    V("toString",       ToString,         0, INVALID)                       \
107    /* Array.prototype.unshift ( ...items ) */                              \
108    V("unshift",        Unshift,          1, ArrayUnshift)                  \
109    /* Array.prototype.values ( ) */                                        \
110    V("values",         Values,           0, ArrayValues)                   \
111    /* Array.prototype.with ( index, value ) */                             \
112    V("with",           With,             2, ArrayWith)
113
114namespace panda::ecmascript::builtins {
115static constexpr uint8_t INDEX_TWO = 2;
116static constexpr uint8_t INDEX_THREE = 3;
117class BuiltinsArray : public base::BuiltinsBase {
118public:
119    // 22.1.1
120    static JSTaggedValue ArrayConstructor(EcmaRuntimeCallInfo *argv);
121
122    // 22.1.2.1
123    static JSTaggedValue From(EcmaRuntimeCallInfo *argv);
124    // 22.1.2.2
125    static JSTaggedValue IsArray(EcmaRuntimeCallInfo *argv);
126    // 22.1.2.3
127    static JSTaggedValue Of(EcmaRuntimeCallInfo *argv);
128    // 22.1.2.5
129    static JSTaggedValue Species(EcmaRuntimeCallInfo *argv);
130
131    // prototype
132    // 22.1.3.1
133    static JSTaggedValue Concat(EcmaRuntimeCallInfo *argv);
134    // 22.1.3.3
135    static JSTaggedValue CopyWithin(EcmaRuntimeCallInfo *argv);
136    // 22.1.3.4
137    static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv);
138    // 22.1.3.5
139    static JSTaggedValue Every(EcmaRuntimeCallInfo *argv);
140    // 22.1.3.6
141    static JSTaggedValue Fill(EcmaRuntimeCallInfo *argv);
142    // 22.1.3.7
143    static JSTaggedValue Filter(EcmaRuntimeCallInfo *argv);
144    // 22.1.3.8
145    static JSTaggedValue Find(EcmaRuntimeCallInfo *argv);
146    // 22.1.3.9
147    static JSTaggedValue FindIndex(EcmaRuntimeCallInfo *argv);
148    // 22.1.3.10
149    static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv);
150    // 22.1.3.11
151    static JSTaggedValue IndexOf(EcmaRuntimeCallInfo *argv);
152    // 22.1.3.12
153    static JSTaggedValue Join(EcmaRuntimeCallInfo *argv);
154    // 22.1.3.13
155    static JSTaggedValue Keys(EcmaRuntimeCallInfo *argv);
156    // 22.1.3.14
157    static JSTaggedValue LastIndexOf(EcmaRuntimeCallInfo *argv);
158    // 22.1.3.15
159    static JSTaggedValue Map(EcmaRuntimeCallInfo *argv);
160    // 22.1.3.16
161    static JSTaggedValue Pop(EcmaRuntimeCallInfo *argv);
162    // 22.1.3.17
163    static JSTaggedValue Push(EcmaRuntimeCallInfo *argv);
164    // 22.1.3.18
165    static JSTaggedValue Reduce(EcmaRuntimeCallInfo *argv);
166    // 22.1.3.19
167    static JSTaggedValue ReduceRight(EcmaRuntimeCallInfo *argv);
168    // 22.1.3.20
169    static JSTaggedValue Reverse(EcmaRuntimeCallInfo *argv);
170    // 22.1.3.21
171    static JSTaggedValue Shift(EcmaRuntimeCallInfo *argv);
172    // 22.1.3.22
173    static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv);
174    // 22.1.3.23
175    static JSTaggedValue Some(EcmaRuntimeCallInfo *argv);
176    // 22.1.3.24
177    static JSTaggedValue Sort(EcmaRuntimeCallInfo *argv);
178    // 22.1.3.25
179    static JSTaggedValue Splice(EcmaRuntimeCallInfo *argv);
180    // 22.1.3.26
181    static JSTaggedValue ToLocaleString(EcmaRuntimeCallInfo *argv);
182    // 22.1.3.27
183    static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv); // no change
184    // 22.1.3.28
185    static JSTaggedValue Unshift(EcmaRuntimeCallInfo *argv); // done
186    // 22.1.3.29
187    static JSTaggedValue Values(EcmaRuntimeCallInfo *argv); // no change
188    // es12 23.1.3.13
189    static JSTaggedValue Includes(EcmaRuntimeCallInfo *argv); // no change
190    // es12 23.1.3.10
191    static JSTaggedValue Flat(EcmaRuntimeCallInfo *argv);
192    // es12 23.1.3.11
193    static JSTaggedValue FlatMap(EcmaRuntimeCallInfo *argv);
194    // 23.1.3.1 Array.prototype.at ( index )
195    static JSTaggedValue At(EcmaRuntimeCallInfo *argv); // no change
196    // 23.1.3.33 Array.prototype.toReversed ( )
197    static JSTaggedValue ToReversed(EcmaRuntimeCallInfo *argv); // no change
198    // 23.1.3.39 Array.prototype.with ( index, value )
199    static JSTaggedValue With(EcmaRuntimeCallInfo *argv); // done
200    // 23.1.3.34 Array.prototype.toSorted ( comparefn )
201    static JSTaggedValue ToSorted(EcmaRuntimeCallInfo *argv);
202    // 23.1.3.11
203    static JSTaggedValue FindLast(EcmaRuntimeCallInfo *argv); // no change
204    // 23.1.3.12
205    static JSTaggedValue FindLastIndex(EcmaRuntimeCallInfo *argv); // no change
206    // 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items )
207    static JSTaggedValue ToSpliced(EcmaRuntimeCallInfo *argv);
208
209    // Excluding the '@@' internal properties
210    static Span<const base::BuiltinFunctionEntry> GetArrayFunctions()
211    {
212        return Span<const base::BuiltinFunctionEntry>(ARRAY_FUNCTIONS);
213    }
214
215    // Excluding the constructor and '@@' internal properties.
216    static Span<const base::BuiltinFunctionEntry> GetArrayPrototypeFunctions()
217    {
218        return Span<const base::BuiltinFunctionEntry>(ARRAY_PROTOTYPE_FUNCTIONS);
219    }
220
221    static size_t GetNumPrototypeInlinedProperties()
222    {
223        // 4 : 4 More inlined entries in Array.prototype for the following functions/accessors:
224        //   (1) 'length' accessor
225        //   (2) Array.prototype.constructor, i.e. Array()
226        //   (3) Array.prototype[@@iterator]()
227        //   (4) Array.prototype[@@unscopables]()
228        return GetArrayPrototypeFunctions().Size() + 4;
229    }
230    static JSTaggedValue ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle,
231        JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator,
232        JSHandle<JSTaggedValue> &callbackFnHandle);
233
234    static JSTaggedValue FilterUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisArgHandle,
235        JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, uint32_t toIndex,
236        JSHandle<JSObject> newArrayHandle, JSHandle<JSTaggedValue> &callbackFnHandle);
237
238    static JSTaggedValue MapUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisArgHandle,
239        JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSHandle<JSObject> newArrayHandle,
240        JSHandle<JSTaggedValue> &callbackFnHandle);
241
242    static JSTaggedValue ReduceInner(EcmaRuntimeCallInfo *argv, int64_t len);
243
244    static JSTaggedValue ReduceRightInner(EcmaRuntimeCallInfo *argv, int64_t len);
245private:
246#define BUILTIN_ARRAY_FUNCTION_ENTRY(name, method, length, id) \
247    base::BuiltinFunctionEntry::Create(name, BuiltinsArray::method, length, kungfu::BuiltinsStubCSigns::id),
248
249    static constexpr std::array ARRAY_FUNCTIONS  = {
250        BUILTIN_ARRAY_FUNCTIONS(BUILTIN_ARRAY_FUNCTION_ENTRY)
251    };
252    static constexpr std::array ARRAY_PROTOTYPE_FUNCTIONS = {
253        BUILTIN_ARRAY_PROTOTYPE_FUNCTIONS(BUILTIN_ARRAY_FUNCTION_ENTRY)
254    };
255#undef BUILTIN_ARRAY_FUNCTION_ENTRY
256
257    static JSTaggedValue IndexOfStable(
258        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle);
259    static JSTaggedValue IndexOfSlowPath(
260        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle);
261    static JSTaggedValue IndexOfSlowPath(
262        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
263        int64_t length, int64_t fromIndex);
264
265    static JSTaggedValue LastIndexOfStable(
266        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle);
267    static JSTaggedValue LastIndexOfSlowPath(
268        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle);
269    static JSTaggedValue LastIndexOfSlowPath(
270        EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal, int64_t fromIndex);
271};
272}  // namespace panda::ecmascript::builtins
273
274#endif  // ECMASCRIPT_BUILTINS_BUILTINS_ARRAY_H
275