1 /*
2 * Copyright (c) 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_INL_H
17 #define ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_INL_H
18
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_regexp.h"
21 #include "ecmascript/js_array.h"
22
23 namespace panda::ecmascript::builtins {
24
25 /* static */
26 template <int N>
GetCapture(JSThread * thread)27 JSTaggedValue RegExpGlobalResult::GetCapture(JSThread *thread)
28 {
29 JSHandle<JSTaggedValue> table = JSHandle<JSTaggedValue>(thread, RegExpExecResultCache::GetGlobalTable(thread));
30 JSHandle<RegExpGlobalResult> globalTable = JSHandle<RegExpGlobalResult>::Cast(table);
31 JSTaggedValue res = globalTable->Get(thread, CAPTURE_START_INDEX + N - 1);
32 int captureNum = globalTable->GetTotalCaptureCounts().GetInt();
33 if (res.IsHole() && (N < captureNum)) {
34 int startIndex = globalTable->GetStartOfCaptureIndex(N).GetInt();
35 int endIndex = globalTable->GetEndOfCaptureIndex(N).GetInt();
36 int len = endIndex - startIndex;
37 if (len < 0) {
38 res = JSTaggedValue::Undefined();
39 } else {
40 res = JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(),
41 JSHandle<EcmaString>(thread, EcmaString::Cast(globalTable->GetInputString(thread))),
42 static_cast<uint32_t>(startIndex), static_cast<uint32_t>(len)));
43 }
44 globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res);
45 } else if (res.IsHole()) {
46 res = thread->GetEcmaVM()->GetFactory()->GetEmptyString().GetTaggedValue();
47 globalTable->Set(thread, CAPTURE_START_INDEX + N - 1, res);
48 }
49 return res;
50 }
51
52 template <RBMode mode>
FindCachedResult(JSThread * thread,const JSHandle<JSTaggedValue> input,CacheType type,const JSHandle<JSTaggedValue> regexp,JSTaggedValue lastIndexInput,JSHandle<JSTaggedValue> extend,bool isIntermediateResult)53 JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread,
54 const JSHandle<JSTaggedValue> input, CacheType type,
55 const JSHandle<JSTaggedValue> regexp,
56 JSTaggedValue lastIndexInput, JSHandle<JSTaggedValue> extend,
57 bool isIntermediateResult)
58 {
59 JSHandle<JSRegExp> regexpObj(regexp);
60 JSTaggedValue pattern = regexpObj->GetOriginalSource<mode>(thread);
61 JSTaggedValue flags = regexpObj->GetOriginalFlags<mode>(thread);
62 JSTaggedValue inputValue = input.GetTaggedValue();
63 JSTaggedValue extendValue = extend.GetTaggedValue();
64 if (!pattern.IsString() || !flags.IsInt() || !input->IsString() || !lastIndexInput.IsInt()) {
65 return JSTaggedValue::Undefined();
66 }
67 uint32_t hash = pattern.GetKeyHashCode(thread) + static_cast<uint32_t>(flags.GetInt()) +
68 input->GetKeyHashCode(thread) + static_cast<uint32_t>(lastIndexInput.GetInt());
69 uint32_t entry = hash & static_cast<uint32_t>(GetCacheLength() - 1);
70 if (!Match<mode>(thread, entry, pattern, flags, inputValue, lastIndexInput, extendValue, type)) {
71 uint32_t entry2 = (entry + 1) & static_cast<uint32_t>(GetCacheLength() - 1);
72 if (!Match<mode>(thread, entry2, pattern, flags, inputValue, lastIndexInput, extendValue, type)) {
73 return JSTaggedValue::Undefined();
74 }
75 entry = entry2;
76 }
77 ASSERT((static_cast<size_t>(CACHE_TABLE_HEADER_SIZE) +
78 static_cast<size_t>(entry) * static_cast<size_t>(ENTRY_SIZE)) <= static_cast<size_t>(UINT32_MAX));
79 uint32_t index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE;
80 // update cached value if input value is changed
81 JSTaggedValue cachedStr = Get<mode>(thread, index + INPUT_STRING_INDEX);
82 if (!cachedStr.IsUndefined() && cachedStr != inputValue) {
83 Set(thread, index + INPUT_STRING_INDEX, inputValue);
84 }
85 JSTaggedValue result;
86 switch (type) {
87 case REPLACE_TYPE:
88 result = Get<mode>(thread, index + RESULT_REPLACE_INDEX);
89 break;
90 case SPLIT_TYPE:
91 result = Get<mode>(thread, index + RESULT_SPLIT_INDEX);
92 break;
93 case MATCH_TYPE:
94 result = Get<mode>(thread, index + RESULT_MATCH_INDEX);
95 break;
96 case EXEC_TYPE:
97 result = Get<mode>(thread, index + RESULT_EXEC_INDEX);
98 break;
99 case INTERMEDIATE_REPLACE_TYPE:
100 result = Get<mode>(thread, index + RESULT_INTERMEDIATE_REPLACE_INDEX);
101 break;
102 case TEST_TYPE:
103 result = Get<mode>(thread, index + RESULT_TEST_INDEX);
104 break;
105 case SEARCH_TYPE:
106 result = Get<mode>(thread, index + RESULT_SEARCH_INDEX);
107 break;
108 default:
109 LOG_ECMA(FATAL) << "this branch is unreachable";
110 UNREACHABLE();
111 break;
112 }
113 SetLastMatchGlobalTableIndex(thread, index);
114 SetUseLastMatch(thread, true);
115 SetNeedUpdateGlobal(thread, true);
116 SetHitCount(thread, GetHitCount() + 1);
117 if (type != SEARCH_TYPE && type != SPLIT_TYPE) {
118 BuiltinsRegExp::SetLastIndex(thread, regexp, Get<RBMode::FAST_NO_RB>(thread, index + LAST_INDEX_INDEX), true);
119 }
120 if (!isIntermediateResult && result.IsJSArray()) {
121 JSHandle<JSArray> resultHandle(thread, JSArray::Cast(result));
122 JSHandle<JSArray> copyArray = thread->GetEcmaVM()->GetFactory()->CloneArrayLiteral(resultHandle);
123 return copyArray.GetTaggedValue();
124 }
125 return result;
126 }
127
128 template <RBMode mode>
Match(JSThread * thread,int entry,JSTaggedValue & pattern,JSTaggedValue & flags,JSTaggedValue & input,JSTaggedValue & lastIndexInputValue,JSTaggedValue & extend,CacheType type)129 bool RegExpExecResultCache::Match(JSThread *thread, int entry, JSTaggedValue &pattern, JSTaggedValue &flags,
130 JSTaggedValue &input, JSTaggedValue &lastIndexInputValue, JSTaggedValue &extend,
131 CacheType type)
132 {
133 ASSERT((static_cast<size_t>(CACHE_TABLE_HEADER_SIZE) +
134 static_cast<size_t>(entry) * static_cast<size_t>(ENTRY_SIZE)) <= static_cast<size_t>(INT_MAX));
135 int index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE;
136
137 JSTaggedValue typeKey = Get<mode>(thread, index + RESULT_REPLACE_INDEX + type);
138 if (typeKey.IsUndefined()) {
139 return false;
140 }
141
142 JSTaggedValue keyPattern = Get<mode>(thread, index + PATTERN_INDEX);
143 if (keyPattern.IsUndefined()) {
144 return false;
145 }
146
147 uint8_t flagsBits = static_cast<uint8_t>(flags.GetInt());
148 JSTaggedValue keyFlags = Get<RBMode::FAST_NO_RB>(thread, index + FLAG_INDEX);
149 uint8_t keyFlagsBits = static_cast<uint8_t>(keyFlags.GetInt());
150 if (flagsBits != keyFlagsBits) {
151 return false;
152 }
153
154 uint32_t lastIndexInputInt = static_cast<uint32_t>(lastIndexInputValue.GetInt());
155 JSTaggedValue keyLastIndexInput = Get<RBMode::FAST_NO_RB>(thread, index + LAST_INDEX_INPUT_INDEX);
156 uint32_t keyLastIndexInputInt = static_cast<uint32_t>(keyLastIndexInput.GetInt());
157 if (lastIndexInputInt != keyLastIndexInputInt) {
158 return false;
159 }
160
161 JSTaggedValue keyInput = Get<mode>(thread, index + INPUT_STRING_INDEX);
162 JSTaggedValue keyExtend = Get<mode>(thread, index + EXTEND_INDEX);
163 EcmaString *patternStr = EcmaString::Cast(pattern.GetTaggedObject());
164 EcmaString *inputStr = EcmaString::Cast(input.GetTaggedObject());
165 EcmaString *keyPatternStr = EcmaString::Cast(keyPattern.GetTaggedObject());
166 EcmaString *keyInputStr = EcmaString::Cast(keyInput.GetTaggedObject());
167 bool extendEqual = false;
168 if (extend.IsString() && keyExtend.IsString()) {
169 EcmaString *extendStr = EcmaString::Cast(extend.GetTaggedObject());
170 EcmaString *keyExtendStr = EcmaString::Cast(keyExtend.GetTaggedObject());
171 extendEqual = EcmaStringAccessor::StringsAreEqual<mode>(thread, extendStr, keyExtendStr);
172 } else if (extend.IsUndefined() && keyExtend.IsUndefined()) {
173 extendEqual = true;
174 } else {
175 return false;
176 }
177 return extendEqual &&
178 EcmaStringAccessor::StringsAreEqual<mode>(thread, patternStr, keyPatternStr) &&
179 EcmaStringAccessor::StringsAreEqual<mode>(thread, inputStr, keyInputStr);
180 }
181 } // namespace panda::ecmascript::builtins
182 #endif // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_INL_H
183