Ignore:
Timestamp:
Jun 27, 2008, 3:35:33 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-06-27 Geoffrey Garen <[email protected]>

Reviewed by Oliver Hunt.


One RegisterFile to rule them all!


SunSpider reports a 0.2% speedup.

This patch removes the RegisterFileStack abstraction and replaces it with
a single register file that


(a) allocates a fixed storage area, including a fixed area for global
vars, so that no operation may cause the register file to reallocate


and

(b) swaps between global storage areas when executing code in different
global objects.


This patch also changes the layout of the register file so that all call
frames, including call frames for global code, get a header. This is
required to support re-entrant global code. It also just makes things simpler.


  • VM/CodeGenerator.cpp: (KJS::CodeGenerator::addGlobalVar): New function. Differs from addVar in that


(a) global vars don't contribute to a CodeBlock's numLocals count, since
global storage is fixed and allocated at startup


and


(b) references to global vars get shifted to elide intermediate stack
between "r" and the global storage area.


  • VM/Machine.cpp: (KJS::Machine::dumpRegisters): Updated this function to match the new register file layout, and added the ability to dump exact identifiers for the different parts of a call frame.


(KJS::Machine::unwindCallFrame): Updated this function to match the new
register file layout.


(KJS::Machine::execute): Updated this function to initialize a call frame
header for global code, and to swap global storage areas when switching
to execution in a new global object.


(KJS::Machine::privateExecute): Got rid of "safeForReentry" and re-reading
of registerBase because the register file is always safe for reentry now,
and registerBase never changes.


  • VM/Machine.h: Moved the call frame header enum from Machine to RegisterFile, to resolve a header dependency problem (a good sign that the enum belonged in RegisterFile all along!)
  • VM/RegisterFile.cpp:
  • VM/RegisterFile.h: Changed RegisterFile to mmap a fixed size register area. This allows us to avoid re-allocting the register file later on. Instead, we rely on the OS to allocate physical pages to the register file as necessary.
  • VM/RegisterFileStack.cpp: Removed. Tada!
  • VM/RegisterFileStack.h: Removed. Tada!
  • kjs/DebuggerCallFrame.cpp: Updated this class to match the new register file layout, greatly simplifying it in the process.
  • kjs/JSActivation.h:
  • kjs/JSActivation.cpp: Moved some of this logic up to JSVariableObject, since the global object now needs to be able to tear off its registers just like the activation object.
  • kjs/JSFunction.cpp: No need to fiddle with the register file anymore.
  • kjs/JSGlobalObject.h:
  • kjs/JSGlobalObject.cpp: Updated JSGlobalObject to support moving its global storage area into and out of the register file.
  • kjs/PropertySlot.cpp: No need to fiddle with the register file anymore.
  • kjs/collector.cpp: Renamed markStackObjectConservatively to markConservatively, since we don't just mark stack objects this way.


Also, added code to mark the machine's register file.

  • kjs/config.h: Moved some platforms #defines from here...
  • wtf/Platform.h: ...to here, to support mmap/VirtualAlloc detection in RegisterFile.h.

LayoutTests:

2008-06-26 Geoffrey Garen <[email protected]>

Reviewed by Oliver Hunt.


