Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (259746 => 259747)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-08 20:01:39 UTC (rev 259747)
@@ -1,3 +1,37 @@
+2020-04-08 Yusuke Suzuki <[email protected]>
+
+ [JSC] Threading JSGlobalObject in RegExp::match properly
+ https://bugs.webkit.org/show_bug.cgi?id=210174
+
+ Reviewed by Saam Barati.
+
+ We thread JSGlobalObject* properly in RegExp::match instead of accessing VM::topCallFrame, which is too hacky.
+
+ * runtime/RegExp.cpp:
+ (JSC::RegExp::match):
+ (JSC::RegExp::matchConcurrently):
+ * runtime/RegExp.h:
+ * runtime/RegExpGlobalData.h:
+ * runtime/RegExpGlobalDataInlines.h:
+ (JSC::RegExpGlobalData::performMatch):
+ * runtime/RegExpInlines.h:
+ (JSC::RegExp::matchInline):
+ * runtime/RegExpMatchesArray.h:
+ (JSC::createRegExpMatchesArray):
+ * runtime/RegExpObjectInlines.h:
+ (JSC::RegExpObject::matchInline):
+ (JSC::collectMatches):
+ * runtime/RegExpPrototype.cpp:
+ (JSC::regExpProtoFuncSearchFast):
+ (JSC::genericSplit):
+ (JSC::regExpProtoFuncSplitFast):
+ * runtime/StringPrototype.cpp:
+ (JSC::removeUsingRegExpSearch):
+ (JSC::replaceUsingRegExpSearch):
+ * testRegExp.cpp:
+ (testOneRegExp):
+ (runFromFiles):
+
2020-04-08 Devin Rousso <[email protected]>
Web Inspector: Storage: cannot clear out multiple or all local storage entries
Modified: trunk/Source/_javascript_Core/runtime/RegExp.cpp (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExp.cpp 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExp.cpp 2020-04-08 20:01:39 UTC (rev 259747)
@@ -286,9 +286,9 @@
}
}
-int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int>& ovector)
+int RegExp::match(JSGlobalObject* globalObject, const String& s, unsigned startOffset, Vector<int>& ovector)
{
- return matchInline(vm, s, startOffset, ovector);
+ return matchInline(globalObject, globalObject->vm(), s, startOffset, ovector);
}
bool RegExp::matchConcurrently(
@@ -299,7 +299,7 @@
if (!hasCodeFor(s.is8Bit() ? Yarr::Char8 : Yarr::Char16))
return false;
- position = matchInline<Vector<int>&, Yarr::MatchFrom::CompilerThread>(vm, s, startOffset, ovector);
+ position = matchInline<Vector<int>&, Yarr::MatchFrom::CompilerThread>(nullptr, vm, s, startOffset, ovector);
if (m_state == ParseError)
return false;
return true;
@@ -350,9 +350,9 @@
}
}
-MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
+MatchResult RegExp::match(JSGlobalObject* globalObject, const String& s, unsigned startOffset)
{
- return matchInline(vm, s, startOffset);
+ return matchInline(globalObject, globalObject->vm(), s, startOffset);
}
bool RegExp::matchConcurrently(VM& vm, const String& s, unsigned startOffset, MatchResult& result)
@@ -362,7 +362,7 @@
if (!hasMatchOnlyCodeFor(s.is8Bit() ? Yarr::Char8 : Yarr::Char16))
return false;
- result = matchInline<Yarr::MatchFrom::CompilerThread>(vm, s, startOffset);
+ result = matchInline<Yarr::MatchFrom::CompilerThread>(nullptr, vm, s, startOffset);
return true;
}
Modified: trunk/Source/_javascript_Core/runtime/RegExp.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExp.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExp.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -76,20 +76,20 @@
m_constructionErrorCode = Yarr::ErrorCode::NoError;
}
- JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int>& ovector);
+ JS_EXPORT_PRIVATE int match(JSGlobalObject*, const String&, unsigned startOffset, Vector<int>& ovector);
// Returns false if we couldn't run the regular _expression_ for any reason.
bool matchConcurrently(VM&, const String&, unsigned startOffset, int& position, Vector<int>& ovector);
- JS_EXPORT_PRIVATE MatchResult match(VM&, const String&, unsigned startOffset);
+ JS_EXPORT_PRIVATE MatchResult match(JSGlobalObject*, const String&, unsigned startOffset);
bool matchConcurrently(VM&, const String&, unsigned startOffset, MatchResult&);
// Call these versions of the match functions if you're desperate for performance.
template<typename VectorType, Yarr::MatchFrom thread = Yarr::MatchFrom::VMThread>
- int matchInline(VM&, const String&, unsigned startOffset, VectorType& ovector);
+ int matchInline(JSGlobalObject* nullOrGlobalObject, VM&, const String&, unsigned startOffset, VectorType& ovector);
template<Yarr::MatchFrom thread = Yarr::MatchFrom::VMThread>
- MatchResult matchInline(VM&, const String&, unsigned startOffset);
+ MatchResult matchInline(JSGlobalObject* nullOrGlobalObject, VM&, const String&, unsigned startOffset);
unsigned numSubpatterns() const { return m_numSubpatterns; }
Modified: trunk/Source/_javascript_Core/runtime/RegExpGlobalData.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpGlobalData.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpGlobalData.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -48,8 +48,8 @@
JSValue getLeftContext(JSGlobalObject*);
JSValue getRightContext(JSGlobalObject*);
- MatchResult performMatch(VM&, JSGlobalObject*, RegExp*, JSString*, const String&, int startOffset, int** ovector);
- MatchResult performMatch(VM&, JSGlobalObject*, RegExp*, JSString*, const String&, int startOffset);
+ MatchResult performMatch(JSGlobalObject*, RegExp*, JSString*, const String&, int startOffset, int** ovector);
+ MatchResult performMatch(JSGlobalObject*, RegExp*, JSString*, const String&, int startOffset);
void recordMatch(VM&, JSGlobalObject*, RegExp*, JSString*, const MatchResult&);
static ptrdiff_t offsetOfCachedResult() { return OBJECT_OFFSETOF(RegExpGlobalData, m_cachedResult); }
Modified: trunk/Source/_javascript_Core/runtime/RegExpGlobalDataInlines.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpGlobalDataInlines.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpGlobalDataInlines.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -39,9 +39,13 @@
_expression_ matching through the performMatch function. We use cached results to calculate,
e.g., RegExp.lastMatch and RegExp.leftParen.
*/
-ALWAYS_INLINE MatchResult RegExpGlobalData::performMatch(VM& vm, JSGlobalObject* owner, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector)
+ALWAYS_INLINE MatchResult RegExpGlobalData::performMatch(JSGlobalObject* owner, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector)
{
- int position = regExp->match(vm, input, startOffset, m_ovector);
+ ASSERT(owner);
+ VM& vm = owner->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ int position = regExp->match(owner, input, startOffset, m_ovector);
+ RETURN_IF_EXCEPTION(scope, MatchResult::failed());
if (ovector)
*ovector = m_ovector.data();
@@ -59,9 +63,13 @@
return MatchResult(position, end);
}
-ALWAYS_INLINE MatchResult RegExpGlobalData::performMatch(VM& vm, JSGlobalObject* owner, RegExp* regExp, JSString* string, const String& input, int startOffset)
+ALWAYS_INLINE MatchResult RegExpGlobalData::performMatch(JSGlobalObject* owner, RegExp* regExp, JSString* string, const String& input, int startOffset)
{
- MatchResult result = regExp->match(vm, input, startOffset);
+ ASSERT(owner);
+ VM& vm = owner->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ MatchResult result = regExp->match(owner, input, startOffset);
+ RETURN_IF_EXCEPTION(scope, MatchResult::failed());
if (result)
m_cachedResult.record(vm, owner, regExp, string, result);
return result;
Modified: trunk/Source/_javascript_Core/runtime/RegExpInlines.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpInlines.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpInlines.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -98,7 +98,7 @@
}
template<typename VectorType, Yarr::MatchFrom matchFrom>
-ALWAYS_INLINE int RegExp::matchInline(VM& vm, const String& s, unsigned startOffset, VectorType& ovector)
+ALWAYS_INLINE int RegExp::matchInline(JSGlobalObject* nullOrGlobalObject, VM& vm, const String& s, unsigned startOffset, VectorType& ovector)
{
#if ENABLE(REGEXP_TRACING)
m_rtMatchCallCount++;
@@ -108,11 +108,12 @@
compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
auto throwError = [&] {
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- // FIXME: Revisit JSGlobalObject.
- // https://bugs.webkit.org/show_bug.cgi?id=203204
- JSGlobalObject* globalObject = vm.topCallFrame->lexicalGlobalObject(vm);
- throwScope.throwException(globalObject, errorToThrow(globalObject));
+ if (matchFrom == Yarr::MatchFrom::CompilerThread)
+ return -1;
+ if (nullOrGlobalObject) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ throwScope.throwException(nullOrGlobalObject, errorToThrow(nullOrGlobalObject));
+ }
if (!hasHardError(m_constructionErrorCode))
reset();
return -1;
@@ -141,11 +142,8 @@
if (result == Yarr::JSRegExpJITCodeFailure) {
// JIT'ed code couldn't handle _expression_, so punt back to the interpreter.
byteCodeCompileIfNecessary(&vm);
- if (m_state == ParseError) {
- if (matchFrom == Yarr::MatchFrom::CompilerThread)
- return -1;
+ if (m_state == ParseError)
return throwError();
- }
result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
}
@@ -232,7 +230,7 @@
}
template<Yarr::MatchFrom matchFrom>
-ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, const String& s, unsigned startOffset)
+ALWAYS_INLINE MatchResult RegExp::matchInline(JSGlobalObject* nullOrGlobalObject, VM& vm, const String& s, unsigned startOffset)
{
#if ENABLE(REGEXP_TRACING)
m_rtMatchOnlyCallCount++;
@@ -242,11 +240,12 @@
compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
auto throwError = [&] {
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- // FIXME: Revisit JSGlobalObject.
- // https://bugs.webkit.org/show_bug.cgi?id=203204
- JSGlobalObject* globalObject = vm.topCallFrame->lexicalGlobalObject(vm);
- throwScope.throwException(globalObject, errorToThrow(globalObject));
+ if (matchFrom == Yarr::MatchFrom::CompilerThread)
+ return MatchResult::failed();
+ if (nullOrGlobalObject) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ throwScope.throwException(nullOrGlobalObject, errorToThrow(nullOrGlobalObject));
+ }
if (!hasHardError(m_constructionErrorCode))
reset();
return MatchResult::failed();
Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -67,7 +67,7 @@
RELEASE_ASSERT(vm.heap.expectDoesGC());
Vector<int, 32> subpatternResults;
- int position = regExp->matchInline(vm, inputValue, startOffset, subpatternResults);
+ int position = regExp->matchInline(globalObject, vm, inputValue, startOffset, subpatternResults);
if (position == -1) {
result = MatchResult::failed();
return nullptr;
Modified: trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h 2020-04-08 20:01:39 UTC (rev 259747)
@@ -106,7 +106,7 @@
if (!regExp->global() && !regExp->sticky()) {
scope.release();
- return globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, input, 0);
+ return globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, input, 0);
}
unsigned lastIndex = getRegExpObjectLastIndexAsUnsigned(globalObject, this, input);
@@ -117,7 +117,7 @@
return MatchResult::failed();
}
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, input, lastIndex);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, input, lastIndex);
RETURN_IF_EXCEPTION(scope, { });
scope.release();
setLastIndex(globalObject, result.end);
@@ -145,7 +145,7 @@
{
auto scope = DECLARE_THROW_SCOPE(vm);
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, s, 0);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, s, 0);
RETURN_IF_EXCEPTION(scope, { });
if (!result)
return jsNull();
@@ -167,7 +167,7 @@
}
if (!length)
end = fixEnd(end);
- result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, s, end);
+ result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, s, end);
if (UNLIKELY(scope.exception())) {
hasException = true;
return;
@@ -195,7 +195,7 @@
// will leave the cached result in the state it ought to have had just before the
// OOM! On the other hand, if this loop concludes that the result is small enough,
// then the iterate() loop below will overwrite the cached result anyway.
- result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, s, end);
+ result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, s, end);
RETURN_IF_EXCEPTION(scope, { });
} while (result);
Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp 2020-04-08 20:01:39 UTC (rev 259747)
@@ -486,7 +486,7 @@
String s = string->value(globalObject);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, s, 0);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, s, 0);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
}
@@ -505,21 +505,28 @@
template<typename ControlFunc, typename PushFunc>
void genericSplit(
- VM& vm, RegExp* regexp, const String& input, unsigned inputSize, unsigned& position,
+ JSGlobalObject* globalObject, RegExp* regexp, const String& input, unsigned inputSize, unsigned& position,
unsigned& matchPosition, bool regExpIsSticky, bool regExpIsUnicode,
const ControlFunc& control, const PushFunc& push)
{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
Vector<int> ovector;
while (matchPosition < inputSize) {
- if (control() == AbortSplit)
- return;
+ {
+ auto result = control();
+ RETURN_IF_EXCEPTION(scope, void());
+ if (result == AbortSplit)
+ return;
+ }
ovector.shrink(0);
// a. Perform ? Set(splitter, "lastIndex", q, true).
// b. Let z be ? RegExpExec(splitter, S).
- int mpos = regexp->match(vm, input, matchPosition, ovector);
+ int mpos = regexp->match(globalObject, input, matchPosition, ovector);
+ RETURN_IF_EXCEPTION(scope, void());
// c. If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
if (mpos < 0) {
@@ -555,8 +562,12 @@
// 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive).
// 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
- if (push(true, position, matchPosition - position) == AbortSplit)
- return;
+ {
+ auto result = push(true, position, matchPosition - position);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (result == AbortSplit)
+ return;
+ }
// 5. Let p be e.
position = matchEnd;
@@ -569,7 +580,9 @@
// a. Let nextCapture be ? Get(z, ! ToString(i)).
// b. Perform ! CreateDataProperty(A, ! ToString(lengthA), nextCapture).
int sub = ovector[i * 2];
- if (push(sub >= 0, sub, ovector[i * 2 + 1] - sub) == AbortSplit)
+ auto result = push(sub >= 0, sub, ovector[i * 2 + 1] - sub);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (result == AbortSplit)
return;
}
@@ -630,7 +643,9 @@
// b. If z is not null, return A.
// c. Perform ! CreateDataProperty(A, "0", S).
// d. Return A.
- if (!regexp->match(vm, input, 0)) {
+ auto matchResult = regexp->match(globalObject, input, 0);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ if (!matchResult) {
result->putDirectIndex(globalObject, 0, inputString);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
}
@@ -646,7 +661,7 @@
unsigned maxSizeForDirectPath = 100000;
genericSplit(
- vm, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
+ globalObject, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
[&] () -> SplitControl {
if (resultLength >= maxSizeForDirectPath)
return AbortSplit;
@@ -678,7 +693,7 @@
unsigned savedMatchPosition = matchPosition;
unsigned dryRunCount = 0;
genericSplit(
- vm, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
+ globalObject, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
[&] () -> SplitControl {
if (resultLength + dryRunCount > MAX_STORAGE_VECTOR_LENGTH)
return AbortSplit;
@@ -690,6 +705,7 @@
return AbortSplit;
return ContinueSplit;
});
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
if (resultLength + dryRunCount > MAX_STORAGE_VECTOR_LENGTH) {
throwOutOfMemoryError(globalObject, scope);
@@ -701,7 +717,7 @@
matchPosition = savedMatchPosition;
genericSplit(
- vm, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
+ globalObject, regexp, input, inputSize, position, matchPosition, regExpIsSticky, regExpIsUnicode,
[&] () -> SplitControl {
return ContinueSplit;
},
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (259746 => 259747)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2020-04-08 20:01:39 UTC (rev 259747)
@@ -489,7 +489,7 @@
unsigned sourceLen = source.length();
while (true) {
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, source, startPosition);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, source, startPosition);
RETURN_IF_EXCEPTION(scope, nullptr);
if (!result)
break;
@@ -560,7 +560,7 @@
RETURN_IF_EXCEPTION(scope, nullptr);
while (true) {
int* ovector;
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, source, startPosition, &ovector);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, source, startPosition, &ovector);
RETURN_IF_EXCEPTION(scope, nullptr);
if (!result)
break;
@@ -620,7 +620,7 @@
} else {
do {
int* ovector;
- MatchResult result = globalObject->regExpGlobalData().performMatch(vm, globalObject, regExp, string, source, startPosition, &ovector);
+ MatchResult result = globalObject->regExpGlobalData().performMatch(globalObject, regExp, string, source, startPosition, &ovector);
RETURN_IF_EXCEPTION(scope, nullptr);
if (!result)
break;
Modified: trunk/Source/_javascript_Core/testRegExp.cpp (259746 => 259747)
--- trunk/Source/_javascript_Core/testRegExp.cpp 2020-04-08 19:59:17 UTC (rev 259746)
+++ trunk/Source/_javascript_Core/testRegExp.cpp 2020-04-08 20:01:39 UTC (rev 259747)
@@ -188,12 +188,12 @@
return res;
}
-static bool testOneRegExp(VM& vm, RegExp* regexp, RegExpTest* regExpTest, bool verbose, unsigned int lineNumber)
+static bool testOneRegExp(JSGlobalObject* globalObject, RegExp* regexp, RegExpTest* regExpTest, bool verbose, unsigned lineNumber)
{
bool result = true;
Vector<int> outVector;
outVector.resize(regExpTest->expectVector.size());
- int matchResult = regexp->match(vm, regExpTest->subject, regExpTest->offset, outVector);
+ int matchResult = regexp->match(globalObject, regExpTest->subject, regExpTest->offset, outVector);
if (matchResult != regExpTest->result) {
result = false;
@@ -465,7 +465,7 @@
if (regexp && regExpTest) {
++tests;
- if (!testOneRegExp(vm, regexp, regExpTest, verbose, lineNumber)) {
+ if (!testOneRegExp(globalObject, regexp, regExpTest, verbose, lineNumber)) {
failures++;
printf("Failure on line %u\n", lineNumber);
}