Shrink size of PropertyCondition by packing UniquedStringImpl* and Kind
authoryusukesuzuki@slowstart.org <yusukesuzuki@slowstart.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Aug 2018 23:21:08 +0000 (23:21 +0000)
committeryusukesuzuki@slowstart.org <yusukesuzuki@slowstart.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Aug 2018 23:21:08 +0000 (23:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188328

Reviewed by Saam Barati.

Source/JavaScriptCore:

Shrinking the size of PropertyCondition can improve memory consumption by a lot.
For example, cnn.com can show 7000 persistent StructureStubClearingWatchpoint
and 6000 LLIntPrototypeLoadAdaptiveStructureWatchpoint which have PropertyCondition
as a member field.

This patch shrinks the size of PropertyCondition by packing UniquedStringImpl* and
PropertyCondition::Kind into uint64_t data in 64bit architecture. Since our address
are within 48bit, we can put PropertyCondition::Kind in this unused bits.
To make it easy, we add WTF::CompactPointerTuple<PointerType, Type>, which automatically
folds a pointer and 1byte type into 64bit data.

This change shrinks PropertyCondition from 24bytes to 16bytes.

* bytecode/PropertyCondition.cpp:
(JSC::PropertyCondition::dumpInContext const):
(JSC::PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint const):
(JSC::PropertyCondition::validityRequiresImpurePropertyWatchpoint const):
(JSC::PropertyCondition::isStillValid const):
(JSC::PropertyCondition::isWatchableWhenValid const):
* bytecode/PropertyCondition.h:
(JSC::PropertyCondition::PropertyCondition):
(JSC::PropertyCondition::presenceWithoutBarrier):
(JSC::PropertyCondition::absenceWithoutBarrier):
(JSC::PropertyCondition::absenceOfSetEffectWithoutBarrier):
(JSC::PropertyCondition::equivalenceWithoutBarrier):
(JSC::PropertyCondition::hasPrototypeWithoutBarrier):
(JSC::PropertyCondition::operator bool const):
(JSC::PropertyCondition::kind const):
(JSC::PropertyCondition::uid const):
(JSC::PropertyCondition::hasOffset const):
(JSC::PropertyCondition::hasAttributes const):
(JSC::PropertyCondition::hasPrototype const):
(JSC::PropertyCondition::hasRequiredValue const):
(JSC::PropertyCondition::hash const):
(JSC::PropertyCondition::operator== const):
(JSC::PropertyCondition::isHashTableDeletedValue const):
(JSC::PropertyCondition::watchingRequiresReplacementWatchpoint const):

Source/WTF:

This patch adds CompactPointerTuple, which can pack a pointer and 8bit value into 8bytes.
In 32bit architecture, it just has two fields for a pointer and 8bit value. In 64bit architecture,
we use upper 5bits (zeros because of the effective width of virtual address) and lower 3bits (zeros
because of the alignment ensured by static_assert) to pack 8bit value into the pointer data. Since
even the 5-level page tables use 57bit effective address, this strategy works well.

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/CompactPointerTuple.h: Added.
(WTF::CompactPointerTuple::encodeType):
(WTF::CompactPointerTuple::decodeType):
(WTF::CompactPointerTuple::CompactPointerTuple):
(WTF::CompactPointerTuple::pointer const):
(WTF::CompactPointerTuple::setPointer):
(WTF::CompactPointerTuple::type const):
(WTF::CompactPointerTuple::setType):
* wtf/Platform.h:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/PropertyCondition.cpp
Source/JavaScriptCore/bytecode/PropertyCondition.h
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/CompactPointerTuple.h [new file with mode: 0644]
Source/WTF/wtf/Platform.h

index 78fd246..7d7186a 100644 (file)
@@ -1,3 +1,48 @@
+2018-08-07  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
+
+        Shrink size of PropertyCondition by packing UniquedStringImpl* and Kind
+        https://bugs.webkit.org/show_bug.cgi?id=188328
+
+        Reviewed by Saam Barati.
+
+        Shrinking the size of PropertyCondition can improve memory consumption by a lot.
+        For example, cnn.com can show 7000 persistent StructureStubClearingWatchpoint
+        and 6000 LLIntPrototypeLoadAdaptiveStructureWatchpoint which have PropertyCondition
+        as a member field.
+
+        This patch shrinks the size of PropertyCondition by packing UniquedStringImpl* and
+        PropertyCondition::Kind into uint64_t data in 64bit architecture. Since our address
+        are within 48bit, we can put PropertyCondition::Kind in this unused bits.
+        To make it easy, we add WTF::CompactPointerTuple<PointerType, Type>, which automatically
+        folds a pointer and 1byte type into 64bit data.
+
+        This change shrinks PropertyCondition from 24bytes to 16bytes.
+
+        * bytecode/PropertyCondition.cpp:
+        (JSC::PropertyCondition::dumpInContext const):
+        (JSC::PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint const):
+        (JSC::PropertyCondition::validityRequiresImpurePropertyWatchpoint const):
+        (JSC::PropertyCondition::isStillValid const):
+        (JSC::PropertyCondition::isWatchableWhenValid const):
+        * bytecode/PropertyCondition.h:
+        (JSC::PropertyCondition::PropertyCondition):
+        (JSC::PropertyCondition::presenceWithoutBarrier):
+        (JSC::PropertyCondition::absenceWithoutBarrier):
+        (JSC::PropertyCondition::absenceOfSetEffectWithoutBarrier):
+        (JSC::PropertyCondition::equivalenceWithoutBarrier):
+        (JSC::PropertyCondition::hasPrototypeWithoutBarrier):
+        (JSC::PropertyCondition::operator bool const):
+        (JSC::PropertyCondition::kind const):
+        (JSC::PropertyCondition::uid const):
+        (JSC::PropertyCondition::hasOffset const):
+        (JSC::PropertyCondition::hasAttributes const):
+        (JSC::PropertyCondition::hasPrototype const):
+        (JSC::PropertyCondition::hasRequiredValue const):
+        (JSC::PropertyCondition::hash const):
+        (JSC::PropertyCondition::operator== const):
+        (JSC::PropertyCondition::isHashTableDeletedValue const):
+        (JSC::PropertyCondition::watchingRequiresReplacementWatchpoint const):
+
 2018-08-07  Mark Lam  <mark.lam@apple.com>
 
         Use a more specific PtrTag for PlatformRegisters PC and LR.
index 43634be..3deb44c 100644 (file)
@@ -43,19 +43,19 @@ void PropertyCondition::dumpInContext(PrintStream& out, DumpContext* context) co
         return;
     }
     
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Presence:
-        out.print(m_kind, " of ", m_uid, " at ", offset(), " with attributes ", attributes());
+        out.print(m_header.type(), " of ", m_header.pointer(), " at ", offset(), " with attributes ", attributes());
         return;
     case Absence:
     case AbsenceOfSetEffect:
