resolve issue of taking 2 seconds to response after clicking mediaquery

Signed-off-by: xujie <xujie101@huawei.com>
This commit is contained in:
xujie 2021-09-10 10:16:05 +08:00
parent c89a833110
commit fa3ad69451
8 changed files with 329 additions and 131 deletions

View File

@ -76,6 +76,13 @@ public:
return u16str;
}
static inline std::string Utf8ToString(const uint8_t *utf8Data, uint32_t dataLen)
{
auto *charData = reinterpret_cast<const char *>(utf8Data);
std::string str(charData, dataLen);
return str;
}
static inline std::u16string Utf8ToU16String(const uint8_t *utf8Data, uint32_t dataLen)
{
auto *charData = reinterpret_cast<const char *>(utf8Data);
@ -104,6 +111,12 @@ public:
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(str);
}
static inline size_t Find(const std::string &thisStr, const std::string &searchStr, int32_t pos)
{
size_t idx = thisStr.find(searchStr, pos);
return idx;
}
static inline size_t Find(const std::u16string &thisStr, const std::u16string &searchStr, int32_t pos)
{
size_t idx = thisStr.find(searchStr, pos);

View File

@ -19,6 +19,7 @@
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/internal_call_params.h"
#include "ecmascript/interpreter/fast_runtime_stub-inl.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_hclass.h"
@ -65,12 +66,13 @@ JSTaggedValue BuiltinsRegExp::RegExpConstructor(EcmaRuntimeCallInfo *argv)
// 4.b If patternIsRegExp is true and flags is undefined
if (patternIsRegExp && flags->IsUndefined()) {
// 4.b.i Let patternConstructor be Get(pattern, "constructor").
JSHandle<JSTaggedValue> patternConstructor =
JSObject::GetProperty(thread, pattern, constructorString).GetValue();
JSTaggedValue patternConstructor =
FastRuntimeStub::FastGetPropertyByName(thread, pattern.GetTaggedValue(),
constructorString.GetTaggedValue());
// 4.b.ii ReturnIfAbrupt(patternConstructor).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 4.b.iii If SameValue(newTarget, patternConstructor) is true, return pattern.
if (JSTaggedValue::SameValue(newTarget.GetTaggedValue(), patternConstructor.GetTaggedValue())) {
if (JSTaggedValue::SameValue(newTarget.GetTaggedValue(), patternConstructor)) {
return pattern.GetTaggedValue();
}
}
@ -155,8 +157,14 @@ JSTaggedValue BuiltinsRegExp::Exec(EcmaRuntimeCallInfo *argv)
// throw a TypeError exception.
THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have [[RegExpMatcher]]", JSTaggedValue::Exception());
}
bool isCached = true;
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
if (cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount()) {
isCached = false;
}
// 6. Return RegExpBuiltinExec(R, S).
JSTaggedValue result = RegExpBuiltinExec(thread, thisObj, string);
JSTaggedValue result = RegExpBuiltinExec(thread, thisObj, string, isCached);
return JSTaggedValue(result);
}
@ -182,7 +190,7 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv)
}
// 5. Let match be RegExpExec(R, string).
JSTaggedValue matchResult = RegExpExec(thread, thisObj, string);
JSTaggedValue matchResult = RegExpExec(thread, thisObj, string, false);
// 6. ReturnIfAbrupt(match).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 7. If match is not null, return true; else return false.
@ -368,6 +376,11 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
// 3. Let S be ToString(string)
JSHandle<JSTaggedValue> inputString = GetCallArg(argv, 0);
JSHandle<EcmaString> stringHandle = JSTaggedValue::ToString(thread, inputString);
bool isCached = true;
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
if (cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount()) {
isCached = false;
}
// 4. ReturnIfAbrupt(string).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> string = JSHandle<JSTaggedValue>::Cast(stringHandle);
@ -376,29 +389,44 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
}
// 5. Let global be ToBoolean(Get(rx, "global")).
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> global(factory->NewFromCanBeCompressString("global"));
auto globalValue = JSObject::GetProperty(thread, thisObj, global).GetValue();
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
JSHandle<JSTaggedValue> global = globalConst->GetHandledGlobalString();
JSTaggedValue globalValue = FastRuntimeStub::FastGetPropertyByName(thread, thisObj.GetTaggedValue(),
global.GetTaggedValue());
// 6. ReturnIfAbrupt(global).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool isGlobal = globalValue->ToBoolean();
bool isGlobal = globalValue.ToBoolean();
// 7. If global is false, then
if (!isGlobal) {
// a. Return RegExpExec(rx, S).
JSTaggedValue result = RegExpExec(thread, thisObj, string);
JSTaggedValue result = RegExpExec(thread, thisObj, string, isCached);
return JSTaggedValue(result);
}
JSHandle<JSRegExp> regexpObj(thisObj);
JSHandle<JSTaggedValue> pattern(thread, regexpObj->GetOriginalSource());
JSHandle<JSTaggedValue> flag(thread, regexpObj->GetOriginalFlags());
if (isCached) {
JSTaggedValue cacheResult =
cacheTable->FindCachedResult(
thread, pattern, flag, inputString, RegExpExecResultCache::MATCH_TYPE, thisObj);
if (cacheResult != JSTaggedValue::Undefined()) {
return cacheResult;
}
}
// 8. Else global is true
// a. Let fullUnicode be ToBoolean(Get(rx, "unicode")).
JSHandle<JSTaggedValue> unicode(factory->NewFromCanBeCompressString("unicode"));
JSHandle<JSTaggedValue> unicodeHandle = JSObject::GetProperty(thread, thisObj, unicode).GetValue();
JSHandle<JSTaggedValue> unicode = globalConst->GetHandledUnicodeString();
JSTaggedValue uincodeValue = FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(),
unicode.GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool fullUnicode = unicodeHandle->ToBoolean();
bool fullUnicode = uincodeValue.ToBoolean();
// b. ReturnIfAbrupt(fullUnicode)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. Let setStatus be Set(rx, "lastIndex", 0, true).
JSHandle<JSTaggedValue> lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString());
JSHandle<JSTaggedValue> lastIndexString(globalConst->GetHandledLastIndexString());
JSHandle<JSTaggedValue> value(thread, JSTaggedValue(0));
FastRuntimeStub::FastSetProperty(thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue(),
JSTaggedValue(0), true);
JSObject::SetProperty(thread, thisObj, lastIndexString, value, true);
// d. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -410,7 +438,7 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
// g. Repeat,
while (true) {
// i. Let result be RegExpExec(rx, S).
result.Update(RegExpExec(thread, thisObj, string));
result.Update(RegExpExec(thread, thisObj, string, isCached));
// ii. ReturnIfAbrupt(result).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// iii. If result is null, then
@ -419,13 +447,18 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
if (resultNum == 0) {
return JSTaggedValue::Null();
}
if (isCached) {
cacheTable->AddResultInCache(thread, pattern, flag, inputString, array.GetTaggedValue(),
RegExpExecResultCache::MATCH_TYPE, 0);
}
// 2. Else, return A.
return array.GetTaggedValue();
}
// iv. Else result is not null,
// 1. Let matchStr be ToString(Get(result, "0")).
JSHandle<JSTaggedValue> zoreString(factory->NewFromCanBeCompressString("0"));
JSHandle<JSTaggedValue> matchStr(JSObject::GetProperty(thread, result, zoreString).GetValue());
JSHandle<JSTaggedValue> zeroString = globalConst->GetHandledZeroString();
JSHandle<JSTaggedValue> matchStr(
thread, FastRuntimeStub::FastGetProperty(thread, result.GetTaggedValue(), zeroString.GetTaggedValue()));
JSHandle<EcmaString> matchString = JSTaggedValue::ToString(thread, matchStr);
// 2. ReturnIfAbrupt(matchStr).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -435,16 +468,18 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
// 5. If matchStr is the empty String, then
if (JSTaggedValue::ToString(thread, matchValue)->GetLength() == 0) {
// a. Let thisIndex be ToLength(Get(rx, "lastIndex")).
JSHandle<JSTaggedValue> lastIndexHandle =
JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue();
JSHandle<JSTaggedValue> lastIndexHandle(
thread, FastRuntimeStub::FastGetProperty(
thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue()));
JSTaggedNumber thisIndex = JSTaggedValue::ToLength(thread, lastIndexHandle);
// b. ReturnIfAbrupt(thisIndex).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
// d. Let setStatus be Set(rx, "lastIndex", nextIndex, true).
JSHandle<JSTaggedValue> nextIndex(
thread, JSTaggedValue(AdvanceStringIndex(thread, string, thisIndex.GetNumber(), fullUnicode)));
JSObject::SetProperty(thread, thisObj, lastIndexString, nextIndex, true);
JSTaggedValue nextIndex =
JSTaggedValue(AdvanceStringIndex(thread, string, thisIndex.GetNumber(), fullUnicode));
FastRuntimeStub::FastSetProperty(thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue(),
nextIndex, true);
// e. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
@ -466,22 +501,41 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
JSHandle<JSTaggedValue> lastIndexHandle(thread->GlobalConstants()->GetHandledLastIndexString());
uint32_t lastIndex;
JSHandle<JSRegExp> regexpHandle(regexp);
bool isCached = false;
if ((flags & (RegExpParser::FLAG_STICKY | RegExpParser::FLAG_GLOBAL)) == 0) {
lastIndex = 0;
} else {
JSHandle<JSTaggedValue> thisIndexHandle = JSObject::GetProperty(thread, regexp, lastIndexHandle).GetValue();
lastIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSTaggedValue thisIndex =
FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue());
if (thisIndex.IsInt()) {
lastIndex = thisIndex.GetInt();
} else {
JSHandle<JSTaggedValue> thisIndexHandle(thread, thisIndex);
lastIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
JSHandle<JSTaggedValue> tagInputString = JSHandle<JSTaggedValue>::Cast(inputString);
JSHandle<JSTaggedValue> pattern(thread, regexpHandle->GetOriginalSource());
JSHandle<JSTaggedValue> flag(thread, regexpHandle->GetOriginalFlags());
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
if (lastIndex == 0 && inputLength > MIN_REPLACE_STRING_LENGTH) {
uint32_t length = inputString->GetLength();
uint32_t largeStrCount = cacheTable->GetLargeStrCount();
if (largeStrCount != 0) {
if (length > MIN_REPLACE_STRING_LENGTH) {
cacheTable->SetLargeStrCount(thread, --largeStrCount);
}
} else {
cacheTable->SetStrLenThreshold(thread, MIN_REPLACE_STRING_LENGTH);
}
if (lastIndex == 0 && length > cacheTable->GetStrLenThreshold()) {
isCached = true;
}
if (isCached) {
JSTaggedValue cacheResult =
cacheTable->FindCachedResult(thread, pattern, flag, tagInputString, RegExpExecResultCache::REPLACE_TYPE);
cacheTable->FindCachedResult(thread, pattern, flag, tagInputString, RegExpExecResultCache::REPLACE_TYPE,
regexp);
if (cacheResult != JSTaggedValue::Undefined()) {
return cacheResult;
}
@ -545,9 +599,9 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
}
resultString += base::StringHelper::SubString(thread, inputString, nextPosition, inputLength - nextPosition);
JSTaggedValue resultValue = factory->NewFromStdString(resultString).GetTaggedValue();
if (lastIndex == 0 && inputLength > MIN_REPLACE_STRING_LENGTH) {
if (isCached) {
cacheTable->AddResultInCache(thread, pattern, flag, tagInputString, resultValue,
RegExpExecResultCache::REPLACE_TYPE);
RegExpExecResultCache::REPLACE_TYPE, lastIndex);
}
return resultValue;
}
@ -570,12 +624,13 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> string = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> inputReplaceValue = GetCallArg(argv, 1);
JSHandle<EcmaString> srcString = JSTaggedValue::ToString(thread, string);
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
// 4. ReturnIfAbrupt(S).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> inputStr = JSHandle<JSTaggedValue>::Cast(srcString);
// 5. Let lengthS be the number of code unit elements in S.
uint32_t length = static_cast<EcmaString *>(inputStr->GetTaggedObject())->GetLength();
uint32_t length = srcString->GetLength();
// 6. Let functionalReplace be IsCallable(replaceValue).
bool functionalReplace = inputReplaceValue->IsCallable();
JSHandle<EcmaString> replaceValueHandle;
@ -583,49 +638,52 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
replaceValueHandle = JSTaggedValue::ToString(thread, inputReplaceValue);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
JSHandle<JSTaggedValue> lastIndex(thread->GlobalConstants()->GetHandledLastIndexString());
JSHandle<JSTaggedValue> lastIndex = globalConst->GetHandledLastIndexString();
// 8. Let global be ToBoolean(Get(rx, "global")).
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> global(factory->NewFromCanBeCompressString("global"));
auto globalValue = JSObject::GetProperty(thread, thisObj, global).GetValue();
JSHandle<JSTaggedValue> global = globalConst->GetHandledGlobalString();
JSTaggedValue globalValue = FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(),
global.GetTaggedValue());
// 9. ReturnIfAbrupt(global).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool isGlobal = globalValue->ToBoolean();
bool isGlobal = globalValue.ToBoolean();
// 10. If global is true, then
bool fullUnicode = false;
if (isGlobal) {
// a. Let fullUnicode be ToBoolean(Get(rx, "unicode")).
JSHandle<JSTaggedValue> unicode(factory->NewFromCanBeCompressString("unicode"));
JSHandle<JSTaggedValue> fullUnicodeHandle = JSObject::GetProperty(thread, thisObj, unicode).GetValue();
JSHandle<JSTaggedValue> unicode = globalConst->GetHandledUnicodeString();
JSTaggedValue fullUnicodeTag =
FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), unicode.GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
fullUnicode = fullUnicodeHandle->ToBoolean();
fullUnicode = fullUnicodeTag.ToBoolean();
// b. ReturnIfAbrupt(fullUnicode).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. Let setStatus be Set(rx, "lastIndex", 0, true).
JSHandle<JSTaggedValue> lastIndexValue(thread, JSTaggedValue(0));
JSObject::SetProperty(thread, thisObj, lastIndex, lastIndexValue, true);
FastRuntimeStub::FastSetProperty(
thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), JSTaggedValue(0), true);
// d. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
if (isGlobal && !functionalReplace && (replaceValueHandle->GetLength() == 0) && thisObj->IsJSRegExp()) {
JSHClass *hclass = JSHandle<JSObject>::Cast(thisObj)->GetJSHClass();
JSHClass *originHClass = JSHClass::Cast(thread->GlobalConstants()->GetJSRegExpClass().GetTaggedObject());
JSHClass *originHClass = JSHClass::Cast(globalConst->GetJSRegExpClass().GetTaggedObject());
if (hclass == originHClass) {
return RegExpReplaceFast(thread, thisObj, srcString, length);
}
}
JSHandle<JSTaggedValue> matchedStr(factory->NewFromCanBeCompressString("0"));
JSHandle<JSTaggedValue> matchedStr = globalConst->GetHandledZeroString();
// 11. Let results be a new empty List.
JSHandle<JSObject> resultsList(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
int resultsIndex = 0;
// 12. Let done be false.
// 13. Repeat, while done is false
JSMutableHandle<JSTaggedValue> nextIndexHandle(thread, JSTaggedValue(0));
JSMutableHandle<JSTaggedValue> execResult(thread, JSTaggedValue(0));
for (;;) {
// a. Let result be RegExpExec(rx, S).
JSHandle<JSTaggedValue> execResult(thread, RegExpExec(thread, thisObj, inputStr));
execResult.Update(RegExpExec(thread, thisObj, inputStr, false));
// b. ReturnIfAbrupt(result).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. If result is null, set done to true.
@ -640,22 +698,30 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
break;
}
// iii. Else, 1. Let matchStr be ToString(Get(result, "0")).
JSHandle<JSTaggedValue> getMatch = JSObject::GetProperty(thread, execResult, matchedStr).GetValue();
JSHandle<JSTaggedValue> getMatch(
thread, FastRuntimeStub::FastGetProperty(thread, execResult.GetTaggedValue(), matchedStr.GetTaggedValue()));
JSHandle<EcmaString> matchString = JSTaggedValue::ToString(thread, getMatch);
// 2. ReturnIfAbrupt(matchStr).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. If matchStr is the empty String, then
if (matchString->GetLength() == 0) {
// a. Let thisIndex be ToLength(Get(rx, "lastIndex")).
JSHandle<JSTaggedValue> thisIndexHandle = JSObject::GetProperty(thread, thisObj, lastIndex).GetValue();
uint32_t thisIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber();
// b. ReturnIfAbrupt(thisIndex).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> thisIndexHandle(
thread, FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue()));
uint32_t thisIndex = 0;
if (thisIndexHandle->IsInt()) {
thisIndex = thisIndexHandle->GetInt();
} else {
thisIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber();
// b. ReturnIfAbrupt(thisIndex).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
// c. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
uint32_t nextIndex = AdvanceStringIndex(thread, inputStr, thisIndex, fullUnicode);
nextIndexHandle.Update(JSTaggedValue(nextIndex));
// d. Let setStatus be Set(rx, "lastIndex", nextIndex, true).
JSObject::SetProperty(thread, thisObj, lastIndex, nextIndexHandle, true);
FastRuntimeStub::FastSetProperty(
thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), nextIndexHandle.GetTaggedValue(), true);
// e. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
@ -665,13 +731,16 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
// 15. Let nextSourcePosition be 0.
uint32_t nextSourcePosition = 0;
JSHandle<JSTaggedValue> getMatchString;
JSMutableHandle<JSTaggedValue> resultValues(thread, JSTaggedValue(0));
JSMutableHandle<JSTaggedValue> ncapturesHandle(thread, JSTaggedValue(0));
JSMutableHandle<JSTaggedValue> capN(thread, JSTaggedValue(0));
// 16. Repeat, for each result in results,
for (int i = 0; i < resultsIndex; i++) {
JSHandle<JSTaggedValue> resultValues =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(resultsList), i).GetValue();
resultValues.Update(FastRuntimeStub::FastGetPropertyByIndex(thread, resultsList.GetTaggedValue(), i));
// a. Let nCaptures be ToLength(Get(result, "length")).
JSHandle<JSTaggedValue> lengthHandle = thread->GlobalConstants()->GetHandledLengthString();
JSHandle<JSTaggedValue> ncapturesHandle = JSObject::GetProperty(thread, resultValues, lengthHandle).GetValue();
JSHandle<JSTaggedValue> lengthHandle = globalConst->GetHandledLengthString();
ncapturesHandle.Update(
FastRuntimeStub::FastGetProperty(thread, resultValues.GetTaggedValue(), lengthHandle.GetTaggedValue()));
uint32_t ncaptures = JSTaggedValue::ToUint32(thread, ncapturesHandle);
// b. ReturnIfAbrupt(nCaptures).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -687,9 +756,14 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
// g. Let position be ToInteger(Get(result, "index")).
JSHandle<JSTaggedValue> resultIndex(factory->NewFromCanBeCompressString("index"));
JSHandle<JSTaggedValue> positionHandle = JSObject::GetProperty(thread, resultValues, resultIndex).GetValue();
uint32_t position = JSTaggedValue::ToUint32(thread, positionHandle);
// h. ReturnIfAbrupt(position).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t position = 0;
if (positionHandle->IsInt()) {
position = positionHandle->GetInt();
} else {
position = JSTaggedValue::ToUint32(thread, positionHandle);
// h. ReturnIfAbrupt(position).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
// i. Let position be max(min(position, lengthS), 0).
position = std::max<uint32_t>(std::min<uint32_t>(position, length), 0);
// j. Let n be 1.
@ -699,7 +773,7 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
// l. Repeat while n ≤ nCaptures
while (index <= ncaptures) {
// i. Let capN be Get(result, ToString(n)).
JSHandle<JSTaggedValue> capN = JSObject::GetProperty(thread, resultValues, index).GetValue();
capN.Update(FastRuntimeStub::FastGetPropertyByIndex(thread, resultValues.GetTaggedValue(), index));
// ii. ReturnIfAbrupt(capN).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// iii. If capN is not undefined, then
@ -734,7 +808,7 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
replacerArgs->Set(thread, index + 1, JSTaggedValue(position));
replacerArgs->Set(thread, index + 2, inputStr.GetTaggedValue()); // 2: position of string
// iv. Let replValue be Call(replaceValue, undefined, replacerArgs).
JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
ecmascript::InternalCallParams *args = thread->GetInternalCallParams();
args->MakeArgList(*replacerArgs);
JSTaggedValue replaceResult =
@ -807,7 +881,7 @@ JSTaggedValue BuiltinsRegExp::Search(EcmaRuntimeCallInfo *argv)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
// 6. Let result be ? RegExpExec(rx, S).
JSHandle<JSTaggedValue> result(thread, RegExpExec(thread, thisObj, string));
JSHandle<JSTaggedValue> result(thread, RegExpExec(thread, thisObj, string, false));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 7. Let currentLastIndex be ? Get(rx, "lastIndex").
JSHandle<JSTaggedValue> currentLastIndex = JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue();
@ -836,6 +910,7 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
BUILTINS_API_TRACE(argv->GetThread(), RegExp, Split);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
bool isCached = false;
// 1. Let rx be the this value.
JSHandle<JSTaggedValue> thisObj = GetThis(argv);
auto ecmaVm = thread->GetEcmaVM();
@ -895,13 +970,18 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
if (lim == MAX_SPLIT_LIMIT) {
isCached = true;
}
JSHandle<JSRegExp> regexpHandle(thisObj);
JSHandle<JSTaggedValue> pattern(thread, regexpHandle->GetOriginalSource());
JSHandle<JSTaggedValue> flag(thread, regexpHandle->GetOriginalFlags());
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
if (lim == MAX_SPLIT_LIMIT) {
if (isCached) {
JSTaggedValue cacheResult =
cacheTable->FindCachedResult(thread, pattern, flag, inputString, RegExpExecResultCache::SPLIT_TYPE);
cacheTable->FindCachedResult(thread, pattern, flag, inputString, RegExpExecResultCache::SPLIT_TYPE,
thisObj);
if (cacheResult != JSTaggedValue::Undefined()) {
return cacheResult;
}
@ -934,7 +1014,7 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
// 22. If size = 0, then
if (size == 0) {
// a. Let z be RegExpExec(splitter, S).
JSHandle<JSTaggedValue> execResult(thread, RegExpExec(thread, splitter, jsString));
JSHandle<JSTaggedValue> execResult(thread, RegExpExec(thread, splitter, jsString, isCached));
// b. ReturnIfAbrupt(z).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. If z is not null, return A.
@ -958,7 +1038,7 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
JSObject::SetProperty(thread, splitter, lastIndexString, lastIndexvalue, true);
// b. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> execResult(thread, RegExpExec(thread, splitter, jsString));
JSHandle<JSTaggedValue> execResult(thread, RegExpExec(thread, splitter, jsString, isCached));
// d. ReturnIfAbrupt(z).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// e. If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
@ -990,9 +1070,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
++aLength;
// 5. If lengthA = lim, return A.
if (aLength == lim) {
if (lim == MAX_SPLIT_LIMIT) {
if (isCached) {
cacheTable->AddResultInCache(thread, pattern, flag, inputString, array.GetTaggedValue(),
RegExpExecResultCache::SPLIT_TYPE);
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
}
return array.GetTaggedValue();
}
@ -1024,9 +1104,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
++aLength;
// f. If lengthA = lim, return A.
if (aLength == lim) {
if (lim == MAX_SPLIT_LIMIT) {
if (isCached) {
cacheTable->AddResultInCache(thread, pattern, flag, inputString, array.GetTaggedValue(),
RegExpExecResultCache::SPLIT_TYPE);
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
}
return array.GetTaggedValue();
}
@ -1046,7 +1126,7 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
JSObject::CreateDataProperty(thread, array, aLength, tValue);
if (lim == MAX_SPLIT_LIMIT) {
cacheTable->AddResultInCache(thread, pattern, flag, inputString, array.GetTaggedValue(),
RegExpExecResultCache::SPLIT_TYPE);
RegExpExecResultCache::SPLIT_TYPE, endIndex);
}
// 28. Return A.
return array.GetTaggedValue();
@ -1162,34 +1242,53 @@ bool BuiltinsRegExp::GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedV
// 21.2.5.2.2
JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputStr)
const JSHandle<JSTaggedValue> &inputStr, bool isCached)
{
ASSERT(JSObject::IsRegExp(thread, regexp));
ASSERT(inputStr->IsString());
int32_t length = static_cast<EcmaString *>(inputStr->GetTaggedObject())->GetLength();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> lastIndexHandle(thread->GlobalConstants()->GetHandledLastIndexString());
JSHandle<JSTaggedValue> lastIndexResult = JSObject::GetProperty(thread, regexp, lastIndexHandle).GetValue();
JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult);
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
JSHandle<JSTaggedValue> lastIndexHandle = globalConst->GetHandledLastIndexString();
JSTaggedValue result = FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(),
lastIndexHandle.GetTaggedValue());
int32_t lastIndex = 0;
if (result.IsInt()) {
lastIndex = result.GetInt();
} else {
JSHandle<JSTaggedValue> lastIndexResult(thread, result);
JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
lastIndex = lastIndexNumber.GetNumber();
}
JSHandle<JSTaggedValue> globalHandle = globalConst->GetHandledGlobalString();
bool global =
FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), globalHandle.GetTaggedValue()).ToBoolean();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t lastIndex = lastIndexNumber.GetNumber();
JSHandle<JSTaggedValue> globalHandle(factory->NewFromCanBeCompressString("global"));
bool global = JSObject::GetProperty(thread, regexp, globalHandle).GetValue()->ToBoolean();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> stickyHandle(factory->NewFromCanBeCompressString("sticky"));
bool sticky = JSObject::GetProperty(thread, regexp, stickyHandle).GetValue()->ToBoolean();
JSHandle<JSTaggedValue> stickyHandle = globalConst->GetHandledStickyString();
bool sticky =
FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), stickyHandle.GetTaggedValue()).ToBoolean();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!global && !sticky) {
lastIndex = 0;
}
JSHandle<JSRegExp> regexpObj(thread, JSRegExp::Cast(regexp->GetTaggedObject()));
JSHandle<JSRegExp> regexpObj(regexp);
JSHandle<JSTaggedValue> pattern(thread, regexpObj->GetOriginalSource());
JSHandle<JSTaggedValue> flag(thread, regexpObj->GetOriginalFlags());
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
if (lastIndex == 0 && isCached) {
JSTaggedValue cacheResult =
cacheTable->FindCachedResult(thread, pattern, flag, inputStr, RegExpExecResultCache::EXEC_TYPE, regexp);
if (cacheResult != JSTaggedValue::Undefined()) {
return cacheResult;
}
}
auto flagsStr = static_cast<EcmaString *>(regexpObj->GetOriginalFlags().GetTaggedObject());
JSHandle<EcmaString> uString = factory->NewFromCanBeCompressString("u");
JSHandle<EcmaString> uString(globalConst->GetHandledUString());
[[maybe_unused]] bool fullUnicode = base::StringHelper::Contains(flagsStr, *uString);
if (lastIndex > length) {
JSHandle<JSTaggedValue> lastIndexValue(thread, JSTaggedValue(0));
JSObject::SetProperty(thread, regexp, lastIndexHandle, lastIndexValue, true);
FastRuntimeStub::FastSetPropertyByValue(
thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), JSTaggedValue(0));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::Null();
}
@ -1212,7 +1311,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
if (!matchResult.isSuccess_) {
if (global || sticky) {
JSHandle<JSTaggedValue> lastIndexValue(thread, JSTaggedValue(0));
JSObject::SetProperty(thread, regexp, lastIndexHandle, lastIndexValue, true);
FastRuntimeStub::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(),
JSTaggedValue(0));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
return JSTaggedValue::Null();
@ -1220,8 +1320,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
uint32_t endIndex = matchResult.endIndex_;
if (global || sticky) {
// a. Let setStatus be Set(R, "lastIndex", e, true).
JSHandle<JSTaggedValue> lastIndexValue(thread, JSTaggedValue(endIndex));
JSObject::SetProperty(thread, regexp, lastIndexHandle, lastIndexValue, true);
FastRuntimeStub::FastSetPropertyByValue(
thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), JSTaggedValue(endIndex));
// b. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
@ -1229,11 +1329,11 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
JSHandle<JSObject> results(JSArray::ArrayCreate(thread, JSTaggedNumber(capturesSize)));
uint32_t matchIndex = matchResult.index_;
// 24. Perform CreateDataProperty(A, "index", matchIndex).
JSHandle<JSTaggedValue> indexKey(factory->NewFromCanBeCompressString("index"));
JSHandle<JSTaggedValue> indexKey = globalConst->GetHandledIndexString();
JSHandle<JSTaggedValue> indexValue(thread, JSTaggedValue(matchIndex));
JSObject::CreateDataProperty(thread, results, indexKey, indexValue);
// 25. Perform CreateDataProperty(A, "input", S).
JSHandle<JSTaggedValue> inputKey(factory->NewFromCanBeCompressString("input"));
JSHandle<JSTaggedValue> inputKey = globalConst->GetHandledInputString();
JSHandle<JSTaggedValue> inputValue(thread, static_cast<EcmaString *>(inputStr->GetTaggedObject()));
JSObject::CreateDataProperty(thread, results, inputKey, inputValue);
@ -1252,13 +1352,17 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
JSHandle<JSTaggedValue> iValue(thread, capturedValue);
JSObject::CreateDataProperty(thread, results, i, iValue);
}
if (lastIndex == 0 && isCached) {
cacheTable->AddResultInCache(thread, pattern, flag, inputStr, results.GetTaggedValue(),
RegExpExecResultCache::EXEC_TYPE, endIndex);
}
// 29. Return A.
return results.GetTaggedValue();
}
// 21.2.5.2.1
JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputString)
const JSHandle<JSTaggedValue> &inputString, bool isCached)
{
// 1. Assert: Type(R) is Object.
ASSERT(regexp->IsECMAObject());
@ -1269,8 +1373,8 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle<JSTagg
JSHandle<EcmaString> inputStr = JSTaggedValue::ToString(thread, inputString);
JSHandle<JSTaggedValue> execHandle(thread->GlobalConstants()->GetHandledExecString());
JSHandle<JSTaggedValue> exec =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(thisObj), execHandle).GetValue();
JSHandle<JSTaggedValue> exec(
thread, FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), execHandle.GetTaggedValue()));
// 4. ReturnIfAbrupt(exec).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 5. If IsCallable(exec) is true, then
@ -1279,7 +1383,7 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle<JSTagg
JSHClass *originHClass = JSHClass::Cast(thread->GlobalConstants()->GetJSRegExpClass().GetTaggedObject());
if (hclass == originHClass) {
// 7. Return RegExpBuiltinExec(R, S).
return RegExpBuiltinExec(thread, regexp, inputString);
return RegExpBuiltinExec(thread, regexp, inputString, isCached);
}
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>::Cast(thisObj);
InternalCallParams *arguments = thread->GetInternalCallParams();
@ -1299,7 +1403,7 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle<JSTagg
THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have a [[RegExpMatcher]]", JSTaggedValue::Exception());
}
// 7. Return RegExpBuiltinExec(R, S).
return RegExpBuiltinExec(thread, regexp, inputString);
return RegExpBuiltinExec(thread, regexp, inputString, isCached);
}
// 21.2.3.2.1
@ -1427,9 +1531,9 @@ JSTaggedValue BuiltinsRegExp::RegExpInitialize(JSThread *thread, const JSHandle<
regexp->SetLength(thread, JSTaggedValue(static_cast<uint32_t>(getCache.second)));
}
// 14. Let setStatus be Set(obj, "lastIndex", 0, true).
JSHandle<JSTaggedValue> lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString());
JSHandle<JSTaggedValue> value(thread, JSTaggedValue(0));
JSObject::SetProperty(thread, obj, lastIndexString, value, true);
JSHandle<JSTaggedValue> lastIndexString = thread->GlobalConstants()->GetHandledLastIndexString();
FastRuntimeStub::FastSetProperty(thread, obj.GetTaggedValue(), lastIndexString.GetTaggedValue(), JSTaggedValue(0),
true);
// 15. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 16. Return obj.
@ -1477,6 +1581,9 @@ JSTaggedValue RegExpExecResultCache::CreateCacheTable(JSThread *thread)
int length = CACHE_TABLE_HEADER_SIZE + DEFAULT_CACHE_NUMBER * ENTRY_SIZE;
auto table = static_cast<RegExpExecResultCache *>(*thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length));
table->SetLargeStrCount(thread, DEFAULT_LARGE_STRING_COUNT);
table->SetConflictCount(thread, DEFAULT_CONFLICT_COUNT);
table->SetStrLenThreshold(thread, 0);
table->SetHitCount(thread, 0);
table->SetCacheCount(thread, 0);
@ -1485,7 +1592,8 @@ JSTaggedValue RegExpExecResultCache::CreateCacheTable(JSThread *thread)
JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
const JSHandle<JSTaggedValue> &flag,
const JSHandle<JSTaggedValue> &input, CacheType type)
const JSHandle<JSTaggedValue> &input, CacheType type,
const JSHandle<JSTaggedValue> &regexp)
{
JSHandle<EcmaString> patternStr(pattern);
JSHandle<EcmaString> flagStr(flag);
@ -1516,17 +1624,26 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, const JS
case SPLIT_TYPE:
result = Get(index + RESULT_SPLIT_INDEX);
break;
case MATCH_TYPE:
result = Get(index + RESULT_MATCH_INDEX);
break;
case EXEC_TYPE:
result = Get(index + RESULT_EXEC_INDEX);
break;
default:
UNREACHABLE();
break;
}
SetHitCount(thread, GetHitCount() + 1);
JSHandle<JSTaggedValue> lastIndexHandle = thread->GlobalConstants()->GetHandledLastIndexString();
FastRuntimeStub::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(),
Get(index + LAST_INDEX_INDEX));
return result;
}
void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
const JSHandle<JSTaggedValue> &flag, const JSHandle<JSTaggedValue> &input,
JSTaggedValue resultArray, CacheType type)
JSTaggedValue resultArray, CacheType type, uint32_t lastIndex)
{
JSHandle<EcmaString> patternStr(pattern);
JSHandle<EcmaString> flagStr(flag);
@ -1539,13 +1656,14 @@ void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandle<JS
JSTaggedValue patternValue = pattern.GetTaggedValue();
JSTaggedValue flagValue = flag.GetTaggedValue();
JSTaggedValue inputValue = input.GetTaggedValue();
JSTaggedValue lastIndexValue(lastIndex);
uint32_t hash = pattern->GetKeyHashCode() + flag->GetKeyHashCode() + input->GetKeyHashCode();
uint32_t entry = hash & (DEFAULT_CACHE_NUMBER - 1);
uint32_t index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE;
if (Get(index) == JSTaggedValue::Undefined()) {
SetCacheCount(thread, GetCacheCount() + 1);
SetEntry(thread, entry, patternValue, flagValue, inputValue);
SetEntry(thread, entry, patternValue, flagValue, inputValue, lastIndexValue);
UpdateResultArray(thread, entry, resultArray, type);
} else if (Match(entry, patternValue, flagValue, inputValue)) {
UpdateResultArray(thread, entry, resultArray, type);
@ -1554,26 +1672,28 @@ void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandle<JS
uint32_t index2 = CACHE_TABLE_HEADER_SIZE + entry2 * ENTRY_SIZE;
if (Get(index2) == JSTaggedValue::Undefined()) {
SetCacheCount(thread, GetCacheCount() + 1);
SetEntry(thread, entry2, patternValue, flagValue, inputValue);
SetEntry(thread, entry2, patternValue, flagValue, inputValue, lastIndexValue);
UpdateResultArray(thread, entry2, resultArray, type);
} else if (Match(entry2, patternValue, flagValue, inputValue)) {
UpdateResultArray(thread, entry2, resultArray, type);
} else {
SetConflictCount(thread, GetConflictCount() - 1);
SetCacheCount(thread, GetCacheCount() - 1);
ClearEntry(thread, entry2);
SetEntry(thread, entry, patternValue, flagValue, inputValue);
SetEntry(thread, entry, patternValue, flagValue, inputValue, lastIndexValue);
UpdateResultArray(thread, entry, resultArray, type);
}
}
}
void RegExpExecResultCache::SetEntry(JSThread *thread, int entry, JSTaggedValue &pattern, JSTaggedValue &flag,
JSTaggedValue &input)
JSTaggedValue &input, JSTaggedValue &lastIndexValue)
{
int index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE;
Set(thread, index + PATTERN_INDEX, pattern);
Set(thread, index + FLAG_INDEX, flag);
Set(thread, index + INPUT_STRING_INDEX, input);
Set(thread, index + LAST_INDEX_INDEX, lastIndexValue);
}
void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type)
@ -1587,6 +1707,12 @@ void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTag
case SPLIT_TYPE:
Set(thread, index + RESULT_SPLIT_INDEX, resultArray);
break;
case MATCH_TYPE:
Set(thread, index + RESULT_MATCH_INDEX, resultArray);
break;
case EXEC_TYPE:
Set(thread, index + RESULT_EXEC_INDEX, resultArray);
break;
default:
UNREACHABLE();
break;

