[JSC] Shrink sizeof(RegExpObject)
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 06:45:20 +0000 (06:45 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 06:45:20 +0000 (06:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196130

Reviewed by Saam Barati.

sizeof(RegExpObject) is 48B due to one bool flag. We should compress this flag into lower bit of RegExp* field so that we can make RegExpObject 32B.
It saves memory footprint 1.3% in RAMification's regexp.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNewRegexp):
(JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
(JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::RegExpObject):
(JSC::RegExpObject::visitChildren):
(JSC::RegExpObject::getOwnPropertySlot):
(JSC::RegExpObject::defineOwnProperty):
* runtime/RegExpObject.h:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/RegExpObject.h

index ebe9ff9..0fb0780 100644 (file)
@@ -1,3 +1,27 @@
+2019-03-21  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Shrink sizeof(RegExpObject)
+        https://bugs.webkit.org/show_bug.cgi?id=196130
+
+        Reviewed by Saam Barati.
+
+        sizeof(RegExpObject) is 48B due to one bool flag. We should compress this flag into lower bit of RegExp* field so that we can make RegExpObject 32B.
+        It saves memory footprint 1.3% in RAMification's regexp.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNewRegexp):
+        (JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex):
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::RegExpObject):
+        (JSC::RegExpObject::visitChildren):
+        (JSC::RegExpObject::getOwnPropertySlot):
+        (JSC::RegExpObject::defineOwnProperty):
+        * runtime/RegExpObject.h:
+
 2019-03-21  Tomas Popela  <tpopela@redhat.com>
 
         [JSC] Fix build after r243232 on unsupported 64bit architectures
index 85a5a87..c956405 100644 (file)
@@ -9790,9 +9790,8 @@ void SpeculativeJIT::compileNewRegexp(Node* node)
 
     m_jit.storePtr(
         TrustedImmPtr(node->cellOperand()),
-        CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExp()));
+        CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()));
     m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
-    m_jit.store8(TrustedImm32(true), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndexIsWritable()));
     m_jit.mutatorFence(*m_jit.vm());
 
     addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs));
@@ -11130,9 +11129,10 @@ void SpeculativeJIT::compileSetRegExpObjectLastIndex(Node* node)
         speculateRegExpObject(node->child1(), regExpGPR);
         speculationCheck(
             ExoticObjectMode, JSValueRegs(), nullptr,
-            m_jit.branchTest8(
-                JITCompiler::Zero,
-                JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndexIsWritable())));
+            m_jit.branchTestPtr(
+                JITCompiler::NonZero,
+                JITCompiler::Address(regExpGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()),
+                JITCompiler::TrustedImm32(RegExpObject::lastIndexIsNotWritableFlag)));
     }
 
     m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
