• 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     // 21.2.3.1 RegExp ( pattern, flags )
30     static JSTaggedValue RegExpConstructor(EcmaRuntimeCallInfo *argv);
31 
32     // prototype
33     // 21.2.5.2 RegExp.prototype.exec ( string )
34     static JSTaggedValue Exec(EcmaRuntimeCallInfo *argv);
35     // 21.2.5.13 RegExp.prototype.test( S )
36     static JSTaggedValue Test(EcmaRuntimeCallInfo *argv);
37     // 21.2.5.14 RegExp.prototype.toString ( )
38     static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
39     // 21.2.5.3 get RegExp.prototype.flags
40     static JSTaggedValue GetFlags(EcmaRuntimeCallInfo *argv);
41     // 21.2.5.4 get RegExp.prototype.global
42     static JSTaggedValue GetGlobal(EcmaRuntimeCallInfo *argv);
43     // 21.2.5.5 get RegExp.prototype.ignoreCase
44     static JSTaggedValue GetIgnoreCase(EcmaRuntimeCallInfo *argv);
45     // 21.2.5.7 get RegExp.prototype.multiline
46     static JSTaggedValue GetMultiline(EcmaRuntimeCallInfo *argv);
47     static JSTaggedValue GetDotAll(EcmaRuntimeCallInfo *argv);
48     // 21.2.5.10 get RegExp.prototype.source
49     static JSTaggedValue GetSource(EcmaRuntimeCallInfo *argv);
50     // 21.2.5.12 get RegExp.prototype.sticky
51     static JSTaggedValue GetSticky(EcmaRuntimeCallInfo *argv);
52     // 21.2.5.15 get RegExp.prototype.unicode
53     static JSTaggedValue GetUnicode(EcmaRuntimeCallInfo *argv);
54     // 21.2.4.2 get RegExp [ @@species ]
55     static JSTaggedValue GetSpecies(EcmaRuntimeCallInfo *argv);
56     // 21.2.5.6 RegExp.prototype [ @@match ] ( string )
57     static JSTaggedValue Match(EcmaRuntimeCallInfo *argv);
58     // 21.2.5.8 RegExp.prototype [ @@replace ] ( string, replaceValue )
59     static JSTaggedValue Replace(EcmaRuntimeCallInfo *argv);
60     // 21.2.5.9 RegExp.prototype [ @@search ] ( string )
61     static JSTaggedValue Search(EcmaRuntimeCallInfo *argv);
62     // 21.2.5.11 RegExp.prototype [ @@split ] ( string, limit )
63     static JSTaggedValue Split(EcmaRuntimeCallInfo *argv);
64     // 21.2.3.2.3 Runtime Semantics: RegExpCreate ( P, F )
65     static JSTaggedValue RegExpCreate(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
66                                       const JSHandle<JSTaggedValue> &flags);
67     static JSTaggedValue FlagsBitsToString(JSThread *thread, uint8_t flags);
68 
69 private:
70     static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000;
71     static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu;
72 
73     static RegExpExecutor::MatchResult Matcher(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
74                                                const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16);
75     // 21.2.5.2.3 AdvanceStringIndex ( S, index, unicode )
76     static uint32_t AdvanceStringIndex(JSThread *thread, const JSHandle<JSTaggedValue> &inputStr, uint32_t index,
77                                        bool unicode);
78 
79     static bool GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
80                                  const uint8_t mask);
81     // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S )
82     static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
83                                            const JSHandle<JSTaggedValue> &inputStr, bool isCached);
84     // 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S )
85     static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
86                                     const JSHandle<JSTaggedValue> &inputString, bool isCached);
87     // 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget )
88     static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget);
89 
90     static uint32_t UpdateExpressionFlags(JSThread *thread, const CString &checkStr);
91 
92     // 21.2.3.2.2 Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
93     static JSTaggedValue RegExpInitialize(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
94                                           const JSHandle<JSTaggedValue> &pattern, const JSHandle<JSTaggedValue> &flags);
95     // 21.2.3.2.4 Runtime Semantics: EscapeRegExpPattern ( P, F )
96     static EcmaString *EscapeRegExpPattern(JSThread *thread, const JSHandle<JSTaggedValue> &src,
97                                            const JSHandle<JSTaggedValue> &flags);
98     static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle<JSTaggedValue> &regexp,
99                                            JSHandle<EcmaString> inputString, uint32_t inputLength);
100 };
101 
102 class RegExpExecResultCache : public TaggedArray {
103 public:
104     enum CacheType {
105         REPLACE_TYPE,
106         SPLIT_TYPE,
107         MATCH_TYPE,
108         EXEC_TYPE
109     };
Cast(TaggedObject * object)110     static RegExpExecResultCache *Cast(TaggedObject *object)
111     {
112         return reinterpret_cast<RegExpExecResultCache *>(object);
113     }
114     static JSTaggedValue CreateCacheTable(JSThread *thread);
115     JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> &patten,
116                                    const JSHandle<JSTaggedValue> &flags, const JSHandle<JSTaggedValue> &input,
117                                    CacheType type, const JSHandle<JSTaggedValue> &regexp);
118     static void AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache,
119                                  const JSHandle<JSTaggedValue> &patten, const JSHandle<JSTaggedValue> &flags,
120                                  const JSHandle<JSTaggedValue> &input, const JSHandle<JSTaggedValue> &resultArray,
121                                  CacheType type, uint32_t lastIndex);
122 
123     static void GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache);
124 
125     void ClearEntry(JSThread *thread, int entry);
126     void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flags, JSTaggedValue &input,
127                   JSTaggedValue &lastIndexValue);
128     void UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type);
129     bool Match(int entry, JSTaggedValue &pattenStr, JSTaggedValue &flagsStr, JSTaggedValue &inputStr);
SetHitCount(JSThread * thread,int hitCount)130     inline void SetHitCount(JSThread *thread, int hitCount)
131     {
132         Set(thread, CACHE_HIT_COUNT_INDEX, JSTaggedValue(hitCount));
133     }
134 
GetHitCount()135     inline int GetHitCount()
136     {
137         return Get(CACHE_HIT_COUNT_INDEX).GetInt();
138     }
139 
SetCacheCount(JSThread * thread,int hitCount)140     inline void SetCacheCount(JSThread *thread, int hitCount)
141     {
142         Set(thread, CACHE_COUNT_INDEX, JSTaggedValue(hitCount));
143     }
144 
GetCacheCount()145     inline int GetCacheCount()
146     {
147         return Get(CACHE_COUNT_INDEX).GetInt();
148     }
149 
Print()150     void Print()
151     {
152         std::cout << "cache count: " << GetCacheCount() << std::endl;
153         std::cout << "cache hit count: " << GetHitCount() << std::endl;
154     }
155 
SetLargeStrCount(JSThread * thread,uint32_t newCount)156     inline void SetLargeStrCount(JSThread *thread, uint32_t newCount)
157     {
158         Set(thread, LARGE_STRING_COUNT_INDEX, JSTaggedValue(newCount));
159     }
160 
SetConflictCount(JSThread * thread,uint32_t newCount)161     inline void SetConflictCount(JSThread *thread, uint32_t newCount)
162     {
163         Set(thread, CONFLICT_COUNT_INDEX, JSTaggedValue(newCount));
164     }
165 
SetStrLenThreshold(JSThread * thread,uint32_t newThreshold)166     inline void SetStrLenThreshold(JSThread *thread, uint32_t newThreshold)
167     {
168         Set(thread, STRING_LENGTH_THRESHOLD_INDEX, JSTaggedValue(newThreshold));
169     }
170 
GetLargeStrCount()171     inline uint32_t GetLargeStrCount()
172     {
173         return Get(LARGE_STRING_COUNT_INDEX).GetInt();
174     }
175 
GetConflictCount()176     inline uint32_t GetConflictCount()
177     {
178         return Get(CONFLICT_COUNT_INDEX).GetInt();
179     }
180 
GetStrLenThreshold()181     inline uint32_t GetStrLenThreshold()
182     {
183         return Get(STRING_LENGTH_THRESHOLD_INDEX).GetInt();
184     }
185 
SetCacheLength(JSThread * thread,int length)186     inline void SetCacheLength(JSThread *thread, int length)
187     {
188         Set(thread, CACHE_LENGTH_INDEX, JSTaggedValue(length));
189     }
190 
GetCacheLength()191     inline int GetCacheLength()
192     {
193         return Get(CACHE_LENGTH_INDEX).GetInt();
194     }
195 
196 private:
197     static constexpr int DEFAULT_LARGE_STRING_COUNT = 10;
198     static constexpr int DEFAULT_CONFLICT_COUNT = 100;
199     static constexpr int INITIAL_CACHE_NUMBER = 0x10;
200     static constexpr int DEFAULT_CACHE_NUMBER = 0x1000;
201     static constexpr int CACHE_COUNT_INDEX = 0;
202     static constexpr int CACHE_HIT_COUNT_INDEX = 1;
203     static constexpr int LARGE_STRING_COUNT_INDEX = 2;
204     static constexpr int CONFLICT_COUNT_INDEX = 3;
205     static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4;
206     static constexpr int CACHE_LENGTH_INDEX = 5;
207     static constexpr int CACHE_TABLE_HEADER_SIZE = 6;
208     static constexpr int PATTERN_INDEX = 0;
209     static constexpr int FLAG_INDEX = 1;
210     static constexpr int INPUT_STRING_INDEX = 2;
211     static constexpr int LAST_INDEX_INDEX = 3;
212     static constexpr int RESULT_REPLACE_INDEX = 4;
213     static constexpr int RESULT_SPLIT_INDEX = 5;
214     static constexpr int RESULT_MATCH_INDEX = 6;
215     static constexpr int RESULT_EXEC_INDEX = 7;
216     static constexpr int ENTRY_SIZE = 8;
217 };
218 }  // namespace panda::ecmascript::builtins
219 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H
220