Opt string regexp

Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I9CRLW?from=project-issue

Signed-off-by: yaochaonan <yaochaonan@huawei.com>
Change-Id: I5c61752f3be923a4d9c48086613afcff5d0d3512
This commit is contained in:
yaochaonan 2024-03-29 17:43:19 +08:00
parent 21dd6c25b1
commit 911a7c1b37
20 changed files with 332 additions and 136 deletions

View File

@ -205,6 +205,8 @@ using SharedArrayBuffer = builtins::BuiltinsSharedArrayBuffer;
using BuiltinsAsyncIterator = builtins::BuiltinsAsyncIterator;
using AsyncGeneratorObject = builtins::BuiltinsAsyncGenerator;
static constexpr size_t REGEXP_INLINE_PROPS = 18;
void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread, bool lazyInit, bool isRealm)
{
thread->CheckSafepointIfSuspended();
@ -1919,7 +1921,7 @@ void Builtins::InitializeRegExp(const JSHandle<GlobalEnv> &env)
[[maybe_unused]] EcmaHandleScope scope(thread_);
// RegExp.prototype
JSHandle<JSFunction> objFun(env->GetObjectFunction());
JSHandle<JSObject> regPrototype = factory_->NewJSObjectByConstructor(objFun);
JSHandle<JSObject> regPrototype = factory_->NewJSObjectByConstructor(env, objFun, REGEXP_INLINE_PROPS);
JSHandle<JSTaggedValue> regPrototypeValue(regPrototype);
// RegExp.prototype_or_hclass
@ -2000,22 +2002,29 @@ void Builtins::InitializeRegExp(const JSHandle<GlobalEnv> &env)
JSHandle<JSFunction>(speciesGetter)->SetLexicalEnv(thread_, env);
// Set RegExp.prototype[@@split]
SetFunctionAtSymbol(env, regPrototype, env->GetSplitSymbol(), "[Symbol.split]", RegExp::Split, FunctionLength::TWO);
JSHandle<JSTaggedValue> splitFunc = SetAndReturnFunctionAtSymbol(
env, regPrototype, env->GetSplitSymbol(), "[Symbol.split]", RegExp::Split, FunctionLength::TWO);
// Set RegExp.prototype[@@search]
SetFunctionAtSymbol(env, regPrototype, env->GetSearchSymbol(), "[Symbol.search]", RegExp::Search,
FunctionLength::ONE);
JSHandle<JSTaggedValue> searchFunc = SetAndReturnFunctionAtSymbol(
env, regPrototype, env->GetSearchSymbol(), "[Symbol.search]", RegExp::Search, FunctionLength::ONE);
// Set RegExp.prototype[@@match]
SetFunctionAtSymbol(env, regPrototype, env->GetMatchSymbol(), "[Symbol.match]", RegExp::Match, FunctionLength::ONE);
JSHandle<JSTaggedValue> matchFunc = SetAndReturnFunctionAtSymbol(
env, regPrototype, env->GetMatchSymbol(), "[Symbol.match]", RegExp::Match, FunctionLength::ONE);
// Set RegExp.prototype[@@matchAll]
SetFunctionAtSymbol(env, regPrototype, env->GetMatchAllSymbol(), "[Symbol.matchAll]", RegExp::MatchAll,
FunctionLength::ONE);
JSHandle<JSTaggedValue> matchAllFunc = SetAndReturnFunctionAtSymbol(
env, regPrototype, env->GetMatchAllSymbol(), "[Symbol.matchAll]", RegExp::MatchAll, FunctionLength::ONE);
// Set RegExp.prototype[@@replace]
SetFunctionAtSymbol(env, regPrototype, env->GetReplaceSymbol(), "[Symbol.replace]", RegExp::Replace,
FunctionLength::TWO);
JSHandle<JSTaggedValue> replaceFunc = SetAndReturnFunctionAtSymbol(
env, regPrototype, env->GetReplaceSymbol(), "[Symbol.replace]", RegExp::Replace, FunctionLength::TWO);
env->SetRegExpFunction(thread_, regexpFunction);
env->SetRegExpPrototype(thread_, regPrototype);
env->SetRegExpExecFunction(thread_, execFunc);
env->SetRegExpSplitFunction(thread_, splitFunc);
env->SetRegExpSearchFunction(thread_, searchFunc);
env->SetRegExpMatchFunction(thread_, matchFunc);
env->SetRegExpMatchAllFunction(thread_, matchAllFunc);
env->SetRegExpReplaceFunction(thread_, replaceFunc);
// Set RegExp.prototype hclass
JSHandle<JSHClass> regPrototypeClass(thread_, regPrototype->GetJSHClass());
env->SetRegExpPrototypeClass(thread_, regPrototypeClass.GetTaggedValue());

View File

@ -483,6 +483,22 @@ JSTaggedValue BuiltinsArkTools::IsRegExpReplaceDetectorValid(EcmaRuntimeCallInfo
return JSTaggedValue(PropertyDetector::IsRegExpReplaceDetectorValid(env));
}
JSTaggedValue BuiltinsArkTools::IsRegExpFlagsDetectorValid(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
return JSTaggedValue(PropertyDetector::IsRegExpFlagsDetectorValid(env));
}
JSTaggedValue BuiltinsArkTools::IsNumberStringNotRegexpLikeDetectorValid(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
return JSTaggedValue(PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env));
}
JSTaggedValue BuiltinsArkTools::IsSymbolIteratorDetectorValid(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -37,6 +37,8 @@
V("isNotHoleProperty", IsNotHoleProperty, 2, INVALID) \
V("isPrototype", IsPrototype, 1, INVALID) \
V("isRegExpReplaceDetectorValid", IsRegExpReplaceDetectorValid, 0, INVALID) \
V("isRegExpFlagsDetectorValid", IsRegExpFlagsDetectorValid, 0, INVALID) \
V("isNumberStringNotRegexpLikeDetectorValid", IsNumberStringNotRegexpLikeDetectorValid, 0, INVALID) \
V("isSymbolIteratorDetectorValid", IsSymbolIteratorDetectorValid, 1, INVALID) \
V("isTSHClass", IsTSHClass, 1, INVALID) \
V("pgoAssertType", PGOAssertType, 2, INVALID) \
@ -210,6 +212,10 @@ public:
static JSTaggedValue IsRegExpReplaceDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsRegExpFlagsDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsNumberStringNotRegexpLikeDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsSymbolIteratorDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue TimeInUs(EcmaRuntimeCallInfo *info);

View File

@ -32,6 +32,7 @@
#include "ecmascript/mem/c_containers.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/object_fast_operator-inl.h"
#include "ecmascript/property_detector-inl.h"
#include "ecmascript/regexp/regexp_parser_cache.h"
#include "ecmascript/tagged_array-inl.h"
@ -207,7 +208,8 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv)
return GetTaggedBoolean(!matchResult.IsNull());
}
bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> regexp)
bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> regexp,
RegExpSymbol symbolTag)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
@ -230,11 +232,30 @@ bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> rege
if (regexpHclass != originRegexpHclass) {
return false;
}
JSObject* protoObj = JSObject::Cast(proto);
// RegExp.prototype.exec
auto execVal = JSObject::Cast(proto)->GetPropertyInlinedProps(JSRegExp::EXEC_INLINE_PROPERTY_INDEX);
JSTaggedValue execVal = protoObj->GetPropertyInlinedProps(JSRegExp::EXEC_INLINE_PROPERTY_INDEX);
if (execVal != env->GetTaggedRegExpExecFunction()) {
return false;
}
JSTaggedValue symbolFunc = JSTaggedValue::Hole();
switch (symbolTag) {
case RegExpSymbol::UNKNOWN:
break;
#define V(UpperCase, Camel) \
case RegExpSymbol::UpperCase: \
symbolFunc = protoObj->GetPropertyInlinedProps( \
JSRegExp::UpperCase##_INLINE_PROPERTY_INDEX); \
if (symbolFunc != env->GetTaggedRegExp##Camel##Function()) { \
return false; \
} \
break;
REGEXP_SYMBOL_FUNCTION_LIST(V)
#undef V
}
if (!PropertyDetector::IsRegExpFlagsDetectorValid(env)) {
return false;
}
return true;
}
@ -263,8 +284,8 @@ JSTaggedValue BuiltinsRegExp::RegExpTestFast(JSThread *thread, JSHandle<JSTagged
JSHandle<EcmaString> inputString = JSHandle<EcmaString>::Cast(inputStr);
bool matchResult = RegExpExecInternal(thread, regexp, inputString, lastIndex);
// 2. Check whether the regexp is global or sticky, which determines whether we update last index later on.
bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool global = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool ifUpdateLastIndex = global || sticky;
if (!matchResult) {
if (ifUpdateLastIndex) {
@ -581,36 +602,42 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
}
bool isFastPath = IsFastRegExp(thread, thisObj);
return RegExpMatch(thread, thisObj, string, isFastPath);
}
JSTaggedValue BuiltinsRegExp::RegExpMatch(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> string, bool isFastPath)
{
bool useCache = true;
JSHandle<RegExpExecResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache());
if (!isFastPath || cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount() == 0) {
useCache = false;
}
bool isGlobal = GetFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL, isFastPath);
bool isGlobal = GetFlag(thread, regexp, RegExpParser::FLAG_GLOBAL, isFastPath);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 7. If global is false, then
if (!isGlobal) {
// a. Return RegExpExec(rx, S).
if (isFastPath) {
return RegExpBuiltinExec(thread, thisObj, string, isFastPath, useCache);
return RegExpBuiltinExec(thread, regexp, string, isFastPath, useCache);
} else {
return RegExpExec(thread, thisObj, string, useCache);
return RegExpExec(thread, regexp, string, useCache);
}
}
if (useCache) {
uint32_t lastIndex = static_cast<uint32_t>(GetLastIndex(thread, thisObj, isFastPath));
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, inputString,
RegExpExecResultCache::MATCH_TYPE, thisObj,
uint32_t lastIndex = static_cast<uint32_t>(GetLastIndex(thread, regexp, isFastPath));
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, string,
RegExpExecResultCache::MATCH_TYPE, regexp,
JSTaggedValue(lastIndex));
if (!cacheResult.IsUndefined()) {
return cacheResult;
}
}
bool fullUnicode = GetFlag(thread, thisObj, RegExpParser::FLAG_UTF16, isFastPath);
bool fullUnicode = GetFlag(thread, regexp, RegExpParser::FLAG_UTF16, isFastPath);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// b. Let setStatus be Set(rx, "lastIndex", 0, true).
SetLastIndex(thread, thisObj, JSTaggedValue(0), isFastPath);
SetLastIndex(thread, regexp, JSTaggedValue(0), isFastPath);
// c. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// d. Let A be ArrayCreate(0).
@ -626,23 +653,23 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
// f. Repeat,
while (true) {
if (isFastPath) {
uint32_t lastIndex = static_cast<uint32_t>(GetLastIndex(thread, thisObj, isFastPath));
uint32_t lastIndex = static_cast<uint32_t>(GetLastIndex(thread, regexp, isFastPath));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
result.Update(RegExpBuiltinExecWithoutResult(thread, thisObj, string, isFastPath, lastIndex, false));
result.Update(RegExpBuiltinExecWithoutResult(thread, regexp, string, isFastPath, lastIndex, false));
JSHandle<RegExpGlobalResult> globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult());
uint32_t endIndex = static_cast<uint32_t>(globalTable->GetEndOfCaptureIndex(0).GetInt());
if (result->IsNull()) {
// 1. If n=0, return null.
lastIndex = static_cast<uint32_t>(GetLastIndex(thread, thisObj, isFastPath));
lastIndex = static_cast<uint32_t>(GetLastIndex(thread, regexp, isFastPath));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (resultNum == 0) {
RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, inputString,
RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, string,
JSHandle<JSTaggedValue>(thread, JSTaggedValue::Null()),
RegExpExecResultCache::MATCH_TYPE,
0, 0);
return JSTaggedValue::Null();
}
RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, inputString,
RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, string,
JSHandle<JSTaggedValue>::Cast(array),
RegExpExecResultCache::MATCH_TYPE,
0, 0);
@ -655,7 +682,7 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
thread->GetEcmaVM(), JSHandle<EcmaString>::Cast(string), startIndex, len)));
} else {
// i. Let result be RegExpExec(rx, S).
result.Update(RegExpExec(thread, thisObj, string, useCache));
result.Update(RegExpExec(thread, regexp, string, useCache));
// ii. ReturnIfAbrupt(result).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// iii. If result is null, then
@ -689,12 +716,12 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
arrLen++;
// 5. If matchStr is the empty String, then
if (EcmaStringAccessor(matchString).GetLength() == 0) {
int64_t lastIndex = GetLastIndex(thread, thisObj, isFastPath);
int64_t lastIndex = GetLastIndex(thread, regexp, isFastPath);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
// d. Let setStatus be Set(rx, "lastIndex", nextIndex, true).
JSTaggedValue nextIndex = JSTaggedValue(AdvanceStringIndex(string, lastIndex, fullUnicode));
SetLastIndex(thread, thisObj, nextIndex, isFastPath);
SetLastIndex(thread, regexp, nextIndex, isFastPath);
// e. ReturnIfAbrupt(setStatus).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
@ -713,7 +740,6 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv)
// 1. Let R be the this value.
// 2. If Type(R) is not Object, throw a TypeError exception.
JSHandle<JSTaggedValue> thisObj = GetThis(argv);
auto ecmaVm = thread->GetEcmaVM();
if (!thisObj->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
}
@ -722,31 +748,38 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> inputString = GetCallArg(argv, 0);
JSHandle<EcmaString> stringHandle = JSTaggedValue::ToString(thread, inputString);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool isFastPath = IsFastRegExp(thread, thisObj);
return RegExpMatchAll(thread, thisObj, stringHandle, isFastPath);
}
JSTaggedValue BuiltinsRegExp::RegExpMatchAll(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<EcmaString> string, bool isFastPath)
{
JSMutableHandle<JSTaggedValue> matcher(thread, JSTaggedValue::Undefined());
bool global = false;
bool fullUnicode = false;
bool isFastPath = IsFastRegExp(thread, thisObj);
if (isFastPath) {
JSHandle<JSRegExp> regexp = JSHandle<JSRegExp>::Cast(thisObj);
JSHandle<JSTaggedValue> pattern(thread, regexp->GetOriginalSource());
JSHandle<JSTaggedValue> flags(thread, regexp->GetOriginalFlags());
JSHandle<JSRegExp> jsRegExp = JSHandle<JSRegExp>::Cast(regexp);
JSHandle<JSTaggedValue> pattern(thread, jsRegExp->GetOriginalSource());
JSHandle<JSTaggedValue> flags(thread, jsRegExp->GetOriginalFlags());
matcher.Update(BuiltinsRegExp::RegExpCreate(thread, pattern, flags));
SetLastIndex(thread, matcher,
JSHandle<JSObject>::Cast(regexp)->GetPropertyInlinedProps(LAST_INDEX_OFFSET), isFastPath);
JSHandle<JSObject>::Cast(jsRegExp)->GetPropertyInlinedProps(LAST_INDEX_OFFSET), isFastPath);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
global = GetOringinalFlag(thread, matcher, RegExpParser::FLAG_GLOBAL);
fullUnicode = GetOringinalFlag(thread, matcher, RegExpParser::FLAG_UTF16);
global = GetOriginalFlag(thread, matcher, RegExpParser::FLAG_GLOBAL);
fullUnicode = GetOriginalFlag(thread, matcher, RegExpParser::FLAG_UTF16);
} else {
auto ecmaVm = thread->GetEcmaVM();
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
JSHandle<JSTaggedValue> defaultConstructor = ecmaVm->GetGlobalEnv()->GetRegExpFunction();
JSHandle<JSObject> objHandle(thisObj);
JSHandle<JSObject> objHandle(regexp);
JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
const GlobalEnvConstants *globalConstants = thread->GlobalConstants();
// 5. Let flags be ? ToString(? Get(R, "flags")).
JSHandle<JSTaggedValue> flagsString(globalConstants->GetHandledFlagsString());
JSHandle<JSTaggedValue> getFlags(JSObject::GetProperty(thread, thisObj, flagsString).GetValue());
JSHandle<JSTaggedValue> getFlags(JSObject::GetProperty(thread, regexp, flagsString).GetValue());
JSHandle<EcmaString> flagsStrHandle = JSTaggedValue::ToString(thread, getFlags);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -755,14 +788,14 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv)
EcmaRuntimeCallInfo *runtimeInfo =
EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 2); // 2: two args
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
runtimeInfo->SetCallArg(thisObj.GetTaggedValue(), flagsStrHandle.GetTaggedValue());
runtimeInfo->SetCallArg(regexp.GetTaggedValue(), flagsStrHandle.GetTaggedValue());
JSTaggedValue taggedMatcher = JSFunction::Construct(runtimeInfo);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
matcher.Update(taggedMatcher);
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
JSHandle<JSTaggedValue> lastIndexString(globalConstants->GetHandledLastIndexString());
JSHandle<JSTaggedValue> getLastIndex(JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue());
JSHandle<JSTaggedValue> getLastIndex(JSObject::GetProperty(thread, regexp, lastIndexString).GetValue());
JSTaggedNumber thisLastIndex = JSTaggedValue::ToLength(thread, getLastIndex);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -787,7 +820,7 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv)
}
// 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
return JSRegExpIterator::CreateRegExpStringIterator(thread, matcher,
stringHandle, global, fullUnicode).GetTaggedValue();
string, global, fullUnicode).GetTaggedValue();
}
JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTaggedValue> regexp,
@ -957,8 +990,8 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread,
bool fullUnicode = false;
bool isFastPath = IsFastRegExp(thread, thisObj);
if (isFastPath) {
isGlobal = GetOringinalFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL);
fullUnicode = GetOringinalFlag(thread, thisObj, RegExpParser::FLAG_UTF16);
isGlobal = GetOriginalFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL);
fullUnicode = GetOriginalFlag(thread, thisObj, RegExpParser::FLAG_UTF16);
if (isGlobal) {
SetLastIndex(thread, thisObj, JSTaggedValue(0), isFastPath);
}
@ -1282,32 +1315,38 @@ JSTaggedValue BuiltinsRegExp::Search(EcmaRuntimeCallInfo *argv)
// 2. If Type(rx) is not Object, throw a TypeError exception.
THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception());
}
return RegExpSearch(thread, thisObj, string);
}
bool isFastPath = IsFastRegExp(thread, thisObj);
JSTaggedValue BuiltinsRegExp::RegExpSearch(JSThread *thread,
const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> string)
{
bool isFastPath = IsFastRegExp(thread, regexp);
if (isFastPath) {
return RegExpSearchFast(thread, thisObj, string);
return RegExpSearchFast(thread, regexp, string);
}
// 4. Let previousLastIndex be ? Get(rx, "lastIndex").
JSHandle<JSTaggedValue> lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString());
JSHandle<JSTaggedValue> previousLastIndex = JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue();
JSHandle<JSTaggedValue> previousLastIndex = JSObject::GetProperty(thread, regexp, lastIndexString).GetValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 5. If SameValue(previousLastIndex, 0) is false, then
// Perform ? Set(rx, "lastIndex", 0, true).
if (!JSTaggedValue::SameValue(previousLastIndex.GetTaggedValue(), JSTaggedValue(0))) {
JSHandle<JSTaggedValue> value(thread, JSTaggedValue(0));
JSObject::SetProperty(thread, thisObj, lastIndexString, value, true);
JSObject::SetProperty(thread, regexp, lastIndexString, value, true);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
// 6. Let result be ? RegExpExec(rx, S).
JSHandle<JSTaggedValue> result(thread, RegExpExec(thread, thisObj, string, false));
JSHandle<JSTaggedValue> result(thread, RegExpExec(thread, regexp, string, false));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 7. Let currentLastIndex be ? Get(rx, "lastIndex").
JSHandle<JSTaggedValue> currentLastIndex = JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue();
JSHandle<JSTaggedValue> currentLastIndex = JSObject::GetProperty(thread, regexp, lastIndexString).GetValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 8. If SameValue(currentLastIndex, previousLastIndex) is false, then
// Perform ? Set(rx, "lastIndex", previousLastIndex, true).
if (!JSTaggedValue::SameValue(previousLastIndex.GetTaggedValue(), currentLastIndex.GetTaggedValue())) {
JSObject::SetProperty(thread, thisObj, lastIndexString, previousLastIndex, true);
JSObject::SetProperty(thread, regexp, lastIndexString, previousLastIndex, true);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
// 9. If result is null, return -1.
@ -1612,8 +1651,8 @@ JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandle<J
return res.GetTaggedValue();
}
bool isUnicode = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_UTF16);
bool isSticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool isUnicode = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_UTF16);
bool isSticky = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
uint32_t nextMatchFrom = 0;
uint32_t lastMatchEnd = 0;
@ -2013,7 +2052,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
// If hasIndices is true, then
// a. Let indicesArray be MakeMatchIndicesIndexPairArray(S, indices, groupNames, hasGroups).
// b. Perform ! CreateDataPropertyOrThrow(A, "indices", indicesArray).
bool hasIndices = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_HASINDICES);
bool hasIndices = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_HASINDICES);
if (hasIndices) {
auto indicesArray = MakeMatchIndicesIndexPairArray(thread, indices, groupNames, hasGroups);
JSHandle<JSTaggedValue> indicesKey = globalConst->GetHandledIndicesString();
@ -2026,8 +2065,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
}
if (useCache) {
uint32_t newLastIndex = lastIndex;
bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool global = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
if (global || sticky) {
newLastIndex = globalTable->GetEndIndex().GetInt();
}
@ -2044,8 +2083,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExecWithoutResult(JSThread *thread, c
bool isFastPath, uint32_t lastIndex, bool useCache)
{
// check global and sticky flag to determine whether need to update lastIndex
bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool global = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
bool sticky = GetOriginalFlag(thread, regexp, RegExpParser::FLAG_STICKY);
bool ifUpdateLastIndex = global || sticky;
if (ifUpdateLastIndex) {
uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength();
@ -2734,7 +2773,7 @@ bool BuiltinsRegExp::GetFlag(JSThread *thread, const JSHandle<JSTaggedValue> reg
}
}
bool BuiltinsRegExp::GetOringinalFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag)
bool BuiltinsRegExp::GetOriginalFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag)
{
return GetFlag(thread, regexp, flag, true);
}

