1 /* 2 * Copyright (c) 2021-2024 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_REGEXP_H 17 #define ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H 18 19 #include "ecmascript/base/builtins_base.h" 20 #include "ecmascript/builtins/builtins_string.h" 21 #include "ecmascript/ecma_runtime_call_info.h" 22 #include "ecmascript/js_tagged_value.h" 23 #include "ecmascript/regexp/regexp_parser.h" 24 #include "ecmascript/tagged_array-inl.h" 25 26 namespace panda::ecmascript::builtins { 27 class BuiltinsRegExp : public base::BuiltinsBase { 28 public: 29 enum RegExpSymbol { 30 SPLIT, 31 SEARCH, 32 MATCH, 33 MATCHALL, 34 REPLACE, 35 UNKNOWN 36 }; 37 // 21.2.3.1 RegExp ( pattern, flags ) 38 static JSTaggedValue RegExpConstructor(EcmaRuntimeCallInfo *argv); 39 40 // prototype 41 // 21.2.5.2 RegExp.prototype.exec ( string ) 42 static JSTaggedValue Exec(EcmaRuntimeCallInfo *argv); 43 // 21.2.5.13 RegExp.prototype.test( S ) 44 static JSTaggedValue Test(EcmaRuntimeCallInfo *argv); 45 // 21.2.5.14 RegExp.prototype.toString ( ) 46 static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv); 47 // 21.2.5.3 get RegExp.prototype.flags 48 static JSTaggedValue GetFlags(EcmaRuntimeCallInfo *argv); 49 // 21.2.5.4 get RegExp.prototype.global 50 static JSTaggedValue GetGlobal(EcmaRuntimeCallInfo *argv); 51 // 21.2.5.5 get RegExp.prototype.ignoreCase 52 static JSTaggedValue GetIgnoreCase(EcmaRuntimeCallInfo *argv); 53 // 21.2.5.7 get RegExp.prototype.multiline 54 static JSTaggedValue GetMultiline(EcmaRuntimeCallInfo *argv); 55 static JSTaggedValue GetDotAll(EcmaRuntimeCallInfo *argv); 56 // 21.2.5.10 get RegExp.prototype.source 57 static JSTaggedValue GetSource(EcmaRuntimeCallInfo *argv); 58 // 21.2.5.12 get RegExp.prototype.sticky 59 static JSTaggedValue GetSticky(EcmaRuntimeCallInfo *argv); 60 // 21.2.5.15 get RegExp.prototype.unicode 61 static JSTaggedValue GetUnicode(EcmaRuntimeCallInfo *argv); 62 // 21.2.4.2 get RegExp [ @@species ] 63 static JSTaggedValue GetSpecies(EcmaRuntimeCallInfo *argv); 64 // 21.2.5.6 RegExp.prototype [ @@match ] ( string ) 65 static JSTaggedValue Match(EcmaRuntimeCallInfo *argv); 66 // 22.2.5.8 RegExp.prototype [ @@matchAll ] ( string ) 67 static JSTaggedValue MatchAll(EcmaRuntimeCallInfo *argv); 68 // 21.2.5.8 RegExp.prototype [ @@replace ] ( string, replaceValue ) 69 static JSTaggedValue Replace(EcmaRuntimeCallInfo *argv); 70 // 21.2.5.9 RegExp.prototype [ @@search ] ( string ) 71 static JSTaggedValue Search(EcmaRuntimeCallInfo *argv); 72 // 21.2.5.11 RegExp.prototype [ @@split ] ( string, limit ) 73 static JSTaggedValue Split(EcmaRuntimeCallInfo *argv); 74 // 21.2.3.2.3 Runtime Semantics: RegExpCreate ( P, F ) 75 static JSTaggedValue RegExpCreate(JSThread *thread, const JSHandle<JSTaggedValue> &pattern, 76 const JSHandle<JSTaggedValue> &flags); 77 static JSTaggedValue FlagsBitsToString(JSThread *thread, uint8_t flags); 78 // 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S ) 79 static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle<JSTaggedValue> ®exp, 80 const JSHandle<JSTaggedValue> &inputString, bool useCache, 81 bool isIntermediateResult = false); 82 // 21.2.5.2.3 AdvanceStringIndex ( S, index, unicode ) 83 static int64_t AdvanceStringIndex(const JSThread *thread, const JSHandle<JSTaggedValue> &inputStr, int64_t index, 84 bool unicode); 85 // 22.2.6.6 get RegExp.prototype.hasIndices 86 static JSTaggedValue GetHasIndices(EcmaRuntimeCallInfo *argv); 87 88 static JSTaggedValue ReplaceInternal(JSThread *thread, 89 JSHandle<JSTaggedValue> thisObj, 90 JSHandle<JSTaggedValue> string, 91 JSHandle<JSTaggedValue> inputReplaceValue); 92 static JSTaggedValue GetAllFlagsInternal(JSThread *thread, JSHandle<JSTaggedValue> &thisObj); 93 static bool IsFastRegExp(JSThread *thread, JSTaggedValue regexp, 94 RegExpSymbol symbolTag = RegExpSymbol::UNKNOWN); 95 static bool GetFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag, bool isFastPath); 96 static bool GetOriginalFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag); 97 static void SetLastIndex(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 98 JSTaggedValue lastIndex, bool isFastPath); 99 static int64_t GetLastIndex(JSThread *thread, const JSHandle<JSTaggedValue> regexp, bool isFastPath); 100 static JSTaggedValue RegExpBuiltinExecWithoutResult(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 101 const JSHandle<JSTaggedValue> inputStr, 102 bool isFastPath, uint32_t lastIndex, bool useCache); 103 // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S ) 104 static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 105 const JSHandle<JSTaggedValue> inputStr, 106 bool isFastPath, bool useCache, bool isIntermediateResult = false); 107 static JSTaggedValue RegExpSearch(JSThread *thread, 108 const JSHandle<JSTaggedValue> regexp, 109 const JSHandle<JSTaggedValue> string); 110 static JSTaggedValue RegExpSearchFast(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 111 const JSHandle<JSTaggedValue> string); 112 static JSTaggedValue RegExpSplit(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 113 JSHandle<JSTaggedValue> jsString, JSHandle<JSTaggedValue> limit, 114 bool isFastPath); 115 static JSTaggedValue GetExecResultIndex(JSThread *thread, const JSHandle<JSTaggedValue> &execResults, 116 bool isFastPath); 117 static JSTaggedValue GetExecResultGroups(JSThread *thread, const JSHandle<JSTaggedValue> &execResults, 118 bool isFastPath); 119 static JSTaggedValue RegExpMatch(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 120 const JSHandle<JSTaggedValue> string, bool isFastPath); 121 static JSTaggedValue RegExpMatchAll(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 122 const JSHandle<EcmaString> string, bool isFastPath); 123 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 124 #define SET_GET_CAPTURE(index) \ 125 static JSTaggedValue GetCapture##index(JSThread *thread, const JSHandle<JSObject> &obj); \ 126 static bool SetCapture##index(JSThread *thread, const JSHandle<JSObject> &obj, \ 127 const JSHandle<JSTaggedValue> &value, bool mayThrow); 128 129 SET_GET_CAPTURE(1) 130 SET_GET_CAPTURE(2) 131 SET_GET_CAPTURE(3) 132 SET_GET_CAPTURE(4) 133 SET_GET_CAPTURE(5) 134 SET_GET_CAPTURE(6) 135 SET_GET_CAPTURE(7) 136 SET_GET_CAPTURE(8) 137 SET_GET_CAPTURE(9) 138 #undef SET_GET_CAPTURE 139 140 #define REGEXP_SYMBOL_FUNCTION_LIST(V) \ 141 V(SPLIT, Split) \ 142 V(SEARCH, Search) \ 143 V(MATCH, Match) \ 144 V(MATCHALL, MatchAll) \ 145 V(REPLACE, Replace) 146 147 private: 148 // Execution with a huge RegExp pattern may cost much time and block other thread SuspendAll, so copy an 149 // OffHeap string and pass it to RegExpExecutor, thus we could transition to native before we do this execution. 150 enum class StringSource { 151 ONHEAP_STRING, 152 OFFHEAP_STRING, 153 }; 154 static constexpr uint32_t MIN_REGEXP_PATTERN_LENGTH_EXECUTE_WITH_OFFHEAP_STRING = 4000; 155 static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000; 156 static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu; 157 static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9; 158 static constexpr uint32_t LAST_INDEX_OFFSET = 0; 159 static constexpr uint32_t EXEC_RESULT_INDEX_OFFSET = 1; 160 static constexpr uint32_t EXEC_RESULT_INPUT_OFFSET = 2; 161 static constexpr uint32_t EXEC_RESULT_GROUPS_OFFSET = 3; 162 163 static constexpr uint32_t REPLACE_RESULT_VAL = 2; 164 static constexpr unsigned REPLACE_LENGTH_BITS = 30; 165 static constexpr unsigned REPLACE_POSITION_BITS = 30; 166 using ReplaceLengthField = BitField<uint32_t, 0, REPLACE_LENGTH_BITS>; // 30 167 using ReplacePositionField = ReplaceLengthField::NextField<uint32_t, REPLACE_POSITION_BITS>; // 60 168 169 static bool Matcher(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 170 const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16, StringSource source); 171 172 static JSTaggedValue GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 173 const JSHandle<JSTaggedValue> &constructor, const uint8_t mask); 174 // 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget ) 175 static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget); 176 177 static uint32_t UpdateExpressionFlags(JSThread *thread, const CString &checkStr); 178 179 // 21.2.3.2.2 Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) 180 static JSTaggedValue RegExpInitialize(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 181 const JSHandle<JSTaggedValue> &pattern, const JSHandle<JSTaggedValue> &flags); 182 // 21.2.3.2.4 Runtime Semantics: EscapeRegExpPattern ( P, F ) 183 static EcmaString *EscapeRegExpPattern(JSThread *thread, const JSHandle<JSTaggedValue> &src, 184 const JSHandle<JSTaggedValue> &flags); 185 static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle<JSTaggedValue> regexp, 186 JSHandle<EcmaString> inputString, uint32_t inputLength); 187 static JSTaggedValue GetLastIndex(JSThread *thread, JSHandle<JSTaggedValue> regexp, 188 uint32_t &lastIndex); 189 static bool ShouldUseCache(JSThread *thread, JSHandle<EcmaString> inputString); 190 static JSTaggedValue MatchAndReplace(JSThread *thread, JSHandle<JSTaggedValue> regexp, 191 JSHandle<EcmaString> inputString, uint32_t &flags, 192 uint32_t lastIndex, uint32_t inputLength, 193 std::string &resultString); 194 static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle<JSTaggedValue> regexp, 195 const JSHandle<JSTaggedValue> inputString, bool useCache); 196 static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle<JSTaggedValue> regexp, 197 const JSHandle<JSTaggedValue> inputStr, bool useCache); 198 // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) 199 static JSHandle<JSTaggedValue> MakeMatchIndicesIndexPairArray(JSThread* thread, 200 const std::vector<std::pair<JSTaggedValue, JSTaggedValue>>& indices, 201 const std::vector<JSHandle<JSTaggedValue>>& groupNames, bool hasGroups); 202 static bool RegExpExecInternal(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 203 JSHandle<EcmaString> inputString, int32_t lastIndex); 204 static JSTaggedValue RegExpSplitFast(JSThread *thread, const JSHandle<JSTaggedValue> regexp, 205 JSHandle<JSTaggedValue> string, uint32_t limit, bool useCache); 206 static JSHandle<EcmaString> CreateStringFromResultArray(JSThread *thread, 207 const CVector<JSHandle<JSTaggedValue>> &resultArray, 208 const std::vector<uint64_t> &resultLengthArray, JSHandle<EcmaString> srcString, 209 uint32_t resultStrLength, bool isUtf8); 210 }; 211 212 class RegExpExecResultCache : public TaggedArray { 213 public: 214 enum CacheType { 215 REPLACE_TYPE, 216 SPLIT_TYPE, 217 MATCH_TYPE, 218 EXEC_TYPE, 219 INTERMEDIATE_REPLACE_TYPE, 220 TEST_TYPE, 221 SEARCH_TYPE, 222 }; Cast(TaggedObject * object)223 static RegExpExecResultCache *Cast(TaggedObject *object) 224 { 225 return reinterpret_cast<RegExpExecResultCache *>(object); 226 } 227 static JSTaggedValue CreateCacheTable(JSThread *thread); 228 // extend as an additional parameter to judge cached 229 template <RBMode mode = RBMode::DEFAULT_RB> 230 JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> input, 231 CacheType type, const JSHandle<JSTaggedValue> regexp, 232 JSTaggedValue lastIndexInput, JSHandle<JSTaggedValue> extend, 233 bool isIntermediateResult = false); 234 // extend as an additional parameter to judge cached 235 static void AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache, 236 const JSHandle<JSTaggedValue> regexp, 237 const JSHandle<JSTaggedValue> input, const JSHandle<JSTaggedValue> resultArray, 238 CacheType type, uint32_t lastIndexInput, uint32_t lastIndex, 239 const JSHandle<JSTaggedValue> extend, 240 bool isIntermediateResult = false); 241 242 static void GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache); 243 244 void ClearEntry(JSThread *thread, int entry); 245 void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flags, JSTaggedValue &input, 246 JSTaggedValue &lastIndexInputValue, JSTaggedValue &lastIndexValue, JSTaggedValue &extendValue, 247 JSTaggedValue &resTableArray); 248 void UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type); 249 template <RBMode mode = RBMode::DEFAULT_RB> 250 bool Match(JSThread *thread, int entry, JSTaggedValue &pattenStr, JSTaggedValue &flagsStr, JSTaggedValue &inputStr, 251 JSTaggedValue &lastIndexInputValue, JSTaggedValue &extend, CacheType type); 252 static JSTaggedValue GetGlobalTable(JSThread *thread); SetHitCount(JSThread * thread,int hitCount)253 inline void SetHitCount(JSThread *thread, int hitCount) 254 { 255 Set<false>(thread, CACHE_HIT_COUNT_INDEX, JSTaggedValue(hitCount)); 256 } 257 GetHitCount()258 inline int GetHitCount() 259 { 260 return GetPrimitive(CACHE_HIT_COUNT_INDEX).GetInt(); 261 } 262 SetCacheCount(JSThread * thread,int hitCount)263 inline void SetCacheCount(JSThread *thread, int hitCount) 264 { 265 Set<false>(thread, CACHE_COUNT_INDEX, JSTaggedValue(hitCount)); 266 } 267 GetCacheCount()268 inline int GetCacheCount() 269 { 270 return GetPrimitive(CACHE_COUNT_INDEX).GetInt(); 271 } 272 Print()273 void Print() 274 { 275 std::cout << "cache count: " << GetCacheCount() << std::endl; 276 std::cout << "cache hit count: " << GetHitCount() << std::endl; 277 } 278 SetLargeStrCount(JSThread * thread,uint32_t newCount)279 inline void SetLargeStrCount(JSThread *thread, uint32_t newCount) 280 { 281 Set<false>(thread, LARGE_STRING_COUNT_INDEX, JSTaggedValue(newCount)); 282 } 283 SetConflictCount(JSThread * thread,uint32_t newCount)284 inline void SetConflictCount(JSThread *thread, uint32_t newCount) 285 { 286 Set<false>(thread, CONFLICT_COUNT_INDEX, JSTaggedValue(newCount)); 287 } 288 SetStrLenThreshold(JSThread * thread,uint32_t newThreshold)289 inline void SetStrLenThreshold(JSThread *thread, uint32_t newThreshold) 290 { 291 Set<false>(thread, STRING_LENGTH_THRESHOLD_INDEX, JSTaggedValue(newThreshold)); 292 } 293 GetLargeStrCount()294 inline uint32_t GetLargeStrCount() 295 { 296 return GetPrimitive(LARGE_STRING_COUNT_INDEX).GetInt(); 297 } 298 GetConflictCount()299 inline uint32_t GetConflictCount() 300 { 301 return GetPrimitive(CONFLICT_COUNT_INDEX).GetInt(); 302 } 303 GetStrLenThreshold()304 inline uint32_t GetStrLenThreshold() 305 { 306 return GetPrimitive(STRING_LENGTH_THRESHOLD_INDEX).GetInt(); 307 } 308 SetCacheLength(JSThread * thread,int length)309 inline void SetCacheLength(JSThread *thread, int length) 310 { 311 Set<false>(thread, CACHE_LENGTH_INDEX, JSTaggedValue(length)); 312 } 313 GetCacheLength()314 inline int GetCacheLength() 315 { 316 return GetPrimitive(CACHE_LENGTH_INDEX).GetInt(); 317 } 318 SetLastMatchGlobalTableIndex(JSThread * thread,int index)319 inline void SetLastMatchGlobalTableIndex(JSThread *thread, int index) 320 { 321 Set<false>(thread, LAST_MATCH_GLOBAL_TABLE_INDEX, JSTaggedValue(index)); 322 } 323 GetLastMatchGlobalTableIndex()324 inline int GetLastMatchGlobalTableIndex() 325 { 326 return GetPrimitive(LAST_MATCH_GLOBAL_TABLE_INDEX).GetInt(); 327 } 328 SetUseLastMatch(JSThread * thread,bool useLastMatchIndex)329 inline void SetUseLastMatch(JSThread *thread, bool useLastMatchIndex) 330 { 331 Set<false>(thread, USE_LAST_MATCH_INDEX, JSTaggedValue(useLastMatchIndex)); 332 } 333 GetUseLastMatch()334 inline bool GetUseLastMatch() 335 { 336 return GetPrimitive(USE_LAST_MATCH_INDEX).IsTrue(); 337 } 338 SetNeedUpdateGlobal(JSThread * thread,bool needUpdateGlobal)339 inline void SetNeedUpdateGlobal(JSThread *thread, bool needUpdateGlobal) 340 { 341 Set<false>(thread, NEED_UPDATE_GLOBAL_INDEX, JSTaggedValue(needUpdateGlobal)); 342 } 343 GetNeedUpdateGlobal()344 inline bool GetNeedUpdateGlobal() 345 { 346 return GetPrimitive(NEED_UPDATE_GLOBAL_INDEX).IsTrue(); 347 } 348 349 private: 350 static constexpr int DEFAULT_LARGE_STRING_COUNT = 10; 351 static constexpr int DEFAULT_CONFLICT_COUNT = 100; 352 static constexpr int INITIAL_CACHE_NUMBER = 0x10; 353 static constexpr int DEFAULT_CACHE_NUMBER = 0x1000; 354 static constexpr int DEFAULT_LAST_MATCH_INDEX = -1; 355 static constexpr int CACHE_COUNT_INDEX = 0; 356 static constexpr int CACHE_HIT_COUNT_INDEX = 1; 357 static constexpr int LARGE_STRING_COUNT_INDEX = 2; 358 static constexpr int CONFLICT_COUNT_INDEX = 3; 359 static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4; 360 static constexpr int CACHE_LENGTH_INDEX = 5; 361 static constexpr int LAST_MATCH_GLOBAL_TABLE_INDEX = 6; // only for capture use 362 static constexpr int USE_LAST_MATCH_INDEX = 7; // only for capture use 363 static constexpr int NEED_UPDATE_GLOBAL_INDEX = 8; // only for capture use 364 static constexpr int CACHE_TABLE_HEADER_SIZE = 9; 365 static constexpr int PATTERN_INDEX = 0; 366 static constexpr int FLAG_INDEX = 1; 367 static constexpr int INPUT_STRING_INDEX = 2; 368 static constexpr int LAST_INDEX_INPUT_INDEX = 3; 369 static constexpr int LAST_INDEX_INDEX = 4; 370 static constexpr int RESULT_REPLACE_INDEX = 5; 371 static constexpr int RESULT_SPLIT_INDEX = 6; 372 static constexpr int RESULT_MATCH_INDEX = 7; 373 static constexpr int RESULT_EXEC_INDEX = 8; 374 static constexpr int RESULT_INTERMEDIATE_REPLACE_INDEX = 9; 375 static constexpr int RESULT_TEST_INDEX = 10; 376 static constexpr int RESULT_SEARCH_INDEX = 11; 377 // Extend index used for saving an additional parameter to judge cached 378 static constexpr int EXTEND_INDEX = 12; 379 static constexpr int CAPTURE_SIZE = 13; 380 static constexpr int ENTRY_SIZE = 14; 381 }; 382 383 class RegExpGlobalResult : public TaggedArray { 384 public: Cast(TaggedObject * object)385 static RegExpGlobalResult *Cast(TaggedObject *object) 386 { 387 return reinterpret_cast<RegExpGlobalResult *>(object); 388 } 389 static JSTaggedValue CreateGlobalResultTable(JSThread *thread); 390 SetCapture(JSThread * thread,int index,JSTaggedValue value)391 void SetCapture(JSThread *thread, int index, JSTaggedValue value) 392 { 393 ASSERT(CAPTURE_START_INDEX + index - 1 < GLOBAL_TABLE_SIZE); 394 Set(thread, CAPTURE_START_INDEX + index - 1, value); 395 } 396 ResetDollar(JSThread * thread)397 void ResetDollar(JSThread *thread) 398 { 399 for (uint32_t i = 0; i < DOLLAR_NUMBER; i++) { 400 Set(thread, CAPTURE_START_INDEX + i, JSTaggedValue::Hole()); 401 } 402 } 403 404 template <int N> 405 static JSTaggedValue GetCapture(JSThread *thread); 406 SetTotalCaptureCounts(JSThread * thread,JSTaggedValue counts)407 void SetTotalCaptureCounts(JSThread *thread, JSTaggedValue counts) 408 { 409 Set(thread, TOTAL_CAPTURE_COUNTS_INDEX, counts); 410 } 411 GetTotalCaptureCounts()412 JSTaggedValue GetTotalCaptureCounts() 413 { 414 return GetPrimitive(TOTAL_CAPTURE_COUNTS_INDEX); 415 } 416 SetEndIndex(JSThread * thread,JSTaggedValue endIndex)417 void SetEndIndex(JSThread *thread, JSTaggedValue endIndex) 418 { 419 Set(thread, END_INDEX, endIndex); 420 } 421 GetEndIndex()422 JSTaggedValue GetEndIndex() 423 { 424 return GetPrimitive(END_INDEX); 425 } 426 SetInputString(JSThread * thread,JSTaggedValue string)427 void SetInputString(JSThread *thread, JSTaggedValue string) 428 { 429 Set(thread, INPUT_STRING_INDEX, string); 430 } 431 GetInputString(JSThread * thread)432 JSTaggedValue GetInputString(JSThread *thread) 433 { 434 return Get(thread, INPUT_STRING_INDEX); 435 } 436 SetStartOfCaptureIndex(JSThread * thread,uint32_t index,JSTaggedValue value)437 void SetStartOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value) 438 { 439 Set(thread, FIRST_CAPTURE_INDEX + index * 2, value); // 2 : double 440 } 441 SetEndOfCaptureIndex(JSThread * thread,uint32_t index,JSTaggedValue value)442 void SetEndOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value) 443 { 444 Set(thread, FIRST_CAPTURE_INDEX + index * 2 + 1, value); // 2 : double 445 } 446 GetStartOfCaptureIndex(uint32_t index)447 JSTaggedValue GetStartOfCaptureIndex(uint32_t index) 448 { 449 return GetPrimitive(FIRST_CAPTURE_INDEX + index * 2); // 2 : double 450 } 451 GetEndOfCaptureIndex(uint32_t index)452 JSTaggedValue GetEndOfCaptureIndex(uint32_t index) 453 { 454 return GetPrimitive(FIRST_CAPTURE_INDEX + index * 2 + 1); // 2 : double 455 } 456 457 static JSHandle<RegExpGlobalResult> GrowCapturesCapacity(JSThread *thread, 458 JSHandle<RegExpGlobalResult>result, uint32_t length); 459 460 static constexpr int FIRST_CAPTURE_INDEX = 12; // capture index starts here 461 462 private: 463 static constexpr int GLOBAL_TABLE_SIZE = 12; // initial length 464 static constexpr int DOLLAR_NUMBER = 9; 465 static constexpr int CAPTURE_START_INDEX = 0; 466 467 static constexpr int TOTAL_CAPTURE_COUNTS_INDEX = 9; // save total capture size 468 static constexpr int INPUT_STRING_INDEX = 10; // save input string 469 static constexpr int END_INDEX = 11; // save last index 470 static constexpr int INITIAL_CAPTURE_INDICES = 18; // length: pairs of capture start index and end index 471 }; 472 } // namespace panda::ecmascript::builtins 473 #endif // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H 474