Changeset 108291 in webkit


Ignore:
Timestamp:
Feb 20, 2012 7:20:37 PM (12 years ago)
Author:
mhahnenberg@apple.com
Message:

Implement fast path for op_new_array in the baseline JIT
https://bugs.webkit.org/show_bug.cgi?id=78612

Reviewed by Filip Pizlo.

  • heap/CopiedAllocator.h:

(CopiedAllocator): Friended the JIT to allow access to m_currentOffset.

  • heap/CopiedSpace.h:

(CopiedSpace): Friended the JIT to allow access to
(JSC::CopiedSpace::allocator):

  • heap/Heap.h:

(JSC::Heap::storageAllocator): Added a getter for the CopiedAllocator class so the JIT
can use it for simple allocation i.e. when we can just bump the offset without having to
do anything else.

  • jit/JIT.cpp:

(JSC::JIT::privateCompileSlowCases): Added new slow case for op_new_array for when
we have to bail out because the fast allocation path fails for whatever reason.

  • jit/JIT.h:

(JIT):

  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicStorage): Added utility function that allows objects to
allocate generic backing stores. This function is used by emitAllocateJSArray.
(JSC):
(JSC::JIT::emitAllocateJSArray): Added utility function that allows the client to
more easily allocate JSArrays. This function is used by emit_op_new_array and I expect
it will also be used for emit_op_new_array_buffer.

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_new_array): Changed to do inline allocation of JSArrays. Still does
a stub call for oversize arrays.
(JSC):
(JSC::JIT::emitSlow_op_new_array): Just bails out to a stub call if we fail in any way on
the fast path.

  • runtime/JSArray.cpp:

(JSC):

  • runtime/JSArray.h: Added lots of offset functions for all the fields that we need to

