Title: [293680] trunk/Source/_javascript_Core
Revision
293680
Author
ysuz...@apple.com
Date
2022-05-02 13:15:44 -0700 (Mon, 02 May 2022)

Log Message

[JSC] Introduce shifting Structure encoding
https://bugs.webkit.org/show_bug.cgi?id=239957

Reviewed by Mark Lam.

For platforms which have limited amount of virtual address space (<= 36 bits), this patch introduces
shifting Structure encoding. We align Structure on a 32-bytes boundary instead of 16 bytes so that
we can ensure that lower 5 bits are zero. Then, we can use 1 bit for nuke, and shifting 4 bits to
convert 36 bit address to 32 bit StructureID. By using this mechanism, we do not need to allocate
large virtual address space for these platforms. If we an address can have more than 36 bits, then
we should just reserve a larger address region since we have enough address space. Current Structure
size is 112 bytes, which is 3.5 atoms at 32 bytes / atom. Hence, this alignment costs us 16 bytes per
Structure.

* Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
* Source/_javascript_Core/heap/Heap.cpp:
* Source/_javascript_Core/heap/StructureAlignedMemoryAllocator.cpp:
* Source/_javascript_Core/jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitNonNullDecodeStructureID):
* Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h:
* Source/_javascript_Core/llint/LowLevelInterpreter64.asm:
* Source/_javascript_Core/runtime/JSCConfig.h:
* Source/_javascript_Core/runtime/JSCell.h:
(JSC::JSCell::atomSize):
* Source/_javascript_Core/runtime/Structure.h:
(JSC::Structure::atomSize):
* Source/_javascript_Core/runtime/StructureID.h:
(JSC::StructureID::decode const):
(JSC::StructureID::tryDecode const):
(JSC::StructureID::encode):
* Source/_javascript_Core/tools/IntegrityInlines.h:
(JSC::Integrity::auditStructureID):

Canonical link: https://commits.webkit.org/250179@main

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (293679 => 293680)


--- trunk/Source/_javascript_Core/ChangeLog	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-05-02 20:15:44 UTC (rev 293680)
@@ -1,3 +1,39 @@
+2022-05-02  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Introduce shifting Structure encoding
+        https://bugs.webkit.org/show_bug.cgi?id=239957
+
+        Reviewed by Mark Lam.
+
+        For platforms which have limited amount of virtual address space (<= 36 bits), this patch introduces
+        shifting Structure encoding. We align Structure on a 32-bytes boundary instead of 16 bytes so that
+        we can ensure that lower 5 bits are zero. Then, we can use 1 bit for nuke, and shifting 4 bits to
+        convert 36 bit address to 32 bit StructureID. By using this mechanism, we do not need to allocate
+        large virtual address space for these platforms. If we an address can have more than 36 bits, then
+        we should just reserve a larger address region since we have enough address space. Current Structure
+        size is 112 bytes, which is 3.5 atoms at 32 bytes / atom. Hence, this alignment costs us 16 bytes per
+        Structure.
+
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+        * heap/Heap.cpp:
+        * heap/StructureAlignedMemoryAllocator.cpp:
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::emitNonNullDecodeStructureID):
+        * llint/LLIntOfflineAsmConfig.h:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/JSCConfig.h:
+        * runtime/JSCell.h:
+        (JSC::JSCell::atomSize):
+        * runtime/Structure.h:
+        (JSC::Structure::atomSize):
+        * runtime/StructureID.h:
+        (JSC::StructureID::decode const):
+        (JSC::StructureID::tryDecode const):
+        (JSC::StructureID::encode):
+        * tools/IntegrityInlines.h:
+        (JSC::Integrity::auditStructureID):
+
 2022-05-01  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Revive JSC's guard against speculation collection

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (293679 => 293680)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2022-05-02 20:15:44 UTC (rev 293680)
@@ -21014,8 +21014,12 @@
 
     LValue decodeNonNullStructure(LValue structureID)
     {
-        LValue maskedStructureID = m_out.bitAnd(structureID, m_out.constInt32(structureIDMask));
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+        return m_out.shl(m_out.zeroExtPtr(structureID), m_out.constIntPtr(StructureID::encodeShiftAmount));
+#else
+        LValue maskedStructureID = m_out.bitAnd(structureID, m_out.constInt32(StructureID::structureIDMask));
         return m_out.add(m_out.constIntPtr(g_jscConfig.startOfStructureHeap), m_out.zeroExtPtr(maskedStructureID));
+#endif
     }
 
     LValue loadStructure(LValue value)

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (293679 => 293680)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2022-05-02 20:15:44 UTC (rev 293680)
@@ -269,7 +269,7 @@
     , name ISO_SUBSPACE_INIT(*this, heapCellType, type)
 
 #define INIT_SERVER_STRUCTURE_ISO_SUBSPACE(name, heapCellType, type) \