View File

@ -81,10 +81,10 @@ private:
const JSHandle<EcmaString> &flag);
// 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S )
static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputStr);
const JSHandle<JSTaggedValue> &inputStr, bool isCached);
// 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S )
static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle<JSTaggedValue> &regexp,
const JSHandle<JSTaggedValue> &inputString);
const JSHandle<JSTaggedValue> &inputString, bool isCached);
// 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget )
static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget);
@ -105,6 +105,8 @@ public:
enum CacheType {
REPLACE_TYPE,
SPLIT_TYPE,
MATCH_TYPE,
EXEC_TYPE
};
static RegExpExecResultCache *Cast(TaggedObject *object)
{
@ -113,12 +115,14 @@ public:
static JSTaggedValue CreateCacheTable(JSThread *thread);
JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> &patten,
const JSHandle<JSTaggedValue> &flag, const JSHandle<JSTaggedValue> &input,
CacheType type);
CacheType type, const JSHandle<JSTaggedValue> &regexp);
void AddResultInCache(JSThread *thread, const JSHandle<JSTaggedValue> &patten, const JSHandle<JSTaggedValue> &flag,
const JSHandle<JSTaggedValue> &input, JSTaggedValue resultArray, CacheType type);
const JSHandle<JSTaggedValue> &input, JSTaggedValue resultArray, CacheType type,
uint32_t lastIndex);
void ClearEntry(JSThread *thread, int entry);
void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flag, JSTaggedValue &input);
void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flag, JSTaggedValue &input,
JSTaggedValue &lastIndexValue);
void UpdateResultArray(JSThread *thread, int entry, JSTaggedValue resultArray, CacheType type);
bool Match(int entry, JSTaggedValue &pattenStr, JSTaggedValue &flagStr, JSTaggedValue &inputStr);
inline void SetHitCount(JSThread *thread, int hitCount)
@ -147,17 +151,55 @@ public:
std::cout << "cache hit count: " << GetHitCount() << std::endl;
}
inline void SetLargeStrCount(JSThread *thread, uint32_t newCount)
{
Set(thread, LARGE_STRING_COUNT_INDEX, JSTaggedValue(newCount));
}
inline void SetConflictCount(JSThread *thread, uint32_t newCount)
{
Set(thread, CONFLICT_COUNT_INDEX, JSTaggedValue(newCount));
}
inline void SetStrLenThreshold(JSThread *thread, uint32_t newThreshold)
{
Set(thread, STRING_LENGTH_THRESHOLD_INDEX, JSTaggedValue(newThreshold));
}
inline uint32_t GetLargeStrCount()
{
return Get(LARGE_STRING_COUNT_INDEX).GetInt();
}
inline uint32_t GetConflictCount()
{
return Get(CONFLICT_COUNT_INDEX).GetInt();
}
inline uint32_t GetStrLenThreshold()
{
return Get(STRING_LENGTH_THRESHOLD_INDEX).GetInt();
}
private:
static constexpr int DEFAULT_LARGE_STRING_COUNT = 10;
static constexpr int DEFAULT_CONFLICT_COUNT = 100;
static constexpr int DEFAULT_CACHE_NUMBER = 0x1000;
static constexpr int CACHE_COUNT_INDEX = 0;
static constexpr int CACHE_HIT_COUNT_INDEX = 1;
static constexpr int CACHE_TABLE_HEADER_SIZE = 2;
static constexpr int LARGE_STRING_COUNT_INDEX = 2;
static constexpr int CONFLICT_COUNT_INDEX = 3;
static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4;
static constexpr int CACHE_TABLE_HEADER_SIZE = 5;
static constexpr int PATTERN_INDEX = 0;
static constexpr int FLAG_INDEX = 1;
static constexpr int INPUT_STRING_INDEX = 2;
static constexpr int RESULT_REPLACE_INDEX = 3;
static constexpr int RESULT_SPLIT_INDEX = 4;
static constexpr int ENTRY_SIZE = 5;
static constexpr int LAST_INDEX_INDEX = 3;
static constexpr int RESULT_REPLACE_INDEX = 4;
static constexpr int RESULT_SPLIT_INDEX = 5;
static constexpr int RESULT_MATCH_INDEX = 6;
static constexpr int RESULT_EXEC_INDEX = 7;
static constexpr int ENTRY_SIZE = 8;
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_REGEXP_H