View File

@ -26,6 +26,14 @@
namespace panda::ecmascript::builtins {
class BuiltinsRegExp : public base::BuiltinsBase {
public:
enum RegExpSymbol {
SPLIT,
SEARCH,
MATCH,
MATCHALL,
REPLACE,
UNKNOWN
};
// 21.2.3.1 RegExp ( pattern, flags )
static JSTaggedValue RegExpConstructor(EcmaRuntimeCallInfo *argv);
@ -82,8 +90,10 @@ public:
JSHandle<JSTaggedValue> string,
JSHandle<JSTaggedValue> inputReplaceValue);
static JSTaggedValue GetAllFlagsInternal(JSThread *thread, JSHandle<JSTaggedValue> &thisObj);
static bool IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> regexp);
static bool IsFastRegExp(JSThread *thread, JSHandle<JSTaggedValue> regexp,
RegExpSymbol symbolTag = RegExpSymbol::UNKNOWN);
static bool GetFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag, bool isFastPath);
static bool GetOriginalFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag);
static void SetLastIndex(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
JSTaggedValue lastIndex, bool isFastPath);
static int64_t GetLastIndex(JSThread *thread, const JSHandle<JSTaggedValue> regexp, bool isFastPath);
@ -94,6 +104,9 @@ public:
static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> inputStr,
bool isFastPath, bool useCache, bool isIntermediateResult = false);
static JSTaggedValue RegExpSearch(JSThread *thread,
const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> string);
static JSTaggedValue RegExpSearchFast(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> string);
static JSTaggedValue RegExpSplit(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
@ -103,6 +116,10 @@ public:
bool isFastPath);
static JSTaggedValue GetExecResultGroups(JSThread *thread, const JSHandle<JSTaggedValue> &execResults,
bool isFastPath);
static JSTaggedValue RegExpMatch(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<JSTaggedValue> string, bool isFastPath);
static JSTaggedValue RegExpMatchAll(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
const JSHandle<EcmaString> string, bool isFastPath);
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SET_GET_CAPTURE(index) \
static JSTaggedValue GetCapture##index(JSThread *thread, const JSHandle<JSObject> &obj); \
@ -120,6 +137,13 @@ public:
SET_GET_CAPTURE(9)
#undef SET_GET_CAPTURE
#define REGEXP_SYMBOL_FUNCTION_LIST(V) \
V(SPLIT, Split) \
V(SEARCH, Search) \
V(MATCH, Match) \
V(MATCHALL, MatchAll) \
V(REPLACE, Replace)
private:
static constexpr uint32_t MIN_REPLACE_STRING_LENGTH = 1000;
static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu;
@ -165,7 +189,6 @@ private:
JSHandle<EcmaString> inputString, int32_t lastIndex);
static JSTaggedValue RegExpSplitFast(JSThread *thread, const JSHandle<JSTaggedValue> regexp,
JSHandle<JSTaggedValue> string, uint32_t limit, bool useCache);
static bool GetOringinalFlag(JSThread *thread, const JSHandle<JSTaggedValue> regexp, uint32_t flag);
static JSHandle<EcmaString> CreateStringFromResultArray(JSThread *thread, const JSHandle<TaggedArray> resultArray,
const std::vector<uint64_t> &resultLengthArray, JSHandle<EcmaString> srcString,
uint32_t resultStrLength, bool isUtf8);

