Ignore:
Timestamp:
Sep 17, 2012, 6:15:04 PM (13 years ago)
Author:
[email protected]
Message:

Refactored the arguments object so it doesn't dictate closure layout
https://bugs.webkit.org/show_bug.cgi?id=96955

Reviewed by Oliver Hunt.

  • bytecode/CodeBlock.h:

(JSC::ExecState::argumentAfterCapture): Helper function for accessing an
argument that has been moved for capture.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator): Generate metadata for arguments
that are captured. We don't move any arguments yet, but we do use this
metadata to tell the arguments object if an argument is stored in the
activation.

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileGetByValOnArguments):
(JSC::DFG::SpeculativeJIT::compileGetArgumentsLength):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile): Updated for the arguments object not
malloc'ing a separate backing store, and for a rename from deletedArguments
to slowArguments.

  • interpreter/CallFrame.h:

(ExecState):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL): Updated for small interface changes.

  • runtime/Arguments.cpp:

(JSC::Arguments::visitChildren):
(JSC::Arguments::copyToArguments):
(JSC::Arguments::fillArgList):
(JSC::Arguments::getOwnPropertySlotByIndex):
(JSC::Arguments::createStrictModeCallerIfNecessary):
(JSC::Arguments::createStrictModeCalleeIfNecessary):
(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::getOwnPropertyDescriptor):
(JSC::Arguments::getOwnPropertyNames):
(JSC::Arguments::putByIndex):
(JSC::Arguments::put):
(JSC::Arguments::deletePropertyByIndex):
(JSC::Arguments::deleteProperty):
(JSC::Arguments::defineOwnProperty):
(JSC::Arguments::tearOff): Moved all data inline into the object, for speed,
and refactored all internal argument accesses to use helper functions, so
we can change the implementation without changing lots of code.

(JSC::Arguments::didTearOffActivation): This function needs to account
for arguments that were moved by the activation object. We do this accounting
through a side vector that tells us where our arguments will be in the
activation.

(JSC::Arguments::tearOffForInlineCallFrame):

  • runtime/Arguments.h:

(Arguments):
(JSC::Arguments::length):
(JSC::Arguments::isTornOff):
(JSC::Arguments::Arguments):
(JSC::Arguments::allocateSlowArguments):
(JSC::Arguments::tryDeleteArgument):
(JSC::Arguments::trySetArgument):
(JSC::Arguments::tryGetArgument):
(JSC::Arguments::isDeletedArgument):
(JSC::Arguments::isArgument):
(JSC::Arguments::argument):
(JSC::Arguments::finishCreation):

  • runtime/JSActivation.h:

(JSC::JSActivation::create):
(JSActivation):
(JSC::JSActivation::captureStart):
(JSC::JSActivation::storageSize):
(JSC::JSActivation::registerOffset):
(JSC::JSActivation::isValid): The activation object is no longer responsible
for copying extra arguments provided by the caller. The argumnents object
does this instead. This means we can allocate and initialize an activation
without worrying about the call frame's argument count.

  • runtime/SymbolTable.h:

