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.

File:
1 edited

Legend:

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