index 4bf88b5..89995e6 100644 (file)
@@ -96,9 +96,8 @@ namespace JSC { namespace FTL {
     macro(JSScope_next, JSScope::offsetOfNext()) \
     macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \
     macro(JSWrapperObject_internalValue, JSWrapperObject::internalValueOffset()) \
-    macro(RegExpObject_regExp, RegExpObject::offsetOfRegExp()) \
+    macro(RegExpObject_regExpAndLastIndexIsNotWritableFlag, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()) \
     macro(RegExpObject_lastIndex, RegExpObject::offsetOfLastIndex()) \
-    macro(RegExpObject_lastIndexIsWritable, RegExpObject::offsetOfLastIndexIsWritable()) \
     macro(ShadowChicken_Packet_callee, OBJECT_OFFSETOF(ShadowChicken::Packet, callee)) \
     macro(ShadowChicken_Packet_frame, OBJECT_OFFSETOF(ShadowChicken::Packet, frame)) \
     macro(ShadowChicken_Packet_callerFrame, OBJECT_OFFSETOF(ShadowChicken::Packet, callerFrame)) \
index a688f2f..8b9a291 100644 (file)
@@ -11290,9 +11290,8 @@ private:
 
         auto structure = m_graph.registerStructure(m_graph.globalObjectFor(m_node->origin.semantic)->regExpStructure());
         LValue fastResultValue = allocateObject<RegExpObject>(structure, m_out.intPtrZero, slowCase);
-        m_out.storePtr(frozenPointer(regexp), fastResultValue, m_heaps.RegExpObject_regExp);
+        m_out.storePtr(frozenPointer(regexp), fastResultValue, m_heaps.RegExpObject_regExpAndLastIndexIsNotWritableFlag);
         m_out.store64(lastIndex, fastResultValue, m_heaps.RegExpObject_lastIndex);
-        m_out.store32As8(m_out.constInt32(true), m_out.address(fastResultValue, m_heaps.RegExpObject_lastIndexIsWritable));
         mutatorFence();
         ValueFromBlock fastResult = m_out.anchor(fastResultValue);
         m_out.jump(continuation);
@@ -11378,7 +11377,9 @@ private:
 
             speculate(
                 ExoticObjectMode, noValue(), nullptr,
-                m_out.isZero32(m_out.load8ZeroExt32(regExp, m_heaps.RegExpObject_lastIndexIsWritable)));
+                m_out.testNonZeroPtr(
+                    m_out.loadPtr(regExp, m_heaps.RegExpObject_regExpAndLastIndexIsNotWritableFlag),
+                    m_out.constIntPtr(RegExpObject::lastIndexIsNotWritableFlag)));
 
             m_out.store64(value, regExp, m_heaps.RegExpObject_lastIndex);
             return;
index 03fbe46..3a9d9a7 100644 (file)
@@ -38,8 +38,7 @@ const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, nullp
 
 RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp)
     : JSNonFinalObject(vm, structure)
-    , m_regExp(vm, this, regExp)
-    , m_lastIndexIsWritable(true)
+    , m_regExpAndLastIndexIsNotWritableFlag(bitwise_cast<uintptr_t>(regExp)) // lastIndexIsNotWritableFlag is not set.
 {
     m_lastIndex.setWithoutWriteBarrier(jsNumber(0));
 }
@@ -56,7 +55,7 @@ void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
-    visitor.append(thisObject->m_regExp);
+    visitor.appendUnbarriered(thisObject->regExp());
     visitor.append(thisObject->m_lastIndex);
 }
 
@@ -65,7 +64,7 @@ bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, Propert
     VM& vm = exec->vm();
     if (propertyName == vm.propertyNames->lastIndex) {
         RegExpObject* regExp = jsCast<RegExpObject*>(object);
-        unsigned attributes = regExp->m_lastIndexIsWritable ? PropertyAttribute::DontDelete | PropertyAttribute::DontEnum : PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly;
+        unsigned attributes = regExp->lastIndexIsWritable() ? PropertyAttribute::DontDelete | PropertyAttribute::DontEnum : PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly;
         slot.setValue(regExp, attributes, regExp->getLastIndex());
         return true;
     }
@@ -117,7 +116,7 @@ bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, Property
             return typeError(exec, scope, shouldThrow, UnconfigurablePropertyChangeEnumerabilityError);
         if (descriptor.isAccessorDescriptor())
             return typeError(exec, scope, shouldThrow, UnconfigurablePropertyChangeAccessMechanismError);
-        if (!regExp->m_lastIndexIsWritable) {
+        if (!regExp->lastIndexIsWritable()) {
             if (descriptor.writablePresent() && descriptor.writable())
                 return typeError(exec, scope, shouldThrow, UnconfigurablePropertyChangeWritabilityError);
             if (descriptor.value() && !sameValue(exec, regExp->getLastIndex(), descriptor.value()))
@@ -129,7 +128,7 @@ bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, Property
             RETURN_IF_EXCEPTION(scope, false);
         }
         if (descriptor.writablePresent() && !descriptor.writable())
-            regExp->m_lastIndexIsWritable = false;
+            regExp->setLastIndexIsNotWritable();
         return true;
     }
 
