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> ®exp, 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> ®exp, 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> ®exp, 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> ®exp, 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> ®exp); 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