• 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 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, JSHandle<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, const JSHandle<TaggedArray> resultArray,
207         const std::vector<uint64_t> &resultLengthArray, JSHandle<EcmaString> srcString,
208         uint32_t resultStrLength, bool isUtf8);
209 };
210 
211 class RegExpExecResultCache : public TaggedArray {
212 public:
213     enum CacheType {
214         REPLACE_TYPE,
215         SPLIT_TYPE,
216         MATCH_TYPE,
217         EXEC_TYPE,
218         INTERMEDIATE_REPLACE_TYPE,
219         TEST_TYPE,
220         SEARCH_TYPE,
221     };
Cast(TaggedObject * object)222     static RegExpExecResultCache *Cast(TaggedObject *object)
223     {
224         return reinterpret_cast<RegExpExecResultCache *>(object);
225     }
226     static JSTaggedValue CreateCacheTable(JSThread *thread);
227     // extend as an additional parameter to judge cached
228     JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> input,
229                                    CacheType type, const JSHandle<JSTaggedValue> regexp,
230                                    JSTaggedValue lastIndexInput, JSHandle<JSTaggedValue> extend,
231                                    bool isIntermediateResult = false);
232     // extend as an additional parameter to judge cached
233     static void AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache,
234                                  const JSHandle<JSTaggedValue> regexp,
235                                  const JSHandle<JSTaggedValue> input, const JSHandle<JSTaggedValue> resultArray,
236                                  CacheType type, uint32_t lastIndexInput, uint32_t lastIndex,
237                                  const JSHandle<JSTaggedValue> extend,
238                                  bool isIntermediateResult = false);
239 
240     static void GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache);
241 
242     void ClearEntry(JSThread *thread, int entry);
243     void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flags, JSTaggedValue &input,
244                   JSTaggedValue &lastIndexInputValue, JSTaggedValue &lastIndexValue, JSTaggedValue &extendValue,
245                   JSTaggedValue &resTableArray);
246     void UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type);
247     bool Match(int entry, JSTaggedValue &pattenStr, JSTaggedValue &flagsStr, JSTaggedValue &inputStr,
248                JSTaggedValue &lastIndexInputValue, JSTaggedValue &extend, CacheType type);
SetHitCount(JSThread * thread,int hitCount)249     inline void SetHitCount(JSThread *thread, int hitCount)
250     {
251         Set(thread, CACHE_HIT_COUNT_INDEX, JSTaggedValue(hitCount));
252     }
253 
GetHitCount()254     inline int GetHitCount()
255     {
256         return Get(CACHE_HIT_COUNT_INDEX).GetInt();
257     }
258 
SetCacheCount(JSThread * thread,int hitCount)259     inline void SetCacheCount(JSThread *thread, int hitCount)
260     {
261         Set(thread, CACHE_COUNT_INDEX, JSTaggedValue(hitCount));
262     }
263 
GetCacheCount()264     inline int GetCacheCount()
265     {
266         return Get(CACHE_COUNT_INDEX).GetInt();
267     }
268 
Print()269     void Print()
270     {
271         std::cout << "cache count: " << GetCacheCount() << std::endl;
272         std::cout << "cache hit count: " << GetHitCount() << std::endl;
273     }
274 
SetLargeStrCount(JSThread * thread,uint32_t newCount)275     inline void SetLargeStrCount(JSThread *thread, uint32_t newCount)
276     {
277         Set(thread, LARGE_STRING_COUNT_INDEX, JSTaggedValue(newCount));
278     }
279 
SetConflictCount(JSThread * thread,uint32_t newCount)280     inline void SetConflictCount(JSThread *thread, uint32_t newCount)
281     {
282         Set(thread, CONFLICT_COUNT_INDEX, JSTaggedValue(newCount));
283     }
284 
SetStrLenThreshold(JSThread * thread,uint32_t newThreshold)285     inline void SetStrLenThreshold(JSThread *thread, uint32_t newThreshold)
286     {
287         Set(thread, STRING_LENGTH_THRESHOLD_INDEX, JSTaggedValue(newThreshold));
288     }
289 
GetLargeStrCount()290     inline uint32_t GetLargeStrCount()
291     {
292         return Get(LARGE_STRING_COUNT_INDEX).GetInt();
293     }
294 
GetConflictCount()295     inline uint32_t GetConflictCount()
296     {
297         return Get(CONFLICT_COUNT_INDEX).GetInt();
298     }
299 
GetStrLenThreshold()300     inline uint32_t GetStrLenThreshold()
301     {
302         return Get(STRING_LENGTH_THRESHOLD_INDEX).GetInt();
303     }
304 
SetCacheLength(JSThread * thread,int length)305     inline void SetCacheLength(JSThread *thread, int length)
306     {
307         Set(thread, CACHE_LENGTH_INDEX, JSTaggedValue(length));
308     }
309 
GetCacheLength()310     inline int GetCacheLength()
311     {
312         return Get(CACHE_LENGTH_INDEX).GetInt();
313     }
314 
315 private:
316     static constexpr int DEFAULT_LARGE_STRING_COUNT = 10;
317     static constexpr int DEFAULT_CONFLICT_COUNT = 100;
318     static constexpr int INITIAL_CACHE_NUMBER = 0x10;
319     static constexpr int DEFAULT_CACHE_NUMBER = 0x1000;
320     static constexpr int CACHE_COUNT_INDEX = 0;
321     static constexpr int CACHE_HIT_COUNT_INDEX = 1;
322     static constexpr int LARGE_STRING_COUNT_INDEX = 2;
323     static constexpr int CONFLICT_COUNT_INDEX = 3;
324     static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4;
325     static constexpr int CACHE_LENGTH_INDEX = 5;
326     static constexpr int CACHE_TABLE_HEADER_SIZE = 6;
327     static constexpr int PATTERN_INDEX = 0;
328     static constexpr int FLAG_INDEX = 1;
329     static constexpr int INPUT_STRING_INDEX = 2;
330     static constexpr int LAST_INDEX_INPUT_INDEX = 3;
331     static constexpr int LAST_INDEX_INDEX = 4;
332     static constexpr int RESULT_REPLACE_INDEX = 5;
333     static constexpr int RESULT_SPLIT_INDEX = 6;
334     static constexpr int RESULT_MATCH_INDEX = 7;
335     static constexpr int RESULT_EXEC_INDEX = 8;
336     static constexpr int RESULT_INTERMEDIATE_REPLACE_INDEX = 9;
337     static constexpr int RESULT_TEST_INDEX = 10;
338     static constexpr int RESULT_SEARCH_INDEX = 11;
339     // Extend index used for saving an additional parameter to judge cached
340     static constexpr int EXTEND_INDEX = 12;
341     static constexpr int CAPTURE_SIZE = 13;
342     static constexpr int ENTRY_SIZE = 14;
343 };
344 
345 class RegExpGlobalResult : public TaggedArray {
346 public:
Cast(TaggedObject * object)347     static RegExpGlobalResult *Cast(TaggedObject *object)
348     {
349         return reinterpret_cast<RegExpGlobalResult *>(object);
350     }
351     static JSTaggedValue CreateGlobalResultTable(JSThread *thread);
352 
SetCapture(JSThread * thread,int index,JSTaggedValue value)353     void SetCapture(JSThread *thread, int index, JSTaggedValue value)
354     {
355         ASSERT(CAPTURE_START_INDEX + index - 1 < GLOBAL_TABLE_SIZE);
356         Set(thread, CAPTURE_START_INDEX + index - 1, value);
357     }
358 
ResetDollar(JSThread * thread)359     void ResetDollar(JSThread *thread)
360     {
361         for (uint32_t i = 0; i < DOLLAR_NUMBER; i++) {
362             Set(thread, CAPTURE_START_INDEX + i, JSTaggedValue::Hole());
363         }
364     }
365 
366     template <int N>
367     static JSTaggedValue GetCapture(JSThread *thread);
368 
SetTotalCaptureCounts(JSThread * thread,JSTaggedValue counts)369     void SetTotalCaptureCounts(JSThread *thread, JSTaggedValue counts)
370     {
371         Set(thread, TOTAL_CAPTURE_COUNTS_INDEX, counts);
372     }
373 
GetTotalCaptureCounts()374     JSTaggedValue GetTotalCaptureCounts()
375     {
376         return Get(TOTAL_CAPTURE_COUNTS_INDEX);
377     }
378 
SetEndIndex(JSThread * thread,JSTaggedValue endIndex)379     void SetEndIndex(JSThread *thread, JSTaggedValue endIndex)
380     {
381         Set(thread, END_INDEX, endIndex);
382     }
383 
GetEndIndex()384     JSTaggedValue GetEndIndex()
385     {
386         return Get(END_INDEX);
387     }
388 
SetInputString(JSThread * thread,JSTaggedValue string)389     void SetInputString(JSThread *thread, JSTaggedValue string)
390     {
391         Set(thread, INPUT_STRING_INDEX, string);
392     }
393 
GetInputString()394     JSTaggedValue GetInputString()
395     {
396         return Get(INPUT_STRING_INDEX);
397     }
398 
SetStartOfCaptureIndex(JSThread * thread,uint32_t index,JSTaggedValue value)399     void SetStartOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value)
400     {
401         Set(thread, FIRST_CAPTURE_INDEX + index * 2, value); // 2 : double
402     }
403 
SetEndOfCaptureIndex(JSThread * thread,uint32_t index,JSTaggedValue value)404     void SetEndOfCaptureIndex(JSThread *thread, uint32_t index, JSTaggedValue value)
405     {
406         Set(thread, FIRST_CAPTURE_INDEX + index * 2 + 1, value); // 2 : double
407     }
408 
GetStartOfCaptureIndex(uint32_t index)409     JSTaggedValue GetStartOfCaptureIndex(uint32_t index)
410     {
411         return Get(FIRST_CAPTURE_INDEX + index * 2); // 2 : double
412     }
413 
GetEndOfCaptureIndex(uint32_t index)414     JSTaggedValue GetEndOfCaptureIndex(uint32_t index)
415     {
416         return Get(FIRST_CAPTURE_INDEX + index * 2 + 1); // 2 : double
417     }
418 
419     static JSHandle<RegExpGlobalResult> GrowCapturesCapacity(JSThread *thread,
420         JSHandle<RegExpGlobalResult>result, uint32_t length);
421 
422     static constexpr int FIRST_CAPTURE_INDEX = 12;  // capture index starts here
423 
424 private:
425     static constexpr int GLOBAL_TABLE_SIZE = 12; // initial length
426     static constexpr int DOLLAR_NUMBER = 9;
427     static constexpr int CAPTURE_START_INDEX = 0;
428 
429     static constexpr int TOTAL_CAPTURE_COUNTS_INDEX = 9;  // save total capture size
430     static constexpr int INPUT_STRING_INDEX = 10; // save input string
431     static constexpr int END_INDEX = 11; // save last index
432     static constexpr int INITIAL_CAPTURE_INDICES = 18;  // length: pairs of capture start index and end index
433 };
434 }  // namespace panda::ecmascript::builtins
435 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H
436