Added a test for what happens when a script exceeds the limit on declared
global variables.

  • fast/js/global-var-limit-expected.txt: Added.
  • fast/js/global-var-limit.html: Added.
  • fast/js/global-recursion-on-full-stack-expected.txt: Updated for new (slightly more correct) behavior. Since the stack overflow happens in the middle of a try/catch block, it should be caught, instead of logged to the console.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CodeGenerator.cpp

    r34784 r34838  
    149149}
    150150
    151 bool CodeGenerator::addVar(const Identifier& ident, RegisterID*& r0, bool isConstant)
     151bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
    152152{
    153153    int index = m_nextVar;
     
    168168}
    169169
    170 CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack, bool canCreateVariables)
     170bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
     171{
     172    int index = m_nextVar;
     173    SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
     174    pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
     175
     176    if (!result.second)
     177        index = result.first->second.getIndex();
     178    else {
     179        --m_nextVar;
     180        m_locals.append(index + m_globalVarStorageOffset);
     181    }
     182
     183    r0 = &m_locals[localsIndex(index)];
     184    return result.second;
     185}
     186
     187CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack)
    171188    : m_shouldEmitDebugHooks(!!debugger)
    172189    , m_scopeChain(&scopeChain)
     
    174191    , m_scopeNode(programNode)
    175192    , m_codeBlock(codeBlock)
    176     , m_thisRegister(Machine::ProgramCodeThisRegister)
     193    , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
    177194    , m_finallyDepth(0)
    178195    , m_dynamicScopeDepth(0)
     
    183200    , m_lastOpcodeID(op_end)
    184201{
    185     // Global code can inherit previously defined symbols.
    186     int size = symbolTable->size() + 1; // + 1 slot for  "this"
     202    // FIXME: Move code that modifies the global object to Machine::execute.
     203   
     204    m_codeBlock->numVars = 1; // Allocate space for "this"
     205
     206    JSGlobalObject* globalObject = scopeChain.globalObject();
     207    ExecState* exec = globalObject->globalExec();
     208    RegisterFile* registerFile = &exec->globalData().machine->registerFile();
     209   
     210    // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
     211    m_globalVarStorageOffset =  -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
    187212
    188213    // Add previously defined symbols to bookkeeping.
    189     m_locals.resize(size);
     214    m_locals.resize(symbolTable->size());
    190215    SymbolTable::iterator end = symbolTable->end();
    191216    for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
    192         m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex());
    193 
    194     // Shift new symbols so they get stored prior to previously defined symbols.
    195     m_nextVar -= size;
    196 
    197     JSGlobalObject* globalObject = scopeChain.globalObject();
    198 
    199     ExecState* exec = globalObject->globalExec();
    200    
    201     // FIXME: Move the execution-related parts of this code to Machine::execute.
    202 
    203     if (canCreateVariables) {
     217        m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
     218
     219    bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
     220    if (canOptimizeNewGlobals) {
     221        // Shift new symbols so they get stored prior to existing symbols.
     222        m_nextVar -= symbolTable->size();
     223
    204224        for (size_t i = 0; i < functionStack.size(); ++i) {
    205225            FuncDeclNode* funcDecl = functionStack[i].get();
    206226            globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
    207             emitNewFunction(addVar(funcDecl->m_ident, false), funcDecl);
     227            emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
    208228        }
    209229
    210230        for (size_t i = 0; i < varStack.size(); ++i) {
    211231            if (!globalObject->hasProperty(exec, varStack[i].first))
    212                 emitLoad(addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
     232                emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
    213233        }
    214234    } else {
     
    256276        if (ident == propertyNames().arguments)
    257277            continue;
    258 
    259         RegisterID* r0;
    260         addVar(ident, r0, varStack[i].second & DeclarationStacks::IsConstant);
     278        addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
    261279    }
    262280
     
    280298    , m_scopeNode(evalNode)
    281299    , m_codeBlock(codeBlock)
    282     , m_thisRegister(Machine::ProgramCodeThisRegister)
     300    , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
    283301    , m_finallyDepth(0)
    284302    , m_dynamicScopeDepth(0)
    285303    , m_codeType(EvalCode)
    286304    , m_continueDepth(0)
    287     , m_nextVar(-1)
    288305    , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
    289306    , m_lastOpcodeID(op_end)
     
    817834
    818835    // Reserve space for call frame.
    819     Vector<RefPtr<RegisterID>, Machine::CallFrameHeaderSize> callFrame;
    820     for (int i = 0; i < Machine::CallFrameHeaderSize; ++i)
     836    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
     837    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
    821838        callFrame.append(newTemporary());
    822839
     
    848865{
    849866    // Reserve space for call frame.
    850     Vector<RefPtr<RegisterID>, Machine::CallFrameHeaderSize> callFrame;
    851     for (int i = 0; i < Machine::CallFrameHeaderSize; ++i)
     867    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
     868    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
    852869        callFrame.append(newTemporary());
    853870
Note: See TracChangeset for help on using the changeset viewer.