JSC Sampling Profiler: Detect tester and testee when sampling in RegExp JIT
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 10:43:13 +0000 (10:43 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 10:43:13 +0000 (10:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=152729

Reviewed by Saam Barati.

JSTests:

* stress/sampling-profiler-regexp.js: Added.
(platformSupportsSamplingProfiler.test):
(platformSupportsSamplingProfiler.baz):
(platformSupportsSamplingProfiler):

Source/JavaScriptCore:

This patch extends SamplingProfiler to recognize JIT RegExp execution. We record
executing RegExp in VM so that SamplingProfiler can detect it. This is better
than the previous VM::isExecutingInRegExpJIT flag approach since

1. isExecutingInRegExpJIT is set after starting executing JIT RegExp code. Thus,
if we suspend the thread just before executing this flag, or just after clearing
this flag, SamplingProfiler gets invalid frame, and frame validation fails. We
should set such a flag before and after executing JIT RegExp code.

2. This removes VM dependency from YarrJIT which is not essential one.

We add ExecutionContext enum to RegExp::matchInline not to mark execution if it
is done in non JS thread.

* bytecode/BytecodeDumper.cpp:
(JSC::regexpName):
(JSC::BytecodeDumper<Block>::dumpRegExps):
(JSC::regexpToSourceString): Deleted.
* heap/Heap.cpp:
(JSC::Heap::addCoreConstraints):
* runtime/RegExp.cpp:
(JSC::RegExp::compile):
(JSC::RegExp::match):
(JSC::RegExp::matchConcurrently):
(JSC::RegExp::compileMatchOnly):
(JSC::RegExp::toSourceString const):
* runtime/RegExp.h:
* runtime/RegExpInlines.h:
(JSC::RegExp::matchInline):
* runtime/RegExpMatchesArray.h:
(JSC::createRegExpMatchesArray):
* runtime/SamplingProfiler.cpp:
(JSC::SamplingProfiler::SamplingProfiler):
(JSC::SamplingProfiler::timerLoop):
(JSC::SamplingProfiler::takeSample):
(JSC::SamplingProfiler::processUnverifiedStackTraces):
(JSC::SamplingProfiler::StackFrame::nameFromCallee):
(JSC::SamplingProfiler::StackFrame::displayName):
(JSC::SamplingProfiler::StackFrame::displayNameForJSONTests):
(JSC::SamplingProfiler::StackFrame::functionStartLine):
(JSC::SamplingProfiler::StackFrame::functionStartColumn):
(JSC::SamplingProfiler::StackFrame::sourceID):
(JSC::SamplingProfiler::StackFrame::url):
(WTF::printInternal):
(JSC::SamplingProfiler::~SamplingProfiler): Deleted.
* runtime/SamplingProfiler.h:
* runtime/VM.h:
* yarr/YarrJIT.cpp:
(JSC::Yarr::YarrGenerator::generateEnter):
(JSC::Yarr::YarrGenerator::generateReturn):
(JSC::Yarr::YarrGenerator::YarrGenerator):
(JSC::Yarr::jitCompile):
* yarr/YarrJIT.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227725 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
JSTests/ChangeLog
JSTests/stress/sampling-profiler-regexp.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/runtime/Concurrency.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/RegExp.cpp
Source/JavaScriptCore/runtime/RegExp.h
Source/JavaScriptCore/runtime/RegExpInlines.h
Source/JavaScriptCore/runtime/RegExpMatchesArray.h
Source/JavaScriptCore/runtime/SamplingProfiler.cpp
Source/JavaScriptCore/runtime/SamplingProfiler.h
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/yarr/YarrJIT.cpp
Source/JavaScriptCore/yarr/YarrJIT.h

index d77face..3451da9 100644 (file)
@@ -1,5 +1,17 @@
 2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        JSC Sampling Profiler: Detect tester and testee when sampling in RegExp JIT
+        https://bugs.webkit.org/show_bug.cgi?id=152729
+
+        Reviewed by Saam Barati.
+
+        * stress/sampling-profiler-regexp.js: Added.
+        (platformSupportsSamplingProfiler.test):
+        (platformSupportsSamplingProfiler.baz):
+        (platformSupportsSamplingProfiler):
+
+2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [DFG][FTL] WeakMap#set should have DFG node
         https://bugs.webkit.org/show_bug.cgi?id=180015
 
diff --git a/JSTests/stress/sampling-profiler-regexp.js b/JSTests/stress/sampling-profiler-regexp.js
new file mode 100644 (file)
index 0000000..9a3987c
--- /dev/null
@@ -0,0 +1,18 @@
+if (platformSupportsSamplingProfiler()) {
+    load("./sampling-profiler/samplingProfiler.js");
+
+    function test(regexp, string)
+    {
+        return string.match(regexp);
+    }
+    noInline(test);
+
+    function baz() {
+        var text = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`;
+        var regexp = /.*/gi;
+        for (var i = 0; i < 1e5; ++i)
+            test(regexp, text);
+    }
+
+    runTest(baz, ["/.*/gi", "", "test", "baz"]);
+}
index fcbb9e5..a8ddd55 100644 (file)
@@ -1,5 +1,66 @@
 2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        JSC Sampling Profiler: Detect tester and testee when sampling in RegExp JIT
+        https://bugs.webkit.org/show_bug.cgi?id=152729
+
+        Reviewed by Saam Barati.
+
+        This patch extends SamplingProfiler to recognize JIT RegExp execution. We record
+        executing RegExp in VM so that SamplingProfiler can detect it. This is better
+        than the previous VM::isExecutingInRegExpJIT flag approach since
+
+        1. isExecutingInRegExpJIT is set after starting executing JIT RegExp code. Thus,
+        if we suspend the thread just before executing this flag, or just after clearing
+        this flag, SamplingProfiler gets invalid frame, and frame validation fails. We
+        should set such a flag before and after executing JIT RegExp code.
+
+        2. This removes VM dependency from YarrJIT which is not essential one.
+
+        We add ExecutionContext enum to RegExp::matchInline not to mark execution if it
+        is done in non JS thread.
+
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::regexpName):
+        (JSC::BytecodeDumper<Block>::dumpRegExps):
+        (JSC::regexpToSourceString): Deleted.
+        * heap/Heap.cpp:
+        (JSC::Heap::addCoreConstraints):
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::compile):
+        (JSC::RegExp::match):
+        (JSC::RegExp::matchConcurrently):
+        (JSC::RegExp::compileMatchOnly):
+        (JSC::RegExp::toSourceString const):
+        * runtime/RegExp.h:
+        * runtime/RegExpInlines.h:
+        (JSC::RegExp::matchInline):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::createRegExpMatchesArray):
+        * runtime/SamplingProfiler.cpp:
+        (JSC::SamplingProfiler::SamplingProfiler):
+        (JSC::SamplingProfiler::timerLoop):
+        (JSC::SamplingProfiler::takeSample):
+        (JSC::SamplingProfiler::processUnverifiedStackTraces):
+        (JSC::SamplingProfiler::StackFrame::nameFromCallee):
+        (JSC::SamplingProfiler::StackFrame::displayName):
+        (JSC::SamplingProfiler::StackFrame::displayNameForJSONTests):
+        (JSC::SamplingProfiler::StackFrame::functionStartLine):
+        (JSC::SamplingProfiler::StackFrame::functionStartColumn):
+        (JSC::SamplingProfiler::StackFrame::sourceID):
+        (JSC::SamplingProfiler::StackFrame::url):
+        (WTF::printInternal):
+        (JSC::SamplingProfiler::~SamplingProfiler): Deleted.
+        * runtime/SamplingProfiler.h:
+        * runtime/VM.h:
+        * yarr/YarrJIT.cpp:
+        (JSC::Yarr::YarrGenerator::generateEnter):
+        (JSC::Yarr::YarrGenerator::generateReturn):
+        (JSC::Yarr::YarrGenerator::YarrGenerator):
+        (JSC::Yarr::jitCompile):
+        * yarr/YarrJIT.h:
+
+2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [DFG][FTL] WeakMap#set should have DFG node
         https://bugs.webkit.org/show_bug.cgi?id=180015
 
index de3e290..564bdb5 100644 (file)
                E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA1521DBC3A5600F83516 /* DOMJITHeapRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E35CA1561DBC3A5F00F83516 /* DOMJITAbstractHeap.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA1501DBC3A5600F83516 /* DOMJITAbstractHeap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E35E03601B7AB43E0073AD2A /* InspectorInstrumentationObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E36CA813201F302900368EFF /* Concurrency.h in Headers */ = {isa = PBXBuildFile; fileRef = E36CA812201F301100368EFF /* Concurrency.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = E3794E741B77EB97005543AE /* ModuleAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E393ADD71FE702CC0022D681 /* WeakMapImplInlines.h */; };
                E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorInstrumentationObject.cpp; sourceTree = "<group>"; };
                E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorInstrumentationObject.h; sourceTree = "<group>"; };
                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InspectorInstrumentationObject.js; sourceTree = "<group>"; };
+               E36CA812201F301100368EFF /* Concurrency.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Concurrency.h; sourceTree = "<group>"; };
                E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleAnalyzer.cpp; sourceTree = "<group>"; };
                E3794E741B77EB97005543AE /* ModuleAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleAnalyzer.h; sourceTree = "<group>"; };
                E380A76B1DCD7195000F89E6 /* MacroAssemblerHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerHelpers.h; sourceTree = "<group>"; };
                                A7E5A3A61797432D00E893C0 /* CompilationResult.h */,
                                969A09220ED1E09C00F1F681 /* Completion.cpp */,
                                F5BB2BC5030F772101FCFE1D /* Completion.h */,
+                               E36CA812201F301100368EFF /* Concurrency.h */,
                                0FDB2CE9174896C7007B3C1B /* ConcurrentJSLock.h */,
                                658824B01E5CFDF400FB7359 /* ConfigFile.cpp */,
                                658824AE1E5CFDB000FB7359 /* ConfigFile.h */,
                                0FA2C17C17D7CF84009D015F /* TestRunnerUtils.h in Headers */,
                                FE3422121D6B81C30032BE88 /* ThrowScope.h in Headers */,
                                0F572D4F16879FDD00E57FBD /* ThunkGenerator.h in Headers */,
+                               E36CA813201F302900368EFF /* Concurrency.h in Headers */,
                                A7386556118697B400540279 /* ThunkGenerators.h in Headers */,
                                141448CD13A1783700F5BA1A /* TinyBloomFilter.h in Headers */,
                                0F55989817C86C5800A1E543 /* ToNativeFromValue.h in Headers */,
index fd3be4d..824fe86 100644 (file)
@@ -250,29 +250,9 @@ const Identifier& BytecodeDumper<Block>::identifier(int index) const
     return block()->identifier(index);
 }
 
-static CString regexpToSourceString(RegExp* regExp)
-{
-    char postfix[7] = { '/', 0, 0, 0, 0, 0, 0 };
-    int index = 1;
-    if (regExp->global())
-        postfix[index++] = 'g';
-    if (regExp->ignoreCase())
-        postfix[index++] = 'i';
-    if (regExp->multiline())
-        postfix[index] = 'm';
-    if (regExp->dotAll())
-        postfix[index++] = 's';
-    if (regExp->unicode())
-        postfix[index++] = 'u';
-    if (regExp->sticky())
-        postfix[index++] = 'y';
-
-    return toCString("/", regExp->pattern().impl(), postfix);
-}
-
 static CString regexpName(int re, RegExp* regexp)
 {
-    return toCString(regexpToSourceString(regexp), "(@re", re, ")");
+    return toCString(regexp->toSourceString(), "(@re", re, ")");
 }
 
 template<class Instruction>
@@ -1748,7 +1728,7 @@ void BytecodeDumper<Block>::dumpRegExps(PrintStream& out)
         out.printf("\nm_regexps:\n");
         size_t i = 0;
         do {
-            out.printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(block()->regexp(i)).data());
+            out.print("  re", i, " = ", block()->regexp(i)->toSourceString(), "\n");
             ++i;
         } while (i < count);
     }
index d5e59b2..aa8cc45 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include "config.h"
+#include "Concurrency.h"
 #include "ObjectPropertyConditionSet.h"
 
 #include "JSCInlines.h"
@@ -242,14 +243,10 @@ ObjectPropertyCondition generateCondition(
     return result;
 }
 
-enum Concurrency {
-    MainThread,
-    Concurrent
-};
 template<typename Functor>
 ObjectPropertyConditionSet generateConditions(
     VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* prototype, const Functor& functor,
-    Concurrency concurrency = MainThread)
+    Concurrency concurrency = Concurrency::MainThread)
 {
     Vector<ObjectPropertyCondition> conditions;
     
@@ -289,7 +286,7 @@ ObjectPropertyConditionSet generateConditions(
         structure = object->structure(vm);
         
         if (structure->isDictionary()) {
-            if (concurrency == MainThread) {
+            if (concurrency == Concurrency::MainThread) {
                 if (structure->hasBeenFlattenedBefore()) {
                     if (ObjectPropertyConditionSetInternal::verbose)
                         dataLog("Dictionary has been flattened before, so invalid.\n");
@@ -386,7 +383,7 @@ ObjectPropertyConditionSet generateConditionsForPrototypeEquivalenceConcurrently
                 return false;
             conditions.append(result);
             return true;
-        }, Concurrent);
+        }, Concurrency::Concurrent);
 }
 
 ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
@@ -400,7 +397,7 @@ ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
                 return false;
             conditions.append(result);
             return true;
-        }, Concurrent);
+        }, Concurrency::Concurrent);
 }
 
 ObjectPropertyConditionSet generateConditionsForPropertySetterMissConcurrently(
@@ -415,7 +412,7 @@ ObjectPropertyConditionSet generateConditionsForPropertySetterMissConcurrently(
                 return false;
             conditions.append(result);
             return true;
-        }, Concurrent);
+        }, Concurrency::Concurrent);
 }
 
 ObjectPropertyCondition generateConditionForSelfEquivalence(
index 988be1d..9c473b4 100644 (file)
@@ -2650,6 +2650,7 @@ void Heap::addCoreConstraints()
             
             slotVisitor.appendUnbarriered(m_vm->exception());
             slotVisitor.appendUnbarriered(m_vm->lastException());
+            slotVisitor.appendUnbarriered(m_vm->currentlyExecutingRegExp);
         },
         ConstraintVolatility::GreyedByExecution);
     
diff --git a/Source/JavaScriptCore/runtime/Concurrency.h b/Source/JavaScriptCore/runtime/Concurrency.h
new file mode 100644 (file)
index 0000000..9ae731f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace JSC {
+
+enum class Concurrency {
+    MainThread,
+    Concurrent,
+};
+
+}
index 4f20be0..6daf98f 100644 (file)
@@ -307,7 +307,7 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
 
 #if ENABLE(YARR_JIT)
     if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && VM::canUseRegExpJIT()) {
-        Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode);
+        Yarr::jitCompile(pattern, charSize, m_regExpJITCode);
         if (!m_regExpJITCode.failureReason()) {
             m_state = JITCode;
             return;
@@ -326,7 +326,7 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
 
 int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int>& ovector)
 {
-    return matchInline(vm, s, startOffset, ovector);
+    return matchInline(vm, Concurrency::MainThread, s, startOffset, ovector);
 }
 
 bool RegExp::matchConcurrently(
@@ -337,7 +337,7 @@ bool RegExp::matchConcurrently(
     if (!hasCodeFor(s.is8Bit() ? Yarr::Char8 : Yarr::Char16))
         return false;
 
-    position = match(vm, s, startOffset, ovector);
+    position = matchInline(vm, Concurrency::Concurrent, s, startOffset, ovector);
     return true;
 }
 
@@ -363,7 +363,7 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
 
 #if ENABLE(YARR_JIT)
     if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && VM::canUseRegExpJIT()) {
-        Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode, Yarr::MatchOnly);
+        Yarr::jitCompile(pattern, charSize, m_regExpJITCode, Yarr::MatchOnly);
         if (!m_regExpJITCode.failureReason()) {
             m_state = JITCode;
             return;
@@ -382,7 +382,7 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
 
 MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
 {
-    return matchInline(vm, s, startOffset);
+    return matchInline(vm, Concurrency::MainThread, s, startOffset);
 }
 
 bool RegExp::matchConcurrently(VM& vm, const String& s, unsigned startOffset, MatchResult& result)
@@ -392,7 +392,7 @@ bool RegExp::matchConcurrently(VM& vm, const String& s, unsigned startOffset, Ma
     if (!hasMatchOnlyCodeFor(s.is8Bit() ? Yarr::Char8 : Yarr::Char16))
         return false;
 
-    result = match(vm, s, startOffset);
+    result = matchInline(vm, Concurrency::Concurrent, s, startOffset);
     return true;
 }
 
@@ -409,6 +409,26 @@ void RegExp::deleteCode()
     m_regExpBytecode = nullptr;
 }
 
+String RegExp::toSourceString() const
+{
+    char postfix[8] = { '/', 0, 0, 0, 0, 0, 0, 0 };
+    int index = 1;
+    if (global())
+        postfix[index++] = 'g';
+    if (ignoreCase())
+        postfix[index++] = 'i';
+    if (multiline())
+        postfix[index++] = 'm';
+    if (dotAll())
+        postfix[index++] = 's';
+    if (unicode())
+        postfix[index++] = 'u';
+    if (sticky())
+        postfix[index++] = 'y';
+
+    return makeString("/", pattern(), postfix);
+}
+
 #if ENABLE(YARR_JIT_DEBUG)
 void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int* offsetVector, int jitResult)
 {
index 2ed9f9d..3e50721 100644 (file)
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include "Concurrency.h"
 #include "ConcurrentJSLock.h"
 #include "MatchResult.h"
 #include "RegExpKey.h"
@@ -74,8 +75,8 @@ public:
 
     // Call these versions of the match functions if you're desperate for performance.
     template<typename VectorType>
-    int matchInline(VM&, const String&, unsigned startOffset, VectorType& ovector);
-    MatchResult matchInline(VM&, const String&, unsigned startOffset);
+    int matchInline(VM&, Concurrency, const String&, unsigned startOffset, VectorType& ovector);
+    MatchResult matchInline(VM&, Concurrency, const String&, unsigned startOffset);
     
     unsigned numSubpatterns() const { return m_numSubpatterns; }
 
@@ -122,6 +123,8 @@ public:
 
     RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
 
+    String toSourceString() const;
+
 protected:
     void finishCreation(VM&);
 
@@ -150,6 +153,30 @@ private:
     void matchCompareWithInterpreter(const String&, int startOffset, int* offsetVector, int jitResult);
 #endif
 
+#if ENABLE(YARR_JIT)
+    class RegExpJITFrameTracer {
+        WTF_MAKE_NONCOPYABLE(RegExpJITFrameTracer);
+    public:
+        ALWAYS_INLINE RegExpJITFrameTracer(VM& vm, RegExp& regExp, Concurrency concurrency)
+        {
+            if (concurrency == Concurrency::MainThread) {
+                m_vm = &vm;
+                ASSERT(!m_vm->currentlyExecutingRegExp);
+                m_vm->currentlyExecutingRegExp = &regExp;
+            }
+        }
+
+        ALWAYS_INLINE ~RegExpJITFrameTracer()
+        {
+            if (m_vm)
+                m_vm->currentlyExecutingRegExp = nullptr;
+        }
+
+    private:
+        VM* m_vm { nullptr };
+    };
+#endif
+
     RegExpState m_state { NotCompiled };
     String m_patternString;
     RegExpFlags m_flags;
index b2f1dd3..104bdfc 100644 (file)
@@ -94,7 +94,7 @@ ALWAYS_INLINE void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSiz
 }
 
 template<typename VectorType>
-ALWAYS_INLINE int RegExp::matchInline(VM& vm, const String& s, unsigned startOffset, VectorType& ovector)
+ALWAYS_INLINE int RegExp::matchInline(VM& vm, Concurrency concurrency, const String& s, unsigned startOffset, VectorType& ovector)
 {
 #if ENABLE(REGEXP_TRACING)
     m_rtMatchCallCount++;
@@ -118,10 +118,13 @@ ALWAYS_INLINE int RegExp::matchInline(VM& vm, const String& s, unsigned startOff
 #endif
 
     if (m_state == JITCode) {
-        if (s.is8Bit())
-            result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
-        else
-            result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
+        {
+            RegExpJITFrameTracer tracer { vm, *this, concurrency };
+            if (s.is8Bit())
+                result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
+            else
+                result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
+        }
 
         if (result == Yarr::JSRegExpJITCodeFailure) {
             // JIT'ed code couldn't handle expression, so punt back to the interpreter.
@@ -202,7 +205,7 @@ ALWAYS_INLINE void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSiz
     compileMatchOnly(&vm, charSize);
 }
 
-ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, const String& s, unsigned startOffset)
+ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, Concurrency concurrency, const String& s, unsigned startOffset)
 {
 #if ENABLE(REGEXP_TRACING)
     m_rtMatchOnlyCallCount++;
@@ -223,10 +226,13 @@ ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, const String& s, unsigned
     MatchResult result;
 
     if (m_state == JITCode) {
-        if (s.is8Bit())
-            result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length() EXTRA_JIT_PARAMS);
-        else
-            result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length() EXTRA_JIT_PARAMS);
+        {
+            RegExpJITFrameTracer tracer { vm, *this, concurrency };
+            if (s.is8Bit())
+                result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length() EXTRA_JIT_PARAMS);
+            else
+                result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length() EXTRA_JIT_PARAMS);
+        }
 
 #if ENABLE(REGEXP_TRACING)
         if (!result)
index e387cc7..c29663a 100644 (file)
@@ -63,7 +63,7 @@ ALWAYS_INLINE JSArray* createRegExpMatchesArray(
     RegExp* regExp, unsigned startOffset, MatchResult& result)
 {
     Vector<int, 32> subpatternResults;
-    int position = regExp->matchInline(vm, inputValue, startOffset, subpatternResults);
+    int position = regExp->matchInline(vm, Concurrency::MainThread, inputValue, startOffset, subpatternResults);
     if (position == -1) {
         result = MatchResult::failed();
         return nullptr;
index 9727c18..4ed1069 100644 (file)
@@ -276,11 +276,8 @@ private:
 
 SamplingProfiler::SamplingProfiler(VM& vm, RefPtr<Stopwatch>&& stopwatch)
     : m_vm(vm)
-    , m_weakRandom()
     , m_stopwatch(WTFMove(stopwatch))
     , m_timingInterval(Seconds::fromMicroseconds(Options::sampleInterval()))
-    , m_isPaused(false)
-    , m_isShutDown(false)
 {
     if (sReportStats) {
         sNumTotalWalks = 0;
@@ -290,10 +287,6 @@ SamplingProfiler::SamplingProfiler(VM& vm, RefPtr<Stopwatch>&& stopwatch)
     m_currentFrames.grow(256);
 }
 
-SamplingProfiler::~SamplingProfiler()
-{
-}
-
 void SamplingProfiler::createThreadIfNecessary(const AbstractLocker&)
 {
     ASSERT(m_lock.isLocked());
@@ -317,7 +310,7 @@ void SamplingProfiler::timerLoop()
                 return;
 
             if (!m_isPaused && m_jscExecutionThread)
-                takeSample(locker, stackTraceProcessingTime);
+                stackTraceProcessingTime = takeSample(locker);
 
             m_lastTime = m_stopwatch->elapsedTime();
         }
@@ -332,7 +325,7 @@ void SamplingProfiler::timerLoop()
     }
 }
 
-void SamplingProfiler::takeSample(const AbstractLocker&, Seconds& stackTraceProcessingTime)
+Seconds SamplingProfiler::takeSample(const AbstractLocker&)
 {
     ASSERT(m_lock.isLocked());
     if (m_vm.entryScope) {
@@ -350,6 +343,7 @@ void SamplingProfiler::takeSample(const AbstractLocker&, Seconds& stackTraceProc
             ExecState* callFrame;
             void* machinePC;
             bool topFrameIsLLInt = false;
+            RegExp* regExp = nullptr;
             void* llintPC;
             {
                 PlatformRegisters registers;
@@ -362,11 +356,9 @@ void SamplingProfiler::takeSample(const AbstractLocker&, Seconds& stackTraceProc
             // FIXME: Lets have a way of detecting when we're parsing code.
             // https://bugs.webkit.org/show_bug.cgi?id=152761
             if (ExecutableAllocator::singleton().isValidExecutableMemory(executableAllocatorLocker, machinePC)) {
-                if (m_vm.isExecutingInRegExpJIT) {
-                    // FIXME: We're executing a regexp. Lets gather more intersting data.
-                    // https://bugs.webkit.org/show_bug.cgi?id=152729
+                regExp = m_vm.currentlyExecutingRegExp;
+                if (regExp)
                     callFrame = m_vm.topCallFrame; // We need to do this or else we'd fail our backtrace validation b/c this isn't a JS frame.
-                }
             } else if (LLInt::isLLIntPC(machinePC)) {
                 topFrameIsLLInt = true;
                 // We're okay to take a normal stack trace when the PC
@@ -407,16 +399,16 @@ void SamplingProfiler::takeSample(const AbstractLocker&, Seconds& stackTraceProc
                     stackTrace.uncheckedAppend(frame);
                 }
 
-                m_unprocessedStackTraces.append(UnprocessedStackTrace { nowTime, machinePC, topFrameIsLLInt, llintPC, WTFMove(stackTrace) });
+                m_unprocessedStackTraces.append(UnprocessedStackTrace { nowTime, machinePC, topFrameIsLLInt, llintPC, regExp, WTFMove(stackTrace) });
 
                 if (didRunOutOfVectorSpace)
                     m_currentFrames.grow(m_currentFrames.size() * 1.25);
             }
 
-            auto endTime = MonotonicTime::now();
-            stackTraceProcessingTime = endTime - startTime;
+            return MonotonicTime::now() - startTime;
         }
     }
+    return 0_s;
 }
 
 static ALWAYS_INLINE unsigned tryGetBytecodeIndex(unsigned llintPC, CodeBlock* codeBlock, bool& isValid)
@@ -571,36 +563,44 @@ void SamplingProfiler::processUnverifiedStackTraces()
         // Prepend the top-most inlined frame if needed and gather
         // location information about where the top frame is executing.
         size_t startIndex = 0;
-        if (unprocessedStackTrace.frames.size() && !!unprocessedStackTrace.frames[0].verifiedCodeBlock) {
-            CodeBlock* topCodeBlock = unprocessedStackTrace.frames[0].verifiedCodeBlock;
-            if (unprocessedStackTrace.topFrameIsLLInt) {
-                // We reuse LLInt CodeBlocks for the baseline JIT, so we need to check for both jit types.
-                // This might also be false for various reasons (known and unknown), even though
-                // it's super unlikely. One reason that this can be false is when we throw from a DFG frame,
-                // and we end up having to unwind past an EntryFrame, we will end up executing
-                // inside the LLInt's handleUncaughtException. So we just protect against this
-                // by ignoring it.
-                unsigned bytecodeIndex = 0;
-                if (topCodeBlock->jitType() == JITCode::InterpreterThunk || topCodeBlock->jitType() == JITCode::BaselineJIT) {
-                    bool isValidPC;
-                    unsigned bits;
+        if (!unprocessedStackTrace.frames.isEmpty()) {
+            auto& topFrame = unprocessedStackTrace.frames[0];
+            if (!!topFrame.verifiedCodeBlock) {
+                CodeBlock* topCodeBlock = topFrame.verifiedCodeBlock;
+                if (unprocessedStackTrace.topFrameIsLLInt) {
+                    // We reuse LLInt CodeBlocks for the baseline JIT, so we need to check for both jit types.
+                    // This might also be false for various reasons (known and unknown), even though
+                    // it's super unlikely. One reason that this can be false is when we throw from a DFG frame,
+                    // and we end up having to unwind past an EntryFrame, we will end up executing
+                    // inside the LLInt's handleUncaughtException. So we just protect against this
+                    // by ignoring it.
+                    unsigned bytecodeIndex = 0;
+                    if (topCodeBlock->jitType() == JITCode::InterpreterThunk || topCodeBlock->jitType() == JITCode::BaselineJIT) {
+                        bool isValidPC;
+                        unsigned bits;
 #if USE(JSVALUE64)
-                    bits = static_cast<unsigned>(bitwise_cast<uintptr_t>(unprocessedStackTrace.llintPC));
+                        bits = static_cast<unsigned>(bitwise_cast<uintptr_t>(unprocessedStackTrace.llintPC));
 #else
-                    bits = bitwise_cast<unsigned>(unprocessedStackTrace.llintPC);
+                        bits = bitwise_cast<unsigned>(unprocessedStackTrace.llintPC);
 #endif
-                    bytecodeIndex = tryGetBytecodeIndex(bits, topCodeBlock, isValidPC);
+                        bytecodeIndex = tryGetBytecodeIndex(bits, topCodeBlock, isValidPC);
 
-                    UNUSED_PARAM(isValidPC); // FIXME: do something with this info for the web inspector: https://bugs.webkit.org/show_bug.cgi?id=153455
+                        UNUSED_PARAM(isValidPC); // FIXME: do something with this info for the web inspector: https://bugs.webkit.org/show_bug.cgi?id=153455
 
-                    appendCodeBlock(topCodeBlock, bytecodeIndex);
-                    storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
+                        appendCodeBlock(topCodeBlock, bytecodeIndex);
+                        storeCalleeIntoLastFrame(topFrame.unverifiedCallee);
+                        startIndex = 1;
+                    }
+                } else if (std::optional<CodeOrigin> codeOrigin = topCodeBlock->findPC(unprocessedStackTrace.topPC)) {
+                    appendCodeOrigin(topCodeBlock, *codeOrigin);
+                    storeCalleeIntoLastFrame(topFrame.unverifiedCallee);
                     startIndex = 1;
                 }
-            } else if (std::optional<CodeOrigin> codeOrigin = topCodeBlock->findPC(unprocessedStackTrace.topPC)) {
-                appendCodeOrigin(topCodeBlock, *codeOrigin);
-                storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
-                startIndex = 1;
+            } else if (unprocessedStackTrace.regExp) {
+                appendEmptyFrame();
+                stackTrace.frames.last().regExp = unprocessedStackTrace.regExp;
+                stackTrace.frames.last().frameType = FrameType::RegExp;
+                m_liveCellPointers.add(unprocessedStackTrace.regExp);
             }
         }
 
@@ -712,8 +712,11 @@ void SamplingProfiler::clearData(const AbstractLocker&)
 
 String SamplingProfiler::StackFrame::nameFromCallee(VM& vm)
 {
-    if (!callee)
+    if (!callee) {
+        if (regExp)
+            return regExp->toSourceString();
         return String();
+    }
 
     auto scope = DECLARE_CATCH_SCOPE(vm);
     ExecState* exec = callee->globalObject()->globalExec();
@@ -747,7 +750,7 @@ String SamplingProfiler::StackFrame::displayName(VM& vm)
             return name;
     }
 
-    if (frameType == FrameType::Unknown || frameType == FrameType::C) {
+    if (frameType == FrameType::Unknown || frameType == FrameType::C || frameType == FrameType::RegExp) {
 #if HAVE(DLADDR)
         if (frameType == FrameType::C) {
             auto demangled = WTF::StackTrace::demangle(cCodePC);
@@ -783,7 +786,7 @@ String SamplingProfiler::StackFrame::displayNameForJSONTests(VM& vm)
             return name;
     }
 
-    if (frameType == FrameType::Unknown || frameType == FrameType::C)
+    if (frameType == FrameType::Unknown || frameType == FrameType::C || frameType == FrameType::RegExp)
         return ASCIILiteral("(unknown)");
     if (frameType == FrameType::Host)
         return ASCIILiteral("(host)");
@@ -810,48 +813,79 @@ String SamplingProfiler::StackFrame::displayNameForJSONTests(VM& vm)
 
 int SamplingProfiler::StackFrame::functionStartLine()
 {
-    if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
-        return -1;
-
-    if (executable->isHostFunction())
+    switch (frameType) {
+    case FrameType::Executable:
+        if (executable->isHostFunction())
+            return -1;
+        return static_cast<ScriptExecutable*>(executable)->firstLine();
+
+    case FrameType::Host:
+    case FrameType::RegExp:
+    case FrameType::C:
+    case FrameType::Unknown:
         return -1;
-    return static_cast<ScriptExecutable*>(executable)->firstLine();
+    }
+    ASSERT_NOT_REACHED();
+    return -1;
 }
 
 unsigned SamplingProfiler::StackFrame::functionStartColumn()
 {
-    if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
-        return std::numeric_limits<unsigned>::max();
-
-    if (executable->isHostFunction())
+    switch (frameType) {
+    case FrameType::Executable:
+        if (executable->isHostFunction())
+            return std::numeric_limits<unsigned>::max();
+        return static_cast<ScriptExecutable*>(executable)->startColumn();
+
+    case FrameType::Host:
+    case FrameType::RegExp:
+    case FrameType::C:
+    case FrameType::Unknown:
         return std::numeric_limits<unsigned>::max();
-
-    return static_cast<ScriptExecutable*>(executable)->startColumn();
+    }
+    ASSERT_NOT_REACHED();
+    return std::numeric_limits<unsigned>::max();
 }
 
 intptr_t SamplingProfiler::StackFrame::sourceID()
 {
-    if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
-        return -1;
-
-    if (executable->isHostFunction())
+    switch (frameType) {
+    case FrameType::Executable:
+        if (executable->isHostFunction())
+            return -1;
+        return static_cast<ScriptExecutable*>(executable)->sourceID();
+
+    case FrameType::Host:
+    case FrameType::RegExp:
+    case FrameType::C:
+    case FrameType::Unknown:
         return -1;
-
-    return static_cast<ScriptExecutable*>(executable)->sourceID();
+    }
+    ASSERT_NOT_REACHED();
+    return -1;
 }
 
 String SamplingProfiler::StackFrame::url()
 {
-    if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
-        return emptyString();
+    switch (frameType) {
+    case FrameType::Executable: {
+        if (executable->isHostFunction())
+            return emptyString();
+
+        String url = static_cast<ScriptExecutable*>(executable)->sourceURL();
+        if (url.isEmpty())
+            return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive.
+        return url;
+    }
 
-    if (executable->isHostFunction())
+    case FrameType::Host:
+    case FrameType::RegExp:
+    case FrameType::C:
+    case FrameType::Unknown:
         return emptyString();
-
-    String url = static_cast<ScriptExecutable*>(executable)->sourceURL();
-    if (url.isEmpty())
-        return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive.
-    return url;
+    }
+    ASSERT_NOT_REACHED();
+    return emptyString();
 }
 
 Vector<SamplingProfiler::StackTrace> SamplingProfiler::releaseStackTraces(const AbstractLocker& locker)
@@ -1080,6 +1114,9 @@ void printInternal(PrintStream& out, SamplingProfiler::FrameType frameType)
     case SamplingProfiler::FrameType::Host:
         out.print("Host");
         break;
+    case SamplingProfiler::FrameType::RegExp:
+        out.print("RegExp");
+        break;
     case SamplingProfiler::FrameType::C:
     case SamplingProfiler::FrameType::Unknown:
         out.print("Unknown");
index 7d91ad4..12000f0 100644 (file)
@@ -39,6 +39,7 @@
 
 namespace JSC {
 
+class RegExp;
 class VM;
 class ExecutableBase;
 
@@ -68,6 +69,7 @@ public:
     enum class FrameType { 
         Executable,
         Host,
+        RegExp,
         C,
         Unknown
     };
@@ -85,6 +87,7 @@ public:
         void* cCodePC { nullptr };
         ExecutableBase* executable { nullptr };
         JSObject* callee { nullptr };
+        RegExp* regExp { nullptr };
 
         struct CodeLocation {
             bool hasCodeBlockHash() const
@@ -141,6 +144,7 @@ public:
         void* topPC;
         bool topFrameIsLLInt;
         void* llintPC;
+        RegExp* regExp;
         Vector<UnprocessedStackFrame> frames;
     };
 
@@ -156,7 +160,7 @@ public:
     };
 
     SamplingProfiler(VM&, RefPtr<Stopwatch>&&);
-    ~SamplingProfiler();
+    ~SamplingProfiler() = default;
     void noticeJSLockAcquisition();
     void noticeVMEntry();
     void shutdown();
@@ -185,7 +189,7 @@ public:
 private:
     void createThreadIfNecessary(const AbstractLocker&);
     void timerLoop();
-    void takeSample(const AbstractLocker&, Seconds& stackTraceProcessingTime);
+    Seconds takeSample(const AbstractLocker&);
 
     VM& m_vm;
     WeakRandom m_weakRandom;
@@ -197,8 +201,8 @@ private:
     Lock m_lock;
     RefPtr<Thread> m_thread;
     RefPtr<Thread> m_jscExecutionThread;
-    bool m_isPaused;
-    bool m_isShutDown;
+    bool m_isPaused { false };
+    bool m_isShutDown { false };
     bool m_needsReportAtExit { false };
     HashSet<JSCell*> m_liveCellPointers;
     Vector<UnprocessedStackFrame> m_currentFrames;
index b6a4501..9a2e578 100644 (file)
@@ -118,6 +118,7 @@ class JSWebAssemblyInstance;
 class LLIntOffsetsExtractor;
 class NativeExecutable;
 class PromiseDeferredTimer;
+class RegExp;
 class RegExpCache;
 class Register;
 class RegisterAtOffsetList;
@@ -636,7 +637,7 @@ public:
     Instruction* targetInterpreterPCForThrow;
     uint32_t osrExitIndex;
     void* osrExitJumpDestination;
-    bool isExecutingInRegExpJIT { false };
+    RegExp* currentlyExecutingRegExp { nullptr };
 
     // The threading protocol here is as follows:
     // - You can call scratchBufferForSize from any thread.
index f020731..d489091 100644 (file)
@@ -29,7 +29,6 @@
 #include <wtf/ASCIICType.h>
 #include "LinkBuffer.h"
 #include "Options.h"
-#include "VM.h"
 #include "Yarr.h"
 #include "YarrCanonicalize.h"
 
@@ -41,7 +40,7 @@ namespace JSC { namespace Yarr {
 
 template<YarrJITCompileMode compileMode>
 class YarrGenerator : private MacroAssembler {
-    friend void jitCompile(VM*, YarrCodeBlock& jitObject, const String& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
+    friend void jitCompile(YarrCodeBlock& jitObject, const String& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
 
 #if CPU(ARM)
     static const RegisterID input = ARMRegisters::r0;
@@ -3337,14 +3336,10 @@ class YarrGenerator : private MacroAssembler {
 #elif CPU(MIPS)
         // Do nothing.
 #endif
-
-        store8(TrustedImm32(1), &m_vm->isExecutingInRegExpJIT);
     }
 
     void generateReturn()
     {
-        store8(TrustedImm32(0), &m_vm->isExecutingInRegExpJIT);
-
 #if CPU(X86_64)
 #if OS(WINDOWS)
         // Store the return value in the allocated space pointed by rcx.
@@ -3391,9 +3386,8 @@ class YarrGenerator : private MacroAssembler {
     }
 
 public:
-    YarrGenerator(VM* vm, YarrPattern& pattern, YarrCharSize charSize)
-        : m_vm(vm)
-        , m_pattern(pattern)
+    YarrGenerator(YarrPattern& pattern, YarrCharSize charSize)
+        : m_pattern(pattern)
         , m_charSize(charSize)
         , m_decodeSurrogatePairs(m_charSize == Char16 && m_pattern.unicode())
         , m_unicodeIgnoreCase(m_pattern.unicode() && m_pattern.ignoreCase())
@@ -3495,8 +3489,6 @@ public:
     }
 
 private:
-    VM* m_vm;
-
     YarrPattern& m_pattern;
 
     YarrCharSize m_charSize;
@@ -3560,12 +3552,12 @@ static void dumpCompileFailure(JITFailureReason failure)
     }
 }
 
-void jitCompile(YarrPattern& pattern, YarrCharSize charSize, VM* vm, YarrCodeBlock& jitObject, YarrJITCompileMode mode)
+void jitCompile(YarrPattern& pattern, YarrCharSize charSize, YarrCodeBlock& jitObject, YarrJITCompileMode mode)
 {
     if (mode == MatchOnly)
-        YarrGenerator<MatchOnly>(vm, pattern, charSize).compile(jitObject);
+        YarrGenerator<MatchOnly>(pattern, charSize).compile(jitObject);
     else
-        YarrGenerator<IncludeSubpatterns>(vm, pattern, charSize).compile(jitObject);
+        YarrGenerator<IncludeSubpatterns>(pattern, charSize).compile(jitObject);
 
     if (auto failureReason = jitObject.failureReason()) {
         if (Options::dumpCompiledRegExpPatterns())
index f2a94a7..53cc105 100644 (file)
@@ -45,7 +45,6 @@ constexpr size_t patternContextBufferSize = 8192; // Space caller allocates to s
 
 namespace JSC {
 
-class VM;
 class ExecutablePool;
 
 namespace Yarr {
@@ -205,7 +204,7 @@ enum YarrJITCompileMode {
     MatchOnly,
     IncludeSubpatterns
 };
-void jitCompile(YarrPattern&, YarrCharSize, VM*, YarrCodeBlock& jitObject, YarrJITCompileMode = IncludeSubpatterns);
+void jitCompile(YarrPattern&, YarrCharSize, YarrCodeBlock& jitObject, YarrJITCompileMode = IncludeSubpatterns);
 
 } } // namespace JSC::Yarr