Changeset 167641 in webkit


Ignore:
Timestamp:
Apr 21, 2014 6:37:34 PM (10 years ago)
Author:
mhahnenberg@apple.com
Message:

Arguments objects shouldn't need a destructor
https://bugs.webkit.org/show_bug.cgi?id=131899

Reviewed by Oliver Hunt.

This patch rids Arguments objects of their destructors. It does this by
switching their backing stores to use CopiedSpace rather than malloc memory.

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::emitAllocateArguments): Fix the code emitted for inline
Arguments allocation so that it only emits an extra write for strict mode code rather
than unconditionally.

  • heap/CopyToken.h: New CopyTokens for the two different types of Arguments backing stores.
  • runtime/Arguments.cpp:

(JSC::Arguments::visitChildren): We need to tell the collector to copy the back stores now.
(JSC::Arguments::copyBackingStore): Do the actual copying of the backing stores.
(JSC::Arguments::deletePropertyByIndex): Update all the accesses to SlowArgumentData and m_registerArray.
(JSC::Arguments::deleteProperty):
(JSC::Arguments::defineOwnProperty):
(JSC::Arguments::allocateRegisterArray):
(JSC::Arguments::tearOff):
(JSC::Arguments::destroy): Deleted. We don't need the destructor any more.

  • runtime/Arguments.h:

(JSC::Arguments::registerArraySizeInBytes):
(JSC::Arguments::SlowArgumentData::SlowArgumentData): Switch SlowArgumentData to being allocated
in CopiedSpace. Now the SlowArgumentData and its backing store are a single contiguous CopiedSpace
allocation.
(JSC::Arguments::SlowArgumentData::slowArguments):
(JSC::Arguments::SlowArgumentData::bytecodeToMachineCaptureOffset):
(JSC::Arguments::SlowArgumentData::setBytecodeToMachineCaptureOffset):
(JSC::Arguments::SlowArgumentData::sizeForNumArguments):
(JSC::Arguments::Arguments):
(JSC::Arguments::allocateSlowArguments):
(JSC::Arguments::tryDeleteArgument):
(JSC::Arguments::isDeletedArgument):
(JSC::Arguments::isArgument):
(JSC::Arguments::argument):
(JSC::Arguments::finishCreation):

  • runtime/SymbolTable.h:
Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r167632 r167641  
     12014-04-21  Mark Hahnenberg  <mhahnenberg@apple.com>
     2
     3        Arguments objects shouldn't need a destructor
     4        https://bugs.webkit.org/show_bug.cgi?id=131899
     5
     6        Reviewed by Oliver Hunt.
     7
     8        This patch rids Arguments objects of their destructors. It does this by
     9        switching their backing stores to use CopiedSpace rather than malloc memory.
     10
     11        * dfg/DFGSpeculativeJIT.cpp:
     12        (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Fix the code emitted for inline
     13        Arguments allocation so that it only emits an extra write for strict mode code rather
     14        than unconditionally.
     15        * heap/CopyToken.h: New CopyTokens for the two different types of Arguments backing stores.
     16        * runtime/Arguments.cpp:
     17        (JSC::Arguments::visitChildren): We need to tell the collector to copy the back stores now.
     18        (JSC::Arguments::copyBackingStore): Do the actual copying of the backing stores.
     19        (JSC::Arguments::deletePropertyByIndex): Update all the accesses to SlowArgumentData and m_registerArray.
     20        (JSC::Arguments::deleteProperty):
     21        (JSC::Arguments::defineOwnProperty):
     22        (JSC::Arguments::allocateRegisterArray):
     23        (JSC::Arguments::tearOff):
     24        (JSC::Arguments::destroy): Deleted. We don't need the destructor any more.
     25        * runtime/Arguments.h:
     26        (JSC::Arguments::registerArraySizeInBytes):
     27        (JSC::Arguments::SlowArgumentData::SlowArgumentData): Switch SlowArgumentData to being allocated
     28        in CopiedSpace. Now the SlowArgumentData and its backing store are a single contiguous CopiedSpace
     29        allocation.
     30        (JSC::Arguments::SlowArgumentData::slowArguments):
     31        (JSC::Arguments::SlowArgumentData::bytecodeToMachineCaptureOffset):
     32        (JSC::Arguments::SlowArgumentData::setBytecodeToMachineCaptureOffset):
     33        (JSC::Arguments::SlowArgumentData::sizeForNumArguments):
     34        (JSC::Arguments::Arguments):
     35        (JSC::Arguments::allocateSlowArguments):
     36        (JSC::Arguments::tryDeleteArgument):
     37        (JSC::Arguments::isDeletedArgument):
     38        (JSC::Arguments::isArgument):
     39        (JSC::Arguments::argument):
     40        (JSC::Arguments::finishCreation):
     41        * runtime/SymbolTable.h:
     42
    1432014-04-21  Eric Carlson  <eric.carlson@apple.com>
    244
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r167591 r167641  
    119119
    120120    m_jit.store32(TrustedImm32(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfOverrodeLength()));
    121     m_jit.store8(TrustedImm32(m_jit.isStrictModeFor(m_currentNode->origin.semantic)),
    122         MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode()));
     121    if (m_jit.isStrictModeFor(m_currentNode->origin.semantic))
     122        m_jit.store8(TrustedImm32(1), MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode()));
    123123
    124124    m_jit.storePtr(GPRInfo::callFrameRegister, MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisters()));
  • trunk/Source/JavaScriptCore/heap/CopyToken.h

    r154861 r167641  
    3232    ButterflyCopyToken,
    3333    TypedArrayVectorCopyToken,
    34     MapBackingStoreCopyToken
     34    MapBackingStoreCopyToken,
     35    ArgumentsRegisterArrayCopyToken,
     36    ArgumentsSlowArgumentDataCopyToken
    3537};
    3638
  • trunk/Source/JavaScriptCore/runtime/Arguments.cpp

    r166493 r167641  
    2626#include "Arguments.h"
    2727
     28#include "CopyVisitorInlines.h"
    2829#include "JSActivation.h"
    2930#include "JSArgumentsIterator.h"
     
    3637namespace JSC {
    3738
     39STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(Arguments);
     40
    3841const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
    3942
     
    4649    JSObject::visitChildren(thisObject, visitor);
    4750
    48     if (thisObject->m_registerArray)
     51    if (thisObject->m_registerArray) {
     52        visitor.copyLater(thisObject, ArgumentsRegisterArrayCopyToken,
     53            thisObject->m_registerArray.get(), thisObject->registerArraySizeInBytes());
    4954        visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments);
     55    }
     56    if (thisObject->m_slowArgumentData) {
     57        visitor.copyLater(thisObject, ArgumentsSlowArgumentDataCopyToken,
     58            thisObject->m_slowArgumentData.get(), SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments));
     59    }
    5060    visitor.append(&thisObject->m_callee);
    5161    visitor.append(&thisObject->m_activation);
    5262}
     63
     64void Arguments::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
     65{
     66    Arguments* thisObject = jsCast<Arguments*>(cell);
     67    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     68   
     69
     70    switch (token) {
     71    case ArgumentsRegisterArrayCopyToken: {
     72        WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
     73        if (!registerArray)
     74            return;
     75
     76        if (visitor.checkIfShouldCopy(registerArray)) {
     77            size_t bytes = thisObject->registerArraySizeInBytes();
     78            WriteBarrier<Unknown>* newRegisterArray = static_cast<WriteBarrier<Unknown>*>(visitor.allocateNewSpace(bytes));
     79            memcpy(newRegisterArray, registerArray, bytes);
     80            thisObject->m_registerArray.setWithoutWriteBarrier(newRegisterArray);
     81            visitor.didCopy(registerArray, bytes);
     82        }
     83        return;
     84    }
     85
     86    case ArgumentsSlowArgumentDataCopyToken: {
     87        SlowArgumentData* slowArgumentData = thisObject->m_slowArgumentData.get();
     88        if (!slowArgumentData)
     89            return;
     90
     91        if (visitor.checkIfShouldCopy(slowArgumentData)) {
     92            size_t bytes = SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments);
     93            SlowArgumentData* newSlowArgumentData = static_cast<SlowArgumentData*>(visitor.allocateNewSpace(bytes));
     94            memcpy(newSlowArgumentData, slowArgumentData, bytes);
     95            thisObject->m_slowArgumentData.setWithoutWriteBarrier(newSlowArgumentData);
     96            visitor.didCopy(slowArgumentData, bytes);
     97        }
     98        return;
     99    }
     100
     101    default:
     102        return;
     103    }
     104}
    53105   
    54106static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*);
    55 
    56 void Arguments::destroy(JSCell* cell)
    57 {
    58     static_cast<Arguments*>(cell)->Arguments::~Arguments();
    59 }
    60107
    61108void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t copyLength, int32_t firstVarArgOffset)
     
    227274        if (!Base::deletePropertyByIndex(cell, exec, i))
    228275            return false;
    229         if (thisObject->tryDeleteArgument(i))
     276        if (thisObject->tryDeleteArgument(exec->vm(), i))
    230277            return true;
    231278    }
     
    244291        if (!Base::deleteProperty(cell, exec, propertyName))
    245292            return false;
    246         if (thisObject->tryDeleteArgument(i))
     293        if (thisObject->tryDeleteArgument(exec->vm(), i))
    247294            return true;
    248295    }
     
    289336            if (descriptor.isAccessorDescriptor()) {
    290337                // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
    291                 thisObject->tryDeleteArgument(i);
     338                thisObject->tryDeleteArgument(exec->vm(), i);
    292339            } else { // b. Else
    293340                // i. If Desc.[[Value]] is present, then
     
    298345                // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
    299346                if (descriptor.writablePresent() && !descriptor.writable())
    300                     thisObject->tryDeleteArgument(i);
     347                    thisObject->tryDeleteArgument(exec->vm(), i);
    301348            }
    302349        }
     
    316363}
    317364
     365void Arguments::allocateRegisterArray(VM& vm)
     366{
     367    ASSERT(!m_registerArray);
     368    void* backingStore;
     369    if (!vm.heap.tryAllocateStorage(this, registerArraySizeInBytes(), &backingStore))
     370        RELEASE_ASSERT_NOT_REACHED();
     371    m_registerArray.set(vm, this, static_cast<WriteBarrier<Unknown>*>(backingStore));
     372}
     373
    318374void Arguments::tearOff(CallFrame* callFrame)
    319375{
     
    327383    ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
    328384   
    329     m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments);
     385    allocateRegisterArray(callFrame->vm());
    330386    m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
    331387
     
    335391    if (m_slowArgumentData && !m_activation) {
    336392        for (size_t i = 0; i < m_numArguments; ++i) {
    337             if (m_slowArgumentData->slowArguments[i].status != SlowArgument::Captured)
     393            if (m_slowArgumentData->slowArguments()[i].status != SlowArgument::Captured)
    338394                continue;
    339             m_slowArgumentData->slowArguments[i].status = SlowArgument::Normal;
    340             m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i);
     395            m_slowArgumentData->slowArguments()[i].status = SlowArgument::Normal;
     396            m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
    341397        }
    342398    }
     
    367423        return;
    368424   
    369     m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments);
     425    allocateRegisterArray(callFrame->vm());
    370426    m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
    371427
  • trunk/Source/JavaScriptCore/runtime/Arguments.h

    r167591 r167641  
    2727#include "CodeOrigin.h"
    2828#include "JSActivation.h"
    29 #include "JSDestructibleObject.h"
    3029#include "JSFunction.h"
    3130#include "JSGlobalObject.h"
     
    3736namespace JSC {
    3837
    39 class Arguments : public JSDestructibleObject {
     38class Arguments : public JSNonFinalObject {
    4039    friend class JIT;
    4140    friend class JSArgumentsIterator;
    4241public:
    43     typedef JSDestructibleObject Base;
     42    typedef JSNonFinalObject Base;
    4443
    4544    static Arguments* create(VM& vm, CallFrame* callFrame)
     
    6968
    7069    static void visitChildren(JSCell*, SlotVisitor&);
     70    static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
    7171
    7272    void fillArgList(ExecState*, MarkedArgumentBuffer&);
     
    112112
    113113private:
    114     static void destroy(JSCell*);
    115114    static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
    116115    static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
     
    124123    void createStrictModeCalleeIfNecessary(ExecState*);
    125124
     125    size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier<Unknown>) * m_numArguments; }
     126    void allocateRegisterArray(VM&);
    126127    bool isArgument(size_t);
    127128    bool trySetArgument(VM&, size_t argument, JSValue);
    128129    JSValue tryGetArgument(size_t argument);
    129130    bool isDeletedArgument(size_t);
    130     bool tryDeleteArgument(size_t);
     131    bool tryDeleteArgument(VM&, size_t);
    131132    WriteBarrierBase<Unknown>& argument(size_t);
    132     void allocateSlowArguments();
     133    void allocateSlowArguments(VM&);
    133134
    134135    void init(CallFrame*);
     
    147148
    148149    WriteBarrierBase<Unknown>* m_registers;
    149     std::unique_ptr<WriteBarrier<Unknown>[]> m_registerArray;
     150    CopyWriteBarrier<WriteBarrier<Unknown>> m_registerArray;
    150151
    151152public:
    152153    struct SlowArgumentData {
    153         WTF_MAKE_FAST_ALLOCATED;
    154154    public:
    155 
    156         std::unique_ptr<SlowArgument[]> slowArguments;
    157         int bytecodeToMachineCaptureOffset; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite.
     155        SlowArgumentData()
     156            : m_bytecodeToMachineCaptureOffset(0)
     157        {
     158        }
     159
     160        SlowArgument* slowArguments()
     161        {
     162            return reinterpret_cast<SlowArgument*>(WTF::roundUpToMultipleOf<8>(reinterpret_cast<size_t>(this + 1)));
     163        }
     164
     165        int bytecodeToMachineCaptureOffset() const { return m_bytecodeToMachineCaptureOffset; }
     166        void setBytecodeToMachineCaptureOffset(int newOffset) { m_bytecodeToMachineCaptureOffset = newOffset; }
     167
     168        static size_t sizeForNumArguments(unsigned numArguments)
     169        {
     170            return WTF::roundUpToMultipleOf<8>(sizeof(SlowArgumentData)) + sizeof(SlowArgument) * numArguments;
     171        }
     172
     173    private:
     174        int m_bytecodeToMachineCaptureOffset; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite.
    158175    };
    159176   
    160177private:
    161     std::unique_ptr<SlowArgumentData> m_slowArgumentData;
     178    CopyWriteBarrier<SlowArgumentData> m_slowArgumentData;
    162179
    163180    WriteBarrier<JSFunction> m_callee;
     
    173190
    174191inline Arguments::Arguments(CallFrame* callFrame)
    175     : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
     192    : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
    176193{
    177194}
    178195
    179196inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
    180     : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
    181 {
    182 }
    183 
    184 inline void Arguments::allocateSlowArguments()
    185 {
    186     if (m_slowArgumentData)
     197    : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
     198{
     199}
     200
     201inline void Arguments::allocateSlowArguments(VM& vm)
     202{
     203    if (!!m_slowArgumentData)
    187204        return;
    188     m_slowArgumentData = std::make_unique<SlowArgumentData>();
    189     m_slowArgumentData->bytecodeToMachineCaptureOffset = 0;
    190     m_slowArgumentData->slowArguments = std::make_unique<SlowArgument[]>(m_numArguments);
     205
     206    void* backingStore;
     207    if (!vm.heap.tryAllocateStorage(this, SlowArgumentData::sizeForNumArguments(m_numArguments), &backingStore))
     208        RELEASE_ASSERT_NOT_REACHED();
     209    m_slowArgumentData.set(vm, this, static_cast<SlowArgumentData*>(backingStore));
     210
    191211    for (size_t i = 0; i < m_numArguments; ++i) {
    192         ASSERT(m_slowArgumentData->slowArguments[i].status == SlowArgument::Normal);
    193         m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i);
    194     }
    195 }
    196 
    197 inline bool Arguments::tryDeleteArgument(size_t argument)
     212        ASSERT(m_slowArgumentData->slowArguments()[i].status == SlowArgument::Normal);
     213        m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
     214    }
     215}
     216
     217inline bool Arguments::tryDeleteArgument(VM& vm, size_t argument)
    198218{
    199219    if (!isArgument(argument))
    200220        return false;
    201     allocateSlowArguments();
    202     m_slowArgumentData->slowArguments[argument].status = SlowArgument::Deleted;
     221    allocateSlowArguments(vm);
     222    m_slowArgumentData->slowArguments()[argument].status = SlowArgument::Deleted;
    203223    return true;
    204224}
     
    225245    if (!m_slowArgumentData)
    226246        return false;
    227     if (m_slowArgumentData->slowArguments[argument].status != SlowArgument::Deleted)
     247    if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Deleted)
    228248        return false;
    229249    return true;
     
    234254    if (argument >= m_numArguments)
    235255        return false;
    236     if (m_slowArgumentData && m_slowArgumentData->slowArguments[argument].status == SlowArgument::Deleted)
     256    if (m_slowArgumentData && m_slowArgumentData->slowArguments()[argument].status == SlowArgument::Deleted)
    237257        return false;
    238258    return true;
     
    245265        return m_registers[CallFrame::argumentOffset(argument)];
    246266
    247     int index = m_slowArgumentData->slowArguments[argument].index;
    248     if (!m_activation || m_slowArgumentData->slowArguments[argument].status != SlowArgument::Captured)
     267    int index = m_slowArgumentData->slowArguments()[argument].index;
     268    if (!m_activation || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
    249269        return m_registers[index];
    250270
    251     return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset);
     271    return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
    252272}
    253273
     
    270290        SymbolTable* symbolTable = codeBlock->symbolTable();
    271291        const SlowArgument* slowArguments = codeBlock->machineSlowArguments();
    272         allocateSlowArguments();
     292        allocateSlowArguments(callFrame->vm());
    273293        size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
    274294        for (size_t i = 0; i < count; ++i)
    275             m_slowArgumentData->slowArguments[i] = slowArguments[i];
    276         m_slowArgumentData->bytecodeToMachineCaptureOffset =
    277             codeBlock->framePointerOffsetToGetActivationRegisters();
     295            m_slowArgumentData->slowArguments()[i] = slowArguments[i];
     296        m_slowArgumentData->setBytecodeToMachineCaptureOffset(
     297            codeBlock->framePointerOffsetToGetActivationRegisters());
    278298    }
    279299
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r165676 r167641  
    4040
    4141struct SlowArgument {
    42     WTF_MAKE_FAST_ALLOCATED;
    4342public:
    44 
    4543    enum Status {
    4644        Normal = 0,
Note: See TracChangeset for help on using the changeset viewer.