View File

@ -624,24 +624,14 @@ JSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0);
JSHandle<JSTaggedValue> matchTag = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
if (regexp->IsJSRegExp()) {
JSHandle<RegExpExecResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache());
JSHandle<JSRegExp> re(regexp);
JSHandle<JSTaggedValue> pattern(thread, re->GetOriginalSource());
JSHandle<JSTaggedValue> flags(thread, re->GetOriginalFlags());
bool isFastPath = BuiltinsRegExp::IsFastRegExp(thread, regexp);
if (isFastPath) {
uint32_t lastIndex = static_cast<uint32_t>(BuiltinsRegExp::GetLastIndex(thread, regexp, true));
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, thisTag,
RegExpExecResultCache::MATCH_TYPE, regexp,
JSTaggedValue(lastIndex));
if (!cacheResult.IsUndefined()) {
return cacheResult;
}
if (thisTag->IsString() && regexp->IsECMAObject()) {
if (BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCH)) {
return BuiltinsRegExp::RegExpMatch(thread, regexp, thisTag, true);
}
}
JSHandle<JSTaggedValue> matchTag = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
if (!regexp->IsUndefined() && !regexp->IsNull()) {
JSHandle<JSTaggedValue> matcher = JSObject::GetMethod(thread, regexp, matchTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -676,19 +666,23 @@ JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0);
JSHandle<JSTaggedValue> matchAllTag = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchAllSymbol();
EcmaVM *ecmaVm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
JSHandle<JSTaggedValue> matchAllTag = env->GetMatchAllSymbol();
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
auto ecmaVm = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVm->GetFactory();
JSHandle<JSTaggedValue> gvalue(factory->NewFromASCII("g"));
// 2. If regexp is neither undefined nor null, then
if (!regexp->IsUndefined() && !regexp->IsNull()) {
// a. Let isRegExp be ? IsRegExp(searchValue).
bool isJSRegExp = JSObject::IsRegExp(thread, regexp);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// b. If isRegExp is true, then
if (isJSRegExp) {
if (regexp->IsECMAObject() &&
BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCH)) {
bool isGlobal = BuiltinsRegExp::GetOriginalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL);
if (!isGlobal) {
THROW_TYPE_ERROR_AND_RETURN(thread,
"matchAll called with a non-global RegExp argument",
JSTaggedValue::Exception());
}
} else if (JSObject::IsRegExp(thread, regexp)) {
// i. Let flags be ? Get(searchValue, "flags").
JSHandle<JSTaggedValue> flagsString(globalConst->GetHandledFlagsString());
JSHandle<JSTaggedValue> flags = JSObject::GetProperty(thread, regexp, flagsString).GetValue();
@ -700,7 +694,7 @@ JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv)
JSHandle<EcmaString> flagString = JSTaggedValue::ToString(thread, flags);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm,
flagString, JSHandle<EcmaString>(gvalue));
flagString, ecmaVm->GetFactory()->NewFromASCII("g"));
if (pos == -1) {
THROW_TYPE_ERROR_AND_RETURN(thread,
"matchAll called with a non-global RegExp argument",
@ -708,24 +702,37 @@ JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv)
}
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (thisTag->IsString() && regexp->IsECMAObject()) {
if (PropertyDetector::IsRegExpSpeciesDetectorValid(env) &&
BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCHALL)) {
JSHandle<EcmaString> string = JSHandle<EcmaString>::Cast(thisTag);
return BuiltinsRegExp::RegExpMatchAll(thread, regexp, string, true);
}
}
// c. Let matcher be ? GetMethod(regexp, @@matchAll).
// d. If matcher is not undefined, then
JSHandle<JSTaggedValue> matcher = JSObject::GetMethod(thread, regexp, matchAllTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!matcher->IsUndefined()) {
// i. Return ? Call(matcher, regexp, « O »).
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, matcher, regexp, undefined, 1);
bool canSkip = (PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env) &&
(regexp->IsString() || regexp->IsNumber()));
if (!canSkip) {
JSHandle<JSTaggedValue> matcher = JSObject::GetMethod(thread, regexp, matchAllTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(thisTag.GetTaggedValue());
return JSFunction::Call(info);
if (!matcher->IsUndefined()) {
// i. Return ? Call(matcher, regexp, « O »).
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, matcher, regexp, undefined, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(thisTag.GetTaggedValue());
return JSFunction::Call(info);
}
}
}
// 3. Let S be ? ToString(O).
JSHandle<EcmaString> thisVal = JSTaggedValue::ToString(thread, thisTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 4. Let rx be ? RegExpCreate(regexp, "g").
JSHandle<JSTaggedValue> rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, gvalue));
JSHandle<JSTaggedValue> rx(thread, BuiltinsRegExp::RegExpCreate(
thread, regexp, JSHandle<JSTaggedValue>(ecmaVm->GetFactory()->NewFromASCII("g"))));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, rx, undefined, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
@ -1489,7 +1496,7 @@ JSTaggedValue BuiltinsString::Search(EcmaRuntimeCallInfo *argv)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0);
if (thisTag->IsString() && regexp->IsECMAObject()) {
if (BuiltinsRegExp::IsFastRegExp(thread, regexp)) {
if (BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::SEARCH)) {
return BuiltinsRegExp::RegExpSearchFast(thread, regexp, thisTag);
}
}

