Changeset 128260 in webkit


Ignore:
Timestamp:
Sep 11, 2012 9:08:18 PM (12 years ago)
Author:
ggaren@apple.com
Message:

JSActivation should inline allocate its registers, and eliminate
'arguments' registers in the common case
https://bugs.webkit.org/show_bug.cgi?id=96427

Reviewed by Filip Pizlo.

This cuts the size class for simple closures down to 64 bytes.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator): Set the usesNonStrictEval
flag, which is new. Use a more specific test for whether a function
uses 'arguments', so we can avoid allocating, initializing, and tearing
off those registers in the common case. Distinguish between capturing
arguments and not, so we can avoid allocating space for arguments in
the torn-off object.

We can make this even more general in the future, with some bytecode
generator refactoring.

(JSC::BytecodeGenerator::resolve): Updated for new interface.

  • bytecompiler/BytecodeGenerator.h:

(BytecodeGenerator):
(JSC::BytecodeGenerator::symbolTable): Updated some types.

  • heap/Heap.cpp:

(JSC::Heap::isValidAllocation): Allow large allocations, now that they
are both supported and used.

  • heap/Heap.h:

(Heap): Added a new form of allocateCell that specifies the full size
of the allocation, to allow for extra space on the end.

  • interpreter/CallFrame.h:

(JSC::ExecState::argumentOffset):
(JSC::ExecState::argumentOffsetIncludingThis):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::unwindCallFrame): Refactored this code to be more
specific about tearing off 'arguments' vs activations. This is something
I forgot in my last patch, and it is required now that we can have
acitvations without 'arguments' registers.

  • runtime/Arguments.h:

(JSC::Arguments::setRegisters): No need for setRegisters anymore because
the activation object's storage doesn't change.

  • runtime/JSActivation.cpp:

(JSC::JSActivation::JSActivation): Initialize our storage manually because
it's not declared to the C++ compiler.

(JSC::JSActivation::visitChildren): No copyAndAppend because our storage
is not out-of-line anymore.

(JSC::JSActivation::symbolTableGet):
(JSC::JSActivation::symbolTablePut):
(JSC::JSActivation::getOwnPropertyNames):
(JSC::JSActivation::symbolTablePutWithAttributes):
(JSC::JSActivation::getOwnPropertySlot):
(JSC::JSActivation::getOwnPropertyDescriptor):
(JSC::JSActivation::argumentsGetter): Refactored isTornOff() testing to
avoid using a data member and to avoid hard-coding any offset assumptions.

  • runtime/JSActivation.h:

(JSC):
(JSActivation):
(JSC::JSActivation::create):
(JSC::JSActivation::isDynamicScope):
(JSC::JSActivation::captureStart):
(JSC::JSActivation::storageSize):
(JSC::JSActivation::storageSizeInBytes):
(JSC::JSActivation::registerOffset):
(JSC::JSActivation::tearOff):
(JSC::JSActivation::isTornOff):
(JSC::JSActivation::storage):
(JSC::JSActivation::allocationSize):
(JSC::JSActivation::isValid): New helper functions for doing the math
on our inline storage. Note that in the "AllOfTheThings" tear-off case,
the number of things is not known at compile time, so we store the
number in the argument count register. We can't just copy the raw contents
of the register beacuse we need a value that is safe for precise marking,
and the value in the register file has an invalid tag.

  • runtime/JSCell.h:

(JSC::allocateCell): New function for allocating with extra storage
on the end.

  • runtime/JSSymbolTableObject.h:

(JSC::JSSymbolTableObject::JSSymbolTableObject):
(JSC::JSSymbolTableObject::finishCreation):

  • runtime/JSVariableObject.h:

(JSC::JSVariableObject::JSVariableObject):
(JSVariableObject): Make it easier for subclasses to use their symbol
tables during construction, by passing the table as a constructor argument.

  • runtime/SymbolTable.h:

(JSC::SharedSymbolTable::usesNonStrictEval):
(JSC::SharedSymbolTable::setUsesNonStrictEval):
(SharedSymbolTable):
(JSC::SharedSymbolTable::captureMode):
(JSC::SharedSymbolTable::setCaptureMode):
(JSC::SharedSymbolTable::captureStart):
(JSC::SharedSymbolTable::setCaptureStart):
(JSC::SharedSymbolTable::captureEnd):
(JSC::SharedSymbolTable::setCaptureEnd):
(JSC::SharedSymbolTable::parameterCountIncludingThis):
(JSC::SharedSymbolTable::setParameterCountIncludingThis):
(JSC::SharedSymbolTable::SharedSymbolTable): Added data members to more
precisely describe what kind of capture is in play, and to avoid having
data members in the activation. We expect N activations per symbol table,
so this can be a big savings in heavy closure usage.