-    , name("Isolated" #name "Space", *this, heapCellType, sizeof(type), type::numberOfLowerTierCells, makeUnique<StructureAlignedMemoryAllocator>("Structure"))
+    , name("Isolated" #name "Space", *this, heapCellType, WTF::roundUpToMultipleOf<type::atomSize>(sizeof(type)), type::numberOfLowerTierCells, makeUnique<StructureAlignedMemoryAllocator>("Structure"))
 
 Heap::Heap(VM& vm, HeapType heapType)
     : m_heapType(heapType)

Modified: trunk/Source/_javascript_Core/heap/StructureAlignedMemoryAllocator.cpp (293679 => 293680)


--- trunk/Source/_javascript_Core/heap/StructureAlignedMemoryAllocator.cpp	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/heap/StructureAlignedMemoryAllocator.cpp	2022-05-02 20:15:44 UTC (rev 293680)
@@ -66,7 +66,7 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-#if CPU(ADDRESS64)
+#if CPU(ADDRESS64) && !ENABLE(STRUCTURE_ID_WITH_SHIFT)
 
 class StructureMemoryManager {
 public:
@@ -83,7 +83,7 @@
             mappedHeapSize /= 2;
         }
         g_jscConfig.sizeOfStructureHeap = mappedHeapSize;
-        RELEASE_ASSERT(g_jscConfig.startOfStructureHeap && ((g_jscConfig.startOfStructureHeap & ~structureIDMask) == g_jscConfig.startOfStructureHeap));
+        RELEASE_ASSERT(g_jscConfig.startOfStructureHeap && ((g_jscConfig.startOfStructureHeap & ~StructureID::structureIDMask) == g_jscConfig.startOfStructureHeap));
     }
 
     void* tryMallocStructureBlock()

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp (293679 => 293680)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp	2022-05-02 20:15:44 UTC (rev 293680)
@@ -405,12 +405,15 @@
 
 void AssemblyHelpers::emitNonNullDecodeStructureID(RegisterID source, RegisterID dest)
 {
-    move(source, dest);
-#if CPU(ADDRESS64)
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    lshift64(source, TrustedImm32(StructureID::encodeShiftAmount), dest);
+#elif CPU(ADDRESS64)
     // This could use BFI on arm64 but that only helps if the start of structure heap is encodable as a mov and not as an immediate in the add so it's probably not super important.
-    and32(TrustedImm32(structureIDMask), dest);
+    and32(TrustedImm32(StructureID::structureIDMask), source, dest);
     add64(TrustedImm64(g_jscConfig.startOfStructureHeap), dest);
-#endif // not CPU(ADDRESS64)
+#else // not CPU(ADDRESS64)
+    move(source, dest);
+#endif
 }
 
 void AssemblyHelpers::emitLoadStructure(VM&, RegisterID source, RegisterID dest)

Modified: trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h (293679 => 293680)


--- trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "LLIntCommon.h"
+#include "StructureID.h"
 #include <wtf/Assertions.h>
 #include <wtf/Gigacage.h>
 
@@ -161,6 +162,12 @@
 #define OFFLINE_ASM_ADDRESS64 0
 #endif
 
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+#define OFFLINE_ASM_STRUCTURE_ID_WITH_SHIFT 1
+#else
+#define OFFLINE_ASM_STRUCTURE_ID_WITH_SHIFT 0
+#endif
+
 #if ASSERT_ENABLED
 #define OFFLINE_ASM_ASSERT_ENABLED 1
 #else

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (293679 => 293680)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2022-05-02 20:15:44 UTC (rev 293680)
@@ -741,8 +741,10 @@
 end
 
 macro structureIDToStructureWithScratch(structureIDThenStructure, scratch)
-    if ADDRESS64
-        andq constexpr structureIDMask, structureIDThenStructure
+    if STRUCTURE_ID_WITH_SHIFT
+        lshiftp (constexpr StructureID::encodeShiftAmount), structureIDThenStructure
+    elsif ADDRESS64
+        andq (constexpr StructureID::structureIDMask), structureIDThenStructure
         leap JSCConfig + constexpr JSC::offsetOfJSCConfigStartOfStructureHeap, scratch
         loadp [scratch], scratch
         addp scratch, structureIDThenStructure

Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (293679 => 293680)


--- trunk/Source/_javascript_Core/runtime/JSCell.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -89,6 +89,8 @@
 
     static constexpr uint8_t numberOfLowerTierCells = 8;
 
+    static constexpr size_t atomSize = 16; // This needs to be larger or equal to 16.
+
     static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
 
     enum CreatingEarlyCellTag { CreatingEarlyCell };

Modified: trunk/Source/_javascript_Core/runtime/JSCellInlines.h (293679 => 293680)


--- trunk/Source/_javascript_Core/runtime/JSCellInlines.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/runtime/JSCellInlines.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -75,6 +75,7 @@
     // cell is even constructed. To avoid this possibility, we need to ensure that the
     // structure pointer is still alive at this point.
     ensureStillAliveHere(structure);
+    static_assert(JSCell::atomSize >= MarkedBlock::atomSize);
 }
 
 inline void JSCell::finishCreation(VM& vm)

Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (293679 => 293680)


