⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 245214 in webkit


Ignore:
Timestamp:
May 12, 2019, 3:50:21 PM (7 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Compress Watchpoint size by using enum type and Packed<> data structure
https://bugs.webkit.org/show_bug.cgi?id=197730

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Watchpoint takes 5~ MB memory in Gmail (total memory starts with 400 - 500 MB), so 1~%. Since it is allocated massively,
reducing each size of Watchpoint reduces memory footprint significantly.

As a first step, this patch uses Packed<> and enum to reduce the size of Watchpoint.

  1. Watchpoint should have enum type and should not use vtable. vtable takes one pointer, and it is too costly for such a memory sensitive objects. We perform downcast and dispatch the method of the derived classes based on this enum. Since the # of derived Watchpoint classes are limited (Only 8), we can list up them easily. One unfortunate thing is that we cannot do this for destructor so long as we use "delete" for deleting objects. If we dispatch the destructor of derived class in the destructor of the base class, we call the destructor of the base class multiple times. delete operator override does not help since custom delete operator is called after the destructor is called. While we can fix this issue by always using custom deleter, currently we do not since all the watchpoints do not have members which have non trivial destructor. Once it is strongly required, we can start using custom deleter, but for now, we do not need to do this.
  1. We use Packed<> to compact pointers in Watchpoint. Since Watchpoint is a node of doubly linked list, each one has two pointers for prev and next. This is also too costly. PackedPtr reduces the size and makes alignment 1.S
  1. We use PackedCellPtr<> for JSCells in Watchpoint. This leverages alignment information and makes pointers smaller in Darwin ARM64. One important thing to note here is that since this pointer is packed, it cannot be found by conservative GC scan. It is OK for watchpoint since they are allocated in the heap anyway.

We applied this change to Watchpoint and get the following memory reduction. The highlight is that CodeBlockJettisoningWatchpoint in
ARM64 only takes 2 pointers size.

ORIGINAL X86_64 ARM64

WatchpointSet: 40 32 28
CodeBlockJettisoningWatchpoint: 32 19 15
StructureStubClearingWatchpoint: 56 48 40
AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint: 24 13 11
AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint: 24 13 11
FunctionRareData::AllocationProfileClearingWatchpoint: 32 19 15
ObjectToStringAdaptiveStructureWatchpoint: 56 48 40
LLIntPrototypeLoadAdaptiveStructureWatchpoint: 64 48 48
DFG::AdaptiveStructureWatchpoint: 56 48 40

While we will re-architect the mechanism of Watchpoint, anyway Packed<> mechanism and enum types will be used too.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • bytecode/AdaptiveInferredPropertyValueWatchpointBase.h:
  • bytecode/CodeBlockJettisoningWatchpoint.h:
  • bytecode/CodeOrigin.h:
  • bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp:

(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):

  • bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h:
  • bytecode/StructureStubClearingWatchpoint.cpp:

(JSC::StructureStubClearingWatchpoint::fireInternal):

  • bytecode/StructureStubClearingWatchpoint.h:
  • bytecode/Watchpoint.cpp:

(JSC::Watchpoint::fire):

  • bytecode/Watchpoint.h:

(JSC::Watchpoint::Watchpoint):

  • dfg/DFGAdaptiveStructureWatchpoint.cpp:

(JSC::DFG::AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint):

  • dfg/DFGAdaptiveStructureWatchpoint.h:
  • heap/PackedCellPtr.h: Added.
  • runtime/FunctionRareData.h:
  • runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp: Added.

(JSC::ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint):
(JSC::ObjectToStringAdaptiveStructureWatchpoint::install):
(JSC::ObjectToStringAdaptiveStructureWatchpoint::fireInternal):

  • runtime/ObjectToStringAdaptiveStructureWatchpoint.h: Added.
  • runtime/StructureRareData.cpp:

(JSC::StructureRareData::clearObjectToStringValue):
(JSC::ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint): Deleted.
(JSC::ObjectToStringAdaptiveStructureWatchpoint::install): Deleted.
(JSC::ObjectToStringAdaptiveStructureWatchpoint::fireInternal): Deleted.

  • runtime/StructureRareData.h:

Source/WTF:

This patch introduces a new data structures, WTF::Packed, WTF::PackedPtr, and WTF::PackedAlignedPtr.

  • WTF::Packed

WTF::Packed is data storage. We can read and write trivial (in C++ term [1]) data to this storage. The difference to
the usual storage is that the alignment of this storage is always 1. We access the underlying data by using unalignedLoad/unalignedStore.
This class offers alignment = 1 data structure instead of missing the following characteristics.

  1. Load / Store are non atomic even if the data size is within a pointer width. We should not use this for a member which can be accessed in a racy way. (e.g. fields accessed optimistically from the concurrent compilers).
  1. We cannot take reference / pointer to the underlying storage since they are unaligned.
  1. Access to this storage is unaligned access. The code is using memcpy, and the compiler will convert to an appropriate unaligned access in certain architectures (x86_64 / ARM64). It could be slow. So use it for non performance sensitive & memory sensitive places.
  • WTF::PackedPtr

WTF::PackedPtr is a specialization of WTF::Packed<T*>. And it is basically WTF::PackedAlignedPtr with alignment = 1. We further compact
the pointer by leveraging the platform specific knowledge. In 64bit architectures, the effective width of pointers are less than 64 bit.
In x86_64, it is 48 bits. And Darwin ARM64 is further smaller, 36 bits. This information allows us to compact the pointer to 6 bytes in
x86_64 and 5 bytes in Darwin ARM64.

  • WTF::PackedAlignedPtr

WTF::PackedAlignedPtr is the WTF::PackedPtr with alignment information of the T. If we use this alignment information, we could reduce the
size of packed pointer further in some cases. For example, since we guarantee that JSCells are 16 byte aligned, low 4 bits are empty. Leveraging
this information in Darwin ARM64 platform allows us to make packed JSCell pointer 4 bytes (36 - 4 bits). We do not use passed alignment
information if it is not profitable.

We also have PackedPtrTraits. This is new PtrTraits and use it for various data structures such as Bag<>.

[1]: https://en.cppreference.com/w/cpp/types/is_trivial

  • WTF.xcodeproj/project.pbxproj:
  • wtf/Bag.h:

(WTF::Bag::clear):
(WTF::Bag::iterator::operator++):

  • wtf/CMakeLists.txt:
  • wtf/DumbPtrTraits.h:
  • wtf/DumbValueTraits.h:
  • wtf/MathExtras.h:

(WTF::clzConstexpr):
(WTF::clz):
(WTF::ctzConstexpr):
(WTF::ctz):
(WTF::getLSBSetConstexpr):
(WTF::getMSBSetConstexpr):

  • wtf/Packed.h: Added.

(WTF::Packed::Packed):
(WTF::Packed::get const):
(WTF::Packed::set):
(WTF::Packed::operator=):
(WTF::Packed::exchange):
(WTF::Packed::swap):
(WTF::alignof):
(WTF::PackedPtrTraits::exchange):
(WTF::PackedPtrTraits::swap):
(WTF::PackedPtrTraits::unwrap):

  • wtf/Platform.h:
  • wtf/SentinelLinkedList.h:

(WTF::BasicRawSentinelNode::BasicRawSentinelNode):
(WTF::BasicRawSentinelNode::prev):
(WTF::BasicRawSentinelNode::next):
(WTF::PtrTraits>::remove):
(WTF::PtrTraits>::prepend):
(WTF::PtrTraits>::append):
(WTF::RawNode>::SentinelLinkedList):
(WTF::RawNode>::remove):
(WTF::BasicRawSentinelNode<T>::remove): Deleted.
(WTF::BasicRawSentinelNode<T>::prepend): Deleted.
(WTF::BasicRawSentinelNode<T>::append): Deleted.

  • wtf/StdLibExtras.h:

(WTF::roundUpToMultipleOfImpl):
(WTF::roundUpToMultipleOfImpl0): Deleted.

  • wtf/UnalignedAccess.h:

(WTF::unalignedLoad):
(WTF::unalignedStore):

Tools:

  • TestWebKitAPI/CMakeLists.txt:
  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WTF/MathExtras.cpp:

(TestWebKitAPI::TEST):

  • TestWebKitAPI/Tests/WTF/Packed.cpp: Added.

(TestWebKitAPI::TEST):

Location:
trunk
Files:
5 added
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r245213 r245214  
    607607    heap/MarkingConstraint.h
    608608    heap/MutatorState.h
     609    heap/PackedCellPtr.h
    609610    heap/RegisterState.h
    610611    heap/RunningScope.h
  • trunk/Source/JavaScriptCore/ChangeLog

    r245213 r245214  
     12019-05-12  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Compress Watchpoint size by using enum type and Packed<> data structure
     4        https://bugs.webkit.org/show_bug.cgi?id=197730
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Watchpoint takes 5~ MB memory in Gmail (total memory starts with 400 - 500 MB), so 1~%. Since it is allocated massively,
     9        reducing each size of Watchpoint reduces memory footprint significantly.
     10
     11        As a first step, this patch uses Packed<> and enum to reduce the size of Watchpoint.
     12
     13        1. Watchpoint should have enum type and should not use vtable. vtable takes one pointer, and it is too costly for such a
     14           memory sensitive objects. We perform downcast and dispatch the method of the derived classes based on this enum. Since
     15           the # of derived Watchpoint classes are limited (Only 8), we can list up them easily. One unfortunate thing is that
     16           we cannot do this for destructor so long as we use "delete" for deleting objects. If we dispatch the destructor of derived
     17           class in the destructor of the base class, we call the destructor of the base class multiple times. delete operator override
     18           does not help since custom delete operator is called after the destructor is called. While we can fix this issue by always
     19           using custom deleter, currently we do not since all the watchpoints do not have members which have non trivial destructor.
     20           Once it is strongly required, we can start using custom deleter, but for now, we do not need to do this.
     21
     22        2. We use Packed<> to compact pointers in Watchpoint. Since Watchpoint is a node of doubly linked list, each one has two
     23           pointers for prev and next. This is also too costly. PackedPtr reduces the size and makes alignment 1.S
     24
     25        3. We use PackedCellPtr<> for JSCells in Watchpoint. This leverages alignment information and makes pointers smaller in
     26           Darwin ARM64. One important thing to note here is that since this pointer is packed, it cannot be found by conservative
     27           GC scan. It is OK for watchpoint since they are allocated in the heap anyway.
     28
     29        We applied this change to Watchpoint and get the following memory reduction. The highlight is that CodeBlockJettisoningWatchpoint in
     30        ARM64 only takes 2 pointers size.
     31
     32                                                                              ORIGINAL    X86_64   ARM64
     33            WatchpointSet:                                                    40          32       28
     34            CodeBlockJettisoningWatchpoint:                                   32          19       15
     35            StructureStubClearingWatchpoint:                                  56          48       40
     36            AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint: 24          13       11
     37            AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint:  24          13       11
     38            FunctionRareData::AllocationProfileClearingWatchpoint:            32          19       15
     39            ObjectToStringAdaptiveStructureWatchpoint:                        56          48       40
     40            LLIntPrototypeLoadAdaptiveStructureWatchpoint:                    64          48       48
     41            DFG::AdaptiveStructureWatchpoint:                                 56          48       40
     42
     43        While we will re-architect the mechanism of Watchpoint, anyway Packed<> mechanism and enum types will be used too.
     44
     45        * CMakeLists.txt:
     46        * JavaScriptCore.xcodeproj/project.pbxproj:
     47        * Sources.txt:
     48        * bytecode/AdaptiveInferredPropertyValueWatchpointBase.h:
     49        * bytecode/CodeBlockJettisoningWatchpoint.h:
     50        * bytecode/CodeOrigin.h:
     51        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp:
     52        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
     53        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):
     54        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h:
     55        * bytecode/StructureStubClearingWatchpoint.cpp:
     56        (JSC::StructureStubClearingWatchpoint::fireInternal):
     57        * bytecode/StructureStubClearingWatchpoint.h:
     58        * bytecode/Watchpoint.cpp:
     59        (JSC::Watchpoint::fire):
     60        * bytecode/Watchpoint.h:
     61        (JSC::Watchpoint::Watchpoint):
     62        * dfg/DFGAdaptiveStructureWatchpoint.cpp:
     63        (JSC::DFG::AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint):
     64        * dfg/DFGAdaptiveStructureWatchpoint.h:
     65        * heap/PackedCellPtr.h: Added.
     66        * runtime/FunctionRareData.h:
     67        * runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp: Added.
     68        (JSC::ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint):
     69        (JSC::ObjectToStringAdaptiveStructureWatchpoint::install):
     70        (JSC::ObjectToStringAdaptiveStructureWatchpoint::fireInternal):
     71        * runtime/ObjectToStringAdaptiveStructureWatchpoint.h: Added.
     72        * runtime/StructureRareData.cpp:
     73        (JSC::StructureRareData::clearObjectToStringValue):
     74        (JSC::ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint): Deleted.
     75        (JSC::ObjectToStringAdaptiveStructureWatchpoint::install): Deleted.
     76        (JSC::ObjectToStringAdaptiveStructureWatchpoint::fireInternal): Deleted.
     77        * runtime/StructureRareData.h:
     78
    1792019-05-12  Yusuke Suzuki  <ysuzuki@apple.com>
    280
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r245213 r245214  
    17801780                E3555B8A1DAE03A500F36921 /* DOMJITCallDOMGetterSnippet.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterSnippet.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17811781                E355D38F22446877008F1AD6 /* GlobalExecutable.h in Headers */ = {isa = PBXBuildFile; fileRef = E355D38D2244686B008F1AD6 /* GlobalExecutable.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1782                E356987222841187008CDCCB /* PackedCellPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = E356987122841183008CDCCB /* PackedCellPtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17821783                E35A0B9D220AD87A00AC4474 /* ExecutableBaseInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E35A0B9C220AD87A00AC4474 /* ExecutableBaseInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17831784                E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA1521DBC3A5600F83516 /* DOMJITHeapRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    17931794                E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17941795                E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1796                E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */; };
    17951797                E3A0531A21342B680022EC14 /* WasmStreamingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531621342B660022EC14 /* WasmStreamingParser.h */; };
    17961798                E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531821342B670022EC14 /* WasmSectionParser.h */; };
     
    47744776                E355D38D2244686B008F1AD6 /* GlobalExecutable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalExecutable.h; sourceTree = "<group>"; };
    47754777                E355D38E2244686C008F1AD6 /* GlobalExecutable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GlobalExecutable.cpp; sourceTree = "<group>"; };
     4778                E356987122841183008CDCCB /* PackedCellPtr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PackedCellPtr.h; sourceTree = "<group>"; };
    47764779                E35A0B9C220AD87A00AC4474 /* ExecutableBaseInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableBaseInlines.h; sourceTree = "<group>"; };
    47774780                E35CA14F1DBC3A5600F83516 /* DOMJITAbstractHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAbstractHeap.cpp; sourceTree = "<group>"; };
     
    48004803                E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
    48014804                E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; };
     4805                E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectToStringAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
     4806                E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectToStringAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
    48024807                E3A0531621342B660022EC14 /* WasmStreamingParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmStreamingParser.h; sourceTree = "<group>"; };
    48034808                E3A0531721342B660022EC14 /* WasmSectionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmSectionParser.cpp; sourceTree = "<group>"; };
     
    60266031                                0FA762021DB9242300B7A2FD /* MutatorState.cpp */,
    60276032                                0FA762031DB9242300B7A2FD /* MutatorState.h */,
     6033                                E356987122841183008CDCCB /* PackedCellPtr.h */,
    60286034                                0F9DAA081FD1C3C80079C5B2 /* ParallelSourceAdapter.h */,
    60296035                                0FBB73B61DEF3AAC002C009E /* PreventCollectionScope.h */,
     
    71757181                                BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */,
    71767182                                BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */,
     7183                                E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */,
     7184                                E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */,
    71777185                                F692A8770255597D01FF60F7 /* Operations.cpp */,
    71787186                                F692A8780255597D01FF60F7 /* Operations.h */,
     
    96619669                                0FD3E40C1B618B6600C80E1E /* ObjectPropertyConditionSet.h in Headers */,
    96629670                                BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
     9671                                E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */,
    96639672                                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
    96649673                                14F79F70216EAFD200046D39 /* Opcode.h in Headers */,
     
    96699678                                BC18C4480E16F5CD00B34460 /* Operations.h in Headers */,
    96709679                                0FE228ED1436AB2700196C48 /* Options.h in Headers */,
     9680                                E356987222841187008CDCCB /* PackedCellPtr.h in Headers */,
    96719681                                0F9DAA0A1FD1C3D30079C5B2 /* ParallelSourceAdapter.h in Headers */,
    96729682                                E34E657520668EAA00FB81AC /* ParseHash.h in Headers */,
  • trunk/Source/JavaScriptCore/Sources.txt

    r244233 r245214  
    900900runtime/ObjectInitializationScope.cpp
    901901runtime/ObjectPrototype.cpp
     902runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp
    902903runtime/Operations.cpp
    903904runtime/Options.cpp
  • trunk/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h

    r243560 r245214  
    4646    virtual ~AdaptiveInferredPropertyValueWatchpointBase() = default;
    4747
     48    class StructureWatchpoint final : public Watchpoint {
     49    public:
     50        StructureWatchpoint()
     51            : Watchpoint(Watchpoint::Type::AdaptiveInferredPropertyValueStructure)
     52        { }
     53
     54        void fireInternal(VM&, const FireDetail&);
     55    };
     56    // Own destructor may not be called. Keep members trivially destructible.
     57    static_assert(sizeof(StructureWatchpoint) == sizeof(Watchpoint), "");
     58
     59    class PropertyWatchpoint final : public Watchpoint {
     60    public:
     61        PropertyWatchpoint()
     62            : Watchpoint(Watchpoint::Type::AdaptiveInferredPropertyValueProperty)
     63        { }
     64
     65        void fireInternal(VM&, const FireDetail&);
     66    };
     67    // Own destructor may not be called. Keep members trivially destructible.
     68    static_assert(sizeof(PropertyWatchpoint) == sizeof(Watchpoint), "");
     69
    4870protected:
    4971    virtual bool isValid() const;
     
    5173
    5274private:
    53     class StructureWatchpoint final : public Watchpoint {
    54     public:
    55         StructureWatchpoint() { }
    56     protected:
    57         void fireInternal(VM&, const FireDetail&) override;
    58     };
    59     class PropertyWatchpoint final : public Watchpoint {
    60     public:
    61         PropertyWatchpoint() { }
    62     protected:
    63         void fireInternal(VM&, const FireDetail&) override;
    64     };
    65 
    6675    void fire(VM&, const FireDetail&);
    6776
  • trunk/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h

    r243560 r245214  
    2626#pragma once
    2727
     28#include "PackedCellPtr.h"
    2829#include "Watchpoint.h"
    2930
     
    3536public:
    3637    CodeBlockJettisoningWatchpoint(CodeBlock* codeBlock)
    37         : m_codeBlock(codeBlock)
     38        : Watchpoint(Watchpoint::Type::CodeBlockJettisoning)
     39        , m_codeBlock(codeBlock)
    3840    {
    3941    }
    4042   
    41 protected:
    42     void fireInternal(VM&, const FireDetail&) override;
     43    void fireInternal(VM&, const FireDetail&);
    4344
    4445private:
    45     CodeBlock* m_codeBlock;
     46    JSC_WATCHPOINT_FIELD(PackedCellPtr<CodeBlock>, m_codeBlock);
    4647};
    4748
  • trunk/Source/JavaScriptCore/bytecode/CodeOrigin.h

    r243363 r245214  
    233233    }
    234234
    235 #if CPU(ARM64) && CPU(ADDRESS64)
    236     static constexpr unsigned s_freeBitsAtTop = 28;
    237     static constexpr uintptr_t s_maskCompositeValueForPointer = 0x0000000ffffffff8;
    238 #elif CPU(ADDRESS64)
    239     static constexpr unsigned s_freeBitsAtTop = 16;
    240     static constexpr uintptr_t s_maskCompositeValueForPointer = 0x0000fffffffffff8;
    241 #endif
    242 #if CPU(ADDRESS64)
     235#if CPU(ADDRESS64)
     236    static constexpr unsigned s_freeBitsAtTop = 64 - WTF_CPU_EFFECTIVE_ADDRESS_WIDTH;
     237    static constexpr uintptr_t s_maskCompositeValueForPointer = ((1ULL << WTF_CPU_EFFECTIVE_ADDRESS_WIDTH) - 1) & ~(8ULL - 1);
    243238    static uintptr_t buildCompositeValue(InlineCallFrame* inlineCallFrame, unsigned bytecodeIndex)
    244239    {
  • trunk/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp

    r245050 r245214  
    3434
    3535LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint(CodeBlock* owner, const ObjectPropertyCondition& key, unsigned bytecodeOffset)
    36     : m_owner(owner)
     36    : Watchpoint(Watchpoint::Type::LLIntPrototypeLoadAdaptiveStructure)
     37    , m_owner(owner)
     38    , m_bytecodeOffset(bytecodeOffset)
    3739    , m_key(key)
    38     , m_bytecodeOffset(bytecodeOffset)
    3940{
    4041    RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
     
    5960    }
    6061
    61     auto& instruction = m_owner->instructions().at(m_bytecodeOffset);
    62     clearLLIntGetByIdCache(instruction->as<OpGetById>().metadata(m_owner));
     62    auto& instruction = m_owner->instructions().at(m_bytecodeOffset.get());
     63    clearLLIntGetByIdCache(instruction->as<OpGetById>().metadata(m_owner.get()));
    6364}
    6465
  • trunk/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h

    r245050 r245214  
    2828#include "BytecodeStructs.h"
    2929#include "ObjectPropertyCondition.h"
     30#include "PackedCellPtr.h"
    3031#include "Watchpoint.h"
    3132
     
    4243    const ObjectPropertyCondition& key() const { return m_key; }
    4344
    44 protected:
    45     void fireInternal(VM&, const FireDetail&) override;
     45    void fireInternal(VM&, const FireDetail&);
    4646
    4747private:
    48     CodeBlock* m_owner;
    49     ObjectPropertyCondition m_key;
    50     unsigned m_bytecodeOffset;
     48    // Own destructor may not be called. Keep members trivially destructible.
     49    JSC_WATCHPOINT_FIELD(PackedCellPtr<CodeBlock>, m_owner);
     50    JSC_WATCHPOINT_FIELD(Packed<unsigned>, m_bytecodeOffset);
     51    JSC_WATCHPOINT_FIELD(ObjectPropertyCondition, m_key);
    5152};
    5253
  • trunk/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp

    r243560 r245214  
    3737void StructureStubClearingWatchpoint::fireInternal(VM& vm, const FireDetail&)
    3838{
    39     if (!m_holder.isValid())
     39    if (!m_holder->isValid())
    4040        return;
    4141
     
    4444        // That works, because deleting a watchpoint removes it from the set's list, and
    4545        // the set's list traversal for firing is robust against the set changing.
    46         ConcurrentJSLocker locker(m_holder.codeBlock()->m_lock);
    47         m_holder.stubInfo()->reset(m_holder.codeBlock());
     46        ConcurrentJSLocker locker(m_holder->codeBlock()->m_lock);
     47        m_holder->stubInfo()->reset(m_holder->codeBlock());
    4848        return;
    4949    }
  • trunk/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h

    r243560 r245214  
    4545    WTF_MAKE_FAST_ALLOCATED;
    4646public:
    47     StructureStubClearingWatchpoint(
    48         const ObjectPropertyCondition& key,
    49         WatchpointsOnStructureStubInfo& holder)
    50         : m_key(key)
    51         , m_holder(holder)
     47    StructureStubClearingWatchpoint(const ObjectPropertyCondition& key, WatchpointsOnStructureStubInfo& holder)
     48        : Watchpoint(Watchpoint::Type::StructureStubClearing)
     49        , m_holder(&holder)
     50        , m_key(key)
    5251    {
    5352    }
    5453
    55 protected:
    56     void fireInternal(VM&, const FireDetail&) override;
     54    void fireInternal(VM&, const FireDetail&);
    5755
    5856private:
    59     ObjectPropertyCondition m_key;
    60     WatchpointsOnStructureStubInfo& m_holder;
     57    // Own destructor may not be called. Keep members trivially destructible.
     58    JSC_WATCHPOINT_FIELD(PackedPtr<WatchpointsOnStructureStubInfo>, m_holder);
     59    JSC_WATCHPOINT_FIELD(ObjectPropertyCondition, m_key);
    6160};
    6261
  • trunk/Source/JavaScriptCore/bytecode/Watchpoint.cpp

    r234086 r245214  
    2727#include "Watchpoint.h"
    2828
     29#include "AdaptiveInferredPropertyValueWatchpointBase.h"
     30#include "CodeBlockJettisoningWatchpoint.h"
     31#include "DFGAdaptiveStructureWatchpoint.h"
     32#include "FunctionRareData.h"
    2933#include "HeapInlines.h"
     34#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
     35#include "ObjectToStringAdaptiveStructureWatchpoint.h"
     36#include "StructureStubClearingWatchpoint.h"
    3037#include "VM.h"
    3138#include <wtf/CompilationThread.h>
     
    5360{
    5461    RELEASE_ASSERT(!isOnList());
    55     fireInternal(vm, detail);
     62    switch (m_type) {
     63#define JSC_DEFINE_WATCHPOINT_DISPATCH(type, cast) \
     64    case Type::type: \
     65        static_cast<cast*>(this)->fireInternal(vm, detail); \
     66        break;
     67    JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_DISPATCH)
     68#undef JSC_DEFINE_WATCHPOINT_DISPATCH
     69    }
    5670}
    5771
  • trunk/Source/JavaScriptCore/bytecode/Watchpoint.h

    r245050 r245214  
    9191class WatchpointSet;
    9292
    93 class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
     93// Really unfortunately, we do not have the way to dispatch appropriate destructor in base class' destructor
     94// based on enum type. If we call destructor explicitly in the base class, it ends up calling the base destructor
     95// twice. C++20 allows this by using std::std::destroying_delete_t. But we are not using C++20 right now.
     96//
     97// Because we cannot dispatch destructors of derived classes in the destructor of the base class, what it means is,
     98// 1. Calling Watchpoint::~Watchpoint directly is illegal.
     99// 2. `delete watchpoint` where watchpoint is non-final derived class is illegal. If watchpoint is final derived class, it works.
     100// 3. If we really want to do (2), we need to call `watchpoint->destroy()` instead, and dispatch an appropriate destructor in Watchpoint::destroy.
     101//
     102// Luckily, none of our derived watchpoint classes have members which require destructors. So we do not dispatch
     103// the destructor call to the drived class in the base class. If it becomes really required, we can introduce
     104// a custom deleter for some classes which directly call "delete" to the allocated non-final Watchpoint class
     105// (e.g. std::unique_ptr<Watchpoint>, RefPtr<Watchpoint>), and call Watchpoint::destroy instead of "delete"
     106// operator. But since we do not require it for now, we are doing the simplest thing.
     107#define JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro) \
     108    macro(AdaptiveInferredPropertyValueStructure, AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint) \
     109    macro(AdaptiveInferredPropertyValueProperty, AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint) \
     110    macro(CodeBlockJettisoning, CodeBlockJettisoningWatchpoint) \
     111    macro(LLIntPrototypeLoadAdaptiveStructure, LLIntPrototypeLoadAdaptiveStructureWatchpoint) \
     112    macro(FunctionRareDataAllocationProfileClearing, FunctionRareData::AllocationProfileClearingWatchpoint) \
     113    macro(ObjectToStringAdaptiveStructure, ObjectToStringAdaptiveStructureWatchpoint)
     114
     115#if ENABLE(JIT)
     116#define JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) \
     117    JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro) \
     118    macro(StructureStubClearing, StructureStubClearingWatchpoint)
     119
     120#if ENABLE(DFG_JIT)
     121#define JSC_WATCHPOINT_TYPES(macro) \
     122    JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) \
     123    macro(AdaptiveStructure, DFG::AdaptiveStructureWatchpoint)
     124#else
     125#define JSC_WATCHPOINT_TYPES(macro) \
     126    JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro)
     127#endif
     128
     129#else
     130#define JSC_WATCHPOINT_TYPES(macro) \
     131    JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro)
     132#endif
     133
     134#define JSC_WATCHPOINT_FIELD(type, member) \
     135    type member; \
     136    static_assert(std::is_trivially_destructible<type>::value, ""); \
     137
     138
     139class Watchpoint : public PackedRawSentinelNode<Watchpoint> {
    94140    WTF_MAKE_NONCOPYABLE(Watchpoint);
    95141    WTF_MAKE_NONMOVABLE(Watchpoint);
    96142    WTF_MAKE_FAST_ALLOCATED;
    97143public:
    98     Watchpoint() = default;
    99    
    100     virtual ~Watchpoint();
     144#define JSC_DEFINE_WATCHPOINT_TYPES(type, _) type,
     145    enum class Type : uint8_t {
     146        JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_TYPES)
     147    };
     148#undef JSC_DEFINE_WATCHPOINT_TYPES
     149
     150    Watchpoint(Type type)
     151        : m_type(type)
     152    { }
    101153
    102154protected:
    103     virtual void fireInternal(VM&, const FireDetail&) = 0;
     155    ~Watchpoint();
    104156
    105157private:
    106158    friend class WatchpointSet;
    107159    void fire(VM&, const FireDetail&);
     160
     161    Type m_type;
    108162};
    109163
     
    240294    int8_t m_setIsNotEmpty;
    241295
    242     SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint>> m_set;
     296    SentinelLinkedList<Watchpoint, PackedRawSentinelNode<Watchpoint>> m_set;
    243297};
    244298
  • trunk/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp

    r243560 r245214  
    3434namespace JSC { namespace DFG {
    3535
    36 AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint(
    37     const ObjectPropertyCondition& key,
    38     CodeBlock* codeBlock)
    39     : m_key(key)
     36AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, CodeBlock* codeBlock)
     37    : Watchpoint(Watchpoint::Type::AdaptiveStructure)
    4038    , m_codeBlock(codeBlock)
     39    , m_key(key)
    4140{
    4241    RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
  • trunk/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h

    r243560 r245214  
    2929
    3030#include "ObjectPropertyCondition.h"
     31#include "PackedCellPtr.h"
    3132#include "Watchpoint.h"
    3233
     
    4142    void install(VM&);
    4243
    43 protected:
    44     void fireInternal(VM&, const FireDetail&) override;
     44    void fireInternal(VM&, const FireDetail&);
    4545
    4646private:
    47     ObjectPropertyCondition m_key;
    48     CodeBlock* m_codeBlock;
     47    // Own destructor may not be called. Keep members trivially destructible.
     48    JSC_WATCHPOINT_FIELD(PackedCellPtr<CodeBlock>, m_codeBlock);
     49    JSC_WATCHPOINT_FIELD(ObjectPropertyCondition, m_key);
    4950};
    5051
  • trunk/Source/JavaScriptCore/runtime/FunctionRareData.h

    r243560 r245214  
    2929#include "JSCast.h"
    3030#include "ObjectAllocationProfile.h"
     31#include "PackedCellPtr.h"
    3132#include "Watchpoint.h"
    3233
     
    111112    }
    112113
     114    class AllocationProfileClearingWatchpoint final : public Watchpoint {
     115    public:
     116        AllocationProfileClearingWatchpoint(FunctionRareData* rareData)
     117            : Watchpoint(Watchpoint::Type::FunctionRareDataAllocationProfileClearing)
     118            , m_rareData(rareData)
     119        { }
     120
     121        void fireInternal(VM&, const FireDetail&);
     122
     123    private:
     124        // Own destructor may not be called. Keep members trivially destructible.
     125        JSC_WATCHPOINT_FIELD(PackedCellPtr<FunctionRareData>, m_rareData);
     126    };
     127
    113128protected:
    114129    FunctionRareData(VM&);
     
    116131
    117132private:
    118 
    119     class AllocationProfileClearingWatchpoint final : public Watchpoint {
    120     public:
    121         AllocationProfileClearingWatchpoint(FunctionRareData* rareData)
    122             : m_rareData(rareData)
    123         { }
    124     protected:
    125         void fireInternal(VM&, const FireDetail&) override;
    126     private:
    127         FunctionRareData* m_rareData;
    128     };
    129 
    130133    friend class LLIntOffsetsExtractor;
    131134
  • trunk/Source/JavaScriptCore/runtime/StructureRareData.cpp

    r243560 r245214  
    3333#include "JSCInlines.h"
    3434#include "ObjectPropertyConditionSet.h"
     35#include "ObjectToStringAdaptiveStructureWatchpoint.h"
    3536
    3637namespace JSC {
     
    8889    void handleFire(VM&, const FireDetail&) override;
    8990
    90     StructureRareData* m_structureRareData;
    91 };
    92 
    93 class ObjectToStringAdaptiveStructureWatchpoint final : public Watchpoint {
    94 public:
    95     ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
    96 
    97     void install(VM&);
    98 
    99     const ObjectPropertyCondition& key() const { return m_key; }
    100 
    101 protected:
    102     void fireInternal(VM&, const FireDetail&) override;
    103    
    104 private:
    105     ObjectPropertyCondition m_key;
    10691    StructureRareData* m_structureRareData;
    10792};
     
    165150}
    166151
    167 inline void StructureRareData::clearObjectToStringValue()
     152void StructureRareData::clearObjectToStringValue()
    168153{
    169154    m_objectToStringAdaptiveWatchpointSet.clear();
     
    190175// ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
    191176
    192 ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
    193     : m_key(key)
    194     , m_structureRareData(structureRareData)
    195 {
    196     RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
    197     RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint());
    198 }
    199 
    200 void ObjectToStringAdaptiveStructureWatchpoint::install(VM& vm)
    201 {
    202     RELEASE_ASSERT(m_key.isWatchable());
    203 
    204     m_key.object()->structure(vm)->addTransitionWatchpoint(this);
    205 }
    206 
    207 void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&)
    208 {
    209     if (!m_structureRareData->isLive())
    210         return;
    211 
    212     if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
    213         install(vm);
    214         return;
    215     }
    216 
    217     m_structureRareData->clearObjectToStringValue();
    218 }
    219 
    220177ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
    221178    : Base(key)
  • trunk/Source/JavaScriptCore/runtime/StructureRareData.h

    r243560 r245214  
    3636class JSPropertyNameEnumerator;
    3737class Structure;
     38class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
    3839class ObjectToStringAdaptiveStructureWatchpoint;
    39 class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
    4040
    4141class StructureRareData final : public JSCell {
  • trunk/Source/WTF/ChangeLog

    r245202 r245214  
     12019-05-12  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Compress Watchpoint size by using enum type and Packed<> data structure
     4        https://bugs.webkit.org/show_bug.cgi?id=197730
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch introduces a new data structures, WTF::Packed, WTF::PackedPtr, and WTF::PackedAlignedPtr.
     9
     10        - WTF::Packed
     11
     12            WTF::Packed is data storage. We can read and write trivial (in C++ term [1]) data to this storage. The difference to
     13            the usual storage is that the alignment of this storage is always 1. We access the underlying data by using unalignedLoad/unalignedStore.
     14            This class offers alignment = 1 data structure instead of missing the following characteristics.
     15
     16                1. Load / Store are non atomic even if the data size is within a pointer width. We should not use this for a member which can be accessed
     17                   in a racy way. (e.g. fields accessed optimistically from the concurrent compilers).
     18
     19                2. We cannot take reference / pointer to the underlying storage since they are unaligned.
     20
     21                3. Access to this storage is unaligned access. The code is using memcpy, and the compiler will convert to an appropriate unaligned access
     22                   in certain architectures (x86_64 / ARM64). It could be slow. So use it for non performance sensitive & memory sensitive places.
     23
     24        - WTF::PackedPtr
     25
     26            WTF::PackedPtr is a specialization of WTF::Packed<T*>. And it is basically WTF::PackedAlignedPtr with alignment = 1. We further compact
     27            the pointer by leveraging the platform specific knowledge. In 64bit architectures, the effective width of pointers are less than 64 bit.
     28            In x86_64, it is 48 bits. And Darwin ARM64 is further smaller, 36 bits. This information allows us to compact the pointer to 6 bytes in
     29            x86_64 and 5 bytes in Darwin ARM64.
     30
     31        - WTF::PackedAlignedPtr
     32
     33            WTF::PackedAlignedPtr is the WTF::PackedPtr with alignment information of the T. If we use this alignment information, we could reduce the
     34            size of packed pointer further in some cases. For example, since we guarantee that JSCells are 16 byte aligned, low 4 bits are empty. Leveraging
     35            this information in Darwin ARM64 platform allows us to make packed JSCell pointer 4 bytes (36 - 4 bits). We do not use passed alignment
     36            information if it is not profitable.
     37
     38        We also have PackedPtrTraits. This is new PtrTraits and use it for various data structures such as Bag<>.
     39
     40        [1]: https://en.cppreference.com/w/cpp/types/is_trivial
     41
     42        * WTF.xcodeproj/project.pbxproj:
     43        * wtf/Bag.h:
     44        (WTF::Bag::clear):
     45        (WTF::Bag::iterator::operator++):
     46        * wtf/CMakeLists.txt:
     47        * wtf/DumbPtrTraits.h:
     48        * wtf/DumbValueTraits.h:
     49        * wtf/MathExtras.h:
     50        (WTF::clzConstexpr):
     51        (WTF::clz):
     52        (WTF::ctzConstexpr):
     53        (WTF::ctz):
     54        (WTF::getLSBSetConstexpr):
     55        (WTF::getMSBSetConstexpr):
     56        * wtf/Packed.h: Added.
     57        (WTF::Packed::Packed):
     58        (WTF::Packed::get const):
     59        (WTF::Packed::set):
     60        (WTF::Packed::operator=):
     61        (WTF::Packed::exchange):
     62        (WTF::Packed::swap):
     63        (WTF::alignof):
     64        (WTF::PackedPtrTraits::exchange):
     65        (WTF::PackedPtrTraits::swap):
     66        (WTF::PackedPtrTraits::unwrap):
     67        * wtf/Platform.h:
     68        * wtf/SentinelLinkedList.h:
     69        (WTF::BasicRawSentinelNode::BasicRawSentinelNode):
     70        (WTF::BasicRawSentinelNode::prev):
     71        (WTF::BasicRawSentinelNode::next):
     72        (WTF::PtrTraits>::remove):
     73        (WTF::PtrTraits>::prepend):
     74        (WTF::PtrTraits>::append):
     75        (WTF::RawNode>::SentinelLinkedList):
     76        (WTF::RawNode>::remove):
     77        (WTF::BasicRawSentinelNode<T>::remove): Deleted.
     78        (WTF::BasicRawSentinelNode<T>::prepend): Deleted.
     79        (WTF::BasicRawSentinelNode<T>::append): Deleted.
     80        * wtf/StdLibExtras.h:
     81        (WTF::roundUpToMultipleOfImpl):
     82        (WTF::roundUpToMultipleOfImpl0): Deleted.
     83        * wtf/UnalignedAccess.h:
     84        (WTF::unalignedLoad):
     85        (WTF::unalignedStore):
     86
    1872019-05-10  Saam barati  <sbarati@apple.com>
    288
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r245064 r245214  
    659659                E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRegisters.h; sourceTree = "<group>"; };
    660660                E33D5F871FBED66700BF625E /* RecursableLambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursableLambda.h; sourceTree = "<group>"; };
     661                E34CD0D022810A020020D299 /* Packed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Packed.h; sourceTree = "<group>"; };
    661662                E360C7642127B85B00C90F0E /* UnalignedAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnalignedAccess.h; sourceTree = "<group>"; };
    662663                E360C7652127B85C00C90F0E /* Unexpected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unexpected.h; sourceTree = "<group>"; };
     
    10571058                                A8A472DA151A825B004123FF /* OSRandomSource.cpp */,
    10581059                                A8A472DB151A825B004123FF /* OSRandomSource.h */,
     1060                                E34CD0D022810A020020D299 /* Packed.h */,
    10591061                                A8A472DF151A825B004123FF /* PackedIntVector.h */,
    10601062                                A8A472E0151A825B004123FF /* PageAllocation.h */,
  • trunk/Source/WTF/wtf/Bag.h

    r245202 r245214  
    2929#include <wtf/FastMalloc.h>
    3030#include <wtf/Noncopyable.h>
     31#include <wtf/Packed.h>
    3132
    3233namespace WTF {
     
    3435namespace Private {
    3536
    36 template<typename T>
     37template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>>
    3738class BagNode {
    3839    WTF_MAKE_FAST_ALLOCATED;
    3940public:
     41    using PtrTraits = typename PassedPtrTraits::template RebindTraits<BagNode>;
     42
    4043    template<typename... Args>
    4144    BagNode(Args&&... args)
     
    4447   
    4548    T m_item;
    46     BagNode* m_next { nullptr };
     49    typename PtrTraits::StorageType m_next { nullptr };
    4750};
    4851
    4952} // namespace Private
    5053
    51 template<typename T, typename PtrTraits = DumbPtrTraits<Private::BagNode<T>>>
     54template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>>
    5255class Bag {
    5356    WTF_MAKE_NONCOPYABLE(Bag);
    5457    WTF_MAKE_FAST_ALLOCATED;
    55     using Node = Private::BagNode<T>;
     58    using Node = Private::BagNode<T, PassedPtrTraits>;
     59    using PtrTraits = typename PassedPtrTraits::template RebindTraits<Node>;
    5660
    5761public:
     
    7680        while (head) {
    7781            Node* current = head;
    78             head = current->m_next;
     82            head = Node::PtrTraits::unwrap(current->m_next);
    7983            delete current;
    8084        }
     
    105109        iterator& operator++()
    106110        {
    107             m_node = m_node->m_next;
     111            m_node = Node::PtrTraits::unwrap(m_node->m_next);
    108112            return *this;
    109113        }
     
    149153};
    150154
     155template<typename T>
     156using PackedBag = Bag<T, PackedPtrTraits<T>>;
     157
    151158} // namespace WTF
    152159
    153160using WTF::Bag;
     161using WTF::PackedBag;
  • trunk/Source/WTF/wtf/CMakeLists.txt

    r245064 r245214  
    151151    Optional.h
    152152    OrderMaker.h
     153    Packed.h
    153154    PackedIntVector.h
    154155    PageAllocation.h
  • trunk/Source/WTF/wtf/DumbPtrTraits.h

    r227527 r245214  
    3333template<typename T>
    3434struct DumbPtrTraits {
     35    template<typename U> using RebindTraits = DumbPtrTraits<U>;
     36
    3537    using StorageType = T*;
    3638
  • trunk/Source/WTF/wtf/DumbValueTraits.h

    r227527 r245214  
    3333template<typename T>
    3434struct DumbValueTraits {
     35    template<typename U> using RebindTraits = DumbValueTraits<U>;
     36
    3537    using StorageType = T;
    3638
  • trunk/Source/WTF/wtf/MathExtras.h

    r243544 r245214  
    616616}
    617617
     618template <typename T>
     619constexpr unsigned clzConstexpr(T value)
     620{
     621    constexpr unsigned bitSize = sizeof(T) * CHAR_BIT;
     622
     623    using UT = typename std::make_unsigned<T>::type;
     624    UT uValue = value;
     625
     626    unsigned zeroCount = 0;
     627    for (int i = bitSize - 1; i >= 0; i--) {
     628        if (uValue >> i)
     629            break;
     630        zeroCount++;
     631    }
     632    return zeroCount;
     633}
     634
    618635template<typename T>
    619636inline unsigned clz(T value)
     
    638655    return bitSize;
    639656#else
     657    UNUSED_PARAM(bitSize);
     658    UNUSED_PARAM(uValue);
     659    return clzConstexpr(value);
     660#endif
     661}
     662
     663template <typename T>
     664constexpr unsigned ctzConstexpr(T value)
     665{
     666    constexpr unsigned bitSize = sizeof(T) * CHAR_BIT;
     667
     668    using UT = typename std::make_unsigned<T>::type;
     669    UT uValue = value;
     670
    640671    unsigned zeroCount = 0;
    641     for (int i = bitSize - 1; i >= 0; i--) {
    642         if (uValue >> i)
     672    for (unsigned i = 0; i < bitSize; i++) {
     673        if (uValue & 1)
    643674            break;
     675
    644676        zeroCount++;
     677        uValue >>= 1;
    645678    }
    646679    return zeroCount;
    647 #endif
    648680}
    649681
     
    666698    return bitSize;
    667699#else
    668     unsigned zeroCount = 0;
    669     for (unsigned i = 0; i < bitSize; i++) {
    670         if (uValue & 1)
    671             break;
    672 
    673         zeroCount++;
    674         uValue >>= 1;
    675     }
    676     return zeroCount;
     700    UNUSED_PARAM(bitSize);
     701    UNUSED_PARAM(uValue);
     702    return ctzConstexpr(value);
    677703#endif
    678704}
     
    683709    ASSERT(t);
    684710    return ctz(t);
     711}
     712
     713template<typename T>
     714constexpr unsigned getLSBSetConstexpr(T t)
     715{
     716    ASSERT_UNDER_CONSTEXPR_CONTEXT(t);
     717    return ctzConstexpr(t);
    685718}
    686719
     
    691724    ASSERT(t);
    692725    return bitSize - 1 - clz(t);
     726}
     727
     728template<typename T>
     729constexpr unsigned getMSBSetConstexpr(T t)
     730{
     731    constexpr unsigned bitSize = sizeof(T) * CHAR_BIT;
     732    ASSERT_UNDER_CONSTEXPR_CONTEXT(t);
     733    return bitSize - 1 - clzConstexpr(t);
    693734}
    694735
  • trunk/Source/WTF/wtf/Platform.h

    r245075 r245214  
    748748#endif
    749749
     750#if CPU(ADDRESS64)
     751#if OS(DARWIN) && CPU(ARM64)
     752#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 36
     753#else
     754/* We strongly assume that effective address width is <= 48 in 64bit architectures (e.g. NaN boxing). */
     755#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 48
     756#endif
     757#else
     758#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 32
     759#endif
     760
    750761#if !defined(USE_JSVALUE64) && !defined(USE_JSVALUE32_64)
    751762#if CPU(ADDRESS64) || CPU(ARM64)
  • trunk/Source/WTF/wtf/SentinelLinkedList.h

    r237099 r245214  
    3737#pragma once
    3838
     39#include <wtf/Packed.h>
     40
    3941namespace WTF {
    4042
    4143enum SentinelTag { Sentinel };
    4244
    43 template<typename T>
     45template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>>
    4446class BasicRawSentinelNode {
    4547    WTF_MAKE_FAST_ALLOCATED;
    4648public:
     49    using PtrTraits = typename PassedPtrTraits::template RebindTraits<BasicRawSentinelNode>;
     50
    4751    BasicRawSentinelNode(SentinelTag)
    48         : m_next(0)
    49         , m_prev(0)
    5052    {
    5153    }
    5254   
    53     BasicRawSentinelNode()
    54         : m_next(0)
    55         , m_prev(0)
    56     {
    57     }
     55    BasicRawSentinelNode() = default;
    5856   
    5957    void setPrev(BasicRawSentinelNode* prev) { m_prev = prev; }
    6058    void setNext(BasicRawSentinelNode* next) { m_next = next; }
    6159   
    62     T* prev() { return static_cast<T*>(m_prev); }
    63     T* next() { return static_cast<T*>(m_next); }
     60    T* prev() { return static_cast<T*>(PtrTraits::unwrap(m_prev)); }
     61    T* next() { return static_cast<T*>(PtrTraits::unwrap(m_next)); }
    6462   
    6563    bool isOnList() const
     
    7573   
    7674private:
    77     BasicRawSentinelNode* m_next;
    78     BasicRawSentinelNode* m_prev;
     75    typename PtrTraits::StorageType m_next { nullptr };
     76    typename PtrTraits::StorageType m_prev { nullptr };
    7977};
    8078
     
    119117};
    120118
    121 template <typename T> void BasicRawSentinelNode<T>::remove()
    122 {
    123     SentinelLinkedList<T, BasicRawSentinelNode<T>>::remove(static_cast<T*>(this));
    124 }
    125 
    126 template <typename T> void BasicRawSentinelNode<T>::prepend(BasicRawSentinelNode* node)
    127 {
    128     SentinelLinkedList<T, BasicRawSentinelNode<T>>::prepend(
     119template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::remove()
     120{
     121    SentinelLinkedList<T, BasicRawSentinelNode>::remove(static_cast<T*>(this));
     122}
     123
     124template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::prepend(BasicRawSentinelNode* node)
     125{
     126    SentinelLinkedList<T, BasicRawSentinelNode>::prepend(
    129127        static_cast<T*>(this), static_cast<T*>(node));
    130128}
    131129
    132 template <typename T> void BasicRawSentinelNode<T>::append(BasicRawSentinelNode* node)
    133 {
    134     SentinelLinkedList<T, BasicRawSentinelNode<T>>::append(
     130template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::append(BasicRawSentinelNode* node)
     131{
     132    SentinelLinkedList<T, BasicRawSentinelNode>::append(
    135133        static_cast<T*>(this), static_cast<T*>(node));
    136134}
     
    141139{
    142140    m_headSentinel.setNext(&m_tailSentinel);
    143     m_headSentinel.setPrev(0);
     141    m_headSentinel.setPrev(nullptr);
    144142
    145143    m_tailSentinel.setPrev(&m_headSentinel);
    146     m_tailSentinel.setNext(0);
     144    m_tailSentinel.setNext(nullptr);
    147145}
    148146
     
    201199    next->setPrev(prev);
    202200   
    203     node->setPrev(0);
    204     node->setNext(0);
     201    node->setPrev(nullptr);
     202    node->setNext(nullptr);
    205203}
    206204
     
    272270}
    273271
     272template<typename T>
     273using PackedRawSentinelNode = BasicRawSentinelNode<T, PackedPtrTraits<T>>;
     274
    274275}
    275276
    276277using WTF::BasicRawSentinelNode;
     278using WTF::PackedRawSentinelNode;
    277279using WTF::SentinelLinkedList;
  • trunk/Source/WTF/wtf/StdLibExtras.h

    r244656 r245214  
    173173#define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array))
    174174
    175 ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl0(size_t remainderMask, size_t x)
    176 {
     175ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl(size_t divisor, size_t x)
     176{
     177    size_t remainderMask = divisor - 1;
    177178    return (x + remainderMask) & ~remainderMask;
    178 }
    179 
    180 ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl(size_t divisor, size_t x)
    181 {
    182     return roundUpToMultipleOfImpl0(divisor - 1, x);
    183179}
    184180
  • trunk/Source/WTF/wtf/UnalignedAccess.h

    r235018 r245214  
    3232namespace WTF {
    3333
    34 template<typename IntegralType>
    35 inline IntegralType unalignedLoad(const void* pointer)
     34template<typename Type>
     35inline Type unalignedLoad(const void* pointer)
    3636{
    37     static_assert(std::is_integral<IntegralType>::value || std::is_pointer<IntegralType>::value, "");
    38     IntegralType result { };
    39     memcpy(&result, pointer, sizeof(IntegralType));
     37    static_assert(std::is_trivial<Type>::value, "");
     38    Type result { };
     39    memcpy(&result, pointer, sizeof(Type));
    4040    return result;
    4141}
    4242
    43 template<typename IntegralType>
    44 inline void unalignedStore(void* pointer, IntegralType value)
     43template<typename Type>
     44inline void unalignedStore(void* pointer, Type value)
    4545{
    46     static_assert(std::is_integral<IntegralType>::value || std::is_pointer<IntegralType>::value, "");
    47     memcpy(pointer, &value, sizeof(IntegralType));
     46    static_assert(std::is_trivial<Type>::value, "");
     47    memcpy(pointer, &value, sizeof(Type));
    4848}
    4949
  • trunk/Tools/ChangeLog

    r245204 r245214  
     12019-05-12  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Compress Watchpoint size by using enum type and Packed<> data structure
     4        https://bugs.webkit.org/show_bug.cgi?id=197730
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * TestWebKitAPI/CMakeLists.txt:
     9        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     10        * TestWebKitAPI/Tests/WTF/MathExtras.cpp:
     11        (TestWebKitAPI::TEST):
     12        * TestWebKitAPI/Tests/WTF/Packed.cpp: Added.
     13        (TestWebKitAPI::TEST):
     14
    1152019-05-10  Chris Dumez  <cdumez@apple.com>
    216
  • trunk/Tools/TestWebKitAPI/CMakeLists.txt

    r244857 r245214  
    6161    Tests/WTF/OptionSet.cpp
    6262    Tests/WTF/Optional.cpp
     63    Tests/WTF/Packed.cpp
    6364    Tests/WTF/ParkingLot.cpp
    6465    Tests/WTF/PriorityQueue.cpp
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r245039 r245214  
    861861                E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */; };
    862862                E324A6F02041C82000A76593 /* UniqueArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E398BC0F2041C76300387136 /* UniqueArray.cpp */; };
     863                E32B549222810AC4008AD702 /* Packed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E32B549122810AC0008AD702 /* Packed.cpp */; };
    863864                E373D7911F2CF35200C6FAAF /* Signals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3953F951F2CF32100A76A2E /* Signals.cpp */; };
    864865                E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38A0D341FD50CBC00E98C8B /* Threading.cpp */; };
     
    22322233                E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = StopLoadingFromDidReceiveResponse.html; sourceTree = "<group>"; };
    22332234                E19DB9781B32137C00DB38D4 /* NavigatorLanguage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NavigatorLanguage.mm; sourceTree = "<group>"; };
     2235                E32B549122810AC0008AD702 /* Packed.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Packed.cpp; sourceTree = "<group>"; };
    22342236                E388887020C9098100E632BC /* WorkerPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerPool.cpp; sourceTree = "<group>"; };
    22352237                E38A0D341FD50CBC00E98C8B /* Threading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Threading.cpp; sourceTree = "<group>"; };
     
    33503352                                1AFDE6541953B2C000C48FFA /* Optional.cpp */,
    33513353                                CE50D8C81C8665CE0072EA5A /* OptionSet.cpp */,
     3354                                E32B549122810AC0008AD702 /* Packed.cpp */,
    33523355                                0FE447971B76F1E3009498EB /* ParkingLot.cpp */,
    33533356                                53EC253F1E96BC80000831B9 /* PriorityQueue.cpp */,
     
    39633966                                1A77BAA31D9AFFFC005FC568 /* OptionSet.cpp in Sources */,
    39643967                                7C83DF021D0A590C00FEBCF3 /* OSObjectPtr.cpp in Sources */,
     3968                                E32B549222810AC4008AD702 /* Packed.cpp in Sources */,
    39653969                                7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */,
    39663970                                53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp

    r243418 r245214  
    508508}
    509509
     510TEST(WTF, clzConstexpr)
     511{
     512    EXPECT_EQ(WTF::clzConstexpr<int32_t>(1), 31U);
     513    EXPECT_EQ(WTF::clzConstexpr<int32_t>(42), 26U);
     514    EXPECT_EQ(WTF::clzConstexpr<uint32_t>(static_cast<uint32_t>(-1)), 0U);
     515    EXPECT_EQ(WTF::clzConstexpr<uint32_t>(static_cast<uint32_t>(std::numeric_limits<int32_t>::min()) >> 1), 1U);
     516    EXPECT_EQ(WTF::clzConstexpr<uint32_t>(0), 32U);
     517
     518    EXPECT_EQ(WTF::clzConstexpr<int8_t>(42), 2U);
     519    EXPECT_EQ(WTF::clzConstexpr<int8_t>(3), 6U);
     520    EXPECT_EQ(WTF::clzConstexpr<uint8_t>(static_cast<uint8_t>(-1)), 0U);
     521    EXPECT_EQ(WTF::clzConstexpr<uint8_t>(0), 8U);
     522
     523    EXPECT_EQ(WTF::clzConstexpr<int64_t>(-1), 0U);
     524    EXPECT_EQ(WTF::clzConstexpr<int64_t>(1), 63U);
     525    EXPECT_EQ(WTF::clzConstexpr<int64_t>(3), 62U);
     526    EXPECT_EQ(WTF::clzConstexpr<uint64_t>(42), 58U);
     527    EXPECT_EQ(WTF::clzConstexpr<uint64_t>(0), 64U);
     528}
     529
     530TEST(WTF, ctzConstexpr)
     531{
     532    EXPECT_EQ(WTF::ctzConstexpr<int32_t>(1), 0U);
     533    EXPECT_EQ(WTF::ctzConstexpr<int32_t>(42), 1U);
     534    EXPECT_EQ(WTF::ctzConstexpr<uint32_t>(static_cast<uint32_t>(-1)), 0U);
     535    EXPECT_EQ(WTF::ctzConstexpr<uint32_t>(static_cast<uint32_t>(std::numeric_limits<int32_t>::min()) >> 1), 30U);
     536    EXPECT_EQ(WTF::ctzConstexpr<uint32_t>(0), 32U);
     537
     538    EXPECT_EQ(WTF::ctzConstexpr<int8_t>(42), 1U);
     539    EXPECT_EQ(WTF::ctzConstexpr<int8_t>(3), 0U);
     540    EXPECT_EQ(WTF::ctzConstexpr<uint8_t>(static_cast<uint8_t>(-1)), 0U);
     541    EXPECT_EQ(WTF::ctzConstexpr<uint8_t>(0), 8U);
     542
     543    EXPECT_EQ(WTF::ctzConstexpr<int64_t>(static_cast<uint32_t>(-1)), 0U);
     544    EXPECT_EQ(WTF::ctzConstexpr<int64_t>(1), 0U);
     545    EXPECT_EQ(WTF::ctzConstexpr<int64_t>(3), 0U);
     546    EXPECT_EQ(WTF::ctzConstexpr<uint64_t>(42), 1U);
     547    EXPECT_EQ(WTF::ctzConstexpr<uint64_t>(0), 64U);
     548}
     549
     550TEST(WTF, getLSBSetConstexpr)
     551{
     552    EXPECT_EQ(WTF::getLSBSetConstexpr<int32_t>(1), 0U);
     553    EXPECT_EQ(WTF::getLSBSetConstexpr<int32_t>(42), 1U);
     554    EXPECT_EQ(WTF::getLSBSetConstexpr<uint32_t>(static_cast<uint32_t>(-1)), 0U);
     555    EXPECT_EQ(WTF::getLSBSetConstexpr<uint32_t>(static_cast<uint32_t>(std::numeric_limits<int32_t>::min()) >> 1), 30U);
     556
     557    EXPECT_EQ(WTF::getLSBSetConstexpr<int8_t>(42), 1U);
     558    EXPECT_EQ(WTF::getLSBSetConstexpr<int8_t>(3), 0U);
     559    EXPECT_EQ(WTF::getLSBSetConstexpr<uint8_t>(static_cast<uint8_t>(-1)), 0U);
     560
     561    EXPECT_EQ(WTF::getLSBSetConstexpr<int64_t>(-1), 0U);
     562    EXPECT_EQ(WTF::getLSBSetConstexpr<int64_t>(1), 0U);
     563    EXPECT_EQ(WTF::getLSBSetConstexpr<int64_t>(3), 0U);
     564    EXPECT_EQ(WTF::getLSBSetConstexpr<uint64_t>(42), 1U);
     565}
     566
     567TEST(WTF, getMSBSetConstexpr)
     568{
     569    EXPECT_EQ(WTF::getMSBSetConstexpr<int32_t>(1), 0U);
     570    EXPECT_EQ(WTF::getMSBSetConstexpr<int32_t>(42), 5U);
     571    EXPECT_EQ(WTF::getMSBSetConstexpr<uint32_t>(static_cast<uint32_t>(-1)), 31U);
     572    EXPECT_EQ(WTF::getMSBSetConstexpr<uint32_t>(static_cast<uint32_t>(std::numeric_limits<int32_t>::min()) >> 1), 30U);
     573
     574    EXPECT_EQ(WTF::getMSBSetConstexpr<int8_t>(42), 5U);
     575    EXPECT_EQ(WTF::getMSBSetConstexpr<int8_t>(3), 1U);
     576    EXPECT_EQ(WTF::getMSBSetConstexpr<uint8_t>(static_cast<uint8_t>(-1)), 7U);
     577
     578    EXPECT_EQ(WTF::getMSBSetConstexpr<int64_t>(-1), 63U);
     579    EXPECT_EQ(WTF::getMSBSetConstexpr<int64_t>(1), 0U);
     580    EXPECT_EQ(WTF::getMSBSetConstexpr<int64_t>(3), 1U);
     581    EXPECT_EQ(WTF::getMSBSetConstexpr<uint64_t>(42), 5U);
     582}
     583
    510584} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.