-        out.print(m_kind, " of ", m_uid, " with prototype ", inContext(JSValue(prototype()), context));
+        out.print(m_header.type(), " of ", m_header.pointer(), " with prototype ", inContext(JSValue(prototype()), context));
         return;
     case Equivalence:
-        out.print(m_kind, " of ", m_uid, " with ", inContext(requiredValue(), context));
+        out.print(m_header.type(), " of ", m_header.pointer(), " with ", inContext(requiredValue(), context));
         return;
     case HasPrototype:
-        out.print(m_kind, " with prototype ", inContext(JSValue(prototype()), context));
+        out.print(m_header.type(), " with prototype ", inContext(JSValue(prototype()), context));
         return;
     }
     RELEASE_ASSERT_NOT_REACHED();
@@ -81,7 +81,7 @@ bool PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint(
         return false;
     }
 
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Presence:
     case Absence:
     case AbsenceOfSetEffect:
@@ -102,7 +102,7 @@ bool PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint(
         break;
     }
     
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Presence: {
         unsigned currentAttributes;
         PropertyOffset currentOffset = structure->getConcurrently(uid(), currentAttributes);
@@ -259,7 +259,7 @@ bool PropertyCondition::validityRequiresImpurePropertyWatchpoint(Structure* stru
     if (!*this)
         return false;
     
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Presence:
     case Absence:
     case Equivalence:
@@ -281,7 +281,7 @@ bool PropertyCondition::isStillValid(Structure* structure, JSObject* base) const
     // Currently we assume that an impure property can cause a property to appear, and can also
     // "shadow" an existing JS property on the same object. Hence it affects both presence and
     // absence. It doesn't affect AbsenceOfSetEffect because impure properties aren't ever setters.
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Absence:
         if (structure->typeInfo().getOwnPropertySlotIsImpure() || structure->typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence())
             return false;
@@ -304,7 +304,7 @@ bool PropertyCondition::isWatchableWhenValid(
     if (structure->transitionWatchpointSetHasBeenInvalidated())
         return false;
     
-    switch (m_kind) {
+    switch (m_header.type()) {
     case Equivalence: {
         PropertyOffset offset = structure->getConcurrently(uid());
         
index e2f6b1f..8acb119 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "JSObject.h"
+#include <wtf/CompactPointerTuple.h>
 #include <wtf/HashMap.h>
 
 namespace JSC {
@@ -34,24 +35,24 @@ class TrackedReferences;
 
 class PropertyCondition {
 public:
-    enum Kind {
+    enum Kind : uint8_t {
         Presence,
         Absence,
         AbsenceOfSetEffect,
         Equivalence, // An adaptive watchpoint on this will be a pair of watchpoints, and when the structure transitions, we will set the replacement watchpoint on the new structure.
         HasPrototype
     };
+
+    using Header = CompactPointerTuple<UniquedStringImpl*, Kind>;
     
     PropertyCondition()
-        : m_uid(nullptr)
-        , m_kind(Presence)
+        : m_header(nullptr, Presence)
     {
         memset(&u, 0, sizeof(u));
     }
     
     PropertyCondition(WTF::HashTableDeletedValueType)
-        : m_uid(nullptr)
-        , m_kind(Absence)
+        : m_header(nullptr, Absence)
     {
         memset(&u, 0, sizeof(u));
     }
@@ -59,8 +60,7 @@ public:
     static PropertyCondition presenceWithoutBarrier(UniquedStringImpl* uid, PropertyOffset offset, unsigned attributes)
     {
         PropertyCondition result;
-        result.m_uid = uid;
-        result.m_kind = Presence;
+        result.m_header = Header(uid, Presence);
         result.u.presence.offset = offset;
         result.u.presence.attributes = attributes;
         return result;
@@ -76,8 +76,7 @@ public:
     static PropertyCondition absenceWithoutBarrier(UniquedStringImpl* uid, JSObject* prototype)
     {
         PropertyCondition result;
-        result.m_uid = uid;
-        result.m_kind = Absence;
+        result.m_header = Header(uid, Absence);
         result.u.prototype.prototype = prototype;
         return result;
     }
@@ -94,8 +93,7 @@ public:
         UniquedStringImpl* uid, JSObject* prototype)
     {
         PropertyCondition result;
-        result.m_uid = uid;
-        result.m_kind = AbsenceOfSetEffect;
+        result.m_header = Header(uid, AbsenceOfSetEffect);
         result.u.prototype.prototype = prototype;
         return result;
     }
@@ -112,8 +110,7 @@ public:
         UniquedStringImpl* uid, JSValue value)
     {
         PropertyCondition result;
-        result.m_uid = uid;
-        result.m_kind = Equivalence;
+        result.m_header = Header(uid, Equivalence);
         result.u.equivalence.value = JSValue::encode(value);
         return result;
     }
@@ -129,7 +126,7 @@ public:
     static PropertyCondition hasPrototypeWithoutBarrier(JSObject* prototype)
     {
         PropertyCondition result;
-        result.m_kind = HasPrototype;
+        result.m_header = Header(nullptr, HasPrototype);
         result.u.prototype.prototype = prototype;
         return result;
     }
@@ -141,18 +138,18 @@ public:
         return hasPrototypeWithoutBarrier(prototype);
     }
     
-    explicit operator bool() const { return m_uid || m_kind != Presence; }
+    explicit operator bool() const { return m_header.pointer() || m_header.type() != Presence; }
     
-    Kind kind() const { return m_kind; }
-    UniquedStringImpl* uid() const { return m_uid; }
+    Kind kind() const { return m_header.type(); }
+    UniquedStringImpl* uid() const { return m_header.pointer(); }
     
-    bool hasOffset() const { return !!*this && m_kind == Presence; };
+    bool hasOffset() const { return !!*this && m_header.type() == Presence; };
     PropertyOffset offset() const
     {
         ASSERT(hasOffset());
         return u.presence.offset;
     }
-    bool hasAttributes() const { return !!*this && m_kind == Presence; };
+    bool hasAttributes() const { return !!*this && m_header.type() == Presence; };
     unsigned attributes() const
     {
         ASSERT(hasAttributes());
@@ -162,7 +159,7 @@ public:
     bool hasPrototype() const
     {
         return !!*this
-            && (m_kind == Absence || m_kind == AbsenceOfSetEffect || m_kind == HasPrototype);
+            && (m_header.type() == Absence || m_header.type() == AbsenceOfSetEffect || m_header.type() == HasPrototype);
     }
     JSObject* prototype() const
     {
@@ -170,7 +167,7 @@ public:
         return u.prototype.prototype;
     }
     
-    bool hasRequiredValue() const { return !!*this && m_kind == Equivalence; }
+    bool hasRequiredValue() const { return !!*this && m_header.type() == Equivalence; }
     JSValue requiredValue() const
     {
         ASSERT(hasRequiredValue());
@@ -182,8 +179,8 @@ public:
     
     unsigned hash() const
     {
-        unsigned result = WTF::PtrHash<UniquedStringImpl*>::hash(m_uid) + static_cast<unsigned>(m_kind);
-        switch (m_kind) {
+        unsigned result = WTF::PtrHash<UniquedStringImpl*>::hash(m_header.pointer()) + static_cast<unsigned>(m_header.type());
+        switch (m_header.type()) {
         case Presence:
             result ^= u.presence.offset;
             result ^= u.presence.attributes;
@@ -202,11 +199,11 @@ public:
     
     bool operator==(const PropertyCondition& other) const
     {
-        if (m_uid != other.m_uid)
+        if (m_header.pointer() != other.m_header.pointer())
             return false;
-        if (m_kind != other.m_kind)
+        if (m_header.type() != other.m_header.type())
             return false;
-        switch (m_kind) {
+        switch (m_header.type()) {
         case Presence:
             return u.presence.offset == other.u.presence.offset
                 && u.presence.attributes == other.u.presence.attributes;
@@ -223,7 +220,7 @@ public:
     
     bool isHashTableDeletedValue() const
     {
-        return !m_uid && m_kind == Absence;
+        return !m_header.pointer() && m_header.type() == Absence;
     }
     
     // Two conditions are compatible if they are identical or if they speak of different uids. If
@@ -296,7 +293,7 @@ public:
     }
     bool watchingRequiresReplacementWatchpoint() const
     {
-        return !!*this && m_kind == Equivalence;
+        return !!*this && m_header.type() == Equivalence;
     }
     
     // This means that the objects involved in this are still live.
@@ -313,8 +310,7 @@ public:
 private:
     bool isWatchableWhenValid(Structure*, WatchabilityEffort) const;
 
-    UniquedStringImpl* m_uid;
-    Kind m_kind;
+    Header m_header;
     union {
         struct {
             PropertyOffset offset;
index 89a3550..e5985be 100644 (file)
@@ -1,3 +1,28 @@
+2018-08-07  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
+
+        Shrink size of PropertyCondition by packing UniquedStringImpl* and Kind
+        https://bugs.webkit.org/show_bug.cgi?id=188328
+
+        Reviewed by Saam Barati.
+
+        This patch adds CompactPointerTuple, which can pack a pointer and 8bit value into 8bytes.
+        In 32bit architecture, it just has two fields for a pointer and 8bit value. In 64bit architecture,
+        we use upper 5bits (zeros because of the effective width of virtual address) and lower 3bits (zeros
+        because of the alignment ensured by static_assert) to pack 8bit value into the pointer data. Since
+        even the 5-level page tables use 57bit effective address, this strategy works well.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/CompactPointerTuple.h: Added.
+        (WTF::CompactPointerTuple::encodeType):
+        (WTF::CompactPointerTuple::decodeType):
+        (WTF::CompactPointerTuple::CompactPointerTuple):
+        (WTF::CompactPointerTuple::pointer const):
+        (WTF::CompactPointerTuple::setPointer):
+        (WTF::CompactPointerTuple::type const):
+        (WTF::CompactPointerTuple::setType):
+        * wtf/Platform.h:
+
 2018-08-07  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed, suppress warnings to fix the build.
index 931319e..2f3d53f 100644 (file)
                E38D6E261F5522E300A75CC4 /* StringBuilderJSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringBuilderJSON.cpp; sourceTree = "<group>"; };
                E3A32BC21FC830E2007D7E76 /* JSValueMalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSValueMalloc.cpp; sourceTree = "<group>"; };
                E3A32BC31FC830E2007D7E76 /* JSValueMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueMalloc.h; sourceTree = "<group>"; };
+               E3CF76902115D6BA0091DE48 /* CompactPointerTuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompactPointerTuple.h; sourceTree = "<group>"; };
                E3E158251EADA53C004A079D /* SystemFree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemFree.h; sourceTree = "<group>"; };
                E431CC4A21187ADB000C8A07 /* DispatchSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchSPI.h; sourceTree = "<group>"; };
                E4A0AD371A96245500536DF6 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
                                0F66B2801DC97BAB004A1D3F /* ClockType.cpp */,
                                0F66B2811DC97BAB004A1D3F /* ClockType.h */,
                                0FC4EDE51696149600F65041 /* CommaPrinter.h */,
+                               E3CF76902115D6BA0091DE48 /* CompactPointerTuple.h */,
                                0F8F2B8F172E00F0007DBDA5 /* CompilationThread.cpp */,
                                0F8F2B90172E00F0007DBDA5 /* CompilationThread.h */,
                                A8A47270151A825A004123FF /* Compiler.h */,
index e46802a..9798b9b 100644 (file)
@@ -28,6 +28,7 @@ set(WTF_PUBLIC_HEADERS
     CheckedBoolean.h
     ClockType.h
     CommaPrinter.h
+    CompactPointerTuple.h
     CompilationThread.h
     Compiler.h
     CompletionHandler.h
diff --git a/Source/WTF/wtf/CompactPointerTuple.h b/Source/WTF/wtf/CompactPointerTuple.h
new file mode 100644 (file)
index 0000000..9075a60
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+// The goal of this class is folding a pointer and 1 byte value into 8 bytes in both 32bit and 64bit architectures.
+// 32bit architecture just has a pair of byte and pointer, which should be 8 bytes.
+// In 64bit, we use the upper 5 bits and lower 3 bits (zero due to alignment) since these bits are safe to use even
+// with 5-level page tables where the effective pointer width is 57bits.
+template<typename PointerType, typename Type>
+class CompactPointerTuple {
+public:
+    static_assert(sizeof(Type) == 1, "");
+    static_assert(std::is_pointer<PointerType>::value, "");
+    static_assert(alignof(typename std::remove_pointer<PointerType>::type) >= alignof(void*), "");
+    static_assert(std::is_integral<Type>::value || std::is_enum<Type>::value, "");
+
+    CompactPointerTuple() = default;
+
+#if CPU(ADDRESS64)
+public:
+    static constexpr uint64_t encodeType(uint8_t type)
+    {
+        // Encode 8bit type UUUDDDDD into 64bit data DDDDD..56bit..UUU.
+        return (static_cast<uint64_t>(type) << 59) | (static_cast<uint64_t>(type) >> 5);
+    }
+    static constexpr uint8_t decodeType(uint64_t value)
+    {
+        // Decode 64bit data DDDDD..56bit..UUU into 8bit type UUUDDDDD.
+        return static_cast<uint8_t>((value >> 59) | (value << 5));
+    }
+
+    static constexpr uint64_t typeMask = encodeType(UINT8_MAX);
+    static_assert(0xF800000000000007ULL == typeMask, "");
+    static constexpr uint64_t pointerMask = ~typeMask;
+
+    CompactPointerTuple(PointerType pointer, Type type)
+        : m_data(bitwise_cast<uint64_t>(pointer) | encodeType(static_cast<uint8_t>(type)))
+    {
+        ASSERT((bitwise_cast<uint64_t>(pointer) & 0b111) == 0x0);
+    }
+
+    PointerType pointer() const { return bitwise_cast<PointerType>(m_data & pointerMask); }
+    void setPointer(PointerType pointer)
+    {
+        ASSERT((bitwise_cast<uint64_t>(pointer) & 0b111) == 0x0);
+        m_data = CompactPointerTuple(pointer, type()).m_data;
+    }
+
+    Type type() const { return static_cast<Type>(decodeType(m_data)); }
+    void setType(Type type)
+    {
+        m_data = CompactPointerTuple(pointer(), type).m_data;
+    }
+
+private:
+    uint64_t m_data { 0 };
+#else
+public:
+    CompactPointerTuple(PointerType pointer, Type type)
+        : m_pointer(pointer)
+        , m_type(type)
+    {
+    }
+
+    PointerType pointer() const { return m_pointer; }
+    void setPointer(PointerType pointer) { m_pointer = pointer; }
+    Type type() const { return m_type; }
+    void setType(Type type) { m_type = type; }
+
+private:
+    PointerType m_pointer { nullptr };
+    Type m_type { 0 };
+#endif
+};
+
+} // namespace WTF
+
+using WTF::CompactPointerTuple;
index 27ff5f6..0c6efb8 100644 (file)
 #define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
 #endif
 
+#if COMPILER(GCC_OR_CLANG)
+/* __LP64__ is not defined on 64bit Windows since it uses LLP64. Using __SIZEOF_POINTER__ is simpler. */
+#if __SIZEOF_POINTER__ == 8
+#define WTF_CPU_ADDRESS64 1
+#elif __SIZEOF_POINTER__ == 4
+#define WTF_CPU_ADDRESS32 1
+#else
+#error "Unsupported pointer width"
+#endif
+#elif COMPILER(MSVC)
+#if defined(_WIN64)
+#define WTF_CPU_ADDRESS64 1
+#else
+#define WTF_CPU_ADDRESS32 1
+#endif
+#else
+/* This is the most generic way. But in OS(DARWIN), Platform.h can be included by sandbox definition file (.sb).
+ * At that time, we cannot include "stdint.h" header. So in the case of known compilers, we use predefined constants instead. */
+#include <stdint.h>
+#if UINTPTR_MAX > UINT32_MAX
+#define WTF_CPU_ADDRESS64 1
+#else
+#define WTF_CPU_ADDRESS32 1
+#endif
+#endif
+
 /* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit ==== */
 
 #endif
 
 #if !defined(USE_JSVALUE64) && !defined(USE_JSVALUE32_64)
-#if COMPILER(GCC_OR_CLANG)
-/* __LP64__ is not defined on 64bit Windows since it uses LLP64. Using __SIZEOF_POINTER__ is simpler. */
-#if __SIZEOF_POINTER__ == 8
-#define USE_JSVALUE64 1
-#elif __SIZEOF_POINTER__ == 4
-#define USE_JSVALUE32_64 1
-#else
-#error "Unsupported pointer width"
-#endif
-#elif COMPILER(MSVC)
-#if defined(_WIN64)
+#if CPU(ADDRESS64)
 #define USE_JSVALUE64 1
 #else
 #define USE_JSVALUE32_64 1
 #endif
-#else
-/* This is the most generic way. But in OS(DARWIN), Platform.h can be included by sandbox definition file (.sb).
- * At that time, we cannot include "stdint.h" header. So in the case of known compilers, we use predefined constants instead. */
-#include <stdint.h>
-#if UINTPTR_MAX > UINT32_MAX
-#define USE_JSVALUE64 1
-#else
-#define USE_JSVALUE32_64 1
-#endif
-#endif
 #endif /* !defined(USE_JSVALUE64) && !defined(USE_JSVALUE32_64) */
 
 /* The JIT is enabled by default on all x86, x86-64, ARM & MIPS platforms except ARMv7k. */