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 
114 namespace panda::ecmascript::builtins {
115 static constexpr uint8_t INDEX_TWO = 2;
116 static constexpr uint8_t INDEX_THREE = 3;
117 class BuiltinsArray : public base::BuiltinsBase {
118 public:
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
GetArrayFunctions()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.
GetArrayPrototypeFunctions()216     static Span<const base::BuiltinFunctionEntry> GetArrayPrototypeFunctions()
217     {
218         return Span<const base::BuiltinFunctionEntry>(ARRAY_PROTOTYPE_FUNCTIONS);
219     }
220 
GetNumPrototypeInlinedProperties()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);
245 private:
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