WebKit Bugzilla
Attachment 369518 Details for
Bug 197730
: [JSC] Compress Watchpoint size by using enum type and Packed<> data structure
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197730-20190509131721.patch (text/plain), 74.92 KB, created by
Yusuke Suzuki
on 2019-05-09 13:17:22 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2019-05-09 13:17:22 PDT
Size:
74.92 KB
patch
obsolete
>Subversion Revision: 245147 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 211b315794a70cdeaebfd5b0e10c84d0867fb014..ab5f3d6869eeab78d673d9ed66f6d9b9d07f4622 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,80 @@ >+2019-05-09 Yusuke Suzuki <ysuzuki@apple.com> >+ >+ [JSC] Compress Watchpoint size by using enum type and Packed<> data structure >+ https://bugs.webkit.org/show_bug.cgi?id=197730 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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. >+ >+ 2. 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 >+ >+ 3. We use PackedCellPtr<> for JSCells in Watchpoint. This leverages alignment information and makes pointers smaller in >+ Darin ARM64. >+ >+ We applied this change to Watchpoint and get the following memory reduction in x86_64. >+ >+ WatchpointSet: 40 -> 32 >+ CodeBlockJettisoningWatchpoint: 32 -> 19 >+ StructureStubClearingWatchpoint: 56 -> 48 >+ AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint: 24 -> 13 >+ AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint: 24 -> 13 >+ FunctionRareData::AllocationProfileClearingWatchpoint: 32 -> 19 >+ ObjectToStringAdaptiveStructureWatchpoint: 56 -> 48 >+ LLIntPrototypeLoadAdaptiveStructureWatchpoint: 64 -> 48 >+ DFG::AdaptiveStructureWatchpoint: 56 -> 48 >+ >+ This is smaller in ARM64 environment. >+ >+ 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: >+ > 2019-05-09 Keith Miller <keith_miller@apple.com> > > REGRESSION (r245064): ASSERTION FAILED: m_ptr seen with wasm.yaml/wasm/js-api/test_Data.js.wasm-slow-memory >diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog >index bae84b7d709b9062620e3d8317f1211a4ff12e64..cf1d5dfd599d29ef1c63ea031d39f9544beab560 100644 >--- a/Source/WTF/ChangeLog >+++ b/Source/WTF/ChangeLog >@@ -1,3 +1,86 @@ >+2019-05-09 Yusuke Suzuki <ysuzuki@apple.com> >+ >+ [JSC] Compress Watchpoint size by using enum type and Packed<> data structure >+ https://bugs.webkit.org/show_bug.cgi?id=197730 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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). >+ >+ 2. We cannot take reference / pointer to the underlying storage since they are unaligned. >+ >+ 3. 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::getLSBSetConstexpr): >+ * 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::roundDownToMultipleOfImpl): >+ (WTF::roundDownToMultipleOf): >+ (WTF::roundUpToMultipleOfImpl0): Deleted. >+ * wtf/UnalignedAccess.h: >+ (WTF::unalignedLoad): >+ (WTF::unalignedStore): >+ > 2019-05-08 Zan Dobersek <zdobersek@igalia.com> > > [GLib] Rework WPE RunLoopSourcePriority values >diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt >index fb6210c3f7275e70440fe41fdbc898c6be64574d..cf5a5cca342feb786a4c42d913d66e9b6c6e97eb 100644 >--- a/Source/JavaScriptCore/CMakeLists.txt >+++ b/Source/JavaScriptCore/CMakeLists.txt >@@ -606,6 +606,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS > heap/MarkedSpace.h > heap/MarkingConstraint.h > heap/MutatorState.h >+ heap/PackedCellPtr.h > heap/RegisterState.h > heap/RunningScope.h > heap/SimpleMarkingConstraint.h >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index e7dc887b9aaf815bb3b80a7d42e8a07f894fdd03..4f1563f975a9aa76b3d535f1bd78f7e870d0f3c2 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -1778,6 +1778,7 @@ > E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E3555B8A1DAE03A500F36921 /* DOMJITCallDOMGetterSnippet.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterSnippet.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E355D38F22446877008F1AD6 /* GlobalExecutable.h in Headers */ = {isa = PBXBuildFile; fileRef = E355D38D2244686B008F1AD6 /* GlobalExecutable.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ E356987222841187008CDCCB /* PackedCellPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = E356987122841183008CDCCB /* PackedCellPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E35A0B9D220AD87A00AC4474 /* ExecutableBaseInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E35A0B9C220AD87A00AC4474 /* ExecutableBaseInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 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, ); }; }; >@@ -1791,6 +1792,7 @@ > 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, ); }; }; > E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */; }; > E3A0531A21342B680022EC14 /* WasmStreamingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531621342B660022EC14 /* WasmStreamingParser.h */; }; > E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531821342B670022EC14 /* WasmSectionParser.h */; }; > E3A32BC71FC83147007D7E76 /* WeakMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A32BC61FC8312E007D7E76 /* WeakMapImpl.h */; }; >@@ -4771,6 +4773,7 @@ > E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterSnippet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCallDOMGetterSnippet.h; sourceTree = "<group>"; }; > E355D38D2244686B008F1AD6 /* GlobalExecutable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalExecutable.h; sourceTree = "<group>"; }; > E355D38E2244686C008F1AD6 /* GlobalExecutable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GlobalExecutable.cpp; sourceTree = "<group>"; }; >+ E356987122841183008CDCCB /* PackedCellPtr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PackedCellPtr.h; sourceTree = "<group>"; }; > E35A0B9C220AD87A00AC4474 /* ExecutableBaseInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableBaseInlines.h; sourceTree = "<group>"; }; > E35CA14F1DBC3A5600F83516 /* DOMJITAbstractHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAbstractHeap.cpp; sourceTree = "<group>"; }; > E35CA1501DBC3A5600F83516 /* DOMJITAbstractHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeap.h; sourceTree = "<group>"; }; >@@ -4797,6 +4800,8 @@ > E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; }; > E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; }; > E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; }; >+ E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectToStringAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; }; >+ E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectToStringAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; }; > E3A0531621342B660022EC14 /* WasmStreamingParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmStreamingParser.h; sourceTree = "<group>"; }; > E3A0531721342B660022EC14 /* WasmSectionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmSectionParser.cpp; sourceTree = "<group>"; }; > E3A0531821342B670022EC14 /* WasmSectionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmSectionParser.h; sourceTree = "<group>"; }; >@@ -6023,6 +6028,7 @@ > 0F1FB3981E1F65F900A9BE50 /* MutatorScheduler.h */, > 0FA762021DB9242300B7A2FD /* MutatorState.cpp */, > 0FA762031DB9242300B7A2FD /* MutatorState.h */, >+ E356987122841183008CDCCB /* PackedCellPtr.h */, > 0F9DAA081FD1C3C80079C5B2 /* ParallelSourceAdapter.h */, > 0FBB73B61DEF3AAC002C009E /* PreventCollectionScope.h */, > 0FD0E5EF1E46BF230006AB08 /* RegisterState.h */, >@@ -7172,6 +7178,8 @@ > E3C295DC1ED2CBAA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h */, > BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */, > BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */, >+ E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */, >+ E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */, > F692A8770255597D01FF60F7 /* Operations.cpp */, > F692A8780255597D01FF60F7 /* Operations.h */, > 0FE228EA1436AB2300196C48 /* Options.cpp */, >@@ -9657,6 +9665,7 @@ > 0FD3E40A1B618B6600C80E1E /* ObjectPropertyCondition.h in Headers */, > 0FD3E40C1B618B6600C80E1E /* ObjectPropertyConditionSet.h in Headers */, > BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */, >+ E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */, > E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */, > 14F79F70216EAFD200046D39 /* Opcode.h in Headers */, > FE64872E2141D04800AB0D3E /* OpcodeInlines.h in Headers */, >@@ -9665,6 +9674,7 @@ > A70447EA17A0BD4600F5898E /* OperandsInlines.h in Headers */, > BC18C4480E16F5CD00B34460 /* Operations.h in Headers */, > 0FE228ED1436AB2700196C48 /* Options.h in Headers */, >+ E356987222841187008CDCCB /* PackedCellPtr.h in Headers */, > 0F9DAA0A1FD1C3D30079C5B2 /* ParallelSourceAdapter.h in Headers */, > E34E657520668EAA00FB81AC /* ParseHash.h in Headers */, > 37C738D21EDB56E4003F2B0B /* ParseInt.h in Headers */, >diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt >index f5534441390d1a608aae0dc28ffbef31868329b4..2196c97bbb129e2abdbc30c8f5ccb414d6528fb8 100644 >--- a/Source/JavaScriptCore/Sources.txt >+++ b/Source/JavaScriptCore/Sources.txt >@@ -899,6 +899,7 @@ runtime/NumberPrototype.cpp > runtime/ObjectConstructor.cpp > runtime/ObjectInitializationScope.cpp > runtime/ObjectPrototype.cpp >+runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp > runtime/Operations.cpp > runtime/Options.cpp > runtime/ProgramExecutable.cpp >diff --git a/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h b/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h >index 5d4e02aaefe966003f65218400887e42f1435e89..b14f66dde24d6e9f7d1ce6ce3649ecbcd2599a18 100644 >--- a/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h >+++ b/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h >@@ -45,24 +45,32 @@ class AdaptiveInferredPropertyValueWatchpointBase { > > virtual ~AdaptiveInferredPropertyValueWatchpointBase() = default; > >-protected: >- virtual bool isValid() const; >- virtual void handleFire(VM&, const FireDetail&) = 0; >- >-private: > class StructureWatchpoint final : public Watchpoint { > public: >- StructureWatchpoint() { } >- protected: >- void fireInternal(VM&, const FireDetail&) override; >+ StructureWatchpoint() >+ : Watchpoint(Watchpoint::Type::AdaptiveInferredPropertyValueStructure) >+ { } >+ >+ void fireInternal(VM&, const FireDetail&); >+ >+ // Own destructor may not be called. Keep members trivially destructible. > }; > class PropertyWatchpoint final : public Watchpoint { > public: >- PropertyWatchpoint() { } >- protected: >- void fireInternal(VM&, const FireDetail&) override; >+ PropertyWatchpoint() >+ : Watchpoint(Watchpoint::Type::AdaptiveInferredPropertyValueProperty) >+ { } >+ >+ void fireInternal(VM&, const FireDetail&); >+ >+ // Own destructor may not be called. Keep members trivially destructible. > }; > >+protected: >+ virtual bool isValid() const; >+ virtual void handleFire(VM&, const FireDetail&) = 0; >+ >+private: > void fire(VM&, const FireDetail&); > > ObjectPropertyCondition m_key; >diff --git a/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h b/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h >index af24ea3a6fb302b79260aafcf7efe6faf69ceba5..a41d1dda75ff5e4d300db70e07037ff6c7300287 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h >+++ b/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h >@@ -25,6 +25,7 @@ > > #pragma once > >+#include "PackedCellPtr.h" > #include "Watchpoint.h" > > namespace JSC { >@@ -34,15 +35,16 @@ class CodeBlock; > class CodeBlockJettisoningWatchpoint final : public Watchpoint { > public: > CodeBlockJettisoningWatchpoint(CodeBlock* codeBlock) >- : m_codeBlock(codeBlock) >+ : Watchpoint(Watchpoint::Type::CodeBlockJettisoning) >+ , m_codeBlock(codeBlock) > { > } > >-protected: >- void fireInternal(VM&, const FireDetail&) override; >+ void fireInternal(VM&, const FireDetail&); > > private: >- CodeBlock* m_codeBlock; >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedCellPtr<CodeBlock> m_codeBlock; > }; > > } // namespace JSC >diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.h b/Source/JavaScriptCore/bytecode/CodeOrigin.h >index 551fbec0f7a4f30926c4e6fdf465ddd81cd0e584..b6954e7018bf90a3ec110213e2056cf5bdb34054 100644 >--- a/Source/JavaScriptCore/bytecode/CodeOrigin.h >+++ b/Source/JavaScriptCore/bytecode/CodeOrigin.h >@@ -232,14 +232,9 @@ class CodeOrigin { > return bitwise_cast<InlineCallFrame*>(value); > } > >-#if CPU(ARM64) && CPU(ADDRESS64) >- static constexpr unsigned s_freeBitsAtTop = 28; >- static constexpr uintptr_t s_maskCompositeValueForPointer = 0x0000000ffffffff8; >-#elif CPU(ADDRESS64) >- static constexpr unsigned s_freeBitsAtTop = 16; >- static constexpr uintptr_t s_maskCompositeValueForPointer = 0x0000fffffffffff8; >-#endif > #if CPU(ADDRESS64) >+ static constexpr unsigned s_freeBitsAtTop = 64 - WTF_CPU_EFFECTIVE_ADDRESS_WIDTH; >+ static constexpr uintptr_t s_maskCompositeValueForPointer = ((1ULL << WTF_CPU_EFFECTIVE_ADDRESS_WIDTH) - 1) & ~(8ULL - 1); > static uintptr_t buildCompositeValue(InlineCallFrame* inlineCallFrame, unsigned bytecodeIndex) > { > if (bytecodeIndex == s_invalidBytecodeIndex) >diff --git a/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp b/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp >index 086b513b26e7d9ac7a9879505279b62fbf2bd4a9..0ef6a55c9c719603f1a2e38b580566f0a2467be1 100644 >--- a/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp >+++ b/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp >@@ -33,9 +33,10 @@ > namespace JSC { > > LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint(CodeBlock* owner, const ObjectPropertyCondition& key, unsigned bytecodeOffset) >- : m_owner(owner) >- , m_key(key) >+ : Watchpoint(Watchpoint::Type::LLIntPrototypeLoadAdaptiveStructure) >+ , m_owner(owner) > , m_bytecodeOffset(bytecodeOffset) >+ , m_key(key) > { > RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint()); > RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint()); >@@ -58,8 +59,8 @@ void LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal(VM& vm, const F > return; > } > >- auto& instruction = m_owner->instructions().at(m_bytecodeOffset); >- clearLLIntGetByIdCache(instruction->as<OpGetById>().metadata(m_owner)); >+ auto& instruction = m_owner->instructions().at(m_bytecodeOffset.get()); >+ clearLLIntGetByIdCache(instruction->as<OpGetById>().metadata(m_owner.get())); > } > > void LLIntPrototypeLoadAdaptiveStructureWatchpoint::clearLLIntGetByIdCache(OpGetById::Metadata& metadata) >diff --git a/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h b/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h >index a9b1fcd2587ae86270923e44e613b6775d5a8ff2..fb2c3fc5bc59bcd07ef4d67a941b9099f4f24136 100644 >--- a/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h >+++ b/Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h >@@ -27,6 +27,7 @@ > > #include "BytecodeStructs.h" > #include "ObjectPropertyCondition.h" >+#include "PackedCellPtr.h" > #include "Watchpoint.h" > > namespace JSC { >@@ -41,13 +42,13 @@ class LLIntPrototypeLoadAdaptiveStructureWatchpoint final : public Watchpoint { > > const ObjectPropertyCondition& key() const { return m_key; } > >-protected: >- void fireInternal(VM&, const FireDetail&) override; >+ void fireInternal(VM&, const FireDetail&); > > private: >- CodeBlock* m_owner; >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedCellPtr<CodeBlock> m_owner; >+ Packed<unsigned> m_bytecodeOffset; > ObjectPropertyCondition m_key; >- unsigned m_bytecodeOffset; > }; > > } // namespace JSC >diff --git a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp >index 9416d308ada2f0e03e2916da3fd63955ba72a641..30a1f055259e3ded1a7168ee3526f72c084bee5a 100644 >--- a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp >+++ b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp >@@ -36,15 +36,15 @@ namespace JSC { > > void StructureStubClearingWatchpoint::fireInternal(VM& vm, const FireDetail&) > { >- if (!m_holder.isValid()) >+ if (!m_holder->isValid()) > return; > > if (!m_key || !m_key.isWatchable(PropertyCondition::EnsureWatchability)) { > // This will implicitly cause my own demise: stub reset removes all watchpoints. > // That works, because deleting a watchpoint removes it from the set's list, and > // the set's list traversal for firing is robust against the set changing. >- ConcurrentJSLocker locker(m_holder.codeBlock()->m_lock); >- m_holder.stubInfo()->reset(m_holder.codeBlock()); >+ ConcurrentJSLocker locker(m_holder->codeBlock()->m_lock); >+ m_holder->stubInfo()->reset(m_holder->codeBlock()); > return; > } > >diff --git a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h >index 70b697f69fbdcd490b270d5983b935b4f3c80382..b743fd006a9806973cda3c6a3484ff1a217c247c 100644 >--- a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h >+++ b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h >@@ -44,20 +44,19 @@ class StructureStubClearingWatchpoint final : public Watchpoint { > WTF_MAKE_NONCOPYABLE(StructureStubClearingWatchpoint); > WTF_MAKE_FAST_ALLOCATED; > public: >- StructureStubClearingWatchpoint( >- const ObjectPropertyCondition& key, >- WatchpointsOnStructureStubInfo& holder) >- : m_key(key) >- , m_holder(holder) >+ StructureStubClearingWatchpoint(const ObjectPropertyCondition& key, WatchpointsOnStructureStubInfo& holder) >+ : Watchpoint(Watchpoint::Type::StructureStubClearing) >+ , m_holder(&holder) >+ , m_key(key) > { > } > >-protected: >- void fireInternal(VM&, const FireDetail&) override; >+ void fireInternal(VM&, const FireDetail&); > > private: >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedPtr<WatchpointsOnStructureStubInfo> m_holder; > ObjectPropertyCondition m_key; >- WatchpointsOnStructureStubInfo& m_holder; > }; > > class WatchpointsOnStructureStubInfo { >diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.cpp b/Source/JavaScriptCore/bytecode/Watchpoint.cpp >index 7fa56167bf2045f4c8c33ee155e0ab60a4c36b6d..7e59cc7617d1b78925e8c12085415dbdca2aad0d 100644 >--- a/Source/JavaScriptCore/bytecode/Watchpoint.cpp >+++ b/Source/JavaScriptCore/bytecode/Watchpoint.cpp >@@ -26,7 +26,14 @@ > #include "config.h" > #include "Watchpoint.h" > >+#include "AdaptiveInferredPropertyValueWatchpointBase.h" >+#include "CodeBlockJettisoningWatchpoint.h" >+#include "DFGAdaptiveStructureWatchpoint.h" >+#include "FunctionRareData.h" > #include "HeapInlines.h" >+#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h" >+#include "ObjectToStringAdaptiveStructureWatchpoint.h" >+#include "StructureStubClearingWatchpoint.h" > #include "VM.h" > #include <wtf/CompilationThread.h> > >@@ -52,7 +59,14 @@ Watchpoint::~Watchpoint() > void Watchpoint::fire(VM& vm, const FireDetail& detail) > { > RELEASE_ASSERT(!isOnList()); >- fireInternal(vm, detail); >+ switch (m_type) { >+#define JSC_DEFINE_WATCHPOINT_DISPATCH(type, cast) \ >+ case Type::type: \ >+ static_cast<cast*>(this)->fireInternal(vm, detail); \ >+ break; >+ JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_DISPATCH) >+#undef JSC_DEFINE_WATCHPOINT_DISPATCH >+ } > } > > WatchpointSet::WatchpointSet(WatchpointState state) >diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.h b/Source/JavaScriptCore/bytecode/Watchpoint.h >index 77fba3efa9a5a45791b2b3ece232bf1d221a706b..5cfcc0ef4e0628e25ae43472280e142039630ae7 100644 >--- a/Source/JavaScriptCore/bytecode/Watchpoint.h >+++ b/Source/JavaScriptCore/bytecode/Watchpoint.h >@@ -90,21 +90,64 @@ LazyFireDetail<Types...> createLazyFireDetail(const Types&... types) > > class WatchpointSet; > >-class Watchpoint : public BasicRawSentinelNode<Watchpoint> { >+// Really unfortunately, we do not have the way to dispatch appropriate destructor based on enum type. >+// If we call destructor explicitly in the base class, it ends up calling the base destructor twice. >+// C++20 allows this by using std::std::destroying_delete_t. But we are not using C++20 right now. >+// >+// Luckily, none of our derived watchpoint classes have members which require destructors. So now we do >+// not dispatch the destructor call to the drived class. If it becomes really required, we can introduce >+// a custom deleter to container classes (Bag, Vector etc.) and call Watchpoint::destroy instead of "delete" >+// operator. But since we do not require it for now, we are doing the simplest thing. >+#define JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro) \ >+ macro(AdaptiveInferredPropertyValueStructure, AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint) \ >+ macro(AdaptiveInferredPropertyValueProperty, AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint) \ >+ macro(CodeBlockJettisoning, CodeBlockJettisoningWatchpoint) \ >+ macro(LLIntPrototypeLoadAdaptiveStructure, LLIntPrototypeLoadAdaptiveStructureWatchpoint) \ >+ macro(FunctionRareDataAllocationProfileClearing, FunctionRareData::AllocationProfileClearingWatchpoint) \ >+ macro(ObjectToStringAdaptiveStructure, ObjectToStringAdaptiveStructureWatchpoint) >+ >+#if ENABLE(JIT) >+#define JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) \ >+ JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro) \ >+ macro(StructureStubClearing, StructureStubClearingWatchpoint) >+ >+#if ENABLE(DFG_JIT) >+#define JSC_WATCHPOINT_TYPES(macro) \ >+ JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) \ >+ macro(AdaptiveStructure, DFG::AdaptiveStructureWatchpoint) >+#else >+#define JSC_WATCHPOINT_TYPES(macro) \ >+ JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) >+#endif >+ >+#else >+#define JSC_WATCHPOINT_TYPES(macro) \ >+ JSC_WATCHPOINT_TYPES_WITHOUT_JIT(macro) >+#endif >+ >+ >+class Watchpoint : public PackedRawSentinelNode<Watchpoint> { > WTF_MAKE_NONCOPYABLE(Watchpoint); > WTF_MAKE_NONMOVABLE(Watchpoint); > WTF_MAKE_FAST_ALLOCATED; > public: >- Watchpoint() = default; >- >- virtual ~Watchpoint(); >+#define JSC_DEFINE_WATCHPOINT_TYPES(type, _) type, >+ enum class Type : uint8_t { >+ JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_TYPES) >+ }; >+#undef JSC_DEFINE_WATCHPOINT_TYPES > >-protected: >- virtual void fireInternal(VM&, const FireDetail&) = 0; >+ Watchpoint(Type type) >+ : m_type(type) >+ { } >+ >+ ~Watchpoint(); > > private: > friend class WatchpointSet; > void fire(VM&, const FireDetail&); >+ >+ Type m_type; > }; > > enum WatchpointState { >@@ -239,7 +282,7 @@ class WatchpointSet : public ThreadSafeRefCounted<WatchpointSet> { > int8_t m_state; > int8_t m_setIsNotEmpty; > >- SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint>> m_set; >+ SentinelLinkedList<Watchpoint, PackedRawSentinelNode<Watchpoint>> m_set; > }; > > // InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which >diff --git a/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp b/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp >index 5b9dda6fb0b174aac94a797ca1190cc5496a244d..00dc531dffdd5270a9dd85dc54f6cba088a6b20a 100644 >--- a/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp >+++ b/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp >@@ -33,11 +33,10 @@ > > namespace JSC { namespace DFG { > >-AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint( >- const ObjectPropertyCondition& key, >- CodeBlock* codeBlock) >- : m_key(key) >+AdaptiveStructureWatchpoint::AdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, CodeBlock* codeBlock) >+ : Watchpoint(Watchpoint::Type::AdaptiveStructure) > , m_codeBlock(codeBlock) >+ , m_key(key) > { > RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint()); > RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint()); >diff --git a/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h b/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h >index 94013dc9683f38a9d9437689f2dac0a84e630078..807a79b8336950aed9519dc432dfdd02875fd144 100644 >--- a/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h >+++ b/Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h >@@ -28,6 +28,7 @@ > #if ENABLE(DFG_JIT) > > #include "ObjectPropertyCondition.h" >+#include "PackedCellPtr.h" > #include "Watchpoint.h" > > namespace JSC { namespace DFG { >@@ -40,12 +41,12 @@ class AdaptiveStructureWatchpoint final : public Watchpoint { > > void install(VM&); > >-protected: >- void fireInternal(VM&, const FireDetail&) override; >+ void fireInternal(VM&, const FireDetail&); > > private: >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedCellPtr<CodeBlock> m_codeBlock; > ObjectPropertyCondition m_key; >- CodeBlock* m_codeBlock; > }; > > } } // namespace JSC::DFG >diff --git a/Source/JavaScriptCore/heap/PackedCellPtr.h b/Source/JavaScriptCore/heap/PackedCellPtr.h >new file mode 100644 >index 0000000000000000000000000000000000000000..fe04c0d3c629166626293d1b707e48d8dde847d0 >--- /dev/null >+++ b/Source/JavaScriptCore/heap/PackedCellPtr.h >@@ -0,0 +1,36 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 >+ >+#include "MarkedBlock.h" >+#include <wtf/Packed.h> >+ >+namespace JSC { >+ >+template<typename T> >+using PackedCellPtr = PackedAlignedPtr<T, MarkedBlock::atomSize>; >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/FunctionRareData.h b/Source/JavaScriptCore/runtime/FunctionRareData.h >index 132c27960266f7f0fef59ca6de256345f02f5324..9e566d845e201dae32d0da281faf9eb811395fa3 100644 >--- a/Source/JavaScriptCore/runtime/FunctionRareData.h >+++ b/Source/JavaScriptCore/runtime/FunctionRareData.h >@@ -28,6 +28,7 @@ > #include "InternalFunctionAllocationProfile.h" > #include "JSCast.h" > #include "ObjectAllocationProfile.h" >+#include "PackedCellPtr.h" > #include "Watchpoint.h" > > namespace JSC { >@@ -110,23 +111,25 @@ class FunctionRareData final : public JSCell { > return m_allocationProfileClearingWatchpoint.get(); > } > >-protected: >- FunctionRareData(VM&); >- ~FunctionRareData(); >- >-private: >- > class AllocationProfileClearingWatchpoint final : public Watchpoint { > public: > AllocationProfileClearingWatchpoint(FunctionRareData* rareData) >- : m_rareData(rareData) >+ : Watchpoint(Watchpoint::Type::FunctionRareDataAllocationProfileClearing) >+ , m_rareData(rareData) > { } >- protected: >- void fireInternal(VM&, const FireDetail&) override; >+ >+ void fireInternal(VM&, const FireDetail&); >+ > private: >- FunctionRareData* m_rareData; >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedCellPtr<FunctionRareData> m_rareData; > }; > >+protected: >+ FunctionRareData(VM&); >+ ~FunctionRareData(); >+ >+private: > friend class LLIntOffsetsExtractor; > > // Ideally, there would only be one allocation profile for subclassing but due to Reflect.construct we >diff --git a/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp b/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..7d0e84233065a0c6814c1a4e97a5af0e2bea0d59 >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp >@@ -0,0 +1,63 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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. >+ */ >+ >+#include "config.h" >+#include "ObjectToStringAdaptiveStructureWatchpoint.h" >+ >+#include "ObjectPropertyConditionSet.h" >+#include "StructureRareData.h" >+ >+namespace JSC { >+ >+ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData) >+ : Watchpoint(Watchpoint::Type::ObjectToStringAdaptiveStructure) >+ , m_structureRareData(structureRareData) >+ , m_key(key) >+{ >+ RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint()); >+ RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint()); >+} >+ >+void ObjectToStringAdaptiveStructureWatchpoint::install(VM& vm) >+{ >+ RELEASE_ASSERT(m_key.isWatchable()); >+ >+ m_key.object()->structure(vm)->addTransitionWatchpoint(this); >+} >+ >+void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&) >+{ >+ if (!m_structureRareData->isLive()) >+ return; >+ >+ if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) { >+ install(vm); >+ return; >+ } >+ >+ m_structureRareData->clearObjectToStringValue(); >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.h b/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.h >new file mode 100644 >index 0000000000000000000000000000000000000000..dbb5caf1aa7ac48f2c23539fa47e048fc888768b >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/ObjectToStringAdaptiveStructureWatchpoint.h >@@ -0,0 +1,52 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 >+ >+#include "ObjectPropertyCondition.h" >+#include "PackedCellPtr.h" >+#include "Watchpoint.h" >+ >+namespace JSC { >+ >+class StructureRareData; >+ >+class ObjectToStringAdaptiveStructureWatchpoint final : public Watchpoint { >+public: >+ ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*); >+ >+ void install(VM&); >+ >+ const ObjectPropertyCondition& key() const { return m_key; } >+ >+ void fireInternal(VM&, const FireDetail&); >+ >+private: >+ // Own destructor may not be called. Keep members trivially destructible. >+ PackedCellPtr<StructureRareData> m_structureRareData; >+ ObjectPropertyCondition m_key; >+}; >+ >+} >diff --git a/Source/JavaScriptCore/runtime/StructureRareData.cpp b/Source/JavaScriptCore/runtime/StructureRareData.cpp >index 5c1c5f7f9bf226ccaad40d94dd6ccd9cde97cfc3..99a8d9f7daac217e4c81e7e7126e9c02b374ed3f 100644 >--- a/Source/JavaScriptCore/runtime/StructureRareData.cpp >+++ b/Source/JavaScriptCore/runtime/StructureRareData.cpp >@@ -32,6 +32,7 @@ > #include "JSString.h" > #include "JSCInlines.h" > #include "ObjectPropertyConditionSet.h" >+#include "ObjectToStringAdaptiveStructureWatchpoint.h" > > namespace JSC { > >@@ -90,22 +91,6 @@ class ObjectToStringAdaptiveInferredPropertyValueWatchpoint final : public Adapt > StructureRareData* m_structureRareData; > }; > >-class ObjectToStringAdaptiveStructureWatchpoint final : public Watchpoint { >-public: >- ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*); >- >- void install(VM&); >- >- const ObjectPropertyCondition& key() const { return m_key; } >- >-protected: >- void fireInternal(VM&, const FireDetail&) override; >- >-private: >- ObjectPropertyCondition m_key; >- StructureRareData* m_structureRareData; >-}; >- > void StructureRareData::setObjectToStringValue(ExecState* exec, VM& vm, Structure* ownStructure, JSString* value, PropertySlot toStringTagSymbolSlot) > { > if (m_giveUpOnObjectToStringValueCache) >@@ -164,7 +149,7 @@ void StructureRareData::setObjectToStringValue(ExecState* exec, VM& vm, Structur > m_objectToStringValue.set(vm, this, value); > } > >-inline void StructureRareData::clearObjectToStringValue() >+void StructureRareData::clearObjectToStringValue() > { > m_objectToStringAdaptiveWatchpointSet.clear(); > m_objectToStringAdaptiveInferredValueWatchpoint.reset(); >@@ -189,34 +174,6 @@ void StructureRareData::finalizeUnconditionally(VM& vm) > > // ------------- Methods for Object.prototype.toString() helper watchpoint classes -------------- > >-ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData) >- : m_key(key) >- , m_structureRareData(structureRareData) >-{ >- RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint()); >- RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint()); >-} >- >-void ObjectToStringAdaptiveStructureWatchpoint::install(VM& vm) >-{ >- RELEASE_ASSERT(m_key.isWatchable()); >- >- m_key.object()->structure(vm)->addTransitionWatchpoint(this); >-} >- >-void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&) >-{ >- if (!m_structureRareData->isLive()) >- return; >- >- if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) { >- install(vm); >- return; >- } >- >- m_structureRareData->clearObjectToStringValue(); >-} >- > ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData) > : Base(key) > , m_structureRareData(structureRareData) >diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h >index e03b23f22b294a1248c1eed9e01408a554842a25..9ca7fc4272522f954d1457be3d93b232d71c9017 100644 >--- a/Source/JavaScriptCore/runtime/StructureRareData.h >+++ b/Source/JavaScriptCore/runtime/StructureRareData.h >@@ -35,8 +35,8 @@ namespace JSC { > > class JSPropertyNameEnumerator; > class Structure; >-class ObjectToStringAdaptiveStructureWatchpoint; > class ObjectToStringAdaptiveInferredPropertyValueWatchpoint; >+class ObjectToStringAdaptiveStructureWatchpoint; > > class StructureRareData final : public JSCell { > public: >diff --git a/Source/WTF/WTF.xcodeproj/project.pbxproj b/Source/WTF/WTF.xcodeproj/project.pbxproj >index 8d5efaf23be0ca90d8bf882d6556fa4680196f34..30204fcd8882fa155c61745a3f33d892689b787b 100644 >--- a/Source/WTF/WTF.xcodeproj/project.pbxproj >+++ b/Source/WTF/WTF.xcodeproj/project.pbxproj >@@ -658,6 +658,7 @@ > E311FB161F0A568B003C08DE /* ThreadGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadGroup.h; sourceTree = "<group>"; }; > E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRegisters.h; sourceTree = "<group>"; }; > E33D5F871FBED66700BF625E /* RecursableLambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursableLambda.h; sourceTree = "<group>"; }; >+ E34CD0D022810A020020D299 /* Packed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Packed.h; sourceTree = "<group>"; }; > E360C7642127B85B00C90F0E /* UnalignedAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnalignedAccess.h; sourceTree = "<group>"; }; > E360C7652127B85C00C90F0E /* Unexpected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unexpected.h; sourceTree = "<group>"; }; > E388886D20C9095100E632BC /* WorkerPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerPool.cpp; sourceTree = "<group>"; }; >@@ -1056,6 +1057,7 @@ > 7CBBA07319BB7FDC00BBF025 /* OSObjectPtr.h */, > A8A472DA151A825B004123FF /* OSRandomSource.cpp */, > A8A472DB151A825B004123FF /* OSRandomSource.h */, >+ E34CD0D022810A020020D299 /* Packed.h */, > A8A472DF151A825B004123FF /* PackedIntVector.h */, > A8A472E0151A825B004123FF /* PageAllocation.h */, > A8A472E3151A825B004123FF /* PageBlock.cpp */, >diff --git a/Source/WTF/wtf/Bag.h b/Source/WTF/wtf/Bag.h >index 1f85720db9dacdb89fde1321b332004e886d6783..897d2991b013a4a606ab38fa47c761fef1c9c1a7 100644 >--- a/Source/WTF/wtf/Bag.h >+++ b/Source/WTF/wtf/Bag.h >@@ -28,31 +28,35 @@ > #include <wtf/DumbPtrTraits.h> > #include <wtf/FastMalloc.h> > #include <wtf/Noncopyable.h> >+#include <wtf/Packed.h> > > namespace WTF { > > namespace Private { > >-template<typename T> >+template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>> > class BagNode { > WTF_MAKE_FAST_ALLOCATED; > public: >+ using PtrTraits = typename PassedPtrTraits::template RebindTraits<BagNode>; >+ > template<typename... Args> > BagNode(Args&&... args) > : m_item(std::forward<Args>(args)...) > { } > > T m_item; >- BagNode* m_next { nullptr }; >+ typename PtrTraits::StorageType m_next { nullptr }; > }; > > } // namespace Private > >-template<typename T, typename PtrTraits = DumbPtrTraits<Private::BagNode<T>>> >+template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>> > class Bag { > WTF_MAKE_NONCOPYABLE(Bag); > WTF_MAKE_FAST_ALLOCATED; >- using Node = Private::BagNode<T>; >+ using Node = Private::BagNode<T, PassedPtrTraits>; >+ using PtrTraits = typename PassedPtrTraits::template RebindTraits<Node>; > > public: > Bag() = default; >@@ -83,7 +87,7 @@ class Bag { > Node* head = this->unwrappedHead(); > while (head) { > Node* current = head; >- head = current->m_next; >+ head = Node::PtrTraits::unwrap(current->m_next); > delete current; > } > m_head = nullptr; >@@ -112,7 +116,7 @@ class Bag { > > iterator& operator++() > { >- m_node = m_node->m_next; >+ m_node = Node::PtrTraits::unwrap(m_node->m_next); > return *this; > } > >@@ -156,6 +160,10 @@ class Bag { > typename PtrTraits::StorageType m_head { nullptr }; > }; > >+template<typename T> >+using PackedBag = Bag<T, PackedPtrTraits<T>>; >+ > } // namespace WTF > > using WTF::Bag; >+using WTF::PackedBag; >diff --git a/Source/WTF/wtf/CMakeLists.txt b/Source/WTF/wtf/CMakeLists.txt >index e60ec0be6e1c3431d6f3fd6e86cd7e671d58852a..6d6408019cfd48e9aea0c20736a965b1cce1d0f0 100644 >--- a/Source/WTF/wtf/CMakeLists.txt >+++ b/Source/WTF/wtf/CMakeLists.txt >@@ -150,6 +150,7 @@ set(WTF_PUBLIC_HEADERS > OptionSet.h > Optional.h > OrderMaker.h >+ Packed.h > PackedIntVector.h > PageAllocation.h > PageBlock.h >diff --git a/Source/WTF/wtf/DumbPtrTraits.h b/Source/WTF/wtf/DumbPtrTraits.h >index 982a36882570969217fdcc849724888ff82bad44..51deba76bffe03d5dabc37d5751372e16226345f 100644 >--- a/Source/WTF/wtf/DumbPtrTraits.h >+++ b/Source/WTF/wtf/DumbPtrTraits.h >@@ -32,6 +32,8 @@ namespace WTF { > > template<typename T> > struct DumbPtrTraits { >+ template<typename U> using RebindTraits = DumbPtrTraits<U>; >+ > using StorageType = T*; > > template<typename U> >diff --git a/Source/WTF/wtf/DumbValueTraits.h b/Source/WTF/wtf/DumbValueTraits.h >index fbc63223148eb6f4b48c35e3e87bb78dab9032d5..77c53e95f3969279a9c55987fa908a2cb1febdbf 100644 >--- a/Source/WTF/wtf/DumbValueTraits.h >+++ b/Source/WTF/wtf/DumbValueTraits.h >@@ -32,6 +32,8 @@ namespace WTF { > > template<typename T> > struct DumbValueTraits { >+ template<typename U> using RebindTraits = DumbValueTraits<U>; >+ > using StorageType = T; > > template<typename U> >diff --git a/Source/WTF/wtf/MathExtras.h b/Source/WTF/wtf/MathExtras.h >index 8080533dd792f0f437b66e347c2d11beb3944e95..a460debb6e2861fc5737abfdfb61395d76ab23aa 100644 >--- a/Source/WTF/wtf/MathExtras.h >+++ b/Source/WTF/wtf/MathExtras.h >@@ -692,6 +692,16 @@ inline unsigned getMSBSet(T t) > return bitSize - 1 - clz(t); > } > >+template <typename T> constexpr unsigned getLSBSetConstexpr(T value) >+{ >+ using UnsignedT = typename std::make_unsigned<T>::type; >+ unsigned result = 0; >+ UnsignedT unsignedValue = static_cast<UnsignedT>(value); >+ while (unsignedValue >>= 1) >+ ++result; >+ return result; >+} >+ > } // namespace WTF > > using WTF::opaque; >diff --git a/Source/WTF/wtf/Packed.h b/Source/WTF/wtf/Packed.h >new file mode 100644 >index 0000000000000000000000000000000000000000..80ecebaf25b71290b66148d7e837b09f557f77f5 >--- /dev/null >+++ b/Source/WTF/wtf/Packed.h >@@ -0,0 +1,232 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * 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 >+ >+#include <array> >+#include <wtf/MathExtras.h> >+#include <wtf/StdLibExtras.h> >+#include <wtf/UnalignedAccess.h> >+ >+namespace WTF { >+ >+template<typename T> >+class Packed { >+public: >+ static constexpr bool isPackedType = true; >+ >+ Packed() >+ : Packed(T { }) >+ { >+ } >+ >+ Packed(const T& value) >+ { >+ unalignedStore<T>(m_storage.data(), value); >+ } >+ >+ T get() const >+ { >+ return unalignedLoad<T>(m_storage.data()); >+ } >+ >+ void set(const T& value) >+ { >+ unalignedStore<T>(m_storage.data(), value); >+ } >+ >+ Packed<T>& operator=(const T& value) >+ { >+ set(value); >+ return *this; >+ } >+ >+ template<class U> >+ T exchange(U&& newValue) >+ { >+ T oldValue = get(); >+ set(std::forward<U>(newValue)); >+ return oldValue; >+ } >+ >+ void swap(Packed& other) >+ { >+ m_storage.swap(other.m_storage); >+ } >+ >+ template<typename Other, typename = std::enable_if_t<Other::isPackedType>> >+ void swap(Other& other) >+ { >+ T t1 = get(); >+ T t2 = other.get(); >+ std::swap(t1, t2); >+ set(t1); >+ other.set(t2); >+ } >+ >+ void swap(T& t2) >+ { >+ T t1 = get(); >+ std::swap(t1, t2); >+ set(t1); >+ } >+ >+private: >+ std::array<uint8_t, sizeof(T)> m_storage; >+}; >+ >+// PackedAlignedPtr can take alignment parameter too. PackedAlignedPtr only uses this alignment information if it is profitable: we use >+// alignment information only when we can reduce the size of the storage. Since the pointer width is 36 bits and JSCells are aligned to 16 bytes, >+// we can use 4 bits in Darwin ARM64, we can compact cell pointer into 4 bytes (32 bits). >+template<typename T, size_t alignment = alignof(T)> >+class PackedAlignedPtr { >+public: >+ static constexpr bool isPackedType = true; >+ static constexpr unsigned alignmentShiftSizeIfProfitable = getLSBSetConstexpr(hasOneBitSet(alignment) ? alignment : (roundUpToPowerOfTwo(alignment) >> 1)); >+ static constexpr unsigned storageSizeWithoutAlignmentShift = roundUpToMultipleOf<8>(WTF_CPU_EFFECTIVE_ADDRESS_WIDTH) / 8; >+ static constexpr unsigned storageSizeWithAlignmentShift = roundUpToMultipleOf<8>(WTF_CPU_EFFECTIVE_ADDRESS_WIDTH - alignmentShiftSizeIfProfitable) / 8; >+ static constexpr bool isAlignmentShiftProfitable = storageSizeWithoutAlignmentShift > storageSizeWithAlignmentShift; >+ static constexpr unsigned alignmentShiftSize = isAlignmentShiftProfitable ? alignmentShiftSizeIfProfitable : 0; >+ static constexpr unsigned storageSize = storageSizeWithAlignmentShift; >+ >+ constexpr PackedAlignedPtr() >+ : m_storage() >+ { >+ } >+ >+ constexpr PackedAlignedPtr(std::nullptr_t) >+ : m_storage() >+ { >+ } >+ >+ PackedAlignedPtr(T* value) >+ { >+ set(value); >+ } >+ >+ T* get() const >+ { >+ uintptr_t value = 0; >+#if CPU(LITTLE_ENDIAN) >+ memcpy(&value, m_storage.data(), storageSize); >+#else >+ memcpy(bitwise_cast<uint8_t*>(&value) + (sizeof(void*) - storageSize), m_storage.data(), storageSize); >+#endif >+ if (isAlignmentShiftProfitable) >+ value <<= alignmentShiftSize; >+ return bitwise_cast<T*>(value); >+ } >+ >+ void set(T* passedValue) >+ { >+ uintptr_t value = bitwise_cast<uintptr_t>(passedValue); >+ if (isAlignmentShiftProfitable) >+ value >>= alignmentShiftSize; >+#if CPU(LITTLE_ENDIAN) >+ memcpy(m_storage.data(), &value, storageSize); >+#else >+ memcpy(m_storage.data(), bitwise_cast<uint8_t*>(&value) + (sizeof(void*) - storageSize)); >+#endif >+ } >+ >+ void clear() >+ { >+ set(nullptr); >+ } >+ >+ T* operator->() const { return get(); } >+ T& operator*() const { return *get(); } >+ bool operator!() const { return !get(); } >+ >+ PackedAlignedPtr& operator=(T* value) >+ { >+ set(value); >+ return *this; >+ } >+ >+ template<class U> >+ T exchange(U&& newValue) >+ { >+ T oldValue = get(); >+ set(std::forward<U>(newValue)); >+ return oldValue; >+ } >+ >+ void swap(std::nullptr_t) { clear(); } >+ >+ void swap(PackedAlignedPtr& other) >+ { >+ m_storage.swap(other.m_storage); >+ } >+ >+ template<typename Other, typename = std::enable_if_t<Other::isPackedType>> >+ void swap(Other& other) >+ { >+ T t1 = get(); >+ T t2 = other.get(); >+ std::swap(t1, t2); >+ set(t1); >+ other.set(t2); >+ } >+ >+ void swap(T& t2) >+ { >+ T t1 = get(); >+ std::swap(t1, t2); >+ set(t1); >+ } >+ >+private: >+ std::array<uint8_t, storageSize> m_storage; >+}; >+ >+template<typename T> >+class Packed<T*> : public PackedAlignedPtr<T, 1> { >+public: >+ using Base = PackedAlignedPtr<T, 1>; >+ using Base::Base; >+}; >+ >+template<typename T> >+using PackedPtr = Packed<T*>; >+ >+template<typename T> >+struct PackedPtrTraits { >+ template<typename U> using RebindTraits = PackedPtrTraits<U>; >+ >+ using StorageType = PackedPtr<T>; >+ >+ template<class U> static ALWAYS_INLINE T* exchange(StorageType& ptr, U&& newValue) { return ptr.exchange(newValue); } >+ >+ template<typename Other> static ALWAYS_INLINE void swap(PackedPtr<T>& a, Other& b) { a.swap(b); } >+ >+ static ALWAYS_INLINE T* unwrap(const StorageType& ptr) { return ptr.get(); } >+}; >+ >+} // namespace WTF >+ >+using WTF::Packed; >+using WTF::PackedAlignedPtr; >+using WTF::PackedPtr; >diff --git a/Source/WTF/wtf/Platform.h b/Source/WTF/wtf/Platform.h >index 6e5e02f6fcfede0fd014cd98267436cbe552dfec..623a8aba4a0b56bfea04b419653ee77b6cd971f3 100644 >--- a/Source/WTF/wtf/Platform.h >+++ b/Source/WTF/wtf/Platform.h >@@ -352,6 +352,17 @@ > #endif > #endif > >+#if CPU(ADDRESS64) >+#if OS(DARWIN) && CPU(ARM64) >+#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 36 >+#else >+/* We strongly assume that effective address width is <= 48 in 64bit architectures (e.g. NaN boxing). */ >+#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 48 >+#endif >+#else >+#define WTF_CPU_EFFECTIVE_ADDRESS_WIDTH 32 >+#endif >+ > /* ==== OS() - underlying operating system; only to be used for mandated low-level services like > virtual memory, not to choose a GUI toolkit ==== */ > >diff --git a/Source/WTF/wtf/SentinelLinkedList.h b/Source/WTF/wtf/SentinelLinkedList.h >index ce79890f6fe3897ee0e2da89d23e07fdddd1c28e..75b467a09fa04c01077d65b77055a96b87f2ae6a 100644 >--- a/Source/WTF/wtf/SentinelLinkedList.h >+++ b/Source/WTF/wtf/SentinelLinkedList.h >@@ -36,31 +36,29 @@ > > #pragma once > >+#include <wtf/Packed.h> >+ > namespace WTF { > > enum SentinelTag { Sentinel }; > >-template<typename T> >+template<typename T, typename PassedPtrTraits = DumbPtrTraits<T>> > class BasicRawSentinelNode { > WTF_MAKE_FAST_ALLOCATED; > public: >+ using PtrTraits = typename PassedPtrTraits::template RebindTraits<BasicRawSentinelNode>; >+ > BasicRawSentinelNode(SentinelTag) >- : m_next(0) >- , m_prev(0) > { > } > >- BasicRawSentinelNode() >- : m_next(0) >- , m_prev(0) >- { >- } >+ BasicRawSentinelNode() = default; > > void setPrev(BasicRawSentinelNode* prev) { m_prev = prev; } > void setNext(BasicRawSentinelNode* next) { m_next = next; } > >- T* prev() { return static_cast<T*>(m_prev); } >- T* next() { return static_cast<T*>(m_next); } >+ T* prev() { return static_cast<T*>(PtrTraits::unwrap(m_prev)); } >+ T* next() { return static_cast<T*>(PtrTraits::unwrap(m_next)); } > > bool isOnList() const > { >@@ -74,8 +72,8 @@ class BasicRawSentinelNode { > void append(BasicRawSentinelNode*); > > private: >- BasicRawSentinelNode* m_next; >- BasicRawSentinelNode* m_prev; >+ typename PtrTraits::StorageType m_next { nullptr }; >+ typename PtrTraits::StorageType m_prev { nullptr }; > }; > > template <typename T, typename RawNode = T> class SentinelLinkedList { >@@ -118,20 +116,20 @@ template <typename T, typename RawNode = T> class SentinelLinkedList { > RawNode m_tailSentinel; > }; > >-template <typename T> void BasicRawSentinelNode<T>::remove() >+template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::remove() > { >- SentinelLinkedList<T, BasicRawSentinelNode<T>>::remove(static_cast<T*>(this)); >+ SentinelLinkedList<T, BasicRawSentinelNode>::remove(static_cast<T*>(this)); > } > >-template <typename T> void BasicRawSentinelNode<T>::prepend(BasicRawSentinelNode* node) >+template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::prepend(BasicRawSentinelNode* node) > { >- SentinelLinkedList<T, BasicRawSentinelNode<T>>::prepend( >+ SentinelLinkedList<T, BasicRawSentinelNode>::prepend( > static_cast<T*>(this), static_cast<T*>(node)); > } > >-template <typename T> void BasicRawSentinelNode<T>::append(BasicRawSentinelNode* node) >+template <typename T, typename PtrTraits> void BasicRawSentinelNode<T, PtrTraits>::append(BasicRawSentinelNode* node) > { >- SentinelLinkedList<T, BasicRawSentinelNode<T>>::append( >+ SentinelLinkedList<T, BasicRawSentinelNode>::append( > static_cast<T*>(this), static_cast<T*>(node)); > } > >@@ -140,10 +138,10 @@ template <typename T, typename RawNode> inline SentinelLinkedList<T, RawNode>::S > , m_tailSentinel(Sentinel) > { > m_headSentinel.setNext(&m_tailSentinel); >- m_headSentinel.setPrev(0); >+ m_headSentinel.setPrev(nullptr); > > m_tailSentinel.setPrev(&m_headSentinel); >- m_tailSentinel.setNext(0); >+ m_tailSentinel.setNext(nullptr); > } > > template <typename T, typename RawNode> inline typename SentinelLinkedList<T, RawNode>::iterator SentinelLinkedList<T, RawNode>::begin() >@@ -200,8 +198,8 @@ template <typename T, typename RawNode> inline void SentinelLinkedList<T, RawNod > prev->setNext(next); > next->setPrev(prev); > >- node->setPrev(0); >- node->setNext(0); >+ node->setPrev(nullptr); >+ node->setNext(nullptr); > } > > template <typename T, typename RawNode> >@@ -271,7 +269,11 @@ inline void SentinelLinkedList<T, RawNode>::takeFrom(SentinelLinkedList<T, RawNo > other.m_tailSentinel.setPrev(&other.m_headSentinel); > } > >+template<typename T> >+using PackedRawSentinelNode = BasicRawSentinelNode<T, PackedPtrTraits<T>>; >+ > } > > using WTF::BasicRawSentinelNode; >+using WTF::PackedRawSentinelNode; > using WTF::SentinelLinkedList; >diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h >index 35ec44eb7ec9724aa1c59ecd280e4d6cdbcd3670..9de1b9f877370ef62784d13663dec82e246a868d 100644 >--- a/Source/WTF/wtf/StdLibExtras.h >+++ b/Source/WTF/wtf/StdLibExtras.h >@@ -172,14 +172,10 @@ template<typename T> char (&ArrayLengthHelperFunction(T (&)[0]))[0]; > #endif > #define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array)) > >-ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl0(size_t remainderMask, size_t x) >-{ >- return (x + remainderMask) & ~remainderMask; >-} >- > ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl(size_t divisor, size_t x) > { >- return roundUpToMultipleOfImpl0(divisor - 1, x); >+ size_t remainderMask = divisor - 1; >+ return (x + remainderMask) & ~remainderMask; > } > > // Efficient implementation that takes advantage of powers of two. >@@ -201,6 +197,29 @@ template<size_t divisor, typename T> inline T* roundUpToMultipleOf(T* x) > return reinterpret_cast<T*>(roundUpToMultipleOf<divisor>(reinterpret_cast<size_t>(x))); > } > >+ALWAYS_INLINE constexpr size_t roundDownToMultipleOfImpl(size_t divisor, size_t x) >+{ >+ return x & ~(divisor - 1); >+} >+ >+inline size_t roundDownToMultipleOf(size_t divisor, size_t x) >+{ >+ ASSERT(divisor && !(divisor & (divisor - 1))); >+ return roundDownToMultipleOfImpl(divisor, x); >+} >+ >+template<size_t divisor> constexpr size_t roundDownToMultipleOf(size_t x) >+{ >+ static_assert(divisor && !(divisor & (divisor - 1)), "divisor must be a power of two!"); >+ return roundDownToMultipleOfImpl(divisor, x); >+} >+ >+template<size_t divisor, typename T> inline T* roundDownToMultipleOf(T* x) >+{ >+ static_assert(sizeof(T*) == sizeof(size_t), ""); >+ return reinterpret_cast<T*>(roundDownToMultipleOf<divisor>(reinterpret_cast<size_t>(x))); >+} >+ > enum BinarySearchMode { > KeyMustBePresentInArray, > KeyMightNotBePresentInArray, >@@ -587,5 +606,6 @@ using WTF::isStatelessLambda; > using WTF::is8ByteAligned; > using WTF::mergeDeduplicatedSorted; > using WTF::roundUpToMultipleOf; >+using WTF::roundDownToMultipleOf; > using WTF::safeCast; > using WTF::tryBinarySearch; >diff --git a/Source/WTF/wtf/UnalignedAccess.h b/Source/WTF/wtf/UnalignedAccess.h >index 1a37b4eec1ad2124a35c83c6bc0ecb8edca65336..5a4e9ef4494ef46ca9e4eef77fdcc0d60faa4a11 100644 >--- a/Source/WTF/wtf/UnalignedAccess.h >+++ b/Source/WTF/wtf/UnalignedAccess.h >@@ -31,20 +31,20 @@ > > namespace WTF { > >-template<typename IntegralType> >-inline IntegralType unalignedLoad(const void* pointer) >+template<typename Type> >+inline Type unalignedLoad(const void* pointer) > { >- static_assert(std::is_integral<IntegralType>::value || std::is_pointer<IntegralType>::value, ""); >- IntegralType result { }; >- memcpy(&result, pointer, sizeof(IntegralType)); >+ static_assert(std::is_trivial<Type>::value, ""); >+ Type result { }; >+ memcpy(&result, pointer, sizeof(Type)); > return result; > } > >-template<typename IntegralType> >-inline void unalignedStore(void* pointer, IntegralType value) >+template<typename Type> >+inline void unalignedStore(void* pointer, Type value) > { >- static_assert(std::is_integral<IntegralType>::value || std::is_pointer<IntegralType>::value, ""); >- memcpy(pointer, &value, sizeof(IntegralType)); >+ static_assert(std::is_trivial<Type>::value, ""); >+ memcpy(pointer, &value, sizeof(Type)); > } > > } // namespace WTF >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 410d7eeb150c91fde7de58d63d907c7cfa8e7d8f..cca6d7bfee82c49c61525ff1d51dc5c60680a169 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,15 @@ >+2019-05-09 Yusuke Suzuki <ysuzuki@apple.com> >+ >+ [JSC] Compress Watchpoint size by using enum type and Packed<> data structure >+ https://bugs.webkit.org/show_bug.cgi?id=197730 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * TestWebKitAPI/CMakeLists.txt: >+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: >+ * TestWebKitAPI/Tests/WTF/Packed.cpp: Added. >+ (TestWebKitAPI::TEST): >+ > 2019-05-09 Aakash Jain <aakash_jain@apple.com> > > [ews-app] Add migrations file to repository >diff --git a/Tools/TestWebKitAPI/CMakeLists.txt b/Tools/TestWebKitAPI/CMakeLists.txt >index bea6a6980d4a492317c1667979e50ce0074d812f..c78fc07cd012f364b1a0c4da26c8f2dc8351491e 100644 >--- a/Tools/TestWebKitAPI/CMakeLists.txt >+++ b/Tools/TestWebKitAPI/CMakeLists.txt >@@ -60,6 +60,7 @@ set(TestWTF_SOURCES > Tests/WTF/NeverDestroyed.cpp > Tests/WTF/OptionSet.cpp > Tests/WTF/Optional.cpp >+ Tests/WTF/Packed.cpp > Tests/WTF/ParkingLot.cpp > Tests/WTF/PriorityQueue.cpp > Tests/WTF/RedBlackTree.cpp >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 578b61a1216153d8fa6b1ce6f73787c528618f60..1e8eb8cb7de5c19e28322486974390cb3d8ad725 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -860,6 +860,7 @@ > E1220DCA155B28AA0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E1220DC9155B287D0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html */; }; > E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */; }; > E324A6F02041C82000A76593 /* UniqueArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E398BC0F2041C76300387136 /* UniqueArray.cpp */; }; >+ E32B549222810AC4008AD702 /* Packed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E32B549122810AC0008AD702 /* Packed.cpp */; }; > E373D7911F2CF35200C6FAAF /* Signals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3953F951F2CF32100A76A2E /* Signals.cpp */; }; > E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38A0D341FD50CBC00E98C8B /* Threading.cpp */; }; > E3A1E77F21B25B39008C6007 /* URLParserTextEncoding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3A1E77E21B25B39008C6007 /* URLParserTextEncoding.cpp */; }; >@@ -2231,6 +2232,7 @@ > E194E1BA177E5145009C4D4E /* StopLoadingFromDidReceiveResponse.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StopLoadingFromDidReceiveResponse.mm; sourceTree = "<group>"; }; > E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = StopLoadingFromDidReceiveResponse.html; sourceTree = "<group>"; }; > E19DB9781B32137C00DB38D4 /* NavigatorLanguage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NavigatorLanguage.mm; sourceTree = "<group>"; }; >+ E32B549122810AC0008AD702 /* Packed.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Packed.cpp; sourceTree = "<group>"; }; > E388887020C9098100E632BC /* WorkerPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerPool.cpp; sourceTree = "<group>"; }; > E38A0D341FD50CBC00E98C8B /* Threading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Threading.cpp; sourceTree = "<group>"; }; > E3953F951F2CF32100A76A2E /* Signals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Signals.cpp; sourceTree = "<group>"; }; >@@ -3349,6 +3351,7 @@ > A57D54F21F338C3600A97AA7 /* NeverDestroyed.cpp */, > 1AFDE6541953B2C000C48FFA /* Optional.cpp */, > CE50D8C81C8665CE0072EA5A /* OptionSet.cpp */, >+ E32B549122810AC0008AD702 /* Packed.cpp */, > 0FE447971B76F1E3009498EB /* ParkingLot.cpp */, > 53EC253F1E96BC80000831B9 /* PriorityQueue.cpp */, > 0FC6C4CB141027E0005B7F0C /* RedBlackTree.cpp */, >@@ -3962,6 +3965,7 @@ > 7C83DF011D0A590C00FEBCF3 /* Optional.cpp in Sources */, > 1A77BAA31D9AFFFC005FC568 /* OptionSet.cpp in Sources */, > 7C83DF021D0A590C00FEBCF3 /* OSObjectPtr.cpp in Sources */, >+ E32B549222810AC4008AD702 /* Packed.cpp in Sources */, > 7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */, > 53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */, > 7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */, >diff --git a/Tools/TestWebKitAPI/Tests/WTF/Packed.cpp b/Tools/TestWebKitAPI/Tests/WTF/Packed.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..6ba6f006054c8c274720c45e26ee6e8dc534a788 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WTF/Packed.cpp >@@ -0,0 +1,84 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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. >+ */ >+ >+#include "config.h" >+ >+#include <wtf/Packed.h> >+ >+namespace TestWebKitAPI { >+ >+struct PackedPair { >+ PackedPtr<uint8_t> key { nullptr }; >+ PackedPtr<uint8_t> value { nullptr }; >+}; >+ >+TEST(WTF_Packed, StructSize) >+{ >+ EXPECT_EQ(alignof(PackedPair), 1U); >+#if CPU(X86_64) >+ EXPECT_EQ(sizeof(PackedPair), 12U); >+#endif >+ { >+ Packed<double> value; >+ value = 4.2; >+ EXPECT_EQ(value.get(), 4.2); >+ } >+ { >+ uint64_t originalValue = 0xff00ff00dd00dd00UL; >+ Packed<uint64_t> value; >+ value = originalValue; >+ EXPECT_EQ(value.get(), originalValue); >+ EXPECT_EQ(alignof(Packed<uint64_t>), 1U); >+ EXPECT_EQ(sizeof(Packed<uint64_t>), sizeof(uint64_t)); >+ } >+} >+ >+TEST(WTF_Packed, AssignAndGet) >+{ >+ { >+ PackedPtr<uint8_t> key { nullptr }; >+ uint8_t* max = bitwise_cast<uint8_t*>(((1ULL) << WTF_CPU_EFFECTIVE_ADDRESS_WIDTH) - 1); >+ key = max; >+ EXPECT_EQ(key.get(), max); >+ } >+} >+ >+TEST(WTF_Packed, PackedAlignedPtr) >+{ >+ { >+ PackedAlignedPtr<uint8_t, 256> key { nullptr }; >+ EXPECT_LE(sizeof(key), 5U); >+ } >+ { >+ PackedAlignedPtr<uint8_t, 16> key { nullptr }; >+#if OS(DARWIN) && CPU(ARM64) >+ EXPECT_EQ(sizeof(key), 4U); >+#else >+ EXPECT_LE(sizeof(key), 6U); >+#endif >+ } >+} >+ >+} // namespace TestWebKitAPI
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197730
:
369460
|
369461
|
369465
|
369466
|
369467
|
369468
|
369471
|
369472
|
369474
|
369475
|
369477
|
369492
|
369518
|
369520
|
369522
|
369618
|
369619
|
369627