View File

@ -27,6 +27,7 @@
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/internal_call_params.h"
#include "ecmascript/interpreter/fast_runtime_stub-inl.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_hclass.h"
#include "ecmascript/js_invoker.h"
@ -489,6 +490,15 @@ JSTaggedValue BuiltinsString::IndexOf(EcmaRuntimeCallInfo *argv)
pos = posVal.ToInt32();
}
pos = std::min(std::max(pos, 0), thisLen);
if (thisHandle->IsUtf8() && searchHandle->IsUtf8()) {
std::string thisString = base::StringHelper::Utf8ToString(thisHandle->GetDataUtf8(), thisLen);
std::string searchString = base::StringHelper::Utf8ToString(searchHandle->GetDataUtf8(), searchLen);
int32_t res = base::StringHelper::Find(thisString, searchString, pos);
if (res >= 0 && res < thisLen) {
return GetTaggedInt(res);
}
return GetTaggedInt(-1);
}
std::u16string u16strThis;
std::u16string u16strSearch;
if (thisHandle->IsUtf16()) {
@ -507,8 +517,7 @@ JSTaggedValue BuiltinsString::IndexOf(EcmaRuntimeCallInfo *argv)
if (res >= 0 && res < thisLen) {
return GetTaggedInt(res);
}
res = -1;
return GetTaggedInt(res);
return GetTaggedInt(-1);
}
// 21.1.3.9
@ -1095,7 +1104,7 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
// Let O be RequireObjectCoercible(this value).
JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)));
JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv));
JSHandle<JSObject> thisObj(thisTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> seperatorTag = BuiltinsString::GetCallArg(argv, 0);
@ -1138,8 +1147,7 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (seperatorTag->IsUndefined()) {
// Perform CreateDataProperty(A, "0", S).
JSHandle<JSTaggedValue> zeroKey(thread, JSTaggedValue(0));
JSObject::CreateDataProperty(thread, resultArray, zeroKey, JSHandle<JSTaggedValue>(thisString));
JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString));
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception");
return resultArray.GetTaggedValue();
}
@ -1148,8 +1156,7 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
if (SplitMatch(thisString, 0, seperatorString) != -1) {
return resultArray.GetTaggedValue();
}
JSHandle<JSTaggedValue> zeroKey(thread, JSTaggedValue(0));
JSObject::CreateDataProperty(thread, resultArray, zeroKey, JSHandle<JSTaggedValue>(thisString));
JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString));
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception");
return resultArray.GetTaggedValue();
}
@ -1167,11 +1174,10 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
q = q + 1;
} else {
EcmaString *elementString = EcmaString::FastSubString(thisString, p, q - p, ecmaVm);
JSHandle<JSTaggedValue> arrayLengthKey(thread, JSTaggedValue(arrayLength));
JSHandle<JSTaggedValue> elementTag(thread, elementString);
JSObject::CreateDataProperty(thread, resultArray, arrayLengthKey, elementTag);
JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag);
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
arrayLength = arrayLength + 1;
++arrayLength;
if (arrayLength == lim) {
return resultArray.GetTaggedValue();
}
@ -1181,9 +1187,8 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv)
}
}
EcmaString *elementString = EcmaString::FastSubString(thisString, p, thisLength - p, ecmaVm);
JSHandle<JSTaggedValue> arrayLengthKey(thread, JSTaggedValue(arrayLength));
JSHandle<JSTaggedValue> elementTag(thread, elementString);
JSObject::CreateDataProperty(thread, resultArray, arrayLengthKey, elementTag);
JSObject::CreateDataProperty(thread, resultArray, arrayLength, elementTag);
ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception");
return resultArray.GetTaggedValue();
}