index 1de53c6..b60bac8 100644 (file)
@@ -32,6 +32,8 @@ public:
     using Base = JSNonFinalObject;
     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
 
+    static constexpr uintptr_t lastIndexIsNotWritableFlag = 1;
+
     static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp)
     {
         RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp);
@@ -46,15 +48,24 @@ public:
         return object;
     }
 
-    void setRegExp(VM& vm, RegExp* r) { m_regExp.set(vm, this, r); }
-    RegExp* regExp() const { return m_regExp.get(); }
+    void setRegExp(VM& vm, RegExp* regExp)
+    {
+        uintptr_t result = (m_regExpAndLastIndexIsNotWritableFlag & lastIndexIsNotWritableFlag) | bitwise_cast<uintptr_t>(regExp);
+        m_regExpAndLastIndexIsNotWritableFlag = result;
+        vm.heap.writeBarrier(this, regExp);
+    }
+
+    RegExp* regExp() const
+    {
+        return bitwise_cast<RegExp*>(m_regExpAndLastIndexIsNotWritableFlag & (~lastIndexIsNotWritableFlag));
+    }
 
     bool setLastIndex(ExecState* exec, size_t lastIndex)
     {
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
-        if (LIKELY(m_lastIndexIsWritable)) {
+        if (LIKELY(lastIndexIsWritable())) {
             m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
             return true;
         }
@@ -66,11 +77,10 @@ public:
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
-        if (LIKELY(m_lastIndexIsWritable)) {
+        if (LIKELY(lastIndexIsWritable())) {
             m_lastIndex.set(vm, this, lastIndex);
             return true;
         }
-
         return typeError(exec, scope, shouldThrow, ReadonlyPropertyWriteError);
     }
     JSValue getLastIndex() const
@@ -95,9 +105,9 @@ public:
         return Structure::create(vm, globalObject, prototype, TypeInfo(RegExpObjectType, StructureFlags), info());
     }
 
-    static ptrdiff_t offsetOfRegExp()
+    static ptrdiff_t offsetOfRegExpAndLastIndexIsNotWritableFlag()
     {
-        return OBJECT_OFFSETOF(RegExpObject, m_regExp);
+        return OBJECT_OFFSETOF(RegExpObject, m_regExpAndLastIndexIsNotWritableFlag);
     }
 
     static ptrdiff_t offsetOfLastIndex()
@@ -105,11 +115,6 @@ public:
         return OBJECT_OFFSETOF(RegExpObject, m_lastIndex);
     }
 
-    static ptrdiff_t offsetOfLastIndexIsWritable()
-    {
-        return OBJECT_OFFSETOF(RegExpObject, m_lastIndexIsWritable);
-    }
-
     static size_t allocationSize(Checked<size_t> inlineCapacity)
     {
         ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
@@ -122,6 +127,16 @@ protected:
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
+    bool lastIndexIsWritable() const
+    {
+        return !(m_regExpAndLastIndexIsNotWritableFlag & lastIndexIsNotWritableFlag);
+    }
+
+    void setLastIndexIsNotWritable()
+    {
+        m_regExpAndLastIndexIsNotWritableFlag = (m_regExpAndLastIndexIsNotWritableFlag | lastIndexIsNotWritableFlag);
+    }
+
     JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
@@ -131,9 +146,8 @@ protected:
 private:
     MatchResult matchInline(ExecState*, JSGlobalObject*, JSString*);
 
-    WriteBarrier<RegExp> m_regExp;
+    uintptr_t m_regExpAndLastIndexIsNotWritableFlag { 0 };
     WriteBarrier<Unknown> m_lastIndex;
-    uint8_t m_lastIndexIsWritable;
 };
 
 } // namespace JSC