Changeset 28884 in webkit for trunk/JavaScriptCore/kjs


Ignore:
Timestamp:
Dec 20, 2007, 1:32:06 AM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

Reviewed by Oliver Hunt.


Optimized global access to global variables, using a symbol table.


SunSpider reports a 1.5% overall speedup, a 6.2% speedup on 3d-morph,
and a whopping 33.1% speedup on bitops-bitwise-and.

  • API/JSCallbackObjectFunctions.h: Replaced calls to JSObject:: with calls to Base::, since JSObject is not always our base class. This was always a bug, but the bug is even more apparent after some of my changes.

(KJS::::staticFunctionGetter): Replaced use of getDirect with call to
getOwnPropertySlot. Global declarations are no longer stored in the
property map, so a call to getDirect is insufficient for finding
override properties.

  • API/testapi.c:
  • API/testapi.js: Added test for the getDirect change mentioned above.
  • kjs/ExecState.cpp:
  • kjs/ExecState.h: Dialed back the optimization to store a direct pointer to the localStorage buffer. One ExecState can grow the global object's localStorage without another ExecState's knowledge, so ExecState can't store a direct pointer to the localStorage buffer unless/until we invent a way to update all the relevant ExecStates.
  • kjs/JSGlobalObject.cpp: Inserted the symbol table into get and put operations. (KJS::JSGlobalObject::reset): Reset the symbol table and local storage, too. Also, clear the property map here, removing the need for a separate call.
  • kjs/JSVariableObject.cpp:
  • kjs/JSVariableObject.h: Added support for saving localStorage and the symbol table to the back/forward cache, and restoring them.
  • kjs/function.cpp: (KJS::GlobalFuncImp::callAsFunction): Renamed progNode to evalNode because it's an EvalNode, not a ProgramNode.
  • kjs/lookup.h: (KJS::cacheGlobalObject): Replaced put with faster putDirect, since that's how the rest of lookup.h works. putDirect is safe here because cacheGlobalObject is only used for objects whose names are not valid identifiers.
  • kjs/nodes.cpp: The good stuff!

(KJS::EvalNode::processDeclarations): Replaced hasProperty with
the new hasOwnProperty, which is slightly faster.

  • kjs/object.h: Nixed clearProperties because clear() does this job now.
  • kjs/property_map.cpp:
  • kjs/property_map.h: More back/forward cache support.


  • wtf/Vector.h: (WTF::::grow): Added fast non-branching grow function. I used it in an earlier version of this patch, even though it's not used anymore.

JavaScriptGlue:

Build fix.

  • ForwardingHeaders/wtf/VectorTraits.h: Added.

WebCore:

Reviewed by Oliver Hunt.

Build support:

  • ForwardingHeaders/kjs/SymbolTable.h: Added.
  • ForwardingHeaders/wtf/VectorTraits.h: Added.
  • bindings/js/JSDOMWindowCustom.cpp: (WebCore::JSDOMWindow::customGetOwnPropertySlot): Replaced use of getDirectLocation with getOwnPropertySlot. getDirectLocation is no longer valid, since global declarations are not stored in the property map.

(WebCore::JSDOMWindow::customPut): Replaced use of JSObject::put with
JSGlobalObject::put. JSObject::put is no longer valid, since global
declarations are not stored in the property map.

  • bindings/js/kjs_window.cpp: Replaced JSObject:: calls with Base:: calls, since JSObject is not our base class. This was always a bug, but the bug is even more apparent after some of my changes.

(KJS::Window::clear): Removed call to clearProperties because
JSGlobalObject::reset takes care of that now.

  • history/CachedPage.cpp:
  • history/CachedPage.h: Added support for saving a symbol table and localStorage to the page cache, and restoring it.

WebKit/mac:

Reviewed by Oliver Hunt.

Build fix.

  • ForwardingHeaders/kjs/SymbolTable.h: Added.
  • ForwardingHeaders/wtf/VectorTraits.h: Added.

LayoutTests:

Reviewed by Oliver Hunt.