View File

@ -865,8 +865,6 @@ void Builtins::InitializeSSymbolAttributes(const JSHandle<GlobalEnv> &env)
factory_->NewSPublicSymbolWithChar("Symbol.asyncIterator"));
JSHandle<JSTaggedValue> matchSymbol(
factory_->NewSPublicSymbolWithChar("Symbol.match"));
JSHandle<JSTaggedValue> matchAllSymbol(
factory_->NewSPublicSymbolWithChar("Symbol.matchAll"));
JSHandle<JSTaggedValue> searchSymbol(
factory_->NewSPublicSymbolWithChar("Symbol.search"));
JSHandle<JSTaggedValue> toPrimitiveSymbol(

View File

@ -3164,7 +3164,13 @@ inline void StubBuilder::CheckDetectorName(GateRef glue, GateRef key, Label *fal
VariableType::INT64(), glueGlobalEnv, GlobalEnv::LAST_DETECTOR_SYMBOL_INDEX);
GateRef isDetectorName = BoolAnd(Int64UnsignedLessThanOrEqual(firstDetectorName, keyAddr),
Int64UnsignedLessThanOrEqual(keyAddr, lastDetectorName));
BRANCH(isDetectorName, slow, fallthrough);
Label checkCommonDetector(env_);
BRANCH(isDetectorName, slow, &checkCommonDetector);
Bind(&checkCommonDetector);
auto gFlagsStr = GetGlobalConstantValue(
VariableType::JS_POINTER(), glue, ConstantIndex::FLAGS_INDEX);
GateRef isFlagsStr = Equal(key, gFlagsStr);
BRANCH(isFlagsStr, slow, fallthrough);
}
inline GateRef StubBuilder::LoadPfHeaderFromConstPool(GateRef jsFunc)

