From fa3ad69451eb2d234cc5f2d5d81fde1c36e77615 Mon Sep 17 00:00:00 2001 From: xujie Date: Fri, 10 Sep 2021 10:16:05 +0800 Subject: [PATCH] resolve issue of taking 2 seconds to response after clicking mediaquery Signed-off-by: xujie --- ecmascript/base/string_helper.h | 13 + ecmascript/builtins/builtins_regexp.cpp | 330 ++++++++++++------ ecmascript/builtins/builtins_regexp.h | 60 +++- ecmascript/builtins/builtins_string.cpp | 29 +- ecmascript/global_env_constants.cpp | 6 + ecmascript/global_env_constants.h | 8 +- .../interpreter/fast_runtime_stub-inl.h | 4 +- ecmascript/js_object.cpp | 10 +- 8 files changed, 329 insertions(+), 131 deletions(-) diff --git a/ecmascript/base/string_helper.h b/ecmascript/base/string_helper.h index 38f6f6942f..1f6383def4 100644 --- a/ecmascript/base/string_helper.h +++ b/ecmascript/base/string_helper.h @@ -76,6 +76,13 @@ public: return u16str; } + static inline std::string Utf8ToString(const uint8_t *utf8Data, uint32_t dataLen) + { + auto *charData = reinterpret_cast(utf8Data); + std::string str(charData, dataLen); + return str; + } + static inline std::u16string Utf8ToU16String(const uint8_t *utf8Data, uint32_t dataLen) { auto *charData = reinterpret_cast(utf8Data); @@ -104,6 +111,12 @@ public: return std::wstring_convert, 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); diff --git a/ecmascript/builtins/builtins_regexp.cpp b/ecmascript/builtins/builtins_regexp.cpp index dc994270fb..3a6b0968a1 100644 --- a/ecmascript/builtins/builtins_regexp.cpp +++ b/ecmascript/builtins/builtins_regexp.cpp @@ -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 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 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 inputString = GetCallArg(argv, 0); JSHandle stringHandle = JSTaggedValue::ToString(thread, inputString); + bool isCached = true; + JSHandle cacheTable(thread->GetEcmaVM()->GetRegExpCache()); + if (cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount()) { + isCached = false; + } // 4. ReturnIfAbrupt(string). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle string = JSHandle::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 global(factory->NewFromCanBeCompressString("global")); - auto globalValue = JSObject::GetProperty(thread, thisObj, global).GetValue(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle 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 regexpObj(thisObj); + JSHandle pattern(thread, regexpObj->GetOriginalSource()); + JSHandle 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 unicode(factory->NewFromCanBeCompressString("unicode")); - JSHandle unicodeHandle = JSObject::GetProperty(thread, thisObj, unicode).GetValue(); + JSHandle 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 lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString()); + JSHandle lastIndexString(globalConst->GetHandledLastIndexString()); JSHandle 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 zoreString(factory->NewFromCanBeCompressString("0")); - JSHandle matchStr(JSObject::GetProperty(thread, result, zoreString).GetValue()); + JSHandle zeroString = globalConst->GetHandledZeroString(); + JSHandle matchStr( + thread, FastRuntimeStub::FastGetProperty(thread, result.GetTaggedValue(), zeroString.GetTaggedValue())); JSHandle 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 lastIndexHandle = - JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue(); + JSHandle 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 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 lastIndexHandle(thread->GlobalConstants()->GetHandledLastIndexString()); uint32_t lastIndex; JSHandle regexpHandle(regexp); - + bool isCached = false; if ((flags & (RegExpParser::FLAG_STICKY | RegExpParser::FLAG_GLOBAL)) == 0) { lastIndex = 0; } else { - JSHandle 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 thisIndexHandle(thread, thisIndex); + lastIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } } JSHandle tagInputString = JSHandle::Cast(inputString); JSHandle pattern(thread, regexpHandle->GetOriginalSource()); JSHandle flag(thread, regexpHandle->GetOriginalFlags()); JSHandle 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, JSHandleNewFromStdString(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 string = GetCallArg(argv, 0); JSHandle inputReplaceValue = GetCallArg(argv, 1); JSHandle srcString = JSTaggedValue::ToString(thread, string); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); // 4. ReturnIfAbrupt(S). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle inputStr = JSHandle::Cast(srcString); // 5. Let lengthS be the number of code unit elements in S. - uint32_t length = static_cast(inputStr->GetTaggedObject())->GetLength(); + uint32_t length = srcString->GetLength(); // 6. Let functionalReplace be IsCallable(replaceValue). bool functionalReplace = inputReplaceValue->IsCallable(); JSHandle replaceValueHandle; @@ -583,49 +638,52 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv) replaceValueHandle = JSTaggedValue::ToString(thread, inputReplaceValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - JSHandle lastIndex(thread->GlobalConstants()->GetHandledLastIndexString()); + JSHandle lastIndex = globalConst->GetHandledLastIndexString(); // 8. Let global be ToBoolean(Get(rx, "global")). ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle global(factory->NewFromCanBeCompressString("global")); - auto globalValue = JSObject::GetProperty(thread, thisObj, global).GetValue(); + JSHandle 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 unicode(factory->NewFromCanBeCompressString("unicode")); - JSHandle fullUnicodeHandle = JSObject::GetProperty(thread, thisObj, unicode).GetValue(); + JSHandle 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 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::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 matchedStr(factory->NewFromCanBeCompressString("0")); + JSHandle matchedStr = globalConst->GetHandledZeroString(); // 11. Let results be a new empty List. JSHandle resultsList(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); int resultsIndex = 0; // 12. Let done be false. // 13. Repeat, while done is false JSMutableHandle nextIndexHandle(thread, JSTaggedValue(0)); + JSMutableHandle execResult(thread, JSTaggedValue(0)); for (;;) { // a. Let result be RegExpExec(rx, S). - JSHandle 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 getMatch = JSObject::GetProperty(thread, execResult, matchedStr).GetValue(); + JSHandle getMatch( + thread, FastRuntimeStub::FastGetProperty(thread, execResult.GetTaggedValue(), matchedStr.GetTaggedValue())); JSHandle 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 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 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 getMatchString; + JSMutableHandle resultValues(thread, JSTaggedValue(0)); + JSMutableHandle ncapturesHandle(thread, JSTaggedValue(0)); + JSMutableHandle capN(thread, JSTaggedValue(0)); // 16. Repeat, for each result in results, for (int i = 0; i < resultsIndex; i++) { - JSHandle resultValues = - JSObject::GetProperty(thread, JSHandle(resultsList), i).GetValue(); + resultValues.Update(FastRuntimeStub::FastGetPropertyByIndex(thread, resultsList.GetTaggedValue(), i)); // a. Let nCaptures be ToLength(Get(result, "length")). - JSHandle lengthHandle = thread->GlobalConstants()->GetHandledLengthString(); - JSHandle ncapturesHandle = JSObject::GetProperty(thread, resultValues, lengthHandle).GetValue(); + JSHandle 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 resultIndex(factory->NewFromCanBeCompressString("index")); JSHandle 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(std::min(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 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 undefined(thread, JSTaggedValue::Undefined()); + JSHandle 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 result(thread, RegExpExec(thread, thisObj, string)); + JSHandle result(thread, RegExpExec(thread, thisObj, string, false)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7. Let currentLastIndex be ? Get(rx, "lastIndex"). JSHandle 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 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 regexpHandle(thisObj); JSHandle pattern(thread, regexpHandle->GetOriginalSource()); JSHandle flag(thread, regexpHandle->GetOriginalFlags()); JSHandle 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 execResult(thread, RegExpExec(thread, splitter, jsString)); + JSHandle 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 execResult(thread, RegExpExec(thread, splitter, jsString)); + JSHandle 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 ®exp, - const JSHandle &inputStr) + const JSHandle &inputStr, bool isCached) { ASSERT(JSObject::IsRegExp(thread, regexp)); ASSERT(inputStr->IsString()); int32_t length = static_cast(inputStr->GetTaggedObject())->GetLength(); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle lastIndexHandle(thread->GlobalConstants()->GetHandledLastIndexString()); - JSHandle lastIndexResult = JSObject::GetProperty(thread, regexp, lastIndexHandle).GetValue(); - JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - int32_t lastIndex = lastIndexNumber.GetNumber(); - JSHandle globalHandle(factory->NewFromCanBeCompressString("global")); - bool global = JSObject::GetProperty(thread, regexp, globalHandle).GetValue()->ToBoolean(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle lastIndexHandle = globalConst->GetHandledLastIndexString(); + JSTaggedValue result = FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), + lastIndexHandle.GetTaggedValue()); + int32_t lastIndex = 0; + if (result.IsInt()) { + lastIndex = result.GetInt(); + } else { + JSHandle lastIndexResult(thread, result); + JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + lastIndex = lastIndexNumber.GetNumber(); + } + JSHandle globalHandle = globalConst->GetHandledGlobalString(); + bool global = + FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), globalHandle.GetTaggedValue()).ToBoolean(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle stickyHandle(factory->NewFromCanBeCompressString("sticky")); - bool sticky = JSObject::GetProperty(thread, regexp, stickyHandle).GetValue()->ToBoolean(); + JSHandle 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 regexpObj(thread, JSRegExp::Cast(regexp->GetTaggedObject())); + JSHandle regexpObj(regexp); + JSHandle pattern(thread, regexpObj->GetOriginalSource()); + JSHandle flag(thread, regexpObj->GetOriginalFlags()); + JSHandle 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(regexpObj->GetOriginalFlags().GetTaggedObject()); - JSHandle uString = factory->NewFromCanBeCompressString("u"); + JSHandle uString(globalConst->GetHandledUString()); [[maybe_unused]] bool fullUnicode = base::StringHelper::Contains(flagsStr, *uString); if (lastIndex > length) { - JSHandle 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 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 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 results(JSArray::ArrayCreate(thread, JSTaggedNumber(capturesSize))); uint32_t matchIndex = matchResult.index_; // 24. Perform CreateDataProperty(A, "index", matchIndex). - JSHandle indexKey(factory->NewFromCanBeCompressString("index")); + JSHandle indexKey = globalConst->GetHandledIndexString(); JSHandle indexValue(thread, JSTaggedValue(matchIndex)); JSObject::CreateDataProperty(thread, results, indexKey, indexValue); // 25. Perform CreateDataProperty(A, "input", S). - JSHandle inputKey(factory->NewFromCanBeCompressString("input")); + JSHandle inputKey = globalConst->GetHandledInputString(); JSHandle inputValue(thread, static_cast(inputStr->GetTaggedObject())); JSObject::CreateDataProperty(thread, results, inputKey, inputValue); @@ -1252,13 +1352,17 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle JSHandle 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 ®exp, - const JSHandle &inputString) + const JSHandle &inputString, bool isCached) { // 1. Assert: Type(R) is Object. ASSERT(regexp->IsECMAObject()); @@ -1269,8 +1373,8 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle inputStr = JSTaggedValue::ToString(thread, inputString); JSHandle execHandle(thread->GlobalConstants()->GetHandledExecString()); - JSHandle exec = - JSObject::GetProperty(thread, JSHandle(thisObj), execHandle).GetValue(); + JSHandle 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 JSHandleGlobalConstants()->GetJSRegExpClass().GetTaggedObject()); if (hclass == originHClass) { // 7. Return RegExpBuiltinExec(R, S). - return RegExpBuiltinExec(thread, regexp, inputString); + return RegExpBuiltinExec(thread, regexp, inputString, isCached); } JSHandle obj = JSHandle::Cast(thisObj); InternalCallParams *arguments = thread->GetInternalCallParams(); @@ -1299,7 +1403,7 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandleSetLength(thread, JSTaggedValue(static_cast(getCache.second))); } // 14. Let setStatus be Set(obj, "lastIndex", 0, true). - JSHandle lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString()); - JSHandle value(thread, JSTaggedValue(0)); - JSObject::SetProperty(thread, obj, lastIndexString, value, true); + JSHandle 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(*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 &pattern, const JSHandle &flag, - const JSHandle &input, CacheType type) + const JSHandle &input, CacheType type, + const JSHandle ®exp) { JSHandle patternStr(pattern); JSHandle 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 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 &pattern, const JSHandle &flag, const JSHandle &input, - JSTaggedValue resultArray, CacheType type) + JSTaggedValue resultArray, CacheType type, uint32_t lastIndex) { JSHandle patternStr(pattern); JSHandle flagStr(flag); @@ -1539,13 +1656,14 @@ void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandleGetKeyHashCode() + 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 &flag); // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S ) static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputStr); + const JSHandle &inputStr, bool isCached); // 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S ) static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputString); + const JSHandle &inputString, bool isCached); // 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget ) static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle &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 &patten, const JSHandle &flag, const JSHandle &input, - CacheType type); + CacheType type, const JSHandle ®exp); void AddResultInCache(JSThread *thread, const JSHandle &patten, const JSHandle &flag, - const JSHandle &input, JSTaggedValue resultArray, CacheType type); + const JSHandle &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 diff --git a/ecmascript/builtins/builtins_string.cpp b/ecmascript/builtins/builtins_string.cpp index 370803d4a3..fcaaf86559 100644 --- a/ecmascript/builtins/builtins_string.cpp +++ b/ecmascript/builtins/builtins_string.cpp @@ -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 env = ecmaVm->GetGlobalEnv(); // Let O be RequireObjectCoercible(this value). - JSHandle thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); + JSHandle thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); JSHandle thisObj(thisTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle 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 zeroKey(thread, JSTaggedValue(0)); - JSObject::CreateDataProperty(thread, resultArray, zeroKey, JSHandle(thisString)); + JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle(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 zeroKey(thread, JSTaggedValue(0)); - JSObject::CreateDataProperty(thread, resultArray, zeroKey, JSHandle(thisString)); + JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle(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 arrayLengthKey(thread, JSTaggedValue(arrayLength)); JSHandle 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 arrayLengthKey(thread, JSTaggedValue(arrayLength)); JSHandle 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(); } diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 03a32f56a7..fcb9f3d9df 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -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(JSFunction::PrototypeSetter), reinterpret_cast(JSFunction::PrototypeGetter)); diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 7c90e113ba..50de7a0897 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -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) \ diff --git a/ecmascript/interpreter/fast_runtime_stub-inl.h b/ecmascript/interpreter/fast_runtime_stub-inl.h index 4e5cdfd5da..a6276a00ff 100644 --- a/ecmascript/interpreter/fast_runtime_stub-inl.h +++ b/ecmascript/interpreter/fast_runtime_stub-inl.h @@ -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()->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()->GetObjectType(); + JSType jsType = obj.GetTaggedObject()->GetClass()->GetObjectType(); return jsType >= JSType::JS_ARRAY && jsType <= JSType::JS_PRIMITIVE_REF; } diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index d8fb6ff142..718f552688 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -1152,15 +1152,15 @@ bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle & JSHandle JSObject::GetMethod(JSThread *thread, const JSHandle &obj, const JSHandle &key) { - JSHandle 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(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(thread, func)); } - return func; + return JSHandle(thread, func); } // 7.3.14 SetIntegrityLevel (O, level) -- Gitee