Added some tests to verify some of the changes I made while optimizing
global access to global variables.

  • fast/dom/Window/resources/window-property-clearing-iframe0.html: Added.
  • fast/dom/Window/resources/window-property-clearing-iframe1.html: Added.
  • fast/dom/Window/window-property-clearing-expected.txt: Added.
  • fast/dom/Window/window-property-clearing.html: Added.
  • fast/dom/getter-on-window-object2-expected.txt: Added.
  • fast/dom/getter-on-window-object2.html: Added.

Checked in failing results for these const tests. The symbol table
optimization broke const. (We didn't know this before because our only
tests used global variables.)

  • fast/js/const-expected.txt:
  • fast/js/kde/const-expected.txt:
  • fast/js/resources/for-in-avoid-duplicates.js: Fixed a typo I noticed. Not related to this patch.
  • fast/dom/Window/window-property-shadowing.html: Changed this test to use "this" instead of "window". The fact that "window" worked before, despite an overriding / shadowing var declaration, was a bug.
Location:
trunk/JavaScriptCore/kjs
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/ExecState.cpp

    r28608 r28884  
    7777        break;
    7878    }
     79   
     80    m_localStorage = &m_variableObject->localStorage();
    7981
    8082    if (scopeNode)
     
    104106    return dynamicGlobalObject();
    105107}
    106    
    107 void ExecState::updateLocalStorage()
    108 {
    109     m_localStorageBuffer = m_activation->localStorage().data();
    110 }
    111108
    112109} // namespace KJS
  • trunk/JavaScriptCore/kjs/ExecState.h

    r28608 r28884  
    2525#define ExecState_H
    2626
    27 #include "value.h"
     27#include "LabelStack.h"
     28#include "LocalStorage.h"
     29#include "scope_chain.h"
    2830#include "types.h"
    29 #include "CommonIdentifiers.h"
    30 #include "LabelStack.h"
    31 #include "scope_chain.h"
    3231
    3332namespace KJS  {
     
    4039   
    4140    class ActivationImp;
     41    class CommonIdentifiers;
    4242    class FunctionImp;
    4343    class GlobalFuncImp;
     
    8282       
    8383        ExecState* callingExecState() { return m_callingExec; }
     84        ExecState* savedExec() { return m_savedExec; }
    8485       
    8586        ActivationImp* activationObject() { return m_activation; }
     
    107108        const CommonIdentifiers& propertyNames() const { return *m_propertyNames; }
    108109
    109         LocalStorageEntry* localStorage() { return m_localStorageBuffer; }
    110         void updateLocalStorage();
     110        LocalStorage& localStorage() { return *m_localStorage; }
    111111   
    112112    public:
     
    132132        const List* m_arguments;
    133133        ActivationImp* m_activation;
    134         LocalStorageEntry* m_localStorageBuffer;
     134        LocalStorage* m_localStorage;
    135135
    136136        ScopeChain m_scopeChain;
  • trunk/JavaScriptCore/kjs/JSGlobalObject.cpp

    r28527 r28884  
    130130}
    131131
     132bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
     133{
     134    if (symbolTableGet(propertyName, slot))
     135        return true;
     136    return JSVariableObject::getOwnPropertySlot(exec, propertyName, slot);
     137}
     138
     139void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
     140{
     141    if (symbolTablePut(propertyName, value, attr))
     142        return;
     143    return JSVariableObject::put(exec, propertyName, value, attr);
     144}
     145
    132146static inline JSObject* lastInPrototypeChain(JSObject* object)
    133147{
     
    140154void JSGlobalObject::reset(JSValue* prototype)
    141155{
    142     // Clear before inititalizing, to avoid marking uninitialized (dangerous) or
    143     // stale (wasteful) pointers during possible garbage collection while creating
    144     // new objects below.
    145 
    146     ExecState* exec = &d()->globalExec;
     156    // Clear before inititalizing, to avoid calling mark() on stale pointers --
     157    // which would be wasteful -- or uninitialized pointers -- which would be
     158    // dangerous. (The allocations below may cause a GC.)
     159
     160    _prop.clear();
     161    localStorage().clear();
     162    symbolTable().clear();
    147163
    148164    // Prototypes
     
    182198    d()->typeErrorConstructor = 0;
    183199    d()->URIErrorConstructor = 0;
     200
     201    ExecState* exec = &d()->globalExec;
    184202
    185203    // Prototypes
  • trunk/JavaScriptCore/kjs/JSGlobalObject.h

    r28565 r28884  
    148148        virtual ~JSGlobalObject();
    149149
     150        virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
     151        virtual void put(ExecState*, const Identifier&, JSValue*, int attr = None);
     152
    150153        // Linked list of all global objects.
    151154        static JSGlobalObject* head() { return s_head; }
  • trunk/JavaScriptCore/kjs/JSVariableObject.cpp

    r28777 r28884  
    3131
    3232#include "PropertyNameArray.h"
     33#include "property_map.h"
    3334
    3435namespace KJS {
    3536
    3637UString::Rep* IdentifierRepHashTraits::nullRepPtr = &UString::Rep::null; // Didn't want to make a whole source file for just this.
     38
     39void JSVariableObject::saveSymbolTable(SymbolTable& s) const
     40{
     41    s = *d->symbolTable;
     42}
     43
     44void JSVariableObject::restoreSymbolTable(SymbolTable& s) const
     45{
     46    *d->symbolTable = s;
     47}
     48
     49void JSVariableObject::saveLocalStorage(SavedProperties& p) const
     50{
     51    unsigned count = d->localStorage.size();
     52
     53    p.m_properties.clear();
     54    p.m_count = count;
     55
     56    if (!count)
     57        return;
     58
     59    p.m_properties.set(new SavedProperty[count]);
     60   
     61    SavedProperty* prop = p.m_properties.get();
     62    for (size_t i = 0; i < count; ++i, ++prop) {
     63        LocalStorageEntry& entry = d->localStorage[i];
     64        prop->value = entry.value;
     65        prop->attributes = entry.attributes;
     66    }
     67}
     68
     69void JSVariableObject::restoreLocalStorage(SavedProperties& p) const
     70{
     71    unsigned count = p.m_count;
     72    d->localStorage.resize(count);
     73    SavedProperty* prop = p.m_properties.get();
     74    for (size_t i = 0; i < count; ++i, ++prop)
     75        d->localStorage[i] = LocalStorageEntry(prop->value, prop->attributes);
     76}
    3777
    3878bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
  • trunk/JavaScriptCore/kjs/JSVariableObject.h

    r28608 r28884  
    4040        SymbolTable& symbolTable() { return *d->symbolTable; }
    4141        LocalStorage& localStorage() { return d->localStorage; }
     42       
     43        void saveSymbolTable(SymbolTable& s) const;
     44        void restoreSymbolTable(SymbolTable& s) const;
    4245
     46        void saveLocalStorage(SavedProperties& s) const;
     47        void restoreLocalStorage(SavedProperties& s) const;
     48       
    4349        virtual bool deleteProperty(ExecState*, const Identifier&);
    4450        virtual void getPropertyNames(ExecState*, PropertyNameArray&);
  • trunk/JavaScriptCore/kjs/LocalStorage.h

    r27249 r28884  
    2626#define KJS_LOCAL_STORAGE_H
    2727
    28 #include <wtf/Vector.h>
     28#include <wtf/Forward.h>
     29#include <wtf/VectorTraits.h>
    2930
    3031namespace KJS {
  • trunk/JavaScriptCore/kjs/function.cpp

    r28608 r28884  
    700700        int errLine;
    701701        UString errMsg;
    702         RefPtr<EvalNode> progNode(parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg));
     702        RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg);
    703703
    704704        Debugger* dbg = exec->dynamicGlobalObject()->debugger();
     
    710710
    711711        // no program node means a syntax occurred
    712         if (!progNode)
     712        if (!evalNode)
    713713          return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
    714714
     
    718718        JSGlobalObject* globalObject = switchGlobal ? static_cast<JSGlobalObject*>(thisObj) : exec->dynamicGlobalObject();
    719719        JSObject* thisVal = static_cast<JSObject*>(exec->thisValue());
    720         ExecState newExec(globalObject, thisVal, progNode.get(), EvalCode, exec, globalObject->currentExec());
     720        ExecState newExec(globalObject, thisVal, evalNode.get(), EvalCode, exec, globalObject->currentExec());
    721721        if (exec->hadException())
    722722            newExec.setException(exec->exception());
     
    727727        }
    728728       
    729         Completion c = progNode->execute(&newExec);
     729        Completion c = evalNode->execute(&newExec);
    730730         
    731731        if (switchGlobal)
  • trunk/JavaScriptCore/kjs/lookup.h

    r28468 r28884  
    283283    }
    284284    JSObject* newObject = new ClassCtor(exec);
    285     globalObject->put(exec, propertyName, newObject, Internal | DontEnum);
     285    globalObject->putDirect(propertyName, newObject, Internal | DontEnum);
    286286    return newObject;
    287287  }
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r28855 r28884  
    34893489inline void VarDeclNode::evaluateSingle(ExecState* exec)
    34903490{
     3491    ASSERT(exec->variableObject()->hasOwnProperty(exec, ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
    34913492    const ScopeChain& chain = exec->scopeChain();
    34923493    JSObject* variableObject = exec->variableObject();
     
    34963497    bool inGlobalScope = ++chain.begin() == chain.end();
    34973498
    3498     if (inGlobalScope && (init || !variableObject->getDirect(ident))) {
    3499         JSValue* val = init ? init->evaluate(exec) : jsUndefined();
    3500         int flags = Internal;
    3501         if (exec->codeType() != EvalCode)
    3502             flags |= DontDelete;
    3503         if (varType == VarDeclNode::Constant)
    3504             flags |= ReadOnly;
    3505         variableObject->putDirect(ident, val, flags);
    3506     } else if (init) {
    3507         JSValue* val = init->evaluate(exec);
    3508         KJS_CHECKEXCEPTIONVOID
     3499    if (init) {
     3500        if (inGlobalScope) {
     3501            JSValue* val = init->evaluate(exec);
     3502            int flags = Internal;
     3503            if (exec->codeType() != EvalCode)
     3504                flags |= DontDelete;
     3505            if (varType == VarDeclNode::Constant)
     3506                flags |= ReadOnly;
     3507            variableObject->put(exec, ident, val, flags);
     3508        } else {
     3509            JSValue* val = init->evaluate(exec);
     3510            KJS_CHECKEXCEPTIONVOID
     3511
     3512            // if the variable object is the top of the scope chain, then that must
     3513            // be where this variable is declared, processVarDecls would have put
     3514            // it there. Don't search the scope chain, to optimize this very common case.
     3515            if (chain.top() != variableObject)
     3516                return handleSlowCase(exec, chain, val);
     3517
     3518            unsigned flags = 0;
     3519            variableObject->getPropertyAttributes(ident, flags);
     3520            if (varType == VarDeclNode::Constant)
     3521                flags |= ReadOnly;
    35093522           
    3510         // if the variable object is the top of the scope chain, then that must
    3511         // be where this variable is declared, processVarDecls would have put
    3512         // it there. Don't search the scope chain, to optimize this very common case.
    3513         if (chain.top() != variableObject)
    3514             return handleSlowCase(exec, chain, val);
    3515 
    3516         unsigned flags = 0;
    3517         variableObject->getPropertyAttributes(ident, flags);
    3518         if (varType == VarDeclNode::Constant)
    3519             flags |= ReadOnly;
    3520        
    3521         ASSERT(variableObject->hasProperty(exec, ident));
    3522         variableObject->put(exec, ident, val, flags);
     3523            variableObject->put(exec, ident, val, flags);
     3524        }
    35233525    }
    35243526}
     
    42754277void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
    42764278{
    4277     size_t i, size;
    4278     size_t count = 0;
    4279 
    4280     // The order of additions here implicitly enforces the mutual exclusion described in ECMA 10.1.3.
    4281     for (i = 0, size = m_varStack.size(); i < size; ++i) {
    4282         if (m_varStack[i]->ident != exec->propertyNames().arguments)
    4283             m_symbolTable.set(m_varStack[i]->ident.ustring().rep(), count);
    4284         count++;
    4285     }
    4286 
    4287     for (i = 0, size = m_parameters.size(); i < size; ++i)
    4288         m_symbolTable.set(m_parameters[i].ustring().rep(), count++);
    4289 
    4290     for (i = 0, size = m_functionStack.size(); i < size; ++i)
    4291         m_symbolTable.set(m_functionStack[i]->ident.ustring().rep(), count++);
    4292 }
    4293 
    4294 void FunctionBodyNode::optimizeVariableAccess()
     4279    SymbolTable& symbolTable = exec->variableObject()->symbolTable();
     4280    ASSERT(!symbolTable.size());
     4281
     4282    size_t localStorageIndex = 0;
     4283
     4284    for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
     4285        UString::Rep* rep = m_parameters[i].ustring().rep();
     4286        symbolTable.set(rep, localStorageIndex);
     4287    }
     4288
     4289    for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
     4290        UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
     4291        symbolTable.set(rep, localStorageIndex);
     4292    }
     4293
     4294    for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
     4295        Identifier& ident = m_varStack[i]->ident;
     4296        if (ident == exec->propertyNames().arguments)
     4297            continue;
     4298        symbolTable.add(ident.ustring().rep(), localStorageIndex);
     4299    }
     4300}
     4301
     4302void ProgramNode::initializeSymbolTable(ExecState* exec)
     4303{
     4304    // If a previous script defined a symbol with the same name as one of our
     4305    // symbols, to avoid breaking previously optimized nodes, we need to reuse
     4306    // the symbol's existing storage index. So, we can't be as efficient as
     4307    // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
     4308    // have yet been made.
     4309   
     4310    JSVariableObject* variableObject = exec->variableObject();
     4311    SymbolTable& symbolTable = variableObject->symbolTable();
     4312
     4313    size_t localStorageIndex = symbolTable.size();
     4314    size_t size;
     4315   
     4316    size = m_functionStack.size();
     4317    m_functionIndexes.resize(size);
     4318    for (size_t i = 0; i < size; ++i) {
     4319        UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
     4320        pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
     4321        m_functionIndexes[i] = result.first->second;
     4322        if (result.second)
     4323            ++localStorageIndex;
     4324    }
     4325
     4326    size = m_varStack.size();
     4327    m_varIndexes.resize(size);
     4328    for (size_t i = 0; i < size; ++i) {
     4329        const Identifier& ident = m_varStack[i]->ident;
     4330        if (variableObject->getDirect(ident)) {
     4331            m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
     4332            continue;
     4333        }
     4334
     4335        UString::Rep* rep = ident.ustring().rep();
     4336        pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
     4337        if (!result.second) {
     4338            m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
     4339            continue;
     4340        }
     4341        m_varIndexes[i] = result.first->second;
     4342        ++localStorageIndex;
     4343    }
     4344}
     4345
     4346void ScopeNode::optimizeVariableAccess(ExecState* exec)
    42954347{
    42964348    DeclarationStacks::NodeStack nodeStack;
     
    42994351        return;
    43004352   
     4353    SymbolTable& symbolTable = exec->variableObject()->symbolTable();
    43014354    while (true) {
    4302         node->optimizeVariableAccess(m_symbolTable, nodeStack);
     4355        node->optimizeVariableAccess(symbolTable, nodeStack);
    43034356       
    43044357        size_t size = nodeStack.size();
     
    43154368    if (!m_initialized) {
    43164369        initializeSymbolTable(exec);
    4317         optimizeVariableAccess();
     4370        optimizeVariableAccess(exec);
    43184371       
    43194372        m_initialized = true;
     
    43214374
    43224375    LocalStorage& localStorage = exec->variableObject()->localStorage();
     4376   
     4377    // We can't just resize localStorage here because that would temporarily
     4378    // leave uninitialized entries, which would crash GC during the mark phase.
    43234379    localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
    43244380   
    43254381    int minAttributes = Internal | DontDelete;
    43264382   
    4327     size_t i, size;
    4328 
    4329     // NOTE: Must match the order of addition in initializeSymbolTable().
    4330 
    4331     for (i = 0, size = m_varStack.size(); i < size; ++i) {
     4383    // In order for our localStorage indexes to be correct, we must match the
     4384    // order of addition in initializeSymbolTable().
     4385
     4386    const List& args = *exec->arguments();
     4387    for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
     4388        localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
     4389
     4390    for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
     4391        FuncDeclNode* node = m_functionStack[i];
     4392        localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
     4393    }
     4394
     4395    for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
    43324396        VarDeclNode* node = m_varStack[i];
    43334397        int attributes = minAttributes;
    43344398        if (node->varType == VarDeclNode::Constant)
    43354399            attributes |= ReadOnly;
    4336         localStorage.append(LocalStorageEntry(jsUndefined(), attributes));
    4337     }
    4338 
    4339     const List& args = *exec->arguments();
    4340     for (i = 0, size = m_parameters.size(); i < size; ++i)
    4341         localStorage.append(LocalStorageEntry(args[i], DontDelete));
    4342 
    4343     for (i = 0, size = m_functionStack.size(); i < size; ++i) {
     4400        localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
     4401    }
     4402}
     4403
     4404static void gccIsCrazy() KJS_FAST_CALL;
     4405static void gccIsCrazy()
     4406{
     4407}
     4408
     4409void ProgramNode::processDeclarations(ExecState* exec)
     4410{
     4411    // If you remove this call, some SunSpider tests, including
     4412    // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
     4413    // increase in L2 cache misses. FIXME: WTF?
     4414    gccIsCrazy();
     4415   
     4416    initializeSymbolTable(exec);
     4417    optimizeVariableAccess(exec);
     4418
     4419    LocalStorage& localStorage = exec->variableObject()->localStorage();
     4420
     4421    // We can't just resize localStorage here because that would temporarily
     4422    // leave uninitialized entries, which would crash GC during the mark phase.
     4423    localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
     4424
     4425    int minAttributes = Internal | DontDelete;
     4426
     4427    // In order for our localStorage indexes to be correct, we must match the
     4428    // order of addition in initializeSymbolTable().
     4429
     4430    for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
    43444431        FuncDeclNode* node = m_functionStack[i];
    4345         localStorage.append(LocalStorageEntry(node->makeFunction(exec), minAttributes));
    4346     }
    4347 
    4348     exec->updateLocalStorage();
    4349 }
    4350 
    4351 void ProgramNode::processDeclarations(ExecState* exec)
    4352 {
    4353     size_t i, size;
    4354 
    4355     JSVariableObject* variableObject = exec->variableObject();
    4356    
    4357     int minAttributes = Internal | DontDelete;
    4358 
    4359     for (i = 0, size = m_varStack.size(); i < size; ++i) {
     4432        LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
     4433        size_t index = m_functionIndexes[i];
     4434
     4435        if (index == localStorage.size())
     4436            localStorage.uncheckedAppend(entry);
     4437        else {
     4438            ASSERT(index < localStorage.size());
     4439            localStorage[index] = entry;
     4440        }
     4441    }
     4442
     4443    for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
     4444        size_t index = m_varIndexes[i];
     4445        if (index == missingSymbolMarker())
     4446            continue;
     4447
    43604448        VarDeclNode* node = m_varStack[i];
    4361         if (variableObject->hasProperty(exec, node->ident))
    4362             continue;
    43634449        int attributes = minAttributes;
    43644450        if (node->varType == VarDeclNode::Constant)
    43654451            attributes |= ReadOnly;
    4366         variableObject->put(exec, node->ident, jsUndefined(), attributes);
    4367     }
    4368 
    4369     for (i = 0, size = m_functionStack.size(); i < size; ++i) {
    4370         FuncDeclNode* node = m_functionStack[i];
    4371         variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
     4452        LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
     4453           
     4454        ASSERT(index == localStorage.size());
     4455        localStorage.uncheckedAppend(entry);
    43724456    }
    43734457}
     
    43754459void EvalNode::processDeclarations(ExecState* exec)
    43764460{
     4461    // We could optimize access to pre-existing symbols here, but SunSpider
     4462    // reports that to be a net loss.
     4463
    43774464    size_t i, size;
    43784465
     
    43834470    for (i = 0, size = m_varStack.size(); i < size; ++i) {
    43844471        VarDeclNode* node = m_varStack[i];
    4385         if (variableObject->hasProperty(exec, node->ident))
     4472        if (variableObject->hasOwnProperty(exec, node->ident))
    43864473            continue;
    43874474        int attributes = minAttributes;
  • trunk/JavaScriptCore/kjs/nodes.h

    r28855 r28884  
    19481948    ScopeNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
    19491949
    1950     int sourceId() KJS_FAST_CALL { return m_sourceId; }
    1951     const UString& sourceURL() KJS_FAST_CALL { return m_sourceURL; }
    1952 
    1953   protected:
     1950    int sourceId() const KJS_FAST_CALL { return m_sourceId; }
     1951    const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
     1952
     1953  protected:
     1954    void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
    19541955
    19551956    DeclarationStacks::VarStack m_varStack;
     
    19671968   
    19681969  private:
     1970    void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
    19691971    ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
     1972
     1973    Vector<size_t> m_varIndexes; // Storage indexes belonging to the nodes in m_varStack. (Recorded to avoid double lookup.)
     1974    Vector<size_t> m_functionIndexes; // Storage indexes belonging to the nodes in m_functionStack. (Recorded to avoid double lookup.)
    19701975  };
    19711976
     
    19921997  private:
    19931998    void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
    1994     void optimizeVariableAccess() KJS_FAST_CALL;
    19951999    ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
    19962000
  • trunk/JavaScriptCore/kjs/object.cpp

    r28476 r28884  
    335335}
    336336
     337bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
     338{
     339    PropertySlot slot;
     340    return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
     341}
     342
    337343bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
    338344{
  • trunk/JavaScriptCore/kjs/object.h

    r28527 r28884  
    112112     */
    113113    JSObject();
    114 
     114   
    115115    virtual void mark();
    116116    virtual JSType type() const;
     
    284284     * @return true if the object has the property, otherwise false
    285285     */
    286     bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
    287     bool hasProperty(ExecState *exec, unsigned propertyName) const;
     286    bool hasProperty(ExecState*, const Identifier&) const;
     287    bool hasProperty(ExecState*, unsigned) const;
     288    bool hasOwnProperty(ExecState*, const Identifier&) const;
    288289
    289290    /**
     
    444445    void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
    445446
    446     /**
    447      * Remove all properties from this object.
    448      * This doesn't take DontDelete into account, and isn't in the ECMA spec.
    449      * It's simply a quick way to remove everything stored in the property map.
    450      */
    451     void clearProperties() { _prop.clear(); }
    452 
    453447    void saveProperties(SavedProperties &p) const { _prop.save(p); }
    454448    void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
     
    456450    virtual bool isActivationObject() { return false; }
    457451    virtual bool isGlobalObject() const { return false; }
     452
    458453  protected:
    459454    PropertyMap _prop;
     455
    460456  private:
    461457    const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
  • trunk/JavaScriptCore/kjs/object_object.cpp

    r28476 r28884  
    7575        case ValueOf:
    7676            return thisObj;
    77         case HasOwnProperty: {
    78             PropertySlot slot;
    79             return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(args[0]->toString(exec)), slot));
    80         }
     77        case HasOwnProperty:
     78            return jsBoolean(thisObj->hasOwnProperty(exec, Identifier(args[0]->toString(exec))));
    8179        case IsPrototypeOf: {
    8280            if (!args[0]->isObject())
  • trunk/JavaScriptCore/kjs/property_map.cpp

    r28110 r28884  
    123123};
    124124
    125 struct SavedProperty {
    126     Identifier key;
    127     ProtectedPtr<JSValue> value;
    128     unsigned attributes;
    129 };
    130 
    131125static const unsigned emptyEntryIndex = 0;
    132126static const unsigned deletedSentinelIndex = 1;
  • trunk/JavaScriptCore/kjs/property_map.h

    r28110 r28884  
    2424
    2525#include "identifier.h"
     26#include "protect.h"
    2627#include <wtf/OwnArrayPtr.h>
    2728
     
    3435    struct PropertyMapEntry;
    3536    struct PropertyMapHashTable;
    36     struct SavedProperty;
    3737   
    38     class SavedProperties {
    39         friend class PropertyMap;
    40     public:
     38    struct SavedProperty {
     39        Identifier key;
     40        ProtectedPtr<JSValue> value;
     41        unsigned attributes;
     42    };
     43
     44    struct SavedProperties {
    4145        SavedProperties();
    4246        ~SavedProperties();
    4347       
    44     private:
    4548        unsigned m_count;
    4649        OwnArrayPtr<SavedProperty> m_properties;
     
    5154        PropertyMap();
    5255        ~PropertyMap();
    53 
     56       
    5457        void clear();
    5558       
Note: See TracChangeset for help on using the changeset viewer.