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