mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 01:59:58 +00:00
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:
parent
21dd6c25b1
commit
911a7c1b37
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -3965,11 +3965,11 @@ GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef
|
||||
Jump(&exit);
|
||||
}
|
||||
Label isString(env);
|
||||
Label notString(env);
|
||||
Label checkDetector(env);
|
||||
Bind(¬Number1);
|
||||
{
|
||||
Label notIntenalString(env);
|
||||
BRANCH(TaggedIsString(*varKey), &isString, ¬String);
|
||||
BRANCH(TaggedIsString(*varKey), &isString, &checkDetector);
|
||||
Bind(&isString);
|
||||
{
|
||||
BRANCH(IsInternalString(*varKey), &setByName, ¬IntenalString);
|
||||
@ -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(¬String);
|
||||
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);
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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());
|
Loading…
Reference in New Issue
Block a user