--- trunk/Source/_javascript_Core/runtime/Structure.cpp	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp	2022-05-02 20:15:44 UTC (rev 293680)
@@ -232,6 +232,10 @@
     ASSERT(hasGetterSetterProperties() == m_classInfo->hasStaticSetterOrReadonlyProperties());
 
     validateFlags();
+
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize()>(this) == this);
+#endif
 }
 
 const ClassInfo Structure::s_info = { "Structure"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(Structure) };
@@ -270,6 +274,10 @@
     ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
     ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
     ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
+
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize()>(this) == this);
+#endif
 }
 
 Structure::Structure(VM& vm, Structure* previous)
@@ -319,6 +327,10 @@
     ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
     ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
     ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
+
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize()>(this) == this);
+#endif
 }
 
 Structure::~Structure()

Modified: trunk/Source/_javascript_Core/runtime/Structure.h (293679 => 293680)


--- trunk/Source/_javascript_Core/runtime/Structure.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/runtime/Structure.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -174,7 +174,12 @@
     typedef JSCell Base;
     static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
     static constexpr uint8_t numberOfLowerTierCells = 0;
-    
+
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    static constexpr size_t atomSize = 32;
+#endif
+    static_assert(JSCell::atomSize >= MarkedBlock::atomSize);
+
     enum PolyProtoTag { PolyProto };
     static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
     static Structure* create(PolyProtoTag, VM&, JSGlobalObject*, JSObject* prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);

Modified: trunk/Source/_javascript_Core/runtime/StructureID.h (293679 => 293680)


--- trunk/Source/_javascript_Core/runtime/StructureID.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/runtime/StructureID.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -34,12 +34,28 @@
 
 class Structure;
 
