Ignore:
Timestamp:
Jun 6, 2012, 5:49:34 PM (13 years ago)
Author:
[email protected]
Message:

Global object variable accesses should not require an extra load
https://bugs.webkit.org/show_bug.cgi?id=88385

Source/JavaScriptCore:

Reviewed by Gavin Barraclough and Geoffrey Garen.

Previously, if you wanted to access a global variable, you'd first have
to load the register array from the appropriate global object and then
either load or store at an offset to the register array. This is because
JSGlobalObject inherited from JSVariableObject, and JSVariableObject is
designed with the pessimistic assumption that its register array may
point into the call stack. This is never the case for global objects.
Hence, even though the global object may add more registers at any time,
it does not need to store them in a contiguous array. It can use a
SegmentedVector or similar.

This patch refactors global objects and variable objects as follows:

  • The functionality to track variables in an indexable array using a SymbolTable to map names to indices is moved into JSSymbolTableObject, which is now a supertype of JSVariableObject. JSVariableObject is now just a holder for a registers array and implements the registerAt() method that is left abstract in JSSymbolTableObject. Because all users of JSVariableObject know whether they are a JSStaticScopeObject, JSActivation, or JSGlobalObject, this "abstract" method is not virtual; instead the utility methods that would call registerAt() are now template functions that require you to know statically what subtype of JSSymbolTableObject you're using (JSVariableObject or something else), so that registerAt() can be statically bound.


  • A new class is added called JSSegmentedVariableObject, which only differs from JSVariableObject in how it allocates registers. It uses a SegmentedVector instead of manually managing a pointer to a contiguous slab of registers. This changes the interface somewhat; for example with JSVariableObject if you wanted to add a register you had to do it yourself since the JSVariableObject didn't know how the registers array ought to be allocated. With JSSegmentedVariableObject you can just call addRegisters(). JSSegmentedVariableObject preserves the invariant that once you get a pointer into a register, that pointer will continue to be valid so long as the JSSegmentedVariableObject is alive. This allows the JITs and interpreters to skip the extra load.


  • JSGlobalObject now inherits from JSSegmentedVariableObject. For now (and possibly forever) it is the only subtype of this new class.


  • The bytecode format is changed so that get_global_var and put_global_var have a pointer to the register directly rather than having an index. A convenience method is provided in JSSegmentedVariableObject to get the index given a a pointer, which is used for assertions and debug dumps.


This appears to be a 1% across the board win.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dump):

  • bytecode/Instruction.h:

(Instruction):
(JSC::Instruction::Instruction):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::ResolveResult::registerPointer):
(JSC):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::retrieveLastUnaryOp):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):

  • bytecompiler/BytecodeGenerator.h:

(ResolveResult):
(BytecodeGenerator):

  • dfg/DFGAssemblyHelpers.h:

(AssemblyHelpers):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::globalVarLoadElimination):
(JSC::DFG::CSEPhase::globalVarStoreElimination):
(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::globalObjectFor):
(Graph):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasVarNumber):
(Node):
(JSC::DFG::Node::hasRegisterPointer):
(JSC::DFG::Node::registerPointer):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • heap/Heap.h:

(Heap):
(JSC::Heap::isWriteBarrierEnabled):
(JSC):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):
(JSC::Interpreter::privateExecute):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_global_var):
(JSC::JIT::emit_op_put_global_var):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_global_var):
(JSC::JIT::emit_op_put_global_var):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSGlobalObject.cpp:

(JSC):
(JSC::JSGlobalObject::put):
(JSC::JSGlobalObject::putDirectVirtual):
(JSC::JSGlobalObject::defineOwnProperty):
(JSC::JSGlobalObject::visitChildren):
(JSC::JSGlobalObject::addStaticGlobals):
(JSC::JSGlobalObject::getOwnPropertySlot):
(JSC::JSGlobalObject::getOwnPropertyDescriptor):

  • runtime/JSGlobalObject.h:

(JSGlobalObject):
(JSC::JSGlobalObject::JSGlobalObject):
(JSC):
(JSC::JSGlobalObject::hasOwnPropertyForWrite):

  • runtime/JSSegmentedVariableObject.cpp: Added.

(JSC):
(JSC::JSSegmentedVariableObject::findRegisterIndex):
(JSC::JSSegmentedVariableObject::addRegisters):
(JSC::JSSegmentedVariableObject::visitChildren):

  • runtime/JSSegmentedVariableObject.h: Added.

(JSC):
(JSSegmentedVariableObject):
(JSC::JSSegmentedVariableObject::registerAt):
(JSC::JSSegmentedVariableObject::assertRegisterIsInThisObject):
(JSC::JSSegmentedVariableObject::JSSegmentedVariableObject):
(JSC::JSSegmentedVariableObject::finishCreation):

  • runtime/JSStaticScopeObject.cpp:

(JSC::JSStaticScopeObject::put):
(JSC::JSStaticScopeObject::putDirectVirtual):
(JSC::JSStaticScopeObject::getOwnPropertySlot):

  • runtime/JSSymbolTableObject.cpp: Added.

