• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &regexp,
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