-constexpr CPURegister structureIDMask = structureHeapAddressSize - 1;
+// We would like to define this value in PlatformEnable.h, but it is not possible since the following is relying on MACH_VM_MAX_ADDRESS.
+#if CPU(ADDRESS64) && CPU(ARM64) && OS(DARWIN)
+#if MACH_VM_MAX_ADDRESS_RAW < (1ULL << 36)
+#define ENABLE_STRUCTURE_ID_WITH_SHIFT 1
+static_assert(MACH_VM_MAX_ADDRESS_RAW == MACH_VM_MAX_ADDRESS);
+#endif
+#endif
 
 class StructureID {
 public:
     static constexpr uint32_t nukedStructureIDBit = 1;
 
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
+    // ENABLE(STRUCTURE_ID_WITH_SHIFT) is used when our virtual memory space is limited (specifically, less than or equal to 36 bit) while pointer is 64 bit.
+    // In that case, we round up Structures size with 32 bytes instead of 16 bytes. This ensures that lower 5 bit become zero for Structure.
+    // By shifting this address with 4, we can encode 36 bit address into 32 bit StructureID. And we can ensure that StructureID's lowest bit is still zero
+    // because we round Structure size with 32 bytes. This lowest bit is used for nuke bit.
+    static constexpr unsigned encodeShiftAmount = 4;
+#elif CPU(ADDRESS64)
+    static constexpr CPURegister structureIDMask = structureHeapAddressSize - 1;
+#endif
+
     StructureID() = default;
     StructureID(StructureID const&) = default;
     StructureID& operator=(StructureID const&) = default;
@@ -67,11 +83,36 @@
 };
 static_assert(sizeof(StructureID) == sizeof(uint32_t));
 
-#if CPU(ADDRESS64)
+#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
 
 ALWAYS_INLINE Structure* StructureID::decode() const
 {
+    ASSERT(decontaminate());
+    return reinterpret_cast<Structure*>(static_cast<uintptr_t>(m_bits) << encodeShiftAmount);
+}
+
+ALWAYS_INLINE Structure* StructureID::tryDecode() const
+{
     // Take care to only use the bits from m_bits in the structure's address reservation.
+    uintptr_t address = static_cast<uintptr_t>(decontaminate().m_bits) << encodeShiftAmount;
+    if (address < MarkedBlock::blockSize)
+        return nullptr;
+    return reinterpret_cast<Structure*>(address);
+}
+
+ALWAYS_INLINE StructureID StructureID::encode(const Structure* structure)
+{
+    ASSERT(structure);
+    auto result = StructureID(reinterpret_cast<uintptr_t>(structure) >> encodeShiftAmount);
+    ASSERT(result.decode() == structure);
+    return result;
+}
+
+#elif CPU(ADDRESS64)
+
+ALWAYS_INLINE Structure* StructureID::decode() const
+{
+    // Take care to only use the bits from m_bits in the structure's address reservation.
     ASSERT(decontaminate());
     return reinterpret_cast<Structure*>((static_cast<uintptr_t>(decontaminate().m_bits) & structureIDMask) + g_jscConfig.startOfStructureHeap);
 }

Modified: trunk/Source/_javascript_Core/tools/IntegrityInlines.h (293679 => 293680)


--- trunk/Source/_javascript_Core/tools/IntegrityInlines.h	2022-05-02 20:15:27 UTC (rev 293679)
+++ trunk/Source/_javascript_Core/tools/IntegrityInlines.h	2022-05-02 20:15:44 UTC (rev 293680)
@@ -77,7 +77,7 @@
 ALWAYS_INLINE void auditStructureID(StructureID structureID)
 {
     UNUSED_PARAM(structureID);
-#if CPU(ADDRESS64)
+#if CPU(ADDRESS64) && !ENABLE(STRUCTURE_ID_WITH_SHIFT)
     ASSERT(structureID.bits() <= structureHeapAddressSize + StructureID::nukedStructureIDBit);
 #endif
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to