View File

@ -3965,11 +3965,11 @@ GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef
Jump(&exit);
}
Label isString(env);
Label notString(env);
Label checkDetector(env);
Bind(&notNumber1);
{
Label notIntenalString(env);
BRANCH(TaggedIsString(*varKey), &isString, &notString);
BRANCH(TaggedIsString(*varKey), &isString, &checkDetector);
Bind(&isString);
{
BRANCH(IsInternalString(*varKey), &setByName, &notIntenalString);
@ -3983,21 +3983,21 @@ GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef
{
varKey = CallRuntime(glue, RTSTUB_ID(InsertStringToTable), { *varKey });
isInternal = False();
Jump(&setByName);
Jump(&checkDetector);
}
Bind(&find);
{
varKey = res;
Jump(&setByName);
Jump(&checkDetector);
}
}
}
}
Bind(&notString);
Bind(&checkDetector);
CheckDetectorName(glue, *varKey, &setByName, &exit);
Bind(&setByName);
{
result = SetPropertyByName(glue, receiver, *varKey, value, useOwn, *isInternal, callback,
result = SetPropertyByName(glue, receiver, *varKey, value, useOwn, *isInternal, callback,
true, defineSemantics);
Jump(&exit);
}

View File

@ -118,6 +118,11 @@
V(JSTaggedValue, ListFormatFunction, LIST_FORMAT_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpFunction, REGEXP_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpExecFunction, REGEXP_EXEC_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpSplitFunction, REGEXP_SPLIT_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpSearchFunction, REGEXP_SEARCH_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpMatchFunction, REGEXP_MATCH_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpMatchAllFunction, REGEXP_MATCHALL_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpReplaceFunction, REGEXP_REPLACE_FUNCTION_INDEX) \
V(JSTaggedValue, RegExpPrototype, REGEXP_PROTOTYPE_INDEX) \
V(JSTaggedValue, RegExpPrototypeClass, REGEXP_PROTOTYPE_CLASS_INDEX) \
V(JSTaggedValue, BuiltinsSetFunction, BUILTINS_SET_FUNCTION_INDEX) \
@ -235,6 +240,7 @@
/* DETECTOR SYMBOL BEGIN (Maintain the same order with DETECTOR_SYMBOL_LIST) */ \
V(JSTaggedValue, ReplaceSymbol, REPLACE_SYMBOL_INDEX) \
V(JSTaggedValue, SplitSymbol, SPLIT_SYMBOL_INDEX) \
V(JSTaggedValue, MatchAllSymbol, MATCH_ALL_SYMBOL_INDEX) \
V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX) \
V(JSTaggedValue, SpeciesSymbol, SPECIES_SYMBOL_INDEX) \
/* DETECTOR SYMBOL END */ \
@ -242,7 +248,6 @@
V(JSTaggedValue, ToStringTagSymbol, TOSTRINGTAG_SYMBOL_INDEX) \
V(JSTaggedValue, AsyncIteratorSymbol, ASYNC_ITERATOR_SYMBOL_INDEX) \
V(JSTaggedValue, MatchSymbol, MATCH_SYMBOL_INDEX) \
V(JSTaggedValue, MatchAllSymbol, MATCH_All_SYMBOL_INDEX) \
V(JSTaggedValue, SearchSymbol, SEARCH_SYMBOL_INDEX) \
V(JSTaggedValue, ToPrimitiveSymbol, TOPRIMITIVE_SYMBOL_INDEX) \
V(JSTaggedValue, UnscopablesSymbol, UNSCOPABLES_SYMBOL_INDEX) \

