Ignore:
Timestamp:
Sep 11, 2012, 9:08:18 PM (13 years ago)
Author:
[email protected]
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/bytecompiler
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • 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)
Note: See TracChangeset for help on using the changeset viewer.