• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_BUILTINS_BUILTINS_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_executor.h"
24 #include "ecmascript/regexp/regexp_parser.h"
25 
26 namespace panda::ecmascript::builtins {
27 class BuiltinsRegExp : public base::BuiltinsBase {
28 public:
29     enum RegExpGlobalArrayIndex {
30         DUMP_HEAD,
31         DOLLAR_ONE,
32         DOLLAR_TWO,
33         DOLLAR_THREE,
34         DOLLAR_FOUR,
35         DOLLAR_FIVE,
36         DOLLAR_SIX,
37         DOLLAR_SEVEN,
38         DOLLAR_EIGHT,
39         DOLLAR_NINE
40     };
41 
42     // 21.2.3.1 RegExp ( pattern, flags )
43     static JSTaggedValue RegExpConstructor(EcmaRuntimeCallInfo *argv);
44 
45     // prototype
46     // 21.2.5.2 RegExp.prototype.exec ( string )
47     static JSTaggedValue Exec(EcmaRuntimeCallInfo *argv);
48     // 21.2.5.13 RegExp.prototype.test( S )
49     static JSTaggedValue Test(EcmaRuntimeCallInfo *argv);
50     // 21.2.5.14 RegExp.prototype.toString ( )
51     static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
52     // 21.2.5.3 get RegExp.prototype.flags
53     static JSTaggedValue GetFlags(EcmaRuntimeCallInfo *argv);
54     // 21.2.5.4 get RegExp.prototype.global
55     static JSTaggedValue GetGlobal(EcmaRuntimeCallInfo *argv);
56     // 21.2.5.5 get RegExp.prototype.ignoreCase
57     static JSTaggedValue GetIgnoreCase(EcmaRuntimeCallInfo *argv);
58     // 21.2.5.7 get RegExp.prototype.multiline
59     static JSTaggedValue GetMultiline(EcmaRuntimeCallInfo *argv);
60     static JSTaggedValue GetDotAll(EcmaRuntimeCallInfo *argv);
61     // 21.2.5.10 get RegExp.prototype.source
62     static JSTaggedValue GetSource(EcmaRuntimeCallInfo *argv);
63     // 21.2.5.12 get RegExp.prototype.sticky
64     static JSTaggedValue GetSticky(EcmaRuntimeCallInfo *argv);
65     // 21.2.5.15 get RegExp.prototype.unicode
66     static JSTaggedValue GetUnicode(EcmaRuntimeCallInfo *argv);
67     // 21.2.4.2 get RegExp [ @@species ]
68     static JSTaggedValue GetSpecies(EcmaRuntimeCallInfo *argv);
69     // 21.2.5.6 RegExp.prototype [ @@match ] ( string )
70     static JSTaggedValue Match(EcmaRuntimeCallInfo *argv);
71     // 22.2.5.8 RegExp.prototype [ @@matchAll ] ( string )
72     static JSTaggedValue MatchAll(EcmaRuntimeCallInfo *argv);
73     // 21.2.5.8 RegExp.prototype [ @@replace ] ( string, replaceValue )
74     static JSTaggedValue Replace(EcmaRuntimeCallInfo *argv);
75     // 21.2.5.9 RegExp.prototype [ @@search ] ( string )
76     static JSTaggedValue Search(EcmaRuntimeCallInfo *argv);
77     // 21.2.5.11 RegExp.prototype [ @@split ] ( string, limit )
78     static JSTaggedValue Split(EcmaRuntimeCallInfo *argv);
79     // 21.2.3.2.3 Runtime Semantics: RegExpCreate ( P, F )
80     static JSTaggedValue RegExpCreate(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
81                                       const JSHandle<JSTaggedValue> &flags);
82     static JSTaggedValue FlagsBitsToString(JSThread *thread, uint8_t flags);
83     // 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S )
84     static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
85                                     const JSHandle<JSTaggedValue> &inputString, bool useCache);
86     // 21.2.5.2.3 AdvanceStringIndex ( S, index, unicode )
87     static uint32_t AdvanceStringIndex(const JSHandle<JSTaggedValue> &inputStr, uint32_t index,
88                                        bool unicode);
89 
90 private:
91     static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000;
92     static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu;
93     static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9;
94 
95     static RegExpExecutor::MatchResult Matcher(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
96                                                const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16);
97 
98     static bool GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
99                                  const uint8_t mask);
100     // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S )
101     static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
102                                            const JSHandle<JSTaggedValue> &inputStr, bool useCache);
103 
104     // 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget )
105     static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget);
106 
107     static uint32_t UpdateExpressionFlags(JSThread *thread, const CString &checkStr);
108 
109     static JSHandle<JSTaggedValue> GetDollarString(JSThread *thread, RegExpGlobalArrayIndex index);
110 
111     // 21.2.3.2.2 Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
112     static JSTaggedValue RegExpInitialize(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
113                                           const JSHandle<JSTaggedValue> &pattern, const JSHandle<JSTaggedValue> &flags);
114     // 21.2.3.2.4 Runtime Semantics: EscapeRegExpPattern ( P, F )
115     static EcmaString *EscapeRegExpPattern(JSThread *thread, const JSHandle<JSTaggedValue> &src,
116                                            const JSHandle<JSTaggedValue> &flags);
117     static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle<JSTaggedValue> &regexp,
118                                            JSHandle<EcmaString> inputString, uint32_t inputLength);
119 };
120 
121 class RegExpExecResultCache : public TaggedArray {
122 public:
123     enum CacheType {
124         REPLACE_TYPE,
125         SPLIT_TYPE,
126         MATCH_TYPE,
127         EXEC_TYPE
128     };
Cast(TaggedObject * object)129     static RegExpExecResultCache *Cast(TaggedObject *object)
130     {
131         return reinterpret_cast<RegExpExecResultCache *>(object);
132     }
133     static JSTaggedValue CreateCacheTable(JSThread *thread);
134     // extend as an additional parameter to judge cached
135     JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> &patten,
136                                    const JSHandle<JSTaggedValue> &flags, const JSHandle<JSTaggedValue> &input,
137                                    CacheType type, const JSHandle<JSTaggedValue> &regexp,
138                                    JSTaggedValue extend = JSTaggedValue::Undefined());
139     // extend as an additional parameter to judge cached
140     static void AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache,
141                                  const JSHandle<JSTaggedValue> &patten, const JSHandle<JSTaggedValue> &flags,
142                                  const JSHandle<JSTaggedValue> &input, const JSHandle<JSTaggedValue> &resultArray,
143                                  CacheType type, uint32_t lastIndex, JSTaggedValue extend = JSTaggedValue::Undefined());
144 
145     static void GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache);
146 
147     void ClearEntry(JSThread *thread, int entry);
148     void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flags, JSTaggedValue &input,
149                   JSTaggedValue &lastIndexValue, JSTaggedValue &extendValue);
150     void UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type);
151     bool Match(int entry, JSTaggedValue &pattenStr, JSTaggedValue &flagsStr, JSTaggedValue &inputStr,
152                JSTaggedValue &extend);
SetHitCount(JSThread * thread,int hitCount)153     inline void SetHitCount(JSThread *thread, int hitCount)
154     {
155         Set(thread, CACHE_HIT_COUNT_INDEX, JSTaggedValue(hitCount));
156     }
157 
GetHitCount()158     inline int GetHitCount()
159     {
160         return Get(CACHE_HIT_COUNT_INDEX).GetInt();
161     }
162 
SetCacheCount(JSThread * thread,int hitCount)163     inline void SetCacheCount(JSThread *thread, int hitCount)
164     {
165         Set(thread, CACHE_COUNT_INDEX, JSTaggedValue(hitCount));
166     }
167 
GetCacheCount()168     inline int GetCacheCount()
169     {
170         return Get(CACHE_COUNT_INDEX).GetInt();
171     }
172 
Print()173     void Print()
174     {
175         std::cout << "cache count: " << GetCacheCount() << std::endl;
176         std::cout << "cache hit count: " << GetHitCount() << std::endl;
177     }
178 
SetLargeStrCount(JSThread * thread,uint32_t newCount)179     inline void SetLargeStrCount(JSThread *thread, uint32_t newCount)
180     {
181         Set(thread, LARGE_STRING_COUNT_INDEX, JSTaggedValue(newCount));
182     }
183 
SetConflictCount(JSThread * thread,uint32_t newCount)184     inline void SetConflictCount(JSThread *thread, uint32_t newCount)
185     {
186         Set(thread, CONFLICT_COUNT_INDEX, JSTaggedValue(newCount));
187     }
188 
SetStrLenThreshold(JSThread * thread,uint32_t newThreshold)189     inline void SetStrLenThreshold(JSThread *thread, uint32_t newThreshold)
190     {
191         Set(thread, STRING_LENGTH_THRESHOLD_INDEX, JSTaggedValue(newThreshold));
192     }
193 
GetLargeStrCount()194     inline uint32_t GetLargeStrCount()
195     {
196         return Get(LARGE_STRING_COUNT_INDEX).GetInt();
197     }
198 
GetConflictCount()199     inline uint32_t GetConflictCount()
200     {
201         return Get(CONFLICT_COUNT_INDEX).GetInt();
202     }
203 
GetStrLenThreshold()204     inline uint32_t GetStrLenThreshold()
205     {
206         return Get(STRING_LENGTH_THRESHOLD_INDEX).GetInt();
207     }
208 
SetCacheLength(JSThread * thread,int length)209     inline void SetCacheLength(JSThread *thread, int length)
210     {
211         Set(thread, CACHE_LENGTH_INDEX, JSTaggedValue(length));
212     }
213 
GetCacheLength()214     inline int GetCacheLength()
215     {
216         return Get(CACHE_LENGTH_INDEX).GetInt();
217     }
218 
219 private:
220     static constexpr int DEFAULT_LARGE_STRING_COUNT = 10;
221     static constexpr int DEFAULT_CONFLICT_COUNT = 100;
222     static constexpr int INITIAL_CACHE_NUMBER = 0x10;
223     static constexpr int DEFAULT_CACHE_NUMBER = 0x1000;
224     static constexpr int CACHE_COUNT_INDEX = 0;
225     static constexpr int CACHE_HIT_COUNT_INDEX = 1;
226     static constexpr int LARGE_STRING_COUNT_INDEX = 2;
227     static constexpr int CONFLICT_COUNT_INDEX = 3;
228     static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4;
229     static constexpr int CACHE_LENGTH_INDEX = 5;
230     static constexpr int CACHE_TABLE_HEADER_SIZE = 6;
231     static constexpr int PATTERN_INDEX = 0;
232     static constexpr int FLAG_INDEX = 1;
233     static constexpr int INPUT_STRING_INDEX = 2;
234     static constexpr int LAST_INDEX_INDEX = 3;
235     static constexpr int RESULT_REPLACE_INDEX = 4;
236     static constexpr int RESULT_SPLIT_INDEX = 5;
237     static constexpr int RESULT_MATCH_INDEX = 6;
238     static constexpr int RESULT_EXEC_INDEX = 7;
239     // Extend index used for saving an additional parameter to judge cached
240     static constexpr int EXTEND_INDEX = 8;
241     static constexpr int ENTRY_SIZE = 9;
242 };
243 }  // namespace panda::ecmascript::builtins
244 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H
245