Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197795 => 197796)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-08 21:15:07 UTC (rev 197796)
@@ -1,3 +1,58 @@
+2016-03-08 Filip Pizlo <[email protected]>
+
+ Regexp matching should incur less call overhead
+ https://bugs.webkit.org/show_bug.cgi?id=155181
+
+ Reviewed by Geoffrey Garen.
+
+ Previously we had DFG/FTL code call into the DFGOperation, which then called in to
+ RegExpObject, which then called into createRegExpMatchesArray, which then called into
+ RegExp, which then called the code generated by Yarr.
+
+ Now we have DFG/FTL code call into the DFGOperation, which does all of the things and calls
+ into code generated by Yarr.
+
+ This is another tiny Octane/regexp speed-up.
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * dfg/DFGOperations.cpp:
+ * runtime/RegExp.cpp:
+ (JSC::regExpFlags):
+ (JSC::RegExp::compile):
+ (JSC::RegExp::match):
+ (JSC::RegExp::compileMatchOnly):
+ (JSC::RegExp::deleteCode):
+ (JSC::RegExpFunctionalTestCollector::clearRegExp): Deleted.
+ (JSC::RegExp::compileIfNecessary): Deleted.
+ (JSC::RegExp::compileIfNecessaryMatchOnly): Deleted.
+ * runtime/RegExp.h:
+ * runtime/RegExpInlines.h: Added.
+ (JSC::RegExpFunctionalTestCollector::clearRegExp):
+ (JSC::RegExp::compileIfNecessary):
+ (JSC::RegExp::matchInline):
+ (JSC::RegExp::compileIfNecessaryMatchOnly):
+ * runtime/RegExpMatchesArray.cpp:
+ (JSC::createEmptyRegExpMatchesArray):
+ (JSC::createStructureImpl):
+ (JSC::tryCreateUninitializedRegExpMatchesArray): Deleted.
+ (JSC::createRegExpMatchesArray): Deleted.
+ * runtime/RegExpMatchesArray.h:
+ (JSC::tryCreateUninitializedRegExpMatchesArray):
+ (JSC::createRegExpMatchesArray):
+ * runtime/RegExpObject.cpp:
+ (JSC::RegExpObject::put):
+ (JSC::RegExpObject::exec):
+ (JSC::RegExpObject::match):
+ (JSC::getLastIndexAsUnsigned): Deleted.
+ * runtime/RegExpObject.h:
+ (JSC::RegExpObject::getLastIndex):
+ (JSC::RegExpObject::test):
+ (JSC::RegExpObject::testInline):
+ * runtime/RegExpObjectInlines.h: Added.
+ (JSC::getRegExpObjectLastIndexAsUnsigned):
+ (JSC::RegExpObject::execInline):
+ (JSC::RegExpObject::matchInline):
+
2016-03-08 Mark Lam <[email protected]>
synthesizePrototype() and friends need to be followed by exception checks (or equivalent).
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (197795 => 197796)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-03-08 21:15:07 UTC (rev 197796)
@@ -486,6 +486,8 @@
0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; };
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7C11AD1BC3862C00C74CDB /* CopyBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C11AC1BC3862C00C74CDB /* CopyBarrier.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F7C39FB1C8F629300480151 /* RegExpInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C39FA1C8F629300480151 /* RegExpInlines.h */; };
+ 0F7C39FD1C8F659500480151 /* RegExpObjectInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C39FC1C8F659500480151 /* RegExpObjectInlines.h */; };
0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2636,6 +2638,8 @@
0F79085319A290B200F6310C /* DFGStructureRegistrationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureRegistrationPhase.cpp; path = dfg/DFGStructureRegistrationPhase.cpp; sourceTree = "<group>"; };
0F79085419A290B200F6310C /* DFGStructureRegistrationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureRegistrationPhase.h; path = dfg/DFGStructureRegistrationPhase.h; sourceTree = "<group>"; };
0F7C11AC1BC3862C00C74CDB /* CopyBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyBarrier.h; sourceTree = "<group>"; };
+ 0F7C39FA1C8F629300480151 /* RegExpInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpInlines.h; sourceTree = "<group>"; };
+ 0F7C39FC1C8F659500480151 /* RegExpObjectInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpObjectInlines.h; sourceTree = "<group>"; };
0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; };
0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; };
0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
@@ -5874,11 +5878,13 @@
86F75EFC151C062F007C9BA3 /* RegExpCachedResult.h */,
BCD202BD0E1706A7002C7E82 /* RegExpConstructor.cpp */,
BCD202BE0E1706A7002C7E82 /* RegExpConstructor.h */,
+ 0F7C39FA1C8F629300480151 /* RegExpInlines.h */,
A1712B4011C7B235007A5315 /* RegExpKey.h */,
86F75EFD151C062F007C9BA3 /* RegExpMatchesArray.cpp */,
93CEDDFB0EA91EE600258EBE /* RegExpMatchesArray.h */,
F692A87B0255597D01FF60F7 /* RegExpObject.cpp */,
F692A87C0255597D01FF60F7 /* RegExpObject.h */,
+ 0F7C39FC1C8F659500480151 /* RegExpObjectInlines.h */,
BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */,
BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */,
0FB7F39115ED8E3800F167B2 /* Reject.h */,
@@ -7206,6 +7212,7 @@
0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */,
A78A9775179738B8009DF744 /* DFGFailedFinalizer.h in Headers */,
A7BFF3C0179868940002F462 /* DFGFiltrationResult.h in Headers */,
+ 0F7C39FB1C8F629300480151 /* RegExpInlines.h in Headers */,
A78A9777179738B8009DF744 /* DFGFinalizer.h in Headers */,
0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
0F9D339717FFC4E60073C2BC /* DFGFlushedAt.h in Headers */,
@@ -7925,6 +7932,7 @@
A709F2F017A0AC0400512E98 /* SlowPathCall.h in Headers */,
933040040E6A749400786E6A /* SmallStrings.h in Headers */,
BC18C4640E16F5CD00B34460 /* SourceCode.h in Headers */,
+ 0F7C39FD1C8F659500480151 /* RegExpObjectInlines.h in Headers */,
BC18C4630E16F5CD00B34460 /* SourceProvider.h in Headers */,
E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */,
E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */,
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (197795 => 197796)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2016-03-08 21:15:07 UTC (rev 197796)
@@ -624,7 +624,7 @@
VM& vm = globalObject->vm();
NativeCallFrameTracer tracer(&vm, exec);
- return JSValue::encode(regExpObject->exec(exec, globalObject, argument));
+ return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
}
EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
@@ -637,7 +637,7 @@
JSString* input = argument.toStringOrNull(exec);
if (!input)
return JSValue::encode(jsUndefined());
- return JSValue::encode(regExpObject->exec(exec, globalObject, input));
+ return JSValue::encode(regExpObject->execInline(exec, globalObject, input));
}
EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
@@ -662,7 +662,7 @@
VM& vm = globalObject->vm();
NativeCallFrameTracer tracer(&vm, exec);
- return regExpObject->test(exec, globalObject, input);
+ return regExpObject->testInline(exec, globalObject, input);
}
size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
@@ -675,7 +675,7 @@
JSString* input = argument.toStringOrNull(exec);
if (!input)
return false;
- return regExpObject->test(exec, globalObject, input);
+ return regExpObject->testInline(exec, globalObject, input);
}
size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
Modified: trunk/Source/_javascript_Core/runtime/RegExp.cpp (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExp.cpp 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExp.cpp 2016-03-08 21:15:07 UTC (rev 197796)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2001, 2004 Harri Porten ([email protected])
- * Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2007, 2008, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
* Copyright (C) 2010 Peter Varga ([email protected]), University of Szeged
*
@@ -26,18 +26,11 @@
#include "Lexer.h"
#include "JSCInlines.h"
#include "RegExpCache.h"
+#include "RegExpInlines.h"
#include "Yarr.h"
#include "YarrJIT.h"
#include <wtf/Assertions.h>
-#define REGEXP_FUNC_TEST_DATA_GEN 0
-
-#if REGEXP_FUNC_TEST_DATA_GEN
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#endif
-
namespace JSC {
const ClassInfo RegExp::s_info = { "RegExp", 0, 0, CREATE_METHOD_TABLE(RegExp) };
@@ -81,33 +74,6 @@
}
#if REGEXP_FUNC_TEST_DATA_GEN
-class RegExpFunctionalTestCollector {
- // This class is not thread safe.
-protected:
- static const char* const s_fileName;
-
-public:
- static RegExpFunctionalTestCollector* get();
-
- ~RegExpFunctionalTestCollector();
-
- void outputOneTest(RegExp*, String, int, int*, int);
- void clearRegExp(RegExp* regExp)
- {
- if (regExp == m_lastRegExp)
- m_lastRegExp = 0;
- }
-
-private:
- RegExpFunctionalTestCollector();
-
- void outputEscapedString(const String&, bool escapeSlash = false);
-
- static RegExpFunctionalTestCollector* s_instance;
- FILE* m_file;
- RegExp* m_lastRegExp;
-};
-
const char* const RegExpFunctionalTestCollector::s_fileName = "/tmp/RegExpTestsData";
RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::s_instance = 0;
@@ -320,89 +286,9 @@
m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
-void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSize)
-{
- if (hasCode()) {
-#if ENABLE(YARR_JIT)
- if (m_state != JITCode)
- return;
- if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCode()))
- return;
- if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCode()))
- return;
-#else
- return;
-#endif
- }
-
- compile(&vm, charSize);
-}
-
int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>& ovector)
{
-#if ENABLE(REGEXP_TRACING)
- m_rtMatchCallCount++;
- m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset);
-#endif
-
- ASSERT(m_state != ParseError);
- compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
-
- int offsetVectorSize = (m_numSubpatterns + 1) * 2;
- ovector.resize(offsetVectorSize);
- int* offsetVector = ovector.data();
-
- int result;
-#if ENABLE(YARR_JIT)
- if (m_state == JITCode) {
- if (s.is8Bit())
- result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector).start;
- else
- result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start;
-#if ENABLE(YARR_JIT_DEBUG)
- matchCompareWithInterpreter(s, startOffset, offsetVector, result);
-#endif
- } else
-#endif
- result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
-
- // FIXME: The YARR engine should handle unsigned or size_t length matches.
- // The YARR Interpreter is "unsigned" clean, while the YARR JIT hasn't been addressed.
- // The offset vector handling needs to change as well.
- // Right now we convert a match where the offsets overflowed into match failure.
- // There are two places in WebCore that call the interpreter directly that need to
- // have their offsets changed to int as well. They are yarr/RegularExpression.cpp
- // and inspector/ContentSearchUtilities.cpp
- if (s.length() > INT_MAX) {
- bool overflowed = false;
-
- if (result < -1)
- overflowed = true;
-
- for (unsigned i = 0; i <= m_numSubpatterns; i++) {
- if ((offsetVector[i*2] < -1) || ((offsetVector[i*2] >= 0) && (offsetVector[i*2+1] < -1))) {
- overflowed = true;
- offsetVector[i*2] = -1;
- offsetVector[i*2+1] = -1;
- }
- }
-
- if (overflowed)
- result = -1;
- }
-
- ASSERT(result >= -1);
-
-#if REGEXP_FUNC_TEST_DATA_GEN
- RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
-#endif
-
-#if ENABLE(REGEXP_TRACING)
- if (result != -1)
- m_rtMatchFoundCount++;
-#endif
-
- return result;
+ return matchInline(vm, s, startOffset, ovector);
}
void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
@@ -439,65 +325,9 @@
m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
-void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize)
-{
- if (hasCode()) {
-#if ENABLE(YARR_JIT)
- if (m_state != JITCode)
- return;
- if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCodeMatchOnly()))
- return;
- if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCodeMatchOnly()))
- return;
-#else
- return;
-#endif
- }
-
- compileMatchOnly(&vm, charSize);
-}
-
MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
{
-#if ENABLE(REGEXP_TRACING)
- m_rtMatchOnlyCallCount++;
- m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset);
-#endif
-
- ASSERT(m_state != ParseError);
- compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
-
-#if ENABLE(YARR_JIT)
- if (m_state == JITCode) {
- MatchResult result = s.is8Bit() ?
- m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) :
- m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
-#if ENABLE(REGEXP_TRACING)
- if (!result)
- m_rtMatchOnlyFoundCount++;
-#endif
- return result;
- }
-#endif
-
- int offsetVectorSize = (m_numSubpatterns + 1) * 2;
- int* offsetVector;
- Vector<int, 32> nonReturnedOvector;
- nonReturnedOvector.resize(offsetVectorSize);
- offsetVector = nonReturnedOvector.data();
- int r = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
-#if REGEXP_FUNC_TEST_DATA_GEN
- RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
-#endif
-
- if (r >= 0) {
-#if ENABLE(REGEXP_TRACING)
- m_rtMatchOnlyFoundCount++;
-#endif
- return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
- }
-
- return MatchResult::failed();
+ return matchInline(vm, s, startOffset);
}
void RegExp::deleteCode()
Modified: trunk/Source/_javascript_Core/runtime/RegExp.h (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExp.h 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExp.h 2016-03-08 21:15:07 UTC (rev 197796)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten ([email protected])
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -64,6 +64,11 @@
JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector);
JS_EXPORT_PRIVATE MatchResult match(VM&, const String&, unsigned startOffset);
+
+ // Call these versions of the match functions if you're desperate for performance.
+ int matchInline(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector);
+ MatchResult matchInline(VM&, const String&, unsigned startOffset);
+
unsigned numSubpatterns() const { return m_numSubpatterns; }
bool hasCode()
Added: trunk/Source/_javascript_Core/runtime/RegExpInlines.h (0 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpInlines.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/RegExpInlines.h 2016-03-08 21:15:07 UTC (rev 197796)
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 1999-2001, 2004 Harri Porten ([email protected])
+ * Copyright (c) 2007, 2008, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 Peter Varga ([email protected]), University of Szeged
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef RegExpInlines_h
+#define RegExpInlines_h
+
+#include "RegExp.h"
+#include "JSCInlines.h"
+#include "Yarr.h"
+#include "YarrJIT.h"
+
+#define REGEXP_FUNC_TEST_DATA_GEN 0
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+namespace JSC {
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+class RegExpFunctionalTestCollector {
+ // This class is not thread safe.
+protected:
+ static const char* const s_fileName;
+
+public:
+ static RegExpFunctionalTestCollector* get();
+
+ ~RegExpFunctionalTestCollector();
+
+ void outputOneTest(RegExp*, String, int, int*, int);
+ void clearRegExp(RegExp* regExp)
+ {
+ if (regExp == m_lastRegExp)
+ m_lastRegExp = 0;
+ }
+
+private:
+ RegExpFunctionalTestCollector();
+
+ void outputEscapedString(const String&, bool escapeSlash = false);
+
+ static RegExpFunctionalTestCollector* s_instance;
+ FILE* m_file;
+ RegExp* m_lastRegExp;
+};
+#endif // REGEXP_FUNC_TEST_DATA_GEN
+
+ALWAYS_INLINE void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSize)
+{
+ if (hasCode()) {
+#if ENABLE(YARR_JIT)
+ if (m_state != JITCode)
+ return;
+ if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCode()))
+ return;
+ if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCode()))
+ return;
+#else
+ return;
+#endif
+ }
+
+ compile(&vm, charSize);
+}
+
+ALWAYS_INLINE int RegExp::matchInline(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>& ovector)
+{
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchCallCount++;
+ m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset);
+#endif
+
+ ASSERT(m_state != ParseError);
+ compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ ovector.resize(offsetVectorSize);
+ int* offsetVector = ovector.data();
+
+ int result;
+#if ENABLE(YARR_JIT)
+ if (m_state == JITCode) {
+ if (s.is8Bit())
+ result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector).start;
+ else
+ result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start;
+#if ENABLE(YARR_JIT_DEBUG)
+ matchCompareWithInterpreter(s, startOffset, offsetVector, result);
+#endif
+ } else
+#endif
+ result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
+
+ // FIXME: The YARR engine should handle unsigned or size_t length matches.
+ // The YARR Interpreter is "unsigned" clean, while the YARR JIT hasn't been addressed.
+ // The offset vector handling needs to change as well.
+ // Right now we convert a match where the offsets overflowed into match failure.
+ // There are two places in WebCore that call the interpreter directly that need to
+ // have their offsets changed to int as well. They are yarr/RegularExpression.cpp
+ // and inspector/ContentSearchUtilities.cpp
+ if (s.length() > INT_MAX) {
+ bool overflowed = false;
+
+ if (result < -1)
+ overflowed = true;
+
+ for (unsigned i = 0; i <= m_numSubpatterns; i++) {
+ if ((offsetVector[i*2] < -1) || ((offsetVector[i*2] >= 0) && (offsetVector[i*2+1] < -1))) {
+ overflowed = true;
+ offsetVector[i*2] = -1;
+ offsetVector[i*2+1] = -1;
+ }
+ }
+
+ if (overflowed)
+ result = -1;
+ }
+
+ ASSERT(result >= -1);
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+ RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
+#endif
+
+#if ENABLE(REGEXP_TRACING)
+ if (result != -1)
+ m_rtMatchFoundCount++;
+#endif
+
+ return result;
+}
+
+ALWAYS_INLINE void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize)
+{
+ if (hasCode()) {
+#if ENABLE(YARR_JIT)
+ if (m_state != JITCode)
+ return;
+ if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCodeMatchOnly()))
+ return;
+ if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCodeMatchOnly()))
+ return;
+#else
+ return;
+#endif
+ }
+
+ compileMatchOnly(&vm, charSize);
+}
+
+ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, const String& s, unsigned startOffset)
+{
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchOnlyCallCount++;
+ m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset);
+#endif
+
+ ASSERT(m_state != ParseError);
+ compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+
+#if ENABLE(YARR_JIT)
+ if (m_state == JITCode) {
+ MatchResult result = s.is8Bit() ?
+ m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) :
+ m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
+#if ENABLE(REGEXP_TRACING)
+ if (!result)
+ m_rtMatchOnlyFoundCount++;
+#endif
+ return result;
+ }
+#endif
+
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ int* offsetVector;
+ Vector<int, 32> nonReturnedOvector;
+ nonReturnedOvector.resize(offsetVectorSize);
+ offsetVector = nonReturnedOvector.data();
+ int r = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
+#if REGEXP_FUNC_TEST_DATA_GEN
+ RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
+#endif
+
+ if (r >= 0) {
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchOnlyFoundCount++;
+#endif
+ return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
+ }
+
+ return MatchResult::failed();
+}
+
+} // namespace JSC
+
+#endif // RegExpInlines_h
+
Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp 2016-03-08 21:15:07 UTC (rev 197796)
@@ -26,90 +26,8 @@
#include "config.h"
#include "RegExpMatchesArray.h"
-#include "ButterflyInlines.h"
-#include "JSCInlines.h"
-
namespace JSC {
-static const PropertyOffset indexPropertyOffset = 100;
-static const PropertyOffset inputPropertyOffset = 101;
-
-static JSArray* tryCreateUninitializedRegExpMatchesArray(VM& vm, Structure* structure, unsigned initialLength)
-{
- unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
- if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
- return 0;
-
- void* temp;
- if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)), &temp))
- return 0;
- Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
- butterfly->setVectorLength(vectorLength);
- butterfly->setPublicLength(initialLength);
-
- return JSArray::createWithButterfly(vm, structure, butterfly);
-}
-
-JSArray* createRegExpMatchesArray(
- ExecState* exec, JSGlobalObject* globalObject, JSString* input, RegExp* regExp,
- unsigned startOffset, MatchResult& result)
-{
- SamplingRegion samplingRegion("createRegExpMatchesArray");
-
- VM& vm = globalObject->vm();
-
- Vector<int, 32> subpatternResults;
- int position = regExp->match(vm, input->value(exec), startOffset, subpatternResults);
- if (position == -1) {
- result = MatchResult::failed();
- return nullptr;
- }
-
- result.start = position;
- result.end = subpatternResults[1];
-
- JSArray* array;
-
- // FIXME: This should handle array allocation errors gracefully.
- // https://bugs.webkit.org/show_bug.cgi?id=155144
-
- if (UNLIKELY(globalObject->isHavingABadTime())) {
- array = JSArray::tryCreateUninitialized(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
-
- array->initializeIndex(vm, 0, jsSubstringOfResolved(vm, input, result.start, result.end - result.start));
-
- if (unsigned numSubpatterns = regExp->numSubpatterns()) {
- for (unsigned i = 1; i <= numSubpatterns; ++i) {
- int start = subpatternResults[2 * i];
- if (start >= 0)
- array->initializeIndex(vm, i, JSRopeString::createSubstringOfResolved(vm, input, start, subpatternResults[2 * i + 1] - start));
- else
- array->initializeIndex(vm, i, jsUndefined());
- }
- }
- } else {
- array = tryCreateUninitializedRegExpMatchesArray(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
- RELEASE_ASSERT(array);
-
- array->initializeIndex(vm, 0, jsSubstringOfResolved(vm, input, result.start, result.end - result.start), ArrayWithContiguous);
-
- if (unsigned numSubpatterns = regExp->numSubpatterns()) {
- for (unsigned i = 1; i <= numSubpatterns; ++i) {
- int start = subpatternResults[2 * i];
- if (start >= 0)
- array->initializeIndex(vm, i, JSRopeString::createSubstringOfResolved(vm, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous);
- else
- array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
- }
- }
- }
-
- array->putDirect(vm, indexPropertyOffset, jsNumber(result.start));
- array->putDirect(vm, inputPropertyOffset, input);
-
- return array;
-}
-
JSArray* createEmptyRegExpMatchesArray(JSGlobalObject* globalObject, JSString* input, RegExp* regExp)
{
VM& vm = globalObject->vm();
@@ -139,8 +57,8 @@
}
}
- array->putDirect(vm, indexPropertyOffset, jsNumber(-1));
- array->putDirect(vm, inputPropertyOffset, input);
+ array->putDirect(vm, RegExpMatchesArrayIndexPropertyOffset, jsNumber(-1));
+ array->putDirect(vm, RegExpMatchesArrayInputPropertyOffset, input);
return array;
}
@@ -149,9 +67,9 @@
Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
PropertyOffset offset;
structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset);
- ASSERT(offset == indexPropertyOffset);
+ ASSERT(offset == RegExpMatchesArrayIndexPropertyOffset);
structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset);
- ASSERT(offset == inputPropertyOffset);
+ ASSERT(offset == RegExpMatchesArrayInputPropertyOffset);
return structure;
}
Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h 2016-03-08 21:15:07 UTC (rev 197796)
@@ -20,17 +20,96 @@
#ifndef RegExpMatchesArray_h
#define RegExpMatchesArray_h
+#include "ButterflyInlines.h"
#include "JSArray.h"
+#include "JSCInlines.h"
#include "JSGlobalObject.h"
+#include "RegExpInlines.h"
#include "RegExpObject.h"
namespace JSC {
-JSArray* createRegExpMatchesArray(ExecState*, JSGlobalObject*, JSString*, RegExp*, unsigned startOffset, MatchResult&);
+static const PropertyOffset RegExpMatchesArrayIndexPropertyOffset = 100;
+static const PropertyOffset RegExpMatchesArrayInputPropertyOffset = 101;
+
+ALWAYS_INLINE JSArray* tryCreateUninitializedRegExpMatchesArray(VM& vm, Structure* structure, unsigned initialLength)
+{
+ unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
+ if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
+ return 0;
+
+ void* temp;
+ if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)), &temp))
+ return 0;
+ Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
+ butterfly->setVectorLength(vectorLength);
+ butterfly->setPublicLength(initialLength);
+
+ return JSArray::createWithButterfly(vm, structure, butterfly);
+}
+
+ALWAYS_INLINE JSArray* createRegExpMatchesArray(
+ VM& vm, JSGlobalObject* globalObject, JSString* input, const String& inputValue,
+ RegExp* regExp, unsigned startOffset, MatchResult& result)
+{
+ SamplingRegion samplingRegion("createRegExpMatchesArray");
+
+ Vector<int, 32> subpatternResults;
+ int position = regExp->matchInline(vm, inputValue, startOffset, subpatternResults);
+ if (position == -1) {
+ result = MatchResult::failed();
+ return nullptr;
+ }
+
+ result.start = position;
+ result.end = subpatternResults[1];
+
+ JSArray* array;
+
+ // FIXME: This should handle array allocation errors gracefully.
+ // https://bugs.webkit.org/show_bug.cgi?id=155144
+
+ if (UNLIKELY(globalObject->isHavingABadTime())) {
+ array = JSArray::tryCreateUninitialized(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+
+ array->initializeIndex(vm, 0, jsSubstringOfResolved(vm, input, result.start, result.end - result.start));
+
+ if (unsigned numSubpatterns = regExp->numSubpatterns()) {
+ for (unsigned i = 1; i <= numSubpatterns; ++i) {
+ int start = subpatternResults[2 * i];
+ if (start >= 0)
+ array->initializeIndex(vm, i, JSRopeString::createSubstringOfResolved(vm, input, start, subpatternResults[2 * i + 1] - start));
+ else
+ array->initializeIndex(vm, i, jsUndefined());
+ }
+ }
+ } else {
+ array = tryCreateUninitializedRegExpMatchesArray(vm, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+ RELEASE_ASSERT(array);
+
+ array->initializeIndex(vm, 0, jsSubstringOfResolved(vm, input, result.start, result.end - result.start), ArrayWithContiguous);
+
+ if (unsigned numSubpatterns = regExp->numSubpatterns()) {
+ for (unsigned i = 1; i <= numSubpatterns; ++i) {
+ int start = subpatternResults[2 * i];
+ if (start >= 0)
+ array->initializeIndex(vm, i, JSRopeString::createSubstringOfResolved(vm, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous);
+ else
+ array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
+ }
+ }
+ }
+
+ array->putDirect(vm, RegExpMatchesArrayIndexPropertyOffset, jsNumber(result.start));
+ array->putDirect(vm, RegExpMatchesArrayInputPropertyOffset, input);
+
+ return array;
+}
+
inline JSArray* createRegExpMatchesArray(ExecState* exec, JSGlobalObject* globalObject, JSString* string, RegExp* regExp, unsigned startOffset)
{
MatchResult ignoredResult;
- return createRegExpMatchesArray(exec, globalObject, string, regExp, startOffset, ignoredResult);
+ return createRegExpMatchesArray(globalObject->vm(), globalObject, string, string->value(exec), regExp, startOffset, ignoredResult);
}
JSArray* createEmptyRegExpMatchesArray(JSGlobalObject*, JSString*, RegExp*);
Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject*);
Modified: trunk/Source/_javascript_Core/runtime/RegExpObject.cpp (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpObject.cpp 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExpObject.cpp 2016-03-08 21:15:07 UTC (rev 197796)
@@ -32,6 +32,7 @@
#include "JSCInlines.h"
#include "RegExpConstructor.h"
#include "RegExpMatchesArray.h"
+#include "RegExpObjectInlines.h"
#include "RegExpPrototype.h"
#include <wtf/text/StringBuilder.h>
@@ -159,77 +160,15 @@
Base::put(cell, exec, propertyName, value, slot);
}
-ALWAYS_INLINE unsigned getLastIndexAsUnsigned(
- ExecState* exec, RegExpObject* regExpObject, const String& input)
-{
- JSValue jsLastIndex = regExpObject->getLastIndex();
- unsigned lastIndex;
- if (LIKELY(jsLastIndex.isUInt32())) {
- lastIndex = jsLastIndex.asUInt32();
- if (lastIndex > input.length()) {
- regExpObject->setLastIndex(exec, 0);
- return UINT_MAX;
- }
- } else {
- double doubleLastIndex = jsLastIndex.toInteger(exec);
- if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
- regExpObject->setLastIndex(exec, 0);
- return UINT_MAX;
- }
- lastIndex = static_cast<unsigned>(doubleLastIndex);
- }
- return lastIndex;
-}
-
JSValue RegExpObject::exec(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
{
- RegExp* regExp = this->regExp();
- RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
- String input = string->value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
- VM& vm = globalObject->vm();
-
- if (!regExp->global()) {
- MatchResult result;
- JSArray* array = createRegExpMatchesArray(exec, globalObject, string, regExp, 0, result);
- if (!array)
- return jsNull();
- regExpConstructor->recordMatch(vm, regExp, string, result);
- return array;
- }
-
- unsigned lastIndex = getLastIndexAsUnsigned(exec, this, input);
- if (lastIndex == UINT_MAX)
- return jsNull();
-
- MatchResult result;
- JSArray* array =
- createRegExpMatchesArray(exec, globalObject, string, regExp, lastIndex, result);
- if (!array) {
- setLastIndex(exec, 0);
- return jsNull();
- }
- setLastIndex(exec, result.end);
- regExpConstructor->recordMatch(vm, regExp, string, result);
- return array;
+ return execInline(exec, globalObject, string);
}
// Shared implementation used by test and exec.
MatchResult RegExpObject::match(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
{
- RegExp* regExp = this->regExp();
- RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
- String input = string->value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
- VM& vm = globalObject->vm();
- if (!regExp->global())
- return regExpConstructor->performMatch(vm, regExp, string, input, 0);
-
- unsigned lastIndex = getLastIndexAsUnsigned(exec, this, input);
- if (lastIndex == UINT_MAX)
- return MatchResult::failed();
-
- MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex);
- setLastIndex(exec, result.end);
- return result;
+ return matchInline(exec, globalObject, string);
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/RegExpObject.h (197795 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpObject.h 2016-03-08 21:02:09 UTC (rev 197795)
+++ trunk/Source/_javascript_Core/runtime/RegExpObject.h 2016-03-08 21:15:07 UTC (rev 197796)
@@ -67,7 +67,9 @@
}
bool test(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { return !!match(exec, globalObject, string); }
+ bool testInline(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { return !!matchInline(exec, globalObject, string); }
JSValue exec(ExecState*, JSGlobalObject*, JSString*);
+ JSValue execInline(ExecState*, JSGlobalObject*, JSString*);
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -103,6 +105,7 @@
private:
MatchResult match(ExecState*, JSGlobalObject*, JSString*);
+ MatchResult matchInline(ExecState*, JSGlobalObject*, JSString*);
WriteBarrier<RegExp> m_regExp;
WriteBarrier<Unknown> m_lastIndex;
Added: trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h (0 => 197796)
--- trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/RegExpObjectInlines.h 2016-03-08 21:15:07 UTC (rev 197796)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten ([email protected])
+ * Copyright (C) 2003, 2007, 2008, 2012, 2016 Apple Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef RegExpObjectInlines_h
+#define RegExpObjectInlines_h
+
+#include "ButterflyInlines.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "JSCInlines.h"
+#include "RegExpConstructor.h"
+#include "RegExpMatchesArray.h"
+#include "RegExpObject.h"
+
+namespace JSC {
+
+ALWAYS_INLINE unsigned getRegExpObjectLastIndexAsUnsigned(
+ ExecState* exec, RegExpObject* regExpObject, const String& input)
+{
+ JSValue jsLastIndex = regExpObject->getLastIndex();
+ unsigned lastIndex;
+ if (LIKELY(jsLastIndex.isUInt32())) {
+ lastIndex = jsLastIndex.asUInt32();
+ if (lastIndex > input.length()) {
+ regExpObject->setLastIndex(exec, 0);
+ return UINT_MAX;
+ }
+ } else {
+ double doubleLastIndex = jsLastIndex.toInteger(exec);
+ if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
+ regExpObject->setLastIndex(exec, 0);
+ return UINT_MAX;
+ }
+ lastIndex = static_cast<unsigned>(doubleLastIndex);
+ }
+ return lastIndex;
+}
+
+JSValue RegExpObject::execInline(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
+{
+ RegExp* regExp = this->regExp();
+ RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
+ String input = string->value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
+ VM& vm = globalObject->vm();
+
+ bool global = regExp->global();
+
+ unsigned lastIndex;
+ if (global) {
+ lastIndex = getRegExpObjectLastIndexAsUnsigned(exec, this, input);
+ if (lastIndex == UINT_MAX)
+ return jsNull();
+ } else
+ lastIndex = 0;
+
+ MatchResult result;
+ JSArray* array =
+ createRegExpMatchesArray(vm, globalObject, string, input, regExp, lastIndex, result);
+ if (!array) {
+ if (global)
+ setLastIndex(exec, 0);
+ return jsNull();
+ }
+ if (global)
+ setLastIndex(exec, result.end);
+ regExpConstructor->recordMatch(vm, regExp, string, result);
+ return array;
+}
+
+// Shared implementation used by test and exec.
+MatchResult RegExpObject::matchInline(
+ ExecState* exec, JSGlobalObject* globalObject, JSString* string)
+{
+ RegExp* regExp = this->regExp();
+ RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
+ String input = string->value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
+ VM& vm = globalObject->vm();
+ if (!regExp->global())
+ return regExpConstructor->performMatch(vm, regExp, string, input, 0);
+
+ unsigned lastIndex = getRegExpObjectLastIndexAsUnsigned(exec, this, input);
+ if (lastIndex == UINT_MAX)
+ return MatchResult::failed();
+
+ MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex);
+ setLastIndex(exec, result.end);
+ return result;
+}
+
+} // namespace JSC
+
+#endif // RegExpObjectInlines_h
+