(JSC):
(JSC::JSSymbolTableObject::destroy):
(JSC::JSSymbolTableObject::deleteProperty):
(JSC::JSSymbolTableObject::getOwnPropertyNames):
(JSC::JSSymbolTableObject::putDirectVirtual):
(JSC::JSSymbolTableObject::isDynamicScope):

  • runtime/JSSymbolTableObject.h: Added.

(JSC):
(JSSymbolTableObject):
(JSC::JSSymbolTableObject::symbolTable):
(JSC::JSSymbolTableObject::JSSymbolTableObject):
(JSC::JSSymbolTableObject::finishCreation):
(JSC::symbolTableGet):
(JSC::symbolTablePut):
(JSC::symbolTablePutWithAttributes):

  • runtime/JSVariableObject.cpp:

(JSC):

  • runtime/JSVariableObject.h:

(JSVariableObject):
(JSC::JSVariableObject::JSVariableObject):
(JSC::JSVariableObject::finishCreation):
(JSC):

  • runtime/WriteBarrier.h:

Source/WebCore:

Reviewed by Gavin Barraclough and Geoffrey Garen.

Updated JSDOMWindowBase.cpp to use the new symbol table API. this->symbolTableFoo(...)
becomes symbolTableFoo(this, ...).

No new tests because no change in behavior.

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::updateDocument):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r119441 r119655  
    8080namespace JSC {
    8181
    82 const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
     82const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSSegmentedVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
    8383
    8484const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled };
     
    149149    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
    150150
    151     if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
     151    if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode()))
    152152        return;
    153     JSVariableObject::put(thisObject, exec, propertyName, value, slot);
     153    JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot);
    154154}
    155155
     
    159159    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
    160160
    161     if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
     161    if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes))
    162162        return;
    163163
    164164    JSValue valueBefore = thisObject->getDirect(exec->globalData(), propertyName);
    165165    PutPropertySlot slot;
    166     JSVariableObject::put(thisObject, exec, propertyName, value, slot);
     166    JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot);
    167167    if (!valueBefore) {
    168168        JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName);
     
    177177    PropertySlot slot;
    178178    // silently ignore attempts to add accessors aliasing vars.
    179     if (descriptor.isAccessorDescriptor() && thisObject->symbolTableGet(propertyName, slot))
     179    if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot))
    180180        return false;
    181181    return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
     
    346346    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
    347347    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
    348     JSVariableObject::visitChildren(thisObject, visitor);
     348    JSSegmentedVariableObject::visitChildren(thisObject, visitor);
    349349
    350350    visitIfNeeded(visitor, &thisObject->m_globalScopeChain);
     
    394394    visitIfNeeded(visitor, &thisObject->m_stringObjectStructure);
    395395    visitIfNeeded(visitor, &thisObject->m_internalFunctionStructure);
    396 
    397     if (thisObject->m_registerArray) {
    398         // Outside the execution of global code, when our variables are torn off,
    399         // we can mark the torn-off array.
    400         visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_registerArraySize);
    401     } else if (thisObject->m_registers) {
    402         // During execution of global code, when our variables are in the register file,
    403         // the symbol table tells us how many variables there are, and registers
    404         // points to where they end, and the registers used for execution begin.
    405         visitor.appendValues(thisObject->m_registers - thisObject->symbolTable().size(), thisObject->symbolTable().size());
    406     }
    407396}
    408397
     
    412401}
    413402
    414 void JSGlobalObject::resizeRegisters(size_t newSize)
    415 {
    416     // Previous duplicate symbols may have created spare capacity in m_registerArray.
    417     if (newSize <= m_registerArraySize)
    418         return;
    419 
    420     size_t oldSize = m_registerArraySize;
    421     OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]);
    422     for (size_t i = 0; i < oldSize; ++i)
    423         registerArray[i].set(globalData(), this, m_registerArray[i].get());
    424     for (size_t i = oldSize; i < newSize; ++i)
    425         registerArray[i].setUndefined();
    426 
    427     WriteBarrier<Unknown>* registers = registerArray.get();
    428     setRegisters(registers, registerArray.release(), newSize);
    429 }
    430 
    431403void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
    432404{
    433     resizeRegisters(symbolTable().size() + count);
     405    addRegisters(count);
    434406
    435407    for (int i = 0; i < count; ++i) {
     
    447419{
    448420    JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
    449     if (getStaticFunctionSlot<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot))
     421    if (getStaticFunctionSlot<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot))
    450422        return true;
    451     return thisObject->symbolTableGet(propertyName, slot);
     423    return symbolTableGet(thisObject, propertyName, slot);
    452424}
    453425
     
    455427{
    456428    JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
    457     if (getStaticFunctionDescriptor<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor))
     429    if (getStaticFunctionDescriptor<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor))
    458430        return true;
    459     return thisObject->symbolTableGet(propertyName, descriptor);
     431    return symbolTableGet(thisObject, propertyName, descriptor);
    460432}
    461433
Note: See TracChangeset for help on using the changeset viewer.