Location:
trunk/Source/JavaScriptCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r128259 r128260  
     12012-09-11  Geoffrey Garen  <ggaren@apple.com>
     2
     3        JSActivation should inline allocate its registers, and eliminate
     4        'arguments' registers in the common case
     5        https://bugs.webkit.org/show_bug.cgi?id=96427
     6
     7        Reviewed by Filip Pizlo.
     8
     9        This cuts the size class for simple closures down to 64 bytes.
     10
     11        * bytecompiler/BytecodeGenerator.cpp:
     12        (JSC::BytecodeGenerator::BytecodeGenerator): Set the usesNonStrictEval
     13        flag, which is new. Use a more specific test for whether a function
     14        uses 'arguments', so we can avoid allocating, initializing, and tearing
     15        off those registers in the common case. Distinguish between capturing
     16        arguments and not, so we can avoid allocating space for arguments in
     17        the torn-off object.
     18
     19        We can make this even more general in the future, with some bytecode
     20        generator refactoring.
     21
     22        (JSC::BytecodeGenerator::resolve): Updated for new interface.
     23
     24        * bytecompiler/BytecodeGenerator.h:
     25        (BytecodeGenerator):
     26        (JSC::BytecodeGenerator::symbolTable): Updated some types.
     27
     28        * heap/Heap.cpp:
     29        (JSC::Heap::isValidAllocation): Allow large allocations, now that they
     30        are both supported and used.
     31
     32        * heap/Heap.h:
     33        (Heap): Added a new form of allocateCell that specifies the full size
     34        of the allocation, to allow for extra space on the end.
     35
     36        * interpreter/CallFrame.h:
     37        (JSC::ExecState::argumentOffset):
     38        (JSC::ExecState::argumentOffsetIncludingThis):
     39        * interpreter/Interpreter.cpp:
     40        (JSC::Interpreter::unwindCallFrame): Refactored this code to be more
     41        specific about tearing off 'arguments' vs activations. This is something
     42        I forgot in my last patch, and it is required now that we can have
     43        acitvations without 'arguments' registers.
     44
     45        * runtime/Arguments.h:
     46        (JSC::Arguments::setRegisters): No need for setRegisters anymore because
     47        the activation object's storage doesn't change.
     48
     49        * runtime/JSActivation.cpp:
     50        (JSC::JSActivation::JSActivation): Initialize our storage manually because
     51        it's not declared to the C++ compiler.
     52
     53        (JSC::JSActivation::visitChildren): No copyAndAppend because our storage
     54        is not out-of-line anymore.
     55
     56        (JSC::JSActivation::symbolTableGet):
     57        (JSC::JSActivation::symbolTablePut):
     58        (JSC::JSActivation::getOwnPropertyNames):
     59        (JSC::JSActivation::symbolTablePutWithAttributes):
     60        (JSC::JSActivation::getOwnPropertySlot):
     61        (JSC::JSActivation::getOwnPropertyDescriptor):
     62        (JSC::JSActivation::argumentsGetter): Refactored isTornOff() testing to
     63        avoid using a data member and to avoid hard-coding any offset assumptions.
     64
     65        * runtime/JSActivation.h:
     66        (JSC):
     67        (JSActivation):
     68        (JSC::JSActivation::create):
     69        (JSC::JSActivation::isDynamicScope):
     70        (JSC::JSActivation::captureStart):
     71        (JSC::JSActivation::storageSize):
     72        (JSC::JSActivation::storageSizeInBytes):
     73        (JSC::JSActivation::registerOffset):
     74        (JSC::JSActivation::tearOff):
     75        (JSC::JSActivation::isTornOff):
     76        (JSC::JSActivation::storage):
     77        (JSC::JSActivation::allocationSize):
     78        (JSC::JSActivation::isValid): New helper functions for doing the math
     79        on our inline storage. Note that in the "AllOfTheThings" tear-off case,
     80        the number of things is not known at compile time, so we store the
     81        number in the argument count register. We can't just copy the raw contents
     82        of the register beacuse we need a value that is safe for precise marking,
     83        and the value in the register file has an invalid tag.
     84
     85        * runtime/JSCell.h:
     86        (JSC::allocateCell): New function for allocating with extra storage
     87        on the end.
     88
     89        * runtime/JSSymbolTableObject.h:
     90        (JSC::JSSymbolTableObject::JSSymbolTableObject):
     91        (JSC::JSSymbolTableObject::finishCreation):
     92        * runtime/JSVariableObject.h:
     93        (JSC::JSVariableObject::JSVariableObject):
     94        (JSVariableObject): Make it easier for subclasses to use their symbol
     95        tables during construction, by passing the table as a constructor argument.
     96
     97        * runtime/SymbolTable.h:
     98        (JSC::SharedSymbolTable::usesNonStrictEval):
     99        (JSC::SharedSymbolTable::setUsesNonStrictEval):
     100        (SharedSymbolTable):
     101        (JSC::SharedSymbolTable::captureMode):
     102        (JSC::SharedSymbolTable::setCaptureMode):
     103        (JSC::SharedSymbolTable::captureStart):
     104        (JSC::SharedSymbolTable::setCaptureStart):
     105        (JSC::SharedSymbolTable::captureEnd):
     106        (JSC::SharedSymbolTable::setCaptureEnd):
     107        (JSC::SharedSymbolTable::parameterCountIncludingThis):
     108        (JSC::SharedSymbolTable::setParameterCountIncludingThis):
     109        (JSC::SharedSymbolTable::SharedSymbolTable): Added data members to more
     110        precisely describe what kind of capture is in play, and to avoid having
     111        data members in the activation. We expect N activations per symbol table,
     112        so this can be a big savings in heavy closure usage.
     113
    11142012-09-11  Ryuan Choi  <ryuan.choi@samsung.com>
    2115
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r128096 r128260  
    261261}
    262262
    263 BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
     263BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, SharedSymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
    264264    : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
    265265    , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
     
    296296        m_codeBlock->setNeedsFullScopeChain(true);
    297297
     298    codeBlock->setGlobalData(m_globalData);
     299    symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());   
     300    m_codeBlock->setNumParameters(1); // Allocate space for "this"
     301
    298302    prependComment("entering Program block");
    299303    emitOpcode(op_enter);
    300     codeBlock->setGlobalData(m_globalData);
    301304
    302305    // FIXME: Move code that modifies the global object to Interpreter::execute.
    303306   
    304     m_codeBlock->setNumParameters(1); // Allocate space for "this"
    305307    codeBlock->m_numCapturedVars = codeBlock->m_numVars;
    306308   
     
    343345}
    344346
    345 BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* scope, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
     347BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* scope, SharedSymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
    346348    : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
    347349    , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
     
    379381
    380382    codeBlock->setGlobalData(m_globalData);
    381    
     383    symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
     384    symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1);
     385
    382386    prependComment("entering Function block");
    383387    emitOpcode(op_enter);
     
    389393    }
    390394
    391     if (m_codeBlock->needsFullScopeChain() || functionBody->usesArguments()) {
     395    if (functionBody->usesArguments() || codeBlock->usesEval() || m_shouldEmitDebugHooks) { // May reify arguments object.
    392396        RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code.
    393397        RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'.
     
    418422            instructions().append(argumentsRegister->index());
    419423        }
     424    }
     425
     426    bool capturesAnyArgument = codeBlock->usesArguments() || codeBlock->usesEval() || m_shouldEmitDebugHooks; // May reify arguments object.
     427    if (!capturesAnyArgument && functionBody->hasCapturedVariables()) {
     428        FunctionParameters& parameters = *functionBody->parameters();
     429        for (size_t i = 0; i < parameters.size(); ++i) {
     430            if (!functionBody->captures(parameters[i]))
     431                continue;
     432            capturesAnyArgument = true;
     433            break;
     434        }
     435    }
     436
     437    if (capturesAnyArgument) {
     438        symbolTable->setCaptureMode(SharedSymbolTable::AllOfTheThings);
     439        symbolTable->setCaptureStart(-CallFrame::offsetFor(symbolTable->parameterCountIncludingThis()));
     440    } else {
     441        symbolTable->setCaptureMode(SharedSymbolTable::SomeOfTheThings);
     442        symbolTable->setCaptureStart(m_codeBlock->m_numVars);
    420443    }
    421444
     
    485508    }
    486509
    487     if (m_shouldEmitDebugHooks)
     510    if (m_shouldEmitDebugHooks || codeBlock->usesEval())
    488511        codeBlock->m_numCapturedVars = codeBlock->m_numVars;
     512
     513    symbolTable->setCaptureEnd(codeBlock->m_numCapturedVars);
    489514
    490515    FunctionParameters& parameters = *functionBody->parameters();
     
    515540}
    516541
    517 BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
     542BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SharedSymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
    518543    : m_shouldEmitDebugHooks(scope->globalObject()->debugger())
    519544    , m_shouldEmitProfileHooks(scope->globalObject()->globalObjectMethodTable()->supportsProfiling(scope->globalObject()))
     
    550575        m_codeBlock->setNeedsFullScopeChain(true);
    551576
     577    codeBlock->setGlobalData(m_globalData);
     578    symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());   
     579    m_codeBlock->setNumParameters(1);
     580
    552581    prependComment("entering Eval block");
    553582    emitOpcode(op_enter);
    554     codeBlock->setGlobalData(m_globalData);
    555     m_codeBlock->setNumParameters(1);
    556583
    557584    const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
     
    13561383#if !ASSERT_DISABLED
    13571384            if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject))
    1358                 ASSERT(activation->isValidScopedLookup(entry.getIndex()));
     1385                ASSERT(activation->isValid(entry));
    13591386#endif
    13601387            return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r128096 r128260  
    262262        static bool dumpsGeneratedCode();
    263263
    264         BytecodeGenerator(ProgramNode*, JSScope*, SymbolTable*, ProgramCodeBlock*, CompilationKind);
    265         BytecodeGenerator(FunctionBodyNode*, JSScope*, SymbolTable*, CodeBlock*, CompilationKind);
    266         BytecodeGenerator(EvalNode*, JSScope*, SymbolTable*, EvalCodeBlock*, CompilationKind);
     264        BytecodeGenerator(ProgramNode*, JSScope*, SharedSymbolTable*, ProgramCodeBlock*, CompilationKind);
     265        BytecodeGenerator(FunctionBodyNode*, JSScope*, SharedSymbolTable*, CodeBlock*, CompilationKind);
     266        BytecodeGenerator(EvalNode*, JSScope*, SharedSymbolTable*, EvalCodeBlock*, CompilationKind);
    267267
    268268        ~BytecodeGenerator();
     
    655655        Vector<Instruction>& instructions() { return m_instructions; }
    656656
    657         SymbolTable& symbolTable() { return *m_symbolTable; }
     657        SharedSymbolTable& symbolTable() { return *m_symbolTable; }
    658658#if ENABLE(BYTECODE_COMMENTS)
    659659        Vector<Comment>& comments() { return m_comments; }
     
    698698
    699699        Strong<JSScope> m_scope;
    700         SymbolTable* m_symbolTable;
     700        SharedSymbolTable* m_symbolTable;
    701701
    702702#if ENABLE(BYTECODE_COMMENTS)
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r127829 r128260  
    802802}
    803803
    804 bool Heap::isValidAllocation(size_t bytes)
     804bool Heap::isValidAllocation(size_t)
    805805{
    806806    if (!isValidThreadState(m_globalData))
    807         return false;
    808 
    809     if (bytes > MarkedSpace::maxCellSize)
    810807        return false;
    811808
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r128141 r128260  
    183183        friend class SlotVisitor;
    184184        template<typename T> friend void* allocateCell(Heap&);
     185        template<typename T> friend void* allocateCell(Heap&, size_t);
    185186
    186187        void* allocateWithDestructor(size_t);
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.h

    r127211 r128260  
    191191        size_t argumentCount() const { return argumentCountIncludingThis() - 1; }
    192192        size_t argumentCountIncludingThis() const { return this[RegisterFile::ArgumentCount].payload(); }
    193         static int argumentOffset(size_t argument) { return s_firstArgumentOffset - argument; }
    194         static int argumentOffsetIncludingThis(size_t argument) { return s_thisArgumentOffset - argument; }
     193        static int argumentOffset(int argument) { return s_firstArgumentOffset - argument; }
     194        static int argumentOffsetIncludingThis(int argument) { return s_thisArgumentOffset - argument; }
    195195
    196196        JSValue argument(size_t argument)
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r128111 r128260  
    464464    }
    465465
    466     // If this call frame created an activation or an 'arguments' object, tear it off.
    467     if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
    468         if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
    469             oldCodeBlock->createActivation(callFrame);
    470             scope = callFrame->scope();
    471         }
    472         while (!scope->inherits(&JSActivation::s_info))
    473             scope = scope->next();
    474 
    475         callFrame->setScope(scope);
    476         JSActivation* activation = asActivation(scope);
    477         activation->tearOff(*scope->globalData());
    478         if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
    479             asArguments(arguments)->didTearOffActivation(callFrame->globalData(), activation);
    480     } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
    481         if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
    482             asArguments(arguments)->tearOff(callFrame);
     466    JSValue activation;
     467    if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsActivation()) {
     468        activation = callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue();
     469        if (activation)
     470            jsCast<JSActivation*>(activation)->tearOff(*scope->globalData());
     471    }
     472
     473    if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->usesArguments()) {
     474        if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
     475            if (activation)
     476                jsCast<Arguments*>(arguments)->didTearOffActivation(callFrame->globalData(), jsCast<JSActivation*>(activation));
     477            else
     478                jsCast<Arguments*>(arguments)->tearOff(callFrame);
     479        }
    483480    }
    484481
  • trunk/Source/JavaScriptCore/runtime/Arguments.h

    r126695 r128260  
    111111            d->registers = &activation->registerAt(0);
    112112        }
    113         void setRegisters(WriteBarrierBase<Unknown>* registers) { d->registers = registers; }
    114113
    115114        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
  • trunk/Source/JavaScriptCore/runtime/JSActivation.cpp

    r127363 r128260  
    4242const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
    4343
    44 JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable)
    45     : Base(
    46         callFrame->globalData(),
    47         callFrame->lexicalGlobalObject()->activationStructure(),
    48         callFrame->registers(),
    49         callFrame->scope()
    50     )
    51     , m_registerArray(callFrame->globalData(), this, 0)
    52     , m_numCapturedArgs(max(callFrame->argumentCount(), functionExecutable->parameterCount()))
    53     , m_numCapturedVars(functionExecutable->capturedVariableCount())
    54     , m_isTornOff(false)
    55     , m_requiresDynamicChecks(functionExecutable->usesEval() && !functionExecutable->isStrictMode())
    56     , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister())
    57 {
    58 }
    59 
    60 void JSActivation::finishCreation(CallFrame* callFrame, FunctionExecutable* functionExecutable)
    61 {
    62     Base::finishCreation(callFrame->globalData(), functionExecutable->symbolTable());
    63     ASSERT(inherits(&s_info));
    64 }
    65 
    6644void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
    6745{
     
    7351
    7452    // No need to mark our registers if they're still in the RegisterFile.
    75     PropertyStorage registerArray = thisObject->m_registerArray.get();
    76     if (!registerArray)
     53    if (!thisObject->isTornOff())
    7754        return;
    7855
    79     visitor.copyAndAppend(bitwise_cast<void**>(&registerArray), thisObject->registerArraySizeInBytes(), reinterpret_cast<JSValue*>(registerArray), thisObject->registerArraySize());
    80     thisObject->m_registerArray.set(registerArray, StorageBarrier::Unchecked);
    81     thisObject->m_registers = registerArray + thisObject->registerOffset();
    82 
    83     // Update the arguments object, since it points at our buffer.
    84     CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
    85     if (JSValue v = callFrame->uncheckedR(unmodifiedArgumentsRegister(thisObject->m_argumentsRegister)).jsValue())
    86         jsCast<Arguments*>(v)->setRegisters(thisObject->m_registers);
     56    for (size_t i = 0; i < thisObject->storageSize(); ++i)
     57        visitor.append(&thisObject->storage()[i]);
    8758}
    8859
     
    9465
    9566    // Defend against the inspector asking for a var after it has been optimized out.
    96     if (m_isTornOff && entry.getIndex() >= m_numCapturedVars)
     67    if (isTornOff() && !isValid(entry))
    9768        return false;
    9869
     
    10879
    10980    // Defend against the inspector asking for a var after it has been optimized out.
    110     if (m_isTornOff && entry.getIndex() >= m_numCapturedVars)
     81    if (isTornOff() && !isValid(entry))
    11182        return false;
    11283
     
    130101
    131102    // Defend against the inspector asking for a var after it has been optimized out.
    132     if (m_isTornOff && entry.getIndex() >= m_numCapturedVars)
     103    if (isTornOff() && !isValid(entry))
    133104        return false;
    134105
     
    141112    JSActivation* thisObject = jsCast<JSActivation*>(object);
    142113
    143     if (mode == IncludeDontEnumProperties)
     114    if (mode == IncludeDontEnumProperties && !thisObject->isTornOff())
    144115        propertyNames.add(exec->propertyNames().arguments);
    145116
     
    148119        if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
    149120            continue;
    150         if (it->second.getIndex() >= thisObject->m_numCapturedVars)
     121        if (!thisObject->isValid(it->second))
    151122            continue;
    152123        propertyNames.add(Identifier(exec, it->first.get()));
     
    165136    SymbolTableEntry& entry = iter->second;
    166137    ASSERT(!entry.isNull());
    167     if (entry.getIndex() >= m_numCapturedVars)
     138    if (!isValid(entry))
    168139        return false;
    169140
     
    179150    if (propertyName == exec->propertyNames().arguments) {
    180151        // Defend against the inspector asking for the arguments object after it has been optimized out.
    181         if (!thisObject->m_isTornOff) {
     152        if (!thisObject->isTornOff()) {
    182153            slot.setCustom(thisObject, thisObject->getArgumentsGetter());
    183154            return true;
     
    206177    if (propertyName == exec->propertyNames().arguments) {
    207178        // Defend against the inspector asking for the arguments object after it has been optimized out.
    208         if (!thisObject->m_isTornOff) {
     179        if (!thisObject->isTornOff()) {
    209180            PropertySlot slot;
    210181            JSActivation::getOwnPropertySlot(thisObject, exec, propertyName, slot);
     
    266237JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName)
    267238{
    268     JSActivation* activation = asActivation(slotBase);
     239    JSActivation* activation = jsCast<JSActivation*>(slotBase);
     240    if (activation->isTornOff())
     241        return jsUndefined();
     242
    269243    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
    270     int argumentsRegister = activation->m_argumentsRegister;
     244    int argumentsRegister = callFrame->codeBlock()->argumentsRegister();
    271245    if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
    272246        return arguments;
  • trunk/Source/JavaScriptCore/runtime/JSActivation.h

    r127376 r128260  
    3838namespace JSC {
    3939
    40     class Arguments;
    4140    class Register;
    4241   
    4342    class JSActivation : public JSVariableObject {
    4443    private:
    45         JSActivation(CallFrame*, FunctionExecutable*);
     44        JSActivation(JSGlobalData& globalData, CallFrame*, SharedSymbolTable*, size_t storageSize);
    4645   
    4746    public:
    4847        typedef JSVariableObject Base;
    4948
    50         static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* funcExec)
     49        static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* functionExecutable)
    5150        {
    52             JSActivation* activation = new (NotNull, allocateCell<JSActivation>(globalData.heap)) JSActivation(callFrame, funcExec);
    53             activation->finishCreation(callFrame, funcExec);
     51            size_t storageSize = JSActivation::storageSize(callFrame, functionExecutable->symbolTable());
     52            JSActivation* activation = new (
     53                NotNull,
     54                allocateCell<JSActivation>(
     55                    globalData.heap,
     56                    allocationSize(storageSize)
     57                )
     58            ) JSActivation(globalData, callFrame, functionExecutable->symbolTable(), storageSize);
     59            activation->finishCreation(globalData);
    5460            return activation;
    5561        }
     
    7682        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); }
    7783
    78         bool isValidScopedLookup(int index) { return index < m_numCapturedVars; }
     84        bool isValid(const SymbolTableEntry&);
     85        bool isTornOff();
    7986
    8087    protected:
    81         void finishCreation(CallFrame*, FunctionExecutable*);
    8288        static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
    8389
     
    9298        NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
    9399
    94         size_t registerOffset();
    95         size_t registerArraySize();
    96         size_t registerArraySizeInBytes();
    97 
    98         StorageBarrier m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
    99         int m_numCapturedArgs;
    100         int m_numCapturedVars : 30;
    101         bool m_isTornOff : 1;
    102         bool m_requiresDynamicChecks : 1;
    103         int m_argumentsRegister;
     100        static size_t allocationSize(size_t storageSize);
     101        static size_t storageSize(CallFrame*, SharedSymbolTable*);
     102        static int captureStart(CallFrame*, SharedSymbolTable*);
     103
     104        int registerOffset();
     105        size_t storageSize();
     106        WriteBarrier<Unknown>* storage(); // storageSize() number of registers.
    104107    };
     108
     109    extern int activationCount;
     110    extern int allTheThingsCount;
     111
     112    inline JSActivation::JSActivation(JSGlobalData& globalData, CallFrame* callFrame, SharedSymbolTable* symbolTable, size_t storageSize)
     113        : Base(
     114            globalData,
     115            callFrame->lexicalGlobalObject()->activationStructure(),
     116            callFrame->registers(),
     117            callFrame->scope(),
     118            symbolTable
     119        )
     120    {
     121        WriteBarrier<Unknown>* storage = this->storage();
     122        for (size_t i = 0; i < storageSize; ++i)
     123            new(&storage[i]) WriteBarrier<Unknown>;
     124    }
    105125
    106126    JSActivation* asActivation(JSValue);
     
    119139    inline bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const
    120140    {
    121         requiresDynamicChecks = m_requiresDynamicChecks;
     141        requiresDynamicChecks = symbolTable()->usesNonStrictEval();
    122142        return false;
    123143    }
    124144
    125     inline size_t JSActivation::registerOffset()
    126     {
    127         if (!m_numCapturedArgs)
    128             return 0;
    129 
    130         size_t capturedArgumentCountIncludingThis = m_numCapturedArgs + 1;
    131         return CallFrame::offsetFor(capturedArgumentCountIncludingThis);
    132     }
    133 
    134     inline size_t JSActivation::registerArraySize()
    135     {
    136         return registerOffset() + m_numCapturedVars;
    137     }
    138 
    139     inline size_t JSActivation::registerArraySizeInBytes()
    140     {
    141         return registerArraySize() * sizeof(WriteBarrierBase<Unknown>);
     145    inline int JSActivation::captureStart(CallFrame* callFrame, SharedSymbolTable* symbolTable)
     146    {
     147        if (symbolTable->captureMode() == SharedSymbolTable::AllOfTheThings)
     148            return -CallFrame::offsetFor(std::max<size_t>(callFrame->argumentCountIncludingThis(), symbolTable->parameterCountIncludingThis()));
     149        return symbolTable->captureStart();
     150    }
     151
     152    inline size_t JSActivation::storageSize(CallFrame* callFrame, SharedSymbolTable* symbolTable)
     153    {
     154        return symbolTable->captureEnd() - captureStart(callFrame, symbolTable);
     155    }
     156
     157    inline int JSActivation::registerOffset()
     158    {
     159        return -captureStart(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable());
     160    }
     161
     162    inline size_t JSActivation::storageSize()
     163    {
     164        return storageSize(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable());
    142165    }
    143166
    144167    inline void JSActivation::tearOff(JSGlobalData& globalData)
    145168    {
    146         ASSERT(!m_registerArray);
    147         ASSERT(m_numCapturedVars + m_numCapturedArgs);
    148 
    149         void* allocation = 0;
    150         if (!globalData.heap.tryAllocateStorage(registerArraySizeInBytes(), &allocation))
    151             CRASH();
    152         PropertyStorage registerArray = static_cast<PropertyStorage>(allocation);
    153         PropertyStorage registers = registerArray + registerOffset();
    154 
    155         // arguments
    156         int from = CallFrame::argumentOffset(m_numCapturedArgs - 1);
    157         int to = CallFrame::thisArgumentOffset(); // Skip 'this' because it's not lexically accessible.
    158         for (int i = from; i < to; ++i)
    159             registers[i].set(globalData, this, m_registers[i].get());
    160 
    161         // vars
    162         from = 0;
    163         to = m_numCapturedVars;
    164         for (int i = from; i < to; ++i)
    165             registers[i].set(globalData, this, m_registers[i].get());
    166 
    167         m_registerArray.set(globalData, this, registerArray);
    168         m_registers = registers;
    169         m_isTornOff = true;
     169        ASSERT(!isTornOff());
     170
     171        int registerOffset = this->registerOffset();
     172        WriteBarrierBase<Unknown>* dst = storage() + registerOffset;
     173        WriteBarrierBase<Unknown>* src = m_registers;
     174
     175        if (symbolTable()->captureMode() == SharedSymbolTable::AllOfTheThings) {
     176            int from = -registerOffset;
     177            int to = CallFrame::thisArgumentOffset(); // Skip 'this' because it's not lexically accessible.
     178            for (int i = from; i < to; ++i)
     179                dst[i].set(globalData, this, src[i].get());
     180
     181            dst[RegisterFile::ArgumentCount].set(globalData, this, JSValue(
     182                CallFrame::create(reinterpret_cast<Register*>(src))->argumentCountIncludingThis()));
     183
     184            int captureEnd = symbolTable()->captureEnd();
     185            for (int i = 0; i < captureEnd; ++i)
     186                dst[i].set(globalData, this, src[i].get());
     187        } else {
     188            int captureEnd = symbolTable()->captureEnd();
     189            for (int i = symbolTable()->captureStart(); i < captureEnd; ++i)
     190                dst[i].set(globalData, this, src[i].get());
     191        }
     192
     193        m_registers = dst;
     194        ASSERT(isTornOff());
     195    }
     196
     197    inline bool JSActivation::isTornOff()
     198    {
     199        return m_registers == storage() + registerOffset();
     200    }
     201
     202    inline WriteBarrier<Unknown>* JSActivation::storage()
     203    {
     204        return reinterpret_cast<WriteBarrier<Unknown>*>(
     205            reinterpret_cast<char*>(this) +
     206                WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation))
     207        );
     208    }
     209
     210    inline size_t JSActivation::allocationSize(size_t storageSize)
     211    {
     212        size_t objectSizeInBytes = WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation));
     213        size_t storageSizeInBytes = storageSize * sizeof(WriteBarrier<Unknown>);
     214        return objectSizeInBytes + storageSizeInBytes;
     215    }
     216
     217    inline bool JSActivation::isValid(const SymbolTableEntry& entry)
     218    {
     219        if (entry.getIndex() < captureStart(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable()))
     220            return false;
     221        if (entry.getIndex() >= symbolTable()->captureEnd())
     222            return false;
     223        return true;
    170224    }
    171225
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r128146 r128260  
    6565        friend class MarkedBlock;
    6666        template<typename T> friend void* allocateCell(Heap&);
     67        template<typename T> friend void* allocateCell(Heap&, size_t);
    6768
    6869    public:
     
    338339    }
    339340   
     341    template<typename T>
     342    void* allocateCell(Heap& heap, size_t size)
     343    {
     344        ASSERT(size >= sizeof(T));
     345#if ENABLE(GC_VALIDATION)
     346        ASSERT(!heap.globalData()->isInitializingObject());
     347        heap.globalData()->setInitializingObjectClass(&T::s_info);
     348#endif
     349        JSCell* result = 0;
     350        if (NeedsDestructor<T>::value)
     351            result = static_cast<JSCell*>(heap.allocateWithDestructor(size));
     352        else {
     353            ASSERT(T::s_info.methodTable.destroy == JSCell::destroy);
     354            result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
     355        }
     356        result->clearStructure();
     357        return result;
     358    }
     359   
    340360    inline bool isZapped(const JSCell* cell)
    341361    {
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r127505 r128260  
    2828#include "CallFrame.h"
    2929#include "Interpreter.h"
     30#include "JSFunction.h"
    3031#include "JSGlobalObject.h"
    3132#include "JSString.h"
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r127363 r128260  
    5050    static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
    5151   
    52     JSSymbolTableObject(JSGlobalData& globalData, Structure* structure, JSScope* scope)
     52    JSSymbolTableObject(JSGlobalData& globalData, Structure* structure, JSScope* scope, SharedSymbolTable* symbolTable = 0)
    5353        : Base(globalData, structure, scope)
    5454    {
     55        if (symbolTable)
     56            m_symbolTable.set(globalData, this, symbolTable);
    5557    }
    5658
    57     void finishCreation(JSGlobalData& globalData, SharedSymbolTable* symbolTable = 0)
     59    void finishCreation(JSGlobalData& globalData)
    5860    {
    5961        Base::finishCreation(globalData);
    60         if (!symbolTable)
    61             symbolTable = SharedSymbolTable::create(globalData);
    62         m_symbolTable.set(globalData, this, symbolTable);
     62        if (!m_symbolTable)
     63            m_symbolTable.set(globalData, this, SharedSymbolTable::create(globalData));
    6364    }
    6465
  • trunk/Source/JavaScriptCore/runtime/JSVariableObject.h

    r127363 r128260  
    6161            Structure* structure,
    6262            Register* registers,
    63             JSScope* scope
     63            JSScope* scope,
     64            SharedSymbolTable* symbolTable = 0
    6465        )
    65             : Base(globalData, structure, scope)
     66            : Base(globalData, structure, scope, symbolTable)
    6667            , m_registers(reinterpret_cast<WriteBarrierBase<Unknown>*>(registers))
    6768        {
    68         }
    69 
    70         void finishCreation(JSGlobalData& globalData, SharedSymbolTable* symbolTable = 0)
    71         {
    72             Base::finishCreation(globalData, symbolTable);
    73             COMPILE_ASSERT(sizeof(WriteBarrierBase<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrierBase);
    7469        }
    7570
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r127191 r128260  
    341341        }
    342342
     343        bool usesNonStrictEval() { return m_usesNonStrictEval; }
     344        void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; }
     345
     346        enum CaptureMode {
     347            SomeOfTheThings,
     348            AllOfTheThings
     349        };
     350
     351        CaptureMode captureMode() { return m_captureMode; }
     352        void setCaptureMode(CaptureMode captureMode) { m_captureMode = captureMode; }
     353
     354        int captureStart() { return m_captureStart; }
     355        void setCaptureStart(int captureStart) { m_captureStart = captureStart; }
     356
     357        int captureEnd() { return m_captureEnd; }
     358        void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; }
     359
     360        int parameterCountIncludingThis() { return m_parameterCountIncludingThis; }
     361        void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; }
     362
    343363        static JS_EXPORTDATA const ClassInfo s_info;
    344364
     
    346366        SharedSymbolTable(JSGlobalData& globalData)
    347367            : JSCell(globalData, globalData.sharedSymbolTableStructure.get())
    348         {
    349         }
     368            , m_parameterCountIncludingThis(0)
     369            , m_usesNonStrictEval(false)
     370            , m_captureMode(SomeOfTheThings)
     371            , m_captureStart(0)
     372            , m_captureEnd(0)
     373        {
     374        }
     375
     376        int m_parameterCountIncludingThis;
     377        bool m_usesNonStrictEval;
     378
     379        CaptureMode m_captureMode;
     380        int m_captureStart;
     381        int m_captureEnd;
    350382    };
    351383   
Note: See TracChangeset for help on using the changeset viewer.