View File

@ -450,6 +450,12 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
SetConstant(ConstantIndex::ISO8601_INDEX, factory->NewFromCanBeCompressString("iso8601").GetTaggedValue());
SetConstant(ConstantIndex::GREGORY_INDEX, factory->NewFromCanBeCompressString("gregory").GetTaggedValue());
SetConstant(ConstantIndex::ETHIOAA_INDEX, factory->NewFromCanBeCompressString("ethioaa").GetTaggedValue());
SetConstant(ConstantIndex::STICKY_INDEX, factory->NewFromCanBeCompressString("sticky").GetTaggedValue());
SetConstant(ConstantIndex::U_INDEX, factory->NewFromCanBeCompressString("u").GetTaggedValue());
SetConstant(ConstantIndex::INDEX_INDEX, factory->NewFromCanBeCompressString("index").GetTaggedValue());
SetConstant(ConstantIndex::INPUT_INDEX, factory->NewFromCanBeCompressString("input").GetTaggedValue());
SetConstant(ConstantIndex::UNICODE_INDEX, factory->NewFromCanBeCompressString("unicode").GetTaggedValue());
SetConstant(ConstantIndex::ZERO_INDEX, factory->NewFromCanBeCompressString("0").GetTaggedValue());
auto accessor = factory->NewInternalAccessor(reinterpret_cast<void *>(JSFunction::PrototypeSetter),
reinterpret_cast<void *>(JSFunction::PrototypeGetter));

