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