(JSC::SlowArgument::SlowArgument):
(SlowArgument):
(JSC):
(JSC::SharedSymbolTable::parameterCount):
(SharedSymbolTable):
(JSC::SharedSymbolTable::slowArguments):
(JSC::SharedSymbolTable::setSlowArguments): Added data structures to back
the algorithms above.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/Arguments.h

    r128813 r128832  
    3535namespace JSC {
    3636
    37     struct ArgumentsData {
    38         WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
    39     public:
    40         ArgumentsData() { }
    41         WriteBarrier<JSActivation> activation;
    42 
    43         unsigned numArguments;
    44 
    45         // We make these full byte booleans to make them easy to test from the JIT,
    46         // and because even if they were single-bit booleans we still wouldn't save
    47         // any space.
    48         bool overrodeLength;
    49         bool overrodeCallee;
    50         bool overrodeCaller;
    51         bool isStrictMode;
    52 
    53         WriteBarrierBase<Unknown>* registers;
    54         OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
    55 
    56         OwnArrayPtr<bool> deletedArguments;
    57 
    58         WriteBarrier<JSFunction> callee;
    59     };
    60 
    6137    class Arguments : public JSDestructibleObject {
     38        friend class JIT;
     39        friend class DFG::SpeculativeJIT;
    6240    public:
    6341        typedef JSDestructibleObject Base;
     
    9674        uint32_t length(ExecState* exec) const
    9775        {
    98             if (UNLIKELY(d->overrodeLength))
     76            if (UNLIKELY(m_overrodeLength))
    9977                return get(exec, exec->propertyNames().length).toUInt32(exec);
    100             return d->numArguments;
     78            return m_numArguments;
    10179        }
    10280       
     
    10482        void tearOff(CallFrame*);
    10583        void tearOff(CallFrame*, InlineCallFrame*);
    106         bool isTornOff() const { return d->registerArray; }
    107         void didTearOffActivation(JSGlobalData& globalData, JSActivation* activation)
    108         {
    109             if (isTornOff())
    110                 return;
    111             d->activation.set(globalData, this, activation);
    112             d->registers = &activation->registerAt(0);
    113         }
     84        bool isTornOff() const { return m_registerArray; }
     85        void didTearOffActivation(ExecState*, JSActivation*);
    11486
    11587        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
     
    11890        }
    11991       
    120         static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(Arguments, d); }
    121 
    12292    protected:
    12393        static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
     
    140110        void createStrictModeCalleeIfNecessary(ExecState*);
    141111
     112        bool isArgument(size_t);
     113        bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
     114        JSValue tryGetArgument(size_t argument);
     115        bool isDeletedArgument(size_t);
     116        bool tryDeleteArgument(size_t);
    142117        WriteBarrierBase<Unknown>& argument(size_t);
     118        void allocateSlowArguments();
    143119
    144120        void init(CallFrame*);
    145121
    146         OwnPtr<ArgumentsData> d;
     122        WriteBarrier<JSActivation> m_activation;
     123
     124        unsigned m_numArguments;
     125
     126        // We make these full byte booleans to make them easy to test from the JIT,
     127        // and because even if they were single-bit booleans we still wouldn't save
     128        // any space.
     129        bool m_overrodeLength;
     130        bool m_overrodeCallee;
     131        bool m_overrodeCaller;
     132        bool m_isStrictMode;
     133
     134        WriteBarrierBase<Unknown>* m_registers;
     135        OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
     136
     137        OwnArrayPtr<SlowArgument> m_slowArguments;
     138
     139        WriteBarrier<JSFunction> m_callee;
    147140    };
    148141
     
    157150    inline Arguments::Arguments(CallFrame* callFrame)
    158151        : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
    159         , d(adoptPtr(new ArgumentsData))
    160152    {
    161153    }
     
    163155    inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
    164156        : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
    165         , d(adoptPtr(new ArgumentsData))
    166     {
    167     }
    168 
    169     inline WriteBarrierBase<Unknown>& Arguments::argument(size_t i)
    170     {
    171         return d->registers[CallFrame::argumentOffset(i)];
     157    {
     158    }
     159
     160    inline void Arguments::allocateSlowArguments()
     161    {
     162        if (m_slowArguments)
     163            return;
     164        m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
     165    }
     166
     167    inline bool Arguments::tryDeleteArgument(size_t argument)
     168    {
     169        if (!isArgument(argument))
     170            return false;
     171        allocateSlowArguments();
     172        m_slowArguments[argument].status = SlowArgument::Deleted;
     173        return true;
     174    }
     175
     176    inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
     177    {
     178        if (!isArgument(argument))
     179            return false;
     180        this->argument(argument).set(globalData, this, value);
     181        return true;
     182    }
     183
     184    inline JSValue Arguments::tryGetArgument(size_t argument)
     185    {
     186        if (!isArgument(argument))
     187            return JSValue();
     188        return this->argument(argument).get();
     189    }
     190
     191    inline bool Arguments::isDeletedArgument(size_t argument)
     192    {
     193        if (argument >= m_numArguments)
     194            return false;
     195        if (!m_slowArguments)
     196            return false;
     197        if (m_slowArguments[argument].status != SlowArgument::Deleted)
     198            return false;
     199        return true;
     200    }
     201
     202    inline bool Arguments::isArgument(size_t argument)
     203    {
     204        if (argument >= m_numArguments)
     205            return false;
     206        if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
     207            return false;
     208        return true;
     209    }
     210
     211    inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
     212    {
     213        ASSERT(isArgument(argument));
     214        if (!m_slowArguments || m_slowArguments[argument].status == SlowArgument::Normal)
     215            return m_registers[CallFrame::argumentOffset(argument)];
     216
     217        ASSERT(m_slowArguments[argument].status == SlowArgument::Captured);
     218        if (!m_activation)
     219            return m_registers[m_slowArguments[argument].indexIfCaptured];
     220
     221        return m_activation->registerAt(m_slowArguments[argument].indexIfCaptured);
    172222    }
    173223
     
    178228
    179229        JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
    180         d->numArguments = callFrame->argumentCount();
    181         d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
    182         d->callee.set(callFrame->globalData(), this, callee);
    183         d->overrodeLength = false;
    184         d->overrodeCallee = false;
    185         d->overrodeCaller = false;
    186         d->isStrictMode = callFrame->codeBlock()->isStrictMode();
     230        m_numArguments = callFrame->argumentCount();
     231        m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
     232        m_callee.set(callFrame->globalData(), this, callee);
     233        m_overrodeLength = false;
     234        m_overrodeCallee = false;
     235        m_overrodeCaller = false;
     236        m_isStrictMode = callFrame->codeBlock()->isStrictMode();
    187237
    188238        // The bytecode generator omits op_tear_off_activation in cases of no
    189239        // declared parameters, so we need to tear off immediately.
    190         if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
     240        if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
    191241            tearOff(callFrame);
    192242    }
     
    198248
    199249        JSFunction* callee = inlineCallFrame->callee.get();
    200         d->numArguments = inlineCallFrame->arguments.size() - 1;
    201         d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
    202         d->callee.set(callFrame->globalData(), this, callee);
    203         d->overrodeLength = false;
    204         d->overrodeCallee = false;
    205         d->overrodeCaller = false;
    206         d->isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
     250        m_numArguments = inlineCallFrame->arguments.size() - 1;
     251        m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
     252        m_callee.set(callFrame->globalData(), this, callee);
     253        m_overrodeLength = false;
     254        m_overrodeCallee = false;
     255        m_overrodeCaller = false;
     256        m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
    207257
    208258        // The bytecode generator omits op_tear_off_activation in cases of no
    209259        // declared parameters, so we need to tear off immediately.
    210         if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
     260        if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
    211261            tearOff(callFrame, inlineCallFrame);
    212262    }
Note: See TracChangeset for help on using the changeset viewer.