View File

@ -283,7 +283,13 @@ class JSThread;
V(JSTaggedValue, EthioaaString, ETHIOAA_INDEX, ethioaa) \
/* for regexp. */ \
V(JSTaggedValue, ExecString, EXEC_INDEX, exec) \
V(JSTaggedValue, LastIndexString, LAST_INDEX_INDEX, lastIndex)
V(JSTaggedValue, LastIndexString, LAST_INDEX_INDEX, lastIndex) \
V(JSTaggedValue, StickyString, STICKY_INDEX, sticky) \
V(JSTaggedValue, UString, U_INDEX, u) \
V(JSTaggedValue, IndexString, INDEX_INDEX, index) \
V(JSTaggedValue, InputString, INPUT_INDEX, input) \
V(JSTaggedValue, UnicodeString, UNICODE_INDEX, unicode) \
V(JSTaggedValue, ZeroString, ZERO_INDEX, zero)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define GLOBAL_ENV_CONSTANT_ACCESSOR(V) \

View File

@ -690,13 +690,13 @@ JSTaggedValue FastRuntimeStub::NewLexicalEnvDyn(JSThread *thread, ObjectFactory
// Those interface below is discarded
bool FastRuntimeStub::IsSpecialIndexedObjForGet(JSTaggedValue obj)
{
JSType jsType = obj.GetHeapObject()->ClassAddr<JSHClass>()->GetObjectType();
JSType jsType = obj.GetTaggedObject()->GetClass()->GetObjectType();
return jsType > JSType::JS_ARRAY && jsType <= JSType::JS_PRIMITIVE_REF;
}
bool FastRuntimeStub::IsSpecialIndexedObjForSet(JSTaggedValue obj)
{
JSType jsType = obj.GetHeapObject()->ClassAddr<JSHClass>()->GetObjectType();
JSType jsType = obj.GetTaggedObject()->GetClass()->GetObjectType();
return jsType >= JSType::JS_ARRAY && jsType <= JSType::JS_PRIMITIVE_REF;
}

View File

@ -1152,15 +1152,15 @@ bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &
JSHandle<JSTaggedValue> JSObject::GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key)
{
JSHandle<JSTaggedValue> func = JSTaggedValue::GetProperty(thread, obj, key).GetValue();
if (func->IsUndefined() || func->IsNull()) {
JSTaggedValue func = FastRuntimeStub::FastGetProperty(thread, obj.GetTaggedValue(), key.GetTaggedValue());
if (func.IsUndefined() || func.IsNull()) {
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
}
if (!func->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", func);
if (!func.IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", JSHandle<JSTaggedValue>(thread, func));
}
return func;
return JSHandle<JSTaggedValue>(thread, func);
}
// 7.3.14 SetIntegrityLevel (O, level)