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