• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BUILTINS_BUILTINS_STRING_H
17 #define ECMASCRIPT_BUILTINS_BUILTINS_STRING_H
18 
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/ecma_runtime_call_info.h"
21 #include "ecmascript/js_tagged_value.h"
22 
23 // List of functions in String, excluding the '@@' properties.
24 // V(name, func, length, stubIndex)
25 // where BuiltinsString::func refers to the native implementation of String[name].
26 //       kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
27 #define BUILTIN_STRING_FUNCTIONS(V)                             \
28     /* String.fromCharCode ( ...codeUnits ) */                  \
29     V("fromCharCode",  FromCharCode,  1, StringFromCharCode)    \
30     /* String.fromCodePoint ( ...codePoints ) */                \
31     V("fromCodePoint", FromCodePoint, 1, INVALID)               \
32     /* String.raw ( template, ...substitutions ) */             \
33     V("raw",           Raw,           1, INVALID)
34 
35 // List of functions in String.prototype, excluding the constructor and '@@' properties.
36 // V(name, func, length, stubIndex)
37 // where BuiltinsString::func refers to the native implementation of String.prototype[name].
38 // The following functions in String.prototype are not implemented yet:
39 //   - String.prototype.isWellFormed ( )
40 //   - String.prototype.toWellFormed ( )
41 #define BUILTIN_STRING_PROTOTYPE_FUNCTIONS(V)                                       \
42     /* String.prototype.at ( index ) */                                             \
43     V("at",                At,                1, INVALID)                           \
44     /* String.prototype.charAt ( pos ) */                                           \
45     V("charAt",            CharAt,            1, StringCharAt)                      \
46     /* String.prototype.charCodeAt ( pos ) */                                       \
47     V("charCodeAt",        CharCodeAt,        1, StringCharCodeAt)                  \
48     /* String.prototype.codePointAt ( pos ) */                                      \
49     V("codePointAt",       CodePointAt,       1, INVALID)                           \
50     /* String.prototype.concat ( ...args ) */                                       \
51     V("concat",            Concat,            1, INVALID)                           \
52     /* String.prototype.endsWith ( searchString [ , endPosition ] ) */              \
53     V("endsWith",          EndsWith,          1, INVALID)                           \
54     /* String.prototype.includes ( searchString [ , position ] ) */                 \
55     V("includes",          Includes,          1, INVALID)                           \
56     /* String.prototype.indexOf ( searchString [ , position ] ) */                  \
57     V("indexOf",           IndexOf,           1, StringIndexOf)                     \
58     /* String.prototype.lastIndexOf ( searchString [ , position ] ) */              \
59     V("lastIndexOf",       LastIndexOf,       1, INVALID)                           \
60     /* String.prototype.localeCompare ( that [ , reserved1 [ , reserved2 ] ] ) */   \
61     V("localeCompare",     LocaleCompare,     1, LocaleCompare)                     \
62     /* String.prototype.match ( regexp ) */                                         \
63     V("match",             Match,             1, INVALID)                           \
64     /* String.prototype.matchAll ( regexp ) */                                      \
65     V("matchAll",          MatchAll,          1, INVALID)                           \
66     /* String.prototype.normalize ( [ form ] ) */                                   \
67     V("normalize",         Normalize,         0, INVALID)                           \
68     /* String.prototype.padEnd ( maxLength [ , fillString ] ) */                    \
69     V("padEnd",            PadEnd,            1, INVALID)                           \
70     /* String.prototype.padStart ( maxLength [ , fillString ] ) */                  \
71     V("padStart",          PadStart,          1, INVALID)                           \
72     /* String.prototype.repeat ( count ) */                                         \
73     V("repeat",            Repeat,            1, INVALID)                           \
74     /* String.prototype.replace ( searchValue, replaceValue ) */                    \
75     V("replace",           Replace,           2, StringReplace)                     \
76     /* String.prototype.replaceAll ( searchValue, replaceValue ) */                 \
77     V("replaceAll",        ReplaceAll,        2, INVALID)                           \
78     /* String.prototype.search ( regexp ) */                                        \
79     V("search",            Search,            1, INVALID)                           \
80     /* String.prototype.slice ( start, end ) */                                     \
81     V("slice",             Slice,             2, StringSlice)                       \
82     /* String.prototype.split ( separator, limit ) */                               \
83     V("split",             Split,             2, INVALID)                           \
84     /* String.prototype.startsWith ( searchString [ , position ] ) */               \
85     V("startsWith",        StartsWith,        1, INVALID)                           \
86     /* In Annex B.2.2: Additional Properties of the String.prototype Object */      \
87     /* String.prototype.substr ( start, length ) */                                 \
88     V("substr",            SubStr,            2, INVALID)                           \
89     /* String.prototype.substring ( start, end ) */                                 \
90     V("substring",         Substring,         2, StringSubstring)                   \
91     /* String.prototype.toLocaleLowerCase ( [ reserved1 [ , reserved2 ] ] ) */      \
92     V("toLocaleLowerCase", ToLocaleLowerCase, 0, INVALID)                           \
93     /* String.prototype.toLocaleUpperCase ( [ reserved1 [ , reserved2 ] ] ) */      \
94     V("toLocaleUpperCase", ToLocaleUpperCase, 0, INVALID)                           \
95     /* String.prototype.toLowerCase ( ) */                                          \
96     V("toLowerCase",       ToLowerCase,       0, INVALID)                           \
97     /* String.prototype.toString ( ) */                                             \
98     V("toString",          ToString,          0, INVALID)                           \
99     /* String.prototype.toUpperCase ( ) */                                          \
100     V("toUpperCase",       ToUpperCase,       0, INVALID)                           \
101     /* String.prototype.trim ( ) */                                                 \
102     V("trim",              Trim,              0, StringTrim)                        \
103     /* String.prototype.trimEnd ( ) */                                              \
104     V("trimEnd",           TrimEnd,           0, INVALID)                           \
105     /* In Annex B.2.2: Additional Properties of the String.prototype Object */      \
106     /* Equivalent to trimStart. For compatibility only. */                          \
107     /* String.prototype.trimLeft ( ) */                                             \
108     V("trimLeft",          TrimLeft,          0, INVALID)                           \
109     /* In Annex B.2.2: Additional Properties of the String.prototype Object */      \
110     /* Equivalent to trimEnd. For compatibility only. */                            \
111     /* String.prototype.trimEnd ( ) */                                              \
112     V("trimRight",         TrimRight,         0, INVALID)                           \
113     /* String.prototype.trimStart ( ) */                                            \
114     V("trimStart",         TrimStart,         0, INVALID)                           \
115     /* String.prototype.valueOf ( ) */                                              \
116     V("valueOf",           ValueOf,           0, INVALID)
117 
118 namespace panda::ecmascript::builtins {
119 constexpr int32_t ENCODE_MAX_UTF16 = 0X10FFFF;
120 constexpr uint16_t ENCODE_LEAD_LOW = 0xD800;
121 constexpr uint16_t ENCODE_TRAIL_LOW = 0xDC00;
122 constexpr uint32_t ENCODE_FIRST_FACTOR = 0x400;
123 constexpr uint32_t ENCODE_SECOND_FACTOR = 0x10000;
124 constexpr double DOUBLE_INT_MAX = static_cast<double>(INT_MAX);
125 constexpr double DOUBLE_INT_MIN = static_cast<double>(INT_MIN);
126 
127 class BuiltinsString : public base::BuiltinsBase {
128 public:
129     // 21.1.1.1
130     static JSTaggedValue StringConstructor(EcmaRuntimeCallInfo *argv);
131     // 21.1.2.1
132     static JSTaggedValue FromCharCode(EcmaRuntimeCallInfo *argv);
133     // 21.1.2.2
134     static JSTaggedValue FromCodePoint(EcmaRuntimeCallInfo *argv);
135     // 21.1.2.4
136     static JSTaggedValue Raw(EcmaRuntimeCallInfo *argv);
137 
138     static JSTaggedValue GetSubstitution(JSThread *thread, const JSHandle<EcmaString> &matched,
139                                          const JSHandle<EcmaString> &srcString, int position,
140                                          const JSHandle<TaggedArray> &captureList,
141                                          const JSHandle<JSTaggedValue> &namedCaptures,
142                                          const JSHandle<EcmaString> &replacement);
143     // 21.1.3.1
144     static JSTaggedValue CharAt(EcmaRuntimeCallInfo *argv);
145     // 21.1.3.2
146     static JSTaggedValue CharCodeAt(EcmaRuntimeCallInfo *argv);
147     // 21.1.3.3
148     static JSTaggedValue CodePointAt(EcmaRuntimeCallInfo *argv);
149     // 21.1.3.4
150     static JSTaggedValue Concat(EcmaRuntimeCallInfo *argv);
151     // 21.1.3.5 String.prototype.constructor
152     // 21.1.3.6
153     static JSTaggedValue EndsWith(EcmaRuntimeCallInfo *argv);
154     // 21.1.3.7
155     static JSTaggedValue Includes(EcmaRuntimeCallInfo *argv);
156     // 21.1.3.8
157     static JSTaggedValue IndexOf(EcmaRuntimeCallInfo *argv);
158     // 21.1.3.9
159     static JSTaggedValue LastIndexOf(EcmaRuntimeCallInfo *argv);
160     // 21.1.3.10
161     static JSTaggedValue LocaleCompare(EcmaRuntimeCallInfo *argv);
162     static JSTaggedValue LocaleCompareGC(JSThread *thread, JSHandle<JSTaggedValue> locales,
163                                          JSHandle<EcmaString> thisHandle, JSHandle<EcmaString> thatHandle,
164                                          JSHandle<JSTaggedValue> options, bool cacheable);
165     // 21.1.3.11
166     static JSTaggedValue Match(EcmaRuntimeCallInfo *argv);
167 
168     static JSTaggedValue MatchAll(EcmaRuntimeCallInfo *argv);
169     // 21.1.3.12
170     static JSTaggedValue Normalize(EcmaRuntimeCallInfo *argv);
171 
172     static JSTaggedValue PadStart(EcmaRuntimeCallInfo *argv);
173 
174     static JSTaggedValue PadEnd(EcmaRuntimeCallInfo *argv);
175     // 21.1.3.13
176     static JSTaggedValue Repeat(EcmaRuntimeCallInfo *argv);
177     // 21.1.3.14
178     static JSTaggedValue Replace(EcmaRuntimeCallInfo *argv);
179     // 21.1.3.14.1 Runtime Semantics: GetSubstitution()
180     static JSTaggedValue ReplaceAll(EcmaRuntimeCallInfo *argv);
181     // 21.1.3.15
182     static JSTaggedValue Search(EcmaRuntimeCallInfo *argv);
183     // 21.1.3.16
184     static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv);
185     // 21.1.3.17
186     static JSTaggedValue Split(EcmaRuntimeCallInfo *argv);
187     // 21.1.3.18
188     static JSTaggedValue StartsWith(EcmaRuntimeCallInfo *argv);
189     // 21.1.3.19
190     static JSTaggedValue Substring(EcmaRuntimeCallInfo *argv);
191     // 21.1.3.20
192     static JSTaggedValue ToLocaleLowerCase(EcmaRuntimeCallInfo *argv);
193     // 21.1.3.21
194     static JSTaggedValue ToLocaleUpperCase(EcmaRuntimeCallInfo *argv);
195     // 21.1.3.22
196     static JSTaggedValue ToLowerCase(EcmaRuntimeCallInfo *argv);
197     // 21.1.3.23
198     static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
199     // 21.1.3.24
200     static JSTaggedValue ToUpperCase(EcmaRuntimeCallInfo *argv);
201     // 21.1.3.25
202     static JSTaggedValue Trim(EcmaRuntimeCallInfo *argv);
203 
204     static JSTaggedValue TrimStart(EcmaRuntimeCallInfo *argv);
205 
206     static JSTaggedValue TrimEnd(EcmaRuntimeCallInfo *argv);
207 
208     static JSTaggedValue TrimLeft(EcmaRuntimeCallInfo *argv);
209 
210     static JSTaggedValue TrimRight(EcmaRuntimeCallInfo *argv);
211     // 21.1.3.26
212     static JSTaggedValue ValueOf(EcmaRuntimeCallInfo *argv);
213     // 21.1.3.27
214     static JSTaggedValue GetStringIterator(EcmaRuntimeCallInfo *argv);
215     // 21.1.3
216     static JSTaggedValue ThisStringValue(JSThread *thread, JSTaggedValue value);
217     // 21.1.2.27
218     static JSTaggedValue CreateIterator(EcmaRuntimeCallInfo *argv);
219     // 10.1.2
220     static uint16_t UTF16Decode(uint16_t lead, uint16_t trail);
221     // annexB B.2.3.1
222     static JSTaggedValue SubStr(EcmaRuntimeCallInfo *argv);
223     // 22.1.3.1
224     static JSTaggedValue At(EcmaRuntimeCallInfo *argv);
225 
226     static JSTaggedValue GetLength(EcmaRuntimeCallInfo *argv);
227 
228     // Excluding the '@@' internal properties
GetStringFunctions()229     static Span<const base::BuiltinFunctionEntry> GetStringFunctions()
230     {
231         return Span<const base::BuiltinFunctionEntry>(STRING_FUNCTIONS);
232     }
233 
234     // Excluding the constructor and '@@' internal properties.
GetStringPrototypeFunctions()235     static Span<const base::BuiltinFunctionEntry> GetStringPrototypeFunctions()
236     {
237         return Span<const base::BuiltinFunctionEntry>(STRING_PROTOTYPE_FUNCTIONS);
238     }
239 
GetNumPrototypeInlinedProperties()240     static size_t GetNumPrototypeInlinedProperties()
241     {
242         // 3 : 3 more inline properties in String.prototype:
243         //   (1) String.prototype.constructor
244         //   (2) String.prototype [ @@iterator ]
245         //   (3) get length
246         return GetStringPrototypeFunctions().Size() + 3;
247     }
248     static JSTaggedValue StringToList(JSThread *thread, JSHandle<EcmaString> &str);
249 
250 private:
251 #define BUILTIN_STRING_FUNCTION_ENTRY(name, method, length, builtinId) \
252     base::BuiltinFunctionEntry::Create(name, BuiltinsString::method, length, kungfu::BuiltinsStubCSigns::builtinId),
253 
254     static constexpr std::array STRING_FUNCTIONS = {
255         BUILTIN_STRING_FUNCTIONS(BUILTIN_STRING_FUNCTION_ENTRY)
256     };
257     static constexpr std::array STRING_PROTOTYPE_FUNCTIONS = {
258         BUILTIN_STRING_PROTOTYPE_FUNCTIONS(BUILTIN_STRING_FUNCTION_ENTRY)
259     };
260 #undef BUILTIN_STRING_FUNCTION_ENTRY
261 
262     static JSTaggedValue Pad(EcmaRuntimeCallInfo *argv, bool isStart);
263     static int32_t ConvertDoubleToInt(double d);
264     static JSTaggedValue CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm,
265         const JSHandle<EcmaString> &thisString, uint32_t thisLength, uint32_t lim);
266     static JSTaggedValue CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm,
267         const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
268         uint32_t thisLength, uint32_t seperatorLength, uint32_t lim);
269     static JSTaggedValue CreateArrayThisStringAndSeperatorStringAreNotEmpty(
270         JSThread *thread, EcmaVM *ecmaVm,
271         const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString,
272         uint32_t thisLength, uint32_t seperatorLength, uint32_t lim = UINT32_MAX - 1);
273     // 21.1.3.17.1
274 };
275 
276 class StringSplitResultCache : public TaggedArray {
277 public:
Cast(TaggedObject * object)278     static StringSplitResultCache *Cast(TaggedObject *object)
279     {
280         return reinterpret_cast<StringSplitResultCache*>(object);
281     }
282     static JSTaggedValue CreateCacheTable(const JSThread *thread);
283     static JSTaggedValue FindCachedResult(const JSThread *thread, const JSHandle<StringSplitResultCache> &cache,
284         const JSHandle<EcmaString> &string, const JSHandle<EcmaString> &pattern);
285     static void SetCachedResult(const JSThread *thread, const JSHandle<StringSplitResultCache> &cache,
286         const JSHandle<EcmaString> &string, const JSHandle<EcmaString> &pattern,
287         const JSHandle<TaggedArray> &result);
288 
289 private:
290     static constexpr int CACHE_SIZE = 256;
291     static constexpr int STRING_INDEX = 0;
292     static constexpr int PATTERN_INDEX = 1;
293     static constexpr int ARRAY_INDEX = 2;
294     static constexpr int ENTRY_SIZE = 3;
295 };
296 
297 class StringToListResultCache : public TaggedArray {
298 public:
Cast(TaggedObject * object)299     static StringToListResultCache *Cast(TaggedObject *object)
300     {
301         return reinterpret_cast<StringToListResultCache*>(object);
302     }
303     static JSTaggedValue CreateCacheTable(const JSThread *thread);
304     static JSTaggedValue FindCachedResult(const JSThread *thread, const JSHandle<StringToListResultCache> &cache,
305         const JSHandle<EcmaString> &string);
306     static void SetCachedResult(const JSThread *thread, const JSHandle<StringToListResultCache> &cache,
307         const JSHandle<EcmaString> &string, const JSHandle<TaggedArray> &result);
308 
309     static constexpr int MAX_STRING_LENGTH = 20;
310     static constexpr int CACHE_SIZE = 128;
311     static constexpr int STRING_INDEX = 0;
312     static constexpr int ARRAY_INDEX = 1;
313     static constexpr int ENTRY_SIZE = 2;
314 };
315 }  // namespace panda::ecmascript::builtins
316 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_STRING_H
317