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

Changeset 293710 in webkit


Ignore:
Timestamp:
May 2, 2022, 8:02:04 PM (4 years ago)
Author:
ysuzuki@apple.com
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.
Relanding with debug build failure & crash on static atomSize assumption in IsoSubspace.

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • heap/Heap.cpp:
  • heap/IsoSubspace.h:

(JSC::GCClient::IsoSubspace::allocatorFor):

  • heap/IsoSubspaceInlines.h:

(JSC::GCClient::IsoSubspace::allocate):

  • heap/StructureAlignedMemoryAllocator.cpp:

(JSC::StructureMemoryManager::StructureMemoryManager):

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::emitNonNullDecodeStructureID):

  • llint/LLIntOfflineAsmConfig.h:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSCell.h:
  • runtime/JSCellInlines.h:

(JSC::JSCell::JSCell):

  • runtime/Structure.cpp:

(JSC::Structure::Structure):

  • runtime/Structure.h:
  • runtime/StructureID.h:

(JSC::StructureID::decode const):
(JSC::StructureID::tryDecode const):
(JSC::StructureID::encode):

  • tools/IntegrityInlines.h:

(JSC::Integrity::auditStructureID):

Location:
trunk/Source/JavaScriptCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r293708 r293710  
     12022-05-02  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Introduce shifting Structure encoding
     4        https://bugs.webkit.org/show_bug.cgi?id=239957
     5
     6        Reviewed by Mark Lam.
     7
     8        For platforms which have limited amount of virtual address space (<= 36 bits), this patch introduces
     9        shifting Structure encoding. We align Structure on a 32-bytes boundary instead of 16 bytes so that
     10        we can ensure that lower 5 bits are zero. Then, we can use 1 bit for nuke, and shifting 4 bits to
     11        convert 36 bit address to 32 bit StructureID. By using this mechanism, we do not need to allocate
     12        large virtual address space for these platforms. If we an address can have more than 36 bits, then
     13        we should just reserve a larger address region since we have enough address space. Current Structure
     14        size is 112 bytes, which is 3.5 atoms at 32 bytes / atom. Hence, this alignment costs us 16 bytes per
     15        Structure.
     16        Relanding with debug build failure & crash on static atomSize assumption in IsoSubspace.
     17
     18        * ftl/FTLLowerDFGToB3.cpp:
     19        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
     20        * heap/Heap.cpp:
     21        * heap/IsoSubspace.h:
     22        (JSC::GCClient::IsoSubspace::allocatorFor):
     23        * heap/IsoSubspaceInlines.h:
     24        (JSC::GCClient::IsoSubspace::allocate):
     25        * heap/StructureAlignedMemoryAllocator.cpp:
     26        (JSC::StructureMemoryManager::StructureMemoryManager):
     27        * jit/AssemblyHelpers.cpp:
     28        (JSC::AssemblyHelpers::emitNonNullDecodeStructureID):
     29        * llint/LLIntOfflineAsmConfig.h:
     30        * llint/LowLevelInterpreter64.asm:
     31        * runtime/JSCell.h:
     32        * runtime/JSCellInlines.h:
     33        (JSC::JSCell::JSCell):
     34        * runtime/Structure.cpp:
     35        (JSC::Structure::Structure):
     36        * runtime/Structure.h:
     37        * runtime/StructureID.h:
     38        (JSC::StructureID::decode const):
     39        (JSC::StructureID::tryDecode const):
     40        (JSC::StructureID::encode):
     41        * tools/IntegrityInlines.h:
     42        (JSC::Integrity::auditStructureID):
     43
    1442022-05-01  Yusuke Suzuki  <ysuzuki@apple.com>
    245
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r293685 r293710  
    2101521015    LValue decodeNonNullStructure(LValue structureID)
    2101621016    {
    21017         LValue maskedStructureID = m_out.bitAnd(structureID, m_out.constInt32(structureIDMask));
     21017#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     21018        return m_out.shl(m_out.zeroExtPtr(structureID), m_out.constIntPtr(StructureID::encodeShiftAmount));
     21019#else
     21020        LValue maskedStructureID = m_out.bitAnd(structureID, m_out.constInt32(StructureID::structureIDMask));
    2101821021        return m_out.add(m_out.constIntPtr(g_jscConfig.startOfStructureHeap), m_out.zeroExtPtr(maskedStructureID));
     21022#endif
    2101921023    }
    2102021024
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r293685 r293710  
    270270
    271271#define INIT_SERVER_STRUCTURE_ISO_SUBSPACE(name, heapCellType, type) \
    272     , name("Isolated" #name "Space", *this, heapCellType, sizeof(type), type::numberOfLowerTierCells, makeUnique<StructureAlignedMemoryAllocator>("Structure"))
     272    , name("Isolated" #name "Space", *this, heapCellType, WTF::roundUpToMultipleOf<type::atomSize>(sizeof(type)), type::numberOfLowerTierCells, makeUnique<StructureAlignedMemoryAllocator>("Structure"))
    273273
    274274Heap::Heap(VM& vm, HeapType heapType)
  • trunk/Source/JavaScriptCore/heap/IsoSubspace.h

    r290129 r293710  
    9393ALWAYS_INLINE Allocator IsoSubspace::allocatorFor(size_t size, AllocatorForMode)
    9494{
    95     RELEASE_ASSERT(WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(size) == cellSize());
     95    RELEASE_ASSERT(size <= cellSize());
    9696    return Allocator(&m_localAllocator);
    9797}
  • trunk/Source/JavaScriptCore/heap/IsoSubspaceInlines.h

    r290129 r293710  
    3232ALWAYS_INLINE void* IsoSubspace::allocate(VM& vm, size_t size, GCDeferralContext* deferralContext, AllocationFailureMode failureMode)
    3333{
    34     RELEASE_ASSERT(WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(size) == cellSize());
     34    RELEASE_ASSERT(size <= cellSize());
    3535    Allocator allocator = allocatorFor(size, AllocatorForMode::MustAlreadyHaveAllocator);
    3636    void* result = allocator.allocate(vm.heap, deferralContext, failureMode);
  • trunk/Source/JavaScriptCore/heap/StructureAlignedMemoryAllocator.cpp

    r293685 r293710  
    6767}
    6868
    69 #if CPU(ADDRESS64)
     69#if CPU(ADDRESS64) && !ENABLE(STRUCTURE_ID_WITH_SHIFT)
    7070
    7171class StructureMemoryManager {
    … …  
    8484        }
    8585        g_jscConfig.sizeOfStructureHeap = mappedHeapSize;
    86         RELEASE_ASSERT(g_jscConfig.startOfStructureHeap && ((g_jscConfig.startOfStructureHeap & ~structureIDMask) == g_jscConfig.startOfStructureHeap));
     86        RELEASE_ASSERT(g_jscConfig.startOfStructureHeap && ((g_jscConfig.startOfStructureHeap & ~StructureID::structureIDMask) == g_jscConfig.startOfStructureHeap));
    8787    }
    8888
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp

    r293685 r293710  
    406406void AssemblyHelpers::emitNonNullDecodeStructureID(RegisterID source, RegisterID dest)
    407407{
     408#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     409    lshift64(source, TrustedImm32(StructureID::encodeShiftAmount), dest);
     410#elif CPU(ADDRESS64)
     411    // 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.
     412    and32(TrustedImm32(StructureID::structureIDMask), source, dest);
     413    add64(TrustedImm64(g_jscConfig.startOfStructureHeap), dest);
     414#else // not CPU(ADDRESS64)
    408415    move(source, dest);
    409 #if CPU(ADDRESS64)
    410     // 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.
    411     and32(TrustedImm32(structureIDMask), dest);
    412     add64(TrustedImm64(g_jscConfig.startOfStructureHeap), dest);
    413 #endif // not CPU(ADDRESS64)
     416#endif
    414417}
    415418
  • trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h

    r293685 r293710  
    2727
    2828#include "LLIntCommon.h"
     29#include "StructureID.h"
    2930#include <wtf/Assertions.h>
    3031#include <wtf/Gigacage.h>
    … …  
    162163#endif
    163164
     165#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     166#define OFFLINE_ASM_STRUCTURE_ID_WITH_SHIFT 1
     167#else
     168#define OFFLINE_ASM_STRUCTURE_ID_WITH_SHIFT 0
     169#endif
     170
    164171#if ASSERT_ENABLED
    165172#define OFFLINE_ASM_ASSERT_ENABLED 1
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r293685 r293710  
    742742
    743743macro structureIDToStructureWithScratch(structureIDThenStructure, scratch)
    744     if ADDRESS64
    745         andq constexpr structureIDMask, structureIDThenStructure
     744    if STRUCTURE_ID_WITH_SHIFT
     745        lshiftp (constexpr StructureID::encodeShiftAmount), structureIDThenStructure
     746    elsif ADDRESS64
     747        andq (constexpr StructureID::structureIDMask), structureIDThenStructure
    746748        leap JSCConfig + constexpr JSC::offsetOfJSCConfigStartOfStructureHeap, scratch
    747749        loadp [scratch], scratch
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r293685 r293710  
    9090    static constexpr uint8_t numberOfLowerTierCells = 8;
    9191
     92    static constexpr size_t atomSize = 16; // This needs to be larger or equal to 16.
     93
    9294    static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
    9395
  • trunk/Source/JavaScriptCore/runtime/JSCellInlines.h

    r293685 r293710  
    7676    // structure pointer is still alive at this point.
    7777    ensureStillAliveHere(structure);
     78    static_assert(JSCell::atomSize >= MarkedBlock::atomSize);
    7879}
    7980
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r293685 r293710  
    233233
    234234    validateFlags();
     235
     236#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     237    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize>(this) == this);
     238#endif
    235239}
    236240
    … …  
    271275    ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
    272276    ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
     277
     278#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     279    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize>(this) == this);
     280#endif
    273281}
    274282
    … …  
    320328    ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
    321329    ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
     330
     331#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     332    ASSERT(WTF::roundUpToMultipleOf<Structure::atomSize>(this) == this);
     333#endif
    322334}
    323335
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r293685 r293710  
    175175    static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
    176176    static constexpr uint8_t numberOfLowerTierCells = 0;
    177    
     177
     178#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     179    static constexpr size_t atomSize = 32;
     180#endif
     181    static_assert(JSCell::atomSize >= MarkedBlock::atomSize);
     182
    178183    enum PolyProtoTag { PolyProto };
    179184    static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
  • trunk/Source/JavaScriptCore/runtime/StructureID.h

    r293685 r293710  
    3535class Structure;
    3636
    37 constexpr CPURegister structureIDMask = structureHeapAddressSize - 1;
     37// 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.
     38#if CPU(ADDRESS64) && CPU(ARM64) && OS(DARWIN)
     39#if MACH_VM_MAX_ADDRESS_RAW < (1ULL << 36)
     40#define ENABLE_STRUCTURE_ID_WITH_SHIFT 1
     41static_assert(MACH_VM_MAX_ADDRESS_RAW == MACH_VM_MAX_ADDRESS);
     42#endif
     43#endif
    3844
    3945class StructureID {
    4046public:
    4147    static constexpr uint32_t nukedStructureIDBit = 1;
     48
     49#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     50    // 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.
     51    // 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.
     52    // 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
     53    // because we round Structure size with 32 bytes. This lowest bit is used for nuke bit.
     54    static constexpr unsigned encodeShiftAmount = 4;
     55#elif CPU(ADDRESS64)
     56    static constexpr CPURegister structureIDMask = structureHeapAddressSize - 1;
     57#endif
    4258
    4359    StructureID() = default;
    … …  
    6884static_assert(sizeof(StructureID) == sizeof(uint32_t));
    6985
    70 #if CPU(ADDRESS64)
     86#if ENABLE(STRUCTURE_ID_WITH_SHIFT)
     87
     88ALWAYS_INLINE Structure* StructureID::decode() const
     89{
     90    ASSERT(decontaminate());
     91    return reinterpret_cast<Structure*>(static_cast<uintptr_t>(m_bits) << encodeShiftAmount);
     92}
     93
     94ALWAYS_INLINE Structure* StructureID::tryDecode() const
     95{
     96    // Take care to only use the bits from m_bits in the structure's address reservation.
     97    uintptr_t address = static_cast<uintptr_t>(decontaminate().m_bits) << encodeShiftAmount;
     98    if (address < MarkedBlock::blockSize)
     99        return nullptr;
     100    return reinterpret_cast<Structure*>(address);
     101}
     102
     103ALWAYS_INLINE StructureID StructureID::encode(const Structure* structure)
     104{
     105    ASSERT(structure);
     106    auto result = StructureID(reinterpret_cast<uintptr_t>(structure) >> encodeShiftAmount);
     107    ASSERT(result.decode() == structure);
     108    return result;
     109}
     110
     111#elif CPU(ADDRESS64)
    71112
    72113ALWAYS_INLINE Structure* StructureID::decode() const
  • trunk/Source/JavaScriptCore/tools/IntegrityInlines.h

    r293685 r293710  
    7878{
    7979    UNUSED_PARAM(structureID);
    80 #if CPU(ADDRESS64)
     80#if CPU(ADDRESS64) && !ENABLE(STRUCTURE_ID_WITH_SHIFT)
    8181    ASSERT(structureID.bits() <= structureHeapAddressSize + StructureID::nukedStructureIDBit);
    8282#endif
Note: See TracChangeset for help on using the changeset viewer.