View File

@ -170,10 +170,11 @@ bool JSObject::IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argumen
return false;
}
JSHandle<JSTaggedValue> matchSymbol = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
JSHandle<JSTaggedValue> isRegexp = JSObject::GetProperty(thread, argument, matchSymbol).GetValue();
JSTaggedValue isRegexp = ObjectFastOperator::FastGetPropertyByValue(
thread, argument.GetTaggedValue(), matchSymbol.GetTaggedValue());
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
if (!isRegexp->IsUndefined()) {
return isRegexp->ToBoolean();
if (!isRegexp.IsUndefined()) {
return isRegexp.ToBoolean();
}
JSHandle<JSObject> argumentObj = JSHandle<JSObject>::Cast(argument);
return argumentObj->IsJSRegExp();

View File

@ -25,6 +25,11 @@ namespace panda::ecmascript {
class JSRegExp : public JSObject {
public:
static constexpr int EXEC_INLINE_PROPERTY_INDEX = 1;
static constexpr int SPLIT_INLINE_PROPERTY_INDEX = 13;
static constexpr int SEARCH_INLINE_PROPERTY_INDEX = 14;
static constexpr int MATCH_INLINE_PROPERTY_INDEX = 15;
static constexpr int MATCHALL_INLINE_PROPERTY_INDEX = 16;
static constexpr int REPLACE_INLINE_PROPERTY_INDEX = 17;
CAST_CHECK(JSRegExp, IsJSRegExp);

View File

@ -1007,6 +1007,41 @@ JSHandle<JSObject> ObjectFactory::NewJSAggregateError()
return NewJSObjectByConstructor(constructor);
}
JSHandle<JSObject> ObjectFactory::NewJSObjectByConstructor(JSHandle<GlobalEnv> env,
const JSHandle<JSFunction> &constructor, uint32_t inlinedProps)
{
if (!constructor->HasFunctionPrototype() ||
(constructor->GetProtoOrHClass().IsHeapObject() && constructor->GetFunctionPrototype().IsECMAObject())) {
JSHandle<JSHClass> jshclass;
if (LIKELY(inlinedProps == JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS)) {
jshclass = JSHandle<JSHClass>(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, constructor));
} else {
jshclass = NewEcmaHClass(JSObject::SIZE, inlinedProps, JSType::JS_OBJECT,
env->GetObjectFunctionPrototype());
}
JSHandle<JSObject> obj;
if (jshclass->IsJSSharedObject()) {
obj = NewSharedOldSpaceJSObject(jshclass);
if (jshclass->IsDictionaryMode()) {
auto fieldLayout = jshclass->GetLayout();
ASSERT(fieldLayout.IsDictionary());
auto dict = JSHandle<TaggedArray>(thread_, fieldLayout);
auto properties = NewAndCopySNameDictionary(dict, dict->GetLength());
obj->SetProperties(thread_, properties);
}
} else {
obj = NewJSObjectWithInit(jshclass);
}
return obj;
}
JSHandle<JSObject> result =
NewJSObjectByConstructor(JSHandle<JSFunction>(env->GetObjectFunction()), JSHandle<JSTaggedValue>(constructor));
if (thread_->HasPendingException()) {
LOG_FULL(FATAL) << "NewJSObjectByConstructor should not throw Exception! ";
}
return result;
}
JSHandle<JSObject> ObjectFactory::NewJSObjectByConstructor(const JSHandle<JSFunction> &constructor,
uint32_t inlinedProps)
{

View File

@ -561,6 +561,8 @@ public:
// used for creating jsobject by constructor
JSHandle<JSObject> NewJSObjectByConstructor(const JSHandle<JSFunction> &constructor,
const JSHandle<JSTaggedValue> &newTarget);
JSHandle<JSObject> NewJSObjectByConstructor(JSHandle<GlobalEnv> env,
const JSHandle<JSFunction> &constructor, uint32_t inlinedProps);
JSHandle<JSObject> NewJSObjectByConstructor(const JSHandle<JSFunction> &constructor,
uint32_t inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
void InitializeJSObject(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &jshclass);

View File

@ -514,9 +514,8 @@ JSTaggedValue ObjectFastOperator::SetPropertyByValue(JSThread *thread, JSTaggedV
receiver = receiverHandler.GetTaggedValue();
value = valueHandler.GetTaggedValue();
}
} else {
ObjectOperator::UpdateDetector(thread, receiver, key);
}
ObjectOperator::UpdateDetector(thread, receiver, key);
return ObjectFastOperator::SetPropertyByName<status>(thread, receiver, key, value, sCheckMode);
}
return JSTaggedValue::Hole();

View File

@ -240,8 +240,8 @@ void ObjectOperator::UpdateDetectorOnSetPrototype(const JSThread *thread, JSTagg
if (PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
PropertyDetector::InvalidateRegExpReplaceDetector(env);
}
if (PropertyDetector::IsRegExpSplitDetectorValid(env)) {
PropertyDetector::InvalidateRegExpSplitDetector(env);
if (PropertyDetector::IsRegExpFlagsDetectorValid(env)) {
PropertyDetector::InvalidateRegExpFlagsDetector(env);
}
return;
}
@ -309,6 +309,11 @@ void ObjectOperator::UpdateDetectorOnSetPrototype(const JSThread *thread, JSTagg
PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
return;
}
if ((PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env) &&
JSObject::Cast(receiver)->GetJSHClass()->IsPrototype() && receiver.IsJSPrimitive())) {
PropertyDetector::InvalidateNumberStringNotRegexpLikeDetector(env);
return;
}
}
void ObjectOperator::UpdateDetector()
@ -326,27 +331,18 @@ void ObjectOperator::UpdateDetector(const JSThread *thread, JSTaggedValue receiv
if (!thread->IsReadyToUpdateDetector()) {
return;
}
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
bool maybeDetector = IsDetectorName(env, key);
bool maybeDetector = IsDetectorName(thread, key);
if (!maybeDetector) {
return;
}
// only support symbol keys now
ASSERT(key.IsSymbol());
if (key == env->GetTaggedReplaceSymbol()) {
if (receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype()) {
if (!PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateRegExpReplaceDetector(env);
}
} else if (key == env->GetTaggedSplitSymbol()) {
if (receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype()) {
if (!PropertyDetector::IsRegExpSplitDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateRegExpSplitDetector(env);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
auto globalConst = thread->GlobalConstants();
if (key == env->GetTaggedReplaceSymbol() &&
(receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype())) {
if (!PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateRegExpReplaceDetector(env);
} else if (key == env->GetTaggedIteratorSymbol()) {
if (receiver.IsJSMap() || receiver == env->GetTaggedMapPrototype()) {
if (!PropertyDetector::IsMapIteratorDetectorValid(env)) {
@ -388,22 +384,52 @@ void ObjectOperator::UpdateDetector(const JSThread *thread, JSTaggedValue receiv
PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
}
} else if (key == env->GetTaggedSpeciesSymbol()) {
if (receiver.IsJSObject()) {
if (receiver == env->GetTypedArrayFunction().GetTaggedValue()) {
if (!PropertyDetector::IsTypedArraySpeciesProtectDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateTypedArraySpeciesProtectDetector(env);
}
if (receiver == env->GetRegExpFunction().GetTaggedValue()) {
if (!PropertyDetector::IsRegExpSpeciesDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateRegExpSpeciesDetector(env);
}
} else if ((key == env->GetTaggedReplaceSymbol()) ||
(key == env->GetTaggedSplitSymbol()) ||
(key == env->GetTaggedMatchAllSymbol())) {
if (!PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env)) {
return;
}
// check String.prototype or Number.prototype or Object.prototype
if ((JSObject::Cast(receiver)->GetJSHClass()->IsPrototype() &&
(receiver.IsJSPrimitive() || receiver == env->GetTaggedObjectFunctionPrototype()))) {
PropertyDetector::InvalidateNumberStringNotRegexpLikeDetector(env);
}
} else if (key == globalConst->GetHandledFlagsString().GetTaggedValue() &&
(receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype())) {
if (!PropertyDetector::IsRegExpFlagsDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateRegExpFlagsDetector(env);
}
}
// static
bool ObjectOperator::IsDetectorName(JSHandle<GlobalEnv> env, JSTaggedValue key)
bool ObjectOperator::IsDetectorName(const JSThread *thread, JSTaggedValue key)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
uintptr_t start = GlobalEnv::GetFirstDetectorSymbolAddr(*env);
uintptr_t end = GlobalEnv::GetLastDetectorSymbolAddr(*env);
uintptr_t addr = key.GetRawData();
return (start <= addr) && (addr <= end);
if ((start <= addr) && (addr <= end)) {
return true;
}
if (key == thread->GlobalConstants()->GetHandledFlagsString().GetTaggedValue()) {
return true;
}
return false;
}
SharedFieldType ObjectOperator::GetSharedFieldType() const

View File

@ -65,7 +65,7 @@ public:
void UpdateDetector();
static void PUBLIC_API UpdateDetector(const JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
static void UpdateDetectorOnSetPrototype(const JSThread *thread, JSTaggedValue receiver);
static bool IsDetectorName(JSHandle<GlobalEnv> env, JSTaggedValue key);
static bool IsDetectorName(const JSThread *thread, JSTaggedValue key);
NO_COPY_SEMANTIC(ObjectOperator);
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ObjectOperator);

View File

@ -27,13 +27,15 @@ class PropertyDetector {
public:
#define GLOBAL_ENV_DETECTOR_FIELDS(V) \
V(JSTaggedValue, RegExpReplaceDetector, REGEXP_REPLACE_DETECTOR_INDEX) \
V(JSTaggedValue, RegExpSplitDetector, REGEXP_SPLIT_DETECTOR_INDEX) \
V(JSTaggedValue, MapIteratorDetector, MAP_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, SetIteratorDetector, SET_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, StringIteratorDetector, STRING_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, ArrayIteratorDetector, ARRAY_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, TypedArrayIteratorDetector, TYPED_ARRAY_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, TypedArraySpeciesProtectDetector, TYPED_ARRAY_SPECIES_PROTECT_DETECTOR_INDEX)
V(JSTaggedValue, TypedArraySpeciesProtectDetector, TYPED_ARRAY_SPECIES_PROTECT_DETECTOR_INDEX) \
V(JSTaggedValue, NumberStringNotRegexpLikeDetector, NUMBER_STRING_NOT_REGEXP_LIKE_DETECTOR_INDEX) \
V(JSTaggedValue, RegExpFlagsDetector, REGEXP_FLAGS_DETECTOR_INDEX) \
V(JSTaggedValue, RegExpSpeciesDetector, REGEXP_SPECIES_DETECTOR_INDEX)
#define DECLARE_DETECTOR(type, name, index) \
static inline bool Is##name##Valid(JSHandle<GlobalEnv> env); \
@ -44,6 +46,7 @@ public:
#define DETECTOR_SYMBOL_LIST(V) \
V(ReplaceSymbol, "Symbol.replace", replace ) \
V(SplitSymbol, "Symbol.split", split ) \
V(MatchAllSymbol, "Symbol.matchAll", matchAll) \
V(IteratorSymbol, "Symbol.iterator", iterator) \
V(SpeciesSymbol, "Symbol.species", species)
};

View File

@ -11,6 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
true
false
这是一段原始文本,"3这要替换4"!
true
true
@ -21,3 +23,5 @@ aaa
false
4
false
true
false

View File

@ -20,6 +20,14 @@
* @tc.require: issueI83B0E
*/
print(ArkTools.isRegExpFlagsDetectorValid())
Object.defineProperty(RegExp.prototype, 'flags', {
get: function () {
return undefined;
}
});
print(ArkTools.isRegExpFlagsDetectorValid())
let str = '这是一段原始文本,"3c这要替换4d"!';
let regexp = /([0-9])([a-z])/g
let newStr1 = str.replace(regexp, "$1" );
@ -49,3 +57,7 @@ p[Symbol.replace] = function () {return 4}
let newStr4 = str.replace( /([0-9])([a-z])/g,"$4" );
print(newStr4)
print(ArkTools.isRegExpReplaceDetectorValid())
print(ArkTools.isNumberStringNotRegexpLikeDetectorValid());
String.prototype[Symbol.matchAll] = function () {return "aaa"}
print(ArkTools.isNumberStringNotRegexpLikeDetectorValid());