[JSC] Lazily create empty RegExp
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 16 Feb 2019 04:32:42 +0000 (04:32 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 16 Feb 2019 04:32:42 +0000 (04:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194735

Reviewed by Keith Miller.

Some scripts do not have any RegExp. In that case, allocating MarkedBlock for RegExp is costly.
Previously, there was always one RegExp, "empty RegExp". This patch lazily creates it and drop
one MarkedBlock.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/RegExpCache.cpp:
(JSC::RegExpCache::ensureEmptyRegExpSlow):
(JSC::RegExpCache::initialize): Deleted.
* runtime/RegExpCache.h:
(JSC::RegExpCache::ensureEmptyRegExp):
(JSC::RegExpCache::emptyRegExp const): Deleted.
* runtime/RegExpCachedResult.cpp:
(JSC::RegExpCachedResult::lastResult):
* runtime/RegExpCachedResult.h:
* runtime/VM.cpp:
(JSC::VM::VM):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/RegExpCache.cpp
Source/JavaScriptCore/runtime/RegExpCache.h
Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
Source/JavaScriptCore/runtime/RegExpCachedResult.h
Source/JavaScriptCore/runtime/VM.cpp

index 8049f0c..ae5148f 100644 (file)
@@ -1,5 +1,30 @@
 2019-02-15  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] Lazily create empty RegExp
+        https://bugs.webkit.org/show_bug.cgi?id=194735
+
+        Reviewed by Keith Miller.
+
+        Some scripts do not have any RegExp. In that case, allocating MarkedBlock for RegExp is costly.
+        Previously, there was always one RegExp, "empty RegExp". This patch lazily creates it and drop
+        one MarkedBlock.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/RegExpCache.cpp:
+        (JSC::RegExpCache::ensureEmptyRegExpSlow):
+        (JSC::RegExpCache::initialize): Deleted.
+        * runtime/RegExpCache.h:
+        (JSC::RegExpCache::ensureEmptyRegExp):
+        (JSC::RegExpCache::emptyRegExp const): Deleted.
+        * runtime/RegExpCachedResult.cpp:
+        (JSC::RegExpCachedResult::lastResult):
+        * runtime/RegExpCachedResult.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+
+2019-02-15  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] Make builtin objects more lazily initialized under non-JIT mode
         https://bugs.webkit.org/show_bug.cgi?id=194727
 
index c23c192..d0c7ccd 100644 (file)
@@ -688,7 +688,7 @@ void JSGlobalObject::init(VM& vm)
     m_arrayConstructor.set(vm, this, arrayConstructor);
     
     RegExpConstructor* regExpConstructor = RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get(), m_speciesGetterSetter.get());
-    m_regExpGlobalData.cachedResult().record(vm, this, vm.regExpCache()->emptyRegExp(), jsEmptyString(&vm), MatchResult(0, 0));
+    m_regExpGlobalData.cachedResult().record(vm, this, nullptr, jsEmptyString(&vm), MatchResult(0, 0));
     
     JSArrayBufferConstructor* arrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayBufferPrototype.get(), m_speciesGetterSetter.get());
     m_arrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayBufferConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
index 2cb29c4..d76bb39 100644 (file)
@@ -56,9 +56,11 @@ RegExpCache::RegExpCache(VM* vm)
 {
 }
 
-void RegExpCache::initialize(VM& vm)
+RegExp* RegExpCache::ensureEmptyRegExpSlow(VM& vm)
 {
-    m_emptyRegExp.set(vm, RegExp::create(vm, "", NoFlags));
+    RegExp* regExp = RegExp::create(vm, "", NoFlags);
+    m_emptyRegExp.set(vm, regExp);
+    return regExp;
 }
 
 void RegExpCache::finalize(Handle<Unknown> handle, void*)
index 2f5bdc3..bbda63f 100644 (file)
@@ -46,9 +46,12 @@ public:
     RegExpCache(VM* vm);
     void deleteAllCode();
 
-    void initialize(VM&);
-
-    RegExp* emptyRegExp() const { return m_emptyRegExp.get(); }
+    RegExp* ensureEmptyRegExp(VM& vm)
+    {
+        if (LIKELY(m_emptyRegExp))
+            return m_emptyRegExp.get();
+        return ensureEmptyRegExpSlow(vm);
+    }
 
 private:
     
@@ -58,6 +61,8 @@ private:
 
     void finalize(Handle<Unknown>, void* context) override;
 
+    RegExp* ensureEmptyRegExpSlow(VM&);
+
     RegExp* lookupOrCreate(const WTF::String& patternString, RegExpFlags);
     void addToStrongCache(RegExp*);
     RegExpCacheMap m_weakCache; // Holds all regular expressions currently live.
index c6a6b03..9e100d2 100644 (file)
@@ -45,8 +45,11 @@ void RegExpCachedResult::visitAggregate(SlotVisitor& visitor)
 
 JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
 {
+    VM& vm = exec->vm();
     if (!m_reified) {
-        m_reifiedInput.set(exec->vm(), owner, m_lastInput.get());
+        m_reifiedInput.set(vm, owner, m_lastInput.get());
+        if (!m_lastRegExp)
+            m_lastRegExp.set(vm, owner, vm.regExpCache()->ensureEmptyRegExp(vm));
         if (m_result)
             m_reifiedResult.setWithoutWriteBarrier(createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start));
         else
@@ -54,7 +57,7 @@ JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
         m_reifiedLeftContext.clear();
         m_reifiedRightContext.clear();
         m_reified = true;
-        exec->vm().heap.writeBarrier(owner);
+        vm.heap.writeBarrier(owner);
     }
     return m_reifiedResult.get();
 }
index 88a6c66..a5b0391 100644 (file)
@@ -65,6 +65,8 @@ public:
 
     void visitAggregate(SlotVisitor&);
 
+    // m_lastRegExp would be nullptr when RegExpCachedResult is not reified.
+    // If we find m_lastRegExp is nullptr, it means this should hold the empty RegExp.
     static ptrdiff_t offsetOfLastRegExp() { return OBJECT_OFFSETOF(RegExpCachedResult, m_lastRegExp); }
     static ptrdiff_t offsetOfLastInput() { return OBJECT_OFFSETOF(RegExpCachedResult, m_lastInput); }
     static ptrdiff_t offsetOfResult() { return OBJECT_OFFSETOF(RegExpCachedResult, m_result); }
index 79022d6..0952ffe 100644 (file)
@@ -401,7 +401,6 @@ VM::VM(VMType vmType, HeapType heapType)
     sentinelSetBucket.set(*this, JSSet::BucketType::createSentinel(*this));
     sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this));
 
-    m_regExpCache->initialize(*this);
     smallStrings.initializeCommonStrings(*this);
 
     Thread::current().setCurrentAtomicStringTable(existingEntryAtomicStringTable);