initialize in the JIT.
(ArrayStorage):
(JSC::ArrayStorage::lengthOffset):
(JSC::ArrayStorage::numValuesInVectorOffset):
(JSC::ArrayStorage::allocBaseOffset):
(JSC::ArrayStorage::vectorOffset):
(JSArray):
(JSC::JSArray::sparseValueMapOffset):
(JSC::JSArray::subclassDataOffset):
(JSC::JSArray::indexBiasOffset):
(JSC):
(JSC::JSArray::storageSize): Moved this function from being a static function in the cpp file
to being a static function in the JSArray class. This move allows the JIT to call it to
see what size it should allocate.

Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r108282 r108291  
     12012-02-20  Mark Hahnenberg  <mhahnenberg@apple.com>
     2
     3        Implement fast path for op_new_array in the baseline JIT
     4        https://bugs.webkit.org/show_bug.cgi?id=78612
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * heap/CopiedAllocator.h:
     9        (CopiedAllocator): Friended the JIT to allow access to m_currentOffset.
     10        * heap/CopiedSpace.h:
     11        (CopiedSpace): Friended the JIT to allow access to
     12        (JSC::CopiedSpace::allocator):
     13        * heap/Heap.h:
     14        (JSC::Heap::storageAllocator): Added a getter for the CopiedAllocator class so the JIT
     15        can use it for simple allocation i.e. when we can just bump the offset without having to
     16        do anything else.
     17        * jit/JIT.cpp:
     18        (JSC::JIT::privateCompileSlowCases): Added new slow case for op_new_array for when
     19        we have to bail out because the fast allocation path fails for whatever reason.
     20        * jit/JIT.h:
     21        (JIT):
     22        * jit/JITInlineMethods.h:
     23        (JSC::JIT::emitAllocateBasicStorage): Added utility function that allows objects to
     24        allocate generic backing stores. This function is used by emitAllocateJSArray.
     25        (JSC):
     26        (JSC::JIT::emitAllocateJSArray): Added utility function that allows the client to
     27        more easily allocate JSArrays. This function is used by emit_op_new_array and I expect
     28        it will also be used for emit_op_new_array_buffer.
     29        * jit/JITOpcodes.cpp:
     30        (JSC::JIT::emit_op_new_array): Changed to do inline allocation of JSArrays. Still does
     31        a stub call for oversize arrays.
     32        (JSC):
     33        (JSC::JIT::emitSlow_op_new_array): Just bails out to a stub call if we fail in any way on
     34        the fast path.
     35        * runtime/JSArray.cpp:
     36        (JSC):
     37        * runtime/JSArray.h: Added lots of offset functions for all the fields that we need to
     38        initialize in the JIT.
     39        (ArrayStorage):
     40        (JSC::ArrayStorage::lengthOffset):
     41        (JSC::ArrayStorage::numValuesInVectorOffset):
     42        (JSC::ArrayStorage::allocBaseOffset):
     43        (JSC::ArrayStorage::vectorOffset):
     44        (JSArray):
     45        (JSC::JSArray::sparseValueMapOffset):
     46        (JSC::JSArray::subclassDataOffset):
     47        (JSC::JSArray::indexBiasOffset):
     48        (JSC):
     49        (JSC::JSArray::storageSize): Moved this function from being a static function in the cpp file
     50        to being a static function in the JSArray class. This move allows the JIT to call it to
     51        see what size it should allocate.
     52
    1532012-02-20  Gavin Barraclough  <barraclough@apple.com>
    254
  • trunk/Source/JavaScriptCore/heap/CopiedAllocator.h

    r108267 r108291  
    3232
    3333class CopiedAllocator {
     34    friend class JIT;
    3435public:
    3536    CopiedAllocator();
  • trunk/Source/JavaScriptCore/heap/CopiedSpace.h

    r108267 r108291  
    4747class CopiedSpace {
    4848    friend class SlotVisitor;
     49    friend class JIT;
    4950public:
    5051    CopiedSpace(Heap*);
     
    5455    CheckedBoolean tryReallocate(void**, size_t, size_t);
    5556   
     57    CopiedAllocator& allocator() { return m_allocator; }
     58
    5659    void startedCopying();
    5760    void doneCopying();
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r108119 r108291  
    9898        MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); }
    9999        MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); }
     100        CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
    100101        CheckedBoolean tryAllocateStorage(size_t, void**);
    101102        CheckedBoolean tryReallocateStorage(void**, size_t, size_t);
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r107499 r108291  
    478478#endif
    479479        DEFINE_SLOWCASE_OP(op_neq)
     480        DEFINE_SLOWCASE_OP(op_new_array)
    480481        DEFINE_SLOWCASE_OP(op_new_object)
    481482        DEFINE_SLOWCASE_OP(op_new_func)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r107594 r108291  
    337337
    338338        template<typename ClassType, bool destructor, typename StructureType> void emitAllocateBasicJSObject(StructureType, RegisterID result, RegisterID storagePtr);
     339        void emitAllocateBasicStorage(size_t, RegisterID result, RegisterID storagePtr);
    339340        template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
    340341        void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr);
     342        void emitAllocateJSArray(unsigned valuesRegister, unsigned length, RegisterID cellResult, RegisterID storageResult, RegisterID storagePtr);
    341343       
    342344#if ENABLE(VALUE_PROFILER)
     
    958960        void emitSlow_op_new_func(Instruction*, Vector<SlowCaseEntry>::iterator&);
    959961        void emitSlow_op_new_func_exp(Instruction*, Vector<SlowCaseEntry>::iterator&);
    960 
     962        void emitSlow_op_new_array(Instruction*, Vector<SlowCaseEntry>::iterator&);
    961963       
    962964        void emitRightShift(Instruction*, bool isUnsigned);
  • trunk/Source/JavaScriptCore/jit/JITInlineMethods.h

    r107494 r108291  
    455455}
    456456
     457inline void JIT::emitAllocateBasicStorage(size_t size, RegisterID result, RegisterID storagePtr)
     458{
     459    CopiedAllocator* allocator = &m_globalData->heap.storageAllocator();
     460
     461    // FIXME: We need to check for wrap-around.
     462    // Check to make sure that the allocation will fit in the current block.
     463    loadPtr(&allocator->m_currentOffset, result);
     464    addPtr(TrustedImm32(size), result);
     465    loadPtr(&allocator->m_currentBlock, storagePtr);
     466    addPtr(TrustedImm32(HeapBlock::s_blockSize), storagePtr);
     467    addSlowCase(branchPtr(AboveOrEqual, result, storagePtr));
     468
     469    // Load the original offset.
     470    loadPtr(&allocator->m_currentOffset, result);
     471
     472    // Bump the pointer forward.
     473    move(result, storagePtr);
     474    addPtr(TrustedImm32(size), storagePtr);
     475    storePtr(storagePtr, &allocator->m_currentOffset);
     476}
     477
     478inline void JIT::emitAllocateJSArray(unsigned valuesRegister, unsigned length, RegisterID cellResult, RegisterID storageResult, RegisterID storagePtr)
     479{
     480    unsigned initialLength = std::max(length, 4U);
     481    size_t initialStorage = JSArray::storageSize(initialLength);
     482
     483    // Allocate the cell for the array.
     484    emitAllocateBasicJSObject<JSArray, false>(TrustedImmPtr(m_codeBlock->globalObject()->arrayStructure()), cellResult, storagePtr);
     485
     486    // Allocate the backing store for the array.
     487    emitAllocateBasicStorage(initialStorage, storageResult, storagePtr);
     488
     489    // Store all the necessary info in the ArrayStorage.
     490    storePtr(storageResult, Address(storageResult, ArrayStorage::allocBaseOffset()));
     491    store32(Imm32(length), Address(storageResult, ArrayStorage::lengthOffset()));
     492    store32(Imm32(length), Address(storageResult, ArrayStorage::numValuesInVectorOffset()));
     493
     494    // Store the newly allocated ArrayStorage.
     495    storePtr(storageResult, Address(cellResult, JSArray::storageOffset()));
     496
     497    // Store the vector length and index bias.
     498    store32(Imm32(initialLength), Address(cellResult, JSArray::vectorLengthOffset()));
     499    store32(TrustedImm32(0), Address(cellResult, JSArray::indexBiasOffset()));
     500
     501    // Initialize the subclass data and the sparse value map.
     502    storePtr(TrustedImmPtr(0), Address(cellResult, JSArray::subclassDataOffset()));
     503    storePtr(TrustedImmPtr(0), Address(cellResult, JSArray::sparseValueMapOffset()));
     504
     505    // Store the values we have.
     506    for (unsigned i = 0; i < length; i++) {
     507        loadPtr(Address(callFrameRegister, (valuesRegister + i) * sizeof(Register)), storagePtr);
     508        storePtr(storagePtr, Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i));
     509    }
     510
     511    // Zero out the remaining slots.
     512    for (unsigned i = length; i < initialLength; i++)
     513        storePtr(TrustedImmPtr(0), Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i));
     514}
     515
    457516#if ENABLE(VALUE_PROFILER)
    458517inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile)
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r108112 r108291  
    3030
    3131#include "Arguments.h"
     32#include "CopiedSpaceInlineMethods.h"
    3233#include "Heap.h"
    3334#include "JITInlineMethods.h"
     
    16461647void JIT::emit_op_new_array(Instruction* currentInstruction)
    16471648{
     1649    int length = currentInstruction[3].u.operand;
     1650    // FIXME: Add support for non-empty arrays. This involves copying the values over.
     1651    if (CopiedSpace::isOversize(JSArray::storageSize(length))) {
     1652        JITStubCall stubCall(this, cti_op_new_array);
     1653        stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
     1654        stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
     1655        stubCall.call(currentInstruction[1].u.operand);
     1656        return;
     1657    }
     1658    int dst = currentInstruction[1].u.operand;
     1659    int values = currentInstruction[2].u.operand;
     1660
     1661    emitAllocateJSArray(values, length, regT0, regT1, regT2);
     1662    emitStoreCell(dst, regT0);
     1663}
     1664
     1665void JIT::emitSlow_op_new_array(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1666{
     1667    int length = currentInstruction[3].u.operand;
     1668    if (CopiedSpace::isOversize(JSArray::storageSize(length)))
     1669        return;
     1670    linkSlowCase(iter); // Not enough space in MarkedSpace for cell.
     1671    linkSlowCase(iter); // Not enough space in CopiedSpace for storage.
    16481672    JITStubCall stubCall(this, cti_op_new_array);
    16491673    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r108107 r108291  
    104104// This value is capped by the constant FIRST_VECTOR_GROW defined above.
    105105static unsigned lastArraySize = 0;
    106 
    107 static inline size_t storageSize(unsigned vectorLength)
    108 {
    109     ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH);
    110 
    111     // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH)
    112     // - as asserted above - the following calculation cannot overflow.
    113     size_t size = (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) + (vectorLength * sizeof(WriteBarrier<Unknown>));
    114     // Assertion to detect integer overflow in previous calculation (should not be possible, provided that
    115     // MAX_STORAGE_VECTOR_LENGTH is correctly defined).
    116     ASSERT(((size - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))));
    117 
    118     return size;
    119 }
    120106
    121107static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
  • trunk/Source/JavaScriptCore/runtime/JSArray.h

    r107956 r108291  
    120120#endif
    121121        WriteBarrier<Unknown> m_vector[1];
     122
     123        static ptrdiff_t lengthOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_length); }
     124        static ptrdiff_t numValuesInVectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector); }
     125        static ptrdiff_t allocBaseOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_allocBase); }
     126        static ptrdiff_t vectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_vector); }
    122127    };
    123128
    124129    class JSArray : public JSNonFinalObject {
    125130        friend class Walker;
     131        friend class JIT;
    126132
    127133    protected:
     
    259265
    260266    private:
     267        static size_t storageSize(unsigned vectorLength);
    261268        bool isLengthWritable()
    262269        {
     
    290297        SparseArrayValueMap* m_sparseValueMap;
    291298        void* m_subclassData; // A JSArray subclass can use this to fill the vector lazily.
     299
     300        static ptrdiff_t sparseValueMapOffset() { return OBJECT_OFFSETOF(JSArray, m_sparseValueMap); }
     301        static ptrdiff_t subclassDataOffset() { return OBJECT_OFFSETOF(JSArray, m_subclassData); }
     302        static ptrdiff_t indexBiasOffset() { return OBJECT_OFFSETOF(JSArray, m_indexBias); }
    292303    };
    293304
     
    331342    }
    332343
    333 } // namespace JSC
     344// The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize
     345// function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage
     346// size calculation cannot overflow.  (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) +
     347// (vectorLength * sizeof(WriteBarrier<Unknown>)) must be <= 0xFFFFFFFFU (which is maximum value of size_t).
     348#define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>))
     349
     350// These values have to be macros to be used in max() and min() without introducing
     351// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
     352#define MIN_SPARSE_ARRAY_INDEX 10000U
     353#define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1)
     354    inline size_t JSArray::storageSize(unsigned vectorLength)
     355    {
     356        ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH);
     357   
     358        // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH)
     359        // - as asserted above - the following calculation cannot overflow.
     360        size_t size = (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) + (vectorLength * sizeof(WriteBarrier<Unknown>));
     361        // Assertion to detect integer overflow in previous calculation (should not be possible, provided that
     362        // MAX_STORAGE_VECTOR_LENGTH is correctly defined).
     363        ASSERT(((size - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))));
     364   
     365        return size;
     366    }
     367   
     368    } // namespace JSC
    334369
    335370#endif // JSArray_h
Note: See TracChangeset for help on using the changeset viewer.