Changeset 27126 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Oct 26, 2007, 3:43:03 PM (18 years ago)
Author:
ggaren
Message:

Reviewed by Maciej Stachowiak.


Switched ActivationImp to using a symbol table. For now, though, all
clients take the slow path.


Net .6% speedup on SunSpider.


Slowdowns:

  • ActivationImp now mallocs in its constructor
  • Local variable hits use an extra level of indirection to retrieve data
  • Local variable misses do two lookups

Speedups:

  • Fast initialization of local variables upon function entry


  • kjs/function.cpp: (KJS::ActivationImp::ActivationImp): Malloc a private structure to hold data that won't fit in a JSCell. (KJS::ActivationImp::argumentsGetter): Use slow symbol table path for lookup. (KJS::ActivationImp::getOwnPropertySlot): ditto (KJS::ActivationImp::deleteProperty): ditto (KJS::ActivationImp::put): ditto (KJS::ActivationImp::createArgumentsObject): ditto

(KJS::ActivationImp::mark): Call JSObject::mark first so that one of
our properties doesn't try to recursively mark us. (This caused a crash
in earlier testing. Not sure why we haven't run into it before.)

  • kjs/nodes.cpp: Functions now build a symbol table the first time they're called. (KJS::VarDeclNode::evaluate): (KJS::FunctionBodyNode::FunctionBodyNode): (KJS::FunctionBodyNode::initializeSymbolTable): (KJS::FunctionBodyNode::processDeclarations): (KJS::FunctionBodyNode::processDeclarationsForFunctionCode): (KJS::FunctionBodyNode::processDeclarationsForProgramCode):
  • kjs/nodes.h: (KJS::FunctionBodyNode::symbolTable):
  • wtf/Forward.h: Added Vector.
Location:
trunk/JavaScriptCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r27124 r27126  
     12007-10-26  Geoffrey Garen  <[email protected]>
     2
     3        Reviewed by Maciej Stachowiak.
     4       
     5        Switched ActivationImp to using a symbol table. For now, though, all
     6        clients take the slow path.
     7       
     8        Net .6% speedup on SunSpider.
     9       
     10        Slowdowns:
     11            - ActivationImp now mallocs in its constructor
     12            - Local variable hits use an extra level of indirection to retrieve
     13            data
     14            - Local variable misses do two lookups
     15
     16        Speedups:
     17            - Fast initialization of local variables upon function entry
     18
     19        * JavaScriptCore.xcodeproj/project.pbxproj: Added SymbolTable.h
     20       
     21        * kjs/function.cpp:
     22        (KJS::ActivationImp::ActivationImp): Malloc a private structure to hold
     23        data that won't fit in a JSCell.
     24        (KJS::ActivationImp::argumentsGetter): Use slow symbol table path for
     25        lookup.
     26        (KJS::ActivationImp::getOwnPropertySlot): ditto
     27        (KJS::ActivationImp::deleteProperty): ditto
     28        (KJS::ActivationImp::put): ditto
     29        (KJS::ActivationImp::createArgumentsObject): ditto
     30
     31        (KJS::ActivationImp::mark): Call JSObject::mark first so that one of
     32        our properties doesn't try to recursively mark us. (This caused a crash
     33        in earlier testing. Not sure why we haven't run into it before.)
     34
     35        * kjs/nodes.cpp: Functions now build a symbol table the first time
     36        they're called.
     37        (KJS::VarDeclNode::evaluate):
     38        (KJS::FunctionBodyNode::FunctionBodyNode):
     39        (KJS::FunctionBodyNode::initializeSymbolTable):
     40        (KJS::FunctionBodyNode::processDeclarations):
     41        (KJS::FunctionBodyNode::processDeclarationsForFunctionCode):
     42        (KJS::FunctionBodyNode::processDeclarationsForProgramCode):
     43
     44        * kjs/nodes.h:
     45        (KJS::FunctionBodyNode::symbolTable):
     46
     47        * wtf/Forward.h: Added Vector.
     48
    1492007-10-26  Kevin McCullough  <[email protected]>
    250
  • trunk/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj

    r27123 r27126  
    493493                        <File
    494494                                RelativePath="..\..\kjs\string_object.h"
     495                                >
     496                        </File>
     497                        <File
     498                                RelativePath="..\..\kjs\SymbolTable.h"
    495499                                >
    496500                        </File>
  • trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r27097 r27126  
    6767                1483B58A099BC1950016E4F0 /* JSImmediate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1483B589099BC1950016E4F0 /* JSImmediate.h */; settings = {ATTRIBUTES = (Private, ); }; };
    6868                148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 148A1626095D16BB00666D0D /* ListRefPtr.h */; };
     69                14A396A70CD2933100B5B4FF /* SymbolTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A396A60CD2933100B5B4FF /* SymbolTable.h */; };
    6970                14ABB36F099C076400E2A24F /* value.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB36E099C076400E2A24F /* value.h */; settings = {ATTRIBUTES = (Private, ); }; };
    7071                14ABB455099C2A0F00E2A24F /* JSType.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB454099C2A0F00E2A24F /* JSType.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    421422                1483B589099BC1950016E4F0 /* JSImmediate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSImmediate.h; sourceTree = "<group>"; };
    422423                148A1626095D16BB00666D0D /* ListRefPtr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ListRefPtr.h; sourceTree = "<group>"; };
     424                14A396A60CD2933100B5B4FF /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolTable.h; sourceTree = "<group>"; };
    423425                14ABB36E099C076400E2A24F /* value.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = value.h; sourceTree = "<group>"; };
    424426                14ABB454099C2A0F00E2A24F /* JSType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSType.h; sourceTree = "<group>"; };
     
    10381040                                F692A87F0255597D01FF60F7 /* string_object.cpp */,
    10391041                                F692A8800255597D01FF60F7 /* string_object.h */,
     1042                                14A396A60CD2933100B5B4FF /* SymbolTable.h */,
    10401043                                F692A8840255597D01FF60F7 /* types.h */,
    10411044                                F692A8850255597D01FF60F7 /* ustring.cpp */,
     
    12631266                                A8E894320CD0602400367179 /* JSCallbackObjectFunctions.h in Headers */,
    12641267                                A8E894340CD0603F00367179 /* JSGlobalObject.h in Headers */,
     1268                                14A396A70CD2933100B5B4FF /* SymbolTable.h in Headers */,
    12651269                        );
    12661270                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/JavaScriptCore/kjs/function.cpp

    r27100 r27126  
    391391const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
    392392
    393 // ECMA 10.1.6
    394393ActivationImp::ActivationImp(FunctionImp* function, const List& arguments)
    395     : _function(function), _arguments(arguments), _argumentsObject(0)
    396 {
    397   // FIXME: Do we need to support enumerating the arguments property?
     394    : d(new ActivationImpPrivate(function, arguments))
     395    , symbolTable(&function->body->symbolTable())
     396{
    398397}
    399398
     
    401400{
    402401  ActivationImp* thisObj = static_cast<ActivationImp*>(slot.slotBase());
    403 
    404   // default: return builtin arguments array
    405   if (!thisObj->_argumentsObject)
     402  ActivationImpPrivate* d = thisObj->d.get();
     403 
     404  if (!d->argumentsObject)
    406405    thisObj->createArgumentsObject(exec);
    407406 
    408   return thisObj->_argumentsObject;
     407  return d->argumentsObject;
    409408}
    410409
     
    416415bool ActivationImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    417416{
    418     // do this first so property map arguments property wins over the below
    419     // we don't call JSObject because we won't have getter/setter properties
    420     // and we don't want to support __proto__
     417    // We don't call through to JSObject because there's no way to give an
     418    // acitvation object getter/setter properties, and exposing __proto__ in
     419    // the scope chain would be bizarre.
     420    ASSERT(!_prop.hasGetterSetterProperties());
     421
     422    size_t index;
     423    if (symbolTable->get(propertyName, index)) {
     424        slot.setValueSlot(this, &d->localStorage[index].value);
     425        return true;
     426    }
    421427
    422428    if (JSValue** location = getDirectLocation(propertyName)) {
     
    425431    }
    426432
     433    // Only return the built-in arguments object if it wasn't overridden above.
    427434    if (propertyName == exec->propertyNames().arguments) {
    428435        slot.setCustom(this, getArgumentsGetter());
     
    437444    if (propertyName == exec->propertyNames().arguments)
    438445        return false;
     446
     447    size_t index;
     448    if (symbolTable->get(propertyName, index))
     449        return false;
     450
    439451    return JSObject::deleteProperty(exec, propertyName);
    440452}
     
    442454void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value, int attr)
    443455{
    444   // There's no way that an activation object can have a prototype or getter/setter properties
     456  // There's no way that an activation object can have a prototype or getter/setter properties.
    445457  ASSERT(!_prop.hasGetterSetterProperties());
    446458  ASSERT(prototype() == jsNull());
    447459
     460  size_t index;
     461  if (symbolTable->get(propertyName, index)) {
     462    LocalStorageEntry& entry = d->localStorage[index];
     463    entry.value = value;
     464    entry.attributes = attr;
     465    return;
     466  }
     467
    448468  _prop.put(propertyName, value, attr, (attr == None || attr == DontDelete));
    449469}
     
    451471void ActivationImp::mark()
    452472{
    453     if (_function && !_function->marked())
    454         _function->mark();
    455     if (_argumentsObject && !_argumentsObject->marked())
    456         _argumentsObject->mark();
    457473    JSObject::mark();
     474
     475    if (!d->function->marked())
     476        d->function->mark();
     477
     478    size_t size = d->localStorage.size();
     479    for (size_t i = 0; i < size; ++i) {
     480        JSValue* value = d->localStorage[i].value;
     481        if (!value->marked())
     482            value->mark();
     483    }
     484
     485    if (d->argumentsObject && !d->argumentsObject->marked())
     486        d->argumentsObject->mark();
    458487}
    459488
    460489void ActivationImp::createArgumentsObject(ExecState* exec)
    461490{
    462   _argumentsObject = new Arguments(exec, _function, _arguments, const_cast<ActivationImp*>(this));
    463   // The arguments list is only needed to create the arguments object, so discard it now
    464   _arguments.reset();
     491  d->argumentsObject = new Arguments(exec, d->function, d->arguments, this);
     492
     493  // The arguments list is only needed to create the arguments object, so discard it now.
     494  // This prevents lists of Lists from building up, waiting to be garbage collected.
     495  d->arguments.reset();
    465496}
    466497
  • trunk/JavaScriptCore/kjs/function.h

    r27097 r27126  
    2525#define KJS_FUNCTION_H
    2626
     27#include "SymbolTable.h"
    2728#include "object.h"
    2829#include <wtf/OwnPtr.h>
     
    138139  class ActivationImp : public JSObject {
    139140  public:
    140     ActivationImp(FunctionImp* function, const List& arguments);
     141    struct LocalStorageEntry {
     142        LocalStorageEntry()
     143        {
     144        }
     145
     146        LocalStorageEntry(JSValue* v, int a)
     147            : value(v)
     148            , attributes(a)
     149        {
     150        }
     151
     152        JSValue* value;
     153        int attributes;
     154    };
     155
     156    typedef Vector<LocalStorageEntry, 32> LocalStorage;
     157
     158  private:
     159    struct ActivationImpPrivate {
     160        ActivationImpPrivate(FunctionImp* f, const List& a)
     161            : function(f)
     162            , arguments(a)
     163            , argumentsObject(0)
     164        {
     165            ASSERT(f);
     166        }
     167       
     168        FunctionImp* function;
     169        LocalStorage localStorage;
     170
     171        List arguments;
     172        Arguments* argumentsObject;
     173    };
     174
     175  public:
     176    ActivationImp::ActivationImp(FunctionImp* function, const List& arguments);
    141177
    142178    virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
     
    151187    bool isActivation() { return true; }
    152188
    153     void releaseArguments() { _arguments.reset(); }
     189    void releaseArguments() { d->arguments.reset(); }
     190   
     191    LocalStorage& localStorage() { return d->localStorage; };
    154192
    155193  private:
     
    157195    static JSValue* argumentsGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot);
    158196    void createArgumentsObject(ExecState*);
    159 
    160     FunctionImp* _function;
    161     List _arguments;
    162     mutable Arguments* _argumentsObject;
     197   
     198    OwnPtr<ActivationImpPrivate> d;
     199    SymbolTable* symbolTable;
    163200  };
    164201
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r27100 r27126  
    18351835            flags |= ReadOnly;
    18361836       
    1837         ASSERT(variableObject->getDirect(ident) || ident == exec->propertyNames().arguments);
     1837        ASSERT(variableObject->hasProperty(exec, ident));
    18381838        variableObject->put(exec, ident, val, flags);
    18391839    }
     
    25792579    , m_sourceId(Parser::sid)
    25802580    , m_initializedDeclarationStacks(false)
     2581    , m_initializedSymbolTable(false)
    25812582{
    25822583  setLoc(-1, -1);
     
    26072608}
    26082609
    2609 void FunctionBodyNode::processDeclarationsFunctionCode(ExecState* exec)
     2610void FunctionBodyNode::initializesymbolTable()
    26102611{
    26112612    size_t i, size;
    2612 
    2613     JSObject* variableObject = exec->variableObject();
    2614 
     2613    size_t count = 0;
     2614
     2615    // The order of additions here implicitly enforces the mutual exclusion described in ECMA 10.1.3.
     2616    for (i = 0, size = m_varStack.size(); i < size; ++i)
     2617        m_symbolTable.set(m_varStack[i]->ident, count++);
     2618
     2619    for (i = 0, size = m_parameters.size(); i < size; ++i)
     2620        m_symbolTable.set(m_parameters[i], count++);
     2621
     2622    for (i = 0, size = m_functionStack.size(); i < size; ++i)
     2623        m_symbolTable.set(m_functionStack[i]->ident, count++);
     2624
     2625    m_initializedSymbolTable = true;
     2626}
     2627
     2628void FunctionBodyNode::processDeclarations(ExecState* exec)
     2629{
     2630    if (!m_initializedDeclarationStacks)
     2631        initializeDeclarationStacks(exec);
     2632
     2633    if (exec->codeType() == FunctionCode)
     2634        processDeclarationsForFunctionCode(exec);
     2635    else
     2636        processDeclarationsForProgramCode(exec);
     2637}
     2638
     2639void FunctionBodyNode::processDeclarationsForFunctionCode(ExecState* exec)
     2640{
     2641    if (!m_initializedSymbolTable)
     2642        initializesymbolTable();
     2643
     2644    ASSERT(exec->variableObject()->isActivation());
     2645    ActivationImp::LocalStorage& localStorage = static_cast<ActivationImp*>(exec->variableObject())->localStorage();
     2646    localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
     2647   
    26152648    int minAttributes = Internal | DontDelete;
    2616 
    2617     // The order of additions to the variable object here implicitly enforces the mutual exclusion described in ECMA 10.1.3.
     2649   
     2650    size_t i, size;
     2651
     2652    // NOTE: Must match the order of addition in initializesymbolTable().
     2653
    26182654    for (i = 0, size = m_varStack.size(); i < size; ++i) {
    26192655        VarDeclNode* node = m_varStack[i];
     
    26212657        if (node->varType == VarDeclNode::Constant)
    26222658            attributes |= ReadOnly;
    2623         variableObject->put(exec, node->ident, jsUndefined(), attributes);
     2659        localStorage.append(ActivationImp::LocalStorageEntry(jsUndefined(), attributes));
    26242660    }
    26252661
    26262662    const List& args = *exec->arguments();
    26272663    for (i = 0, size = m_parameters.size(); i < size; ++i)
    2628         variableObject->put(exec, m_parameters[i], args[i], DontDelete);
     2664        localStorage.append(ActivationImp::LocalStorageEntry(args[i], DontDelete));
    26292665
    26302666    for (i = 0, size = m_functionStack.size(); i < size; ++i) {
    26312667        FuncDeclNode* node = m_functionStack[i];
    2632         variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
     2668        localStorage.append(ActivationImp::LocalStorageEntry(node->makeFunction(exec), minAttributes));
    26332669    }
    26342670}
    26352671
    2636 void FunctionBodyNode::processDeclarationsProgramCode(ExecState* exec)
     2672void FunctionBodyNode::processDeclarationsForProgramCode(ExecState* exec)
    26372673{
    26382674    size_t i, size;
     
    26782714}
    26792715
    2680 void FunctionBodyNode::processDeclarations(ExecState* exec)
    2681 {
    2682     if (!m_initializedDeclarationStacks)
    2683         initializeDeclarationStacks(exec);
    2684 
    2685     if (exec->codeType() == FunctionCode)
    2686         processDeclarationsFunctionCode(exec);
    2687     else
    2688         processDeclarationsProgramCode(exec);
    2689 }
    2690 
    26912716Completion FunctionBodyNode::execute(ExecState* exec)
    26922717{
  • trunk/JavaScriptCore/kjs/nodes.h

    r27028 r27126  
    12351235
    12361236    virtual Completion execute(ExecState*) KJS_FAST_CALL;
     1237   
     1238    SymbolTable& symbolTable() { return m_symbolTable; }
    12371239
    12381240    void addParam(const Identifier& ident) KJS_FAST_CALL;
     
    12421244    Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
    12431245    ALWAYS_INLINE void processDeclarations(ExecState*);
    1244     ALWAYS_INLINE void processDeclarationsFunctionCode(ExecState*);
    1245     ALWAYS_INLINE void processDeclarationsProgramCode(ExecState*);
     1246    ALWAYS_INLINE void processDeclarationsForFunctionCode(ExecState*);
     1247    ALWAYS_INLINE void processDeclarationsForProgramCode(ExecState*);
    12461248  private:
    12471249    UString m_sourceURL;
     
    12511253    bool m_initializedDeclarationStacks;
    12521254
    1253     // Properties that will go into the ActivationImp's symbol table. (Used for initializing the ActivationImp.)
    1254     DeclarationStacks::VarStack m_varStack;
    1255     DeclarationStacks::FunctionStack m_functionStack;
    1256     Vector<Identifier> m_parameters;
     1255    void initializesymbolTable();
     1256    bool m_initializedSymbolTable;
     1257   
     1258    // Properties that will go into the ActivationImp's local storage. (Used for initializing the ActivationImp.)
     1259     DeclarationStacks::VarStack m_varStack;
     1260     DeclarationStacks::FunctionStack m_functionStack;
     1261     Vector<Identifier> m_parameters;
     1262
     1263    // Mapping from property name -> local storage index. (Used once to transform the AST, and subsequently for residual slow case lookups.)
     1264    SymbolTable m_symbolTable;
    12571265  };
    12581266
  • trunk/JavaScriptCore/wtf/Forward.h

    r17127 r27126  
    3030    template<typename T> class PassRefPtr;
    3131    template<typename T> class RefPtr;
     32    template<typename T, size_t inlineCapacity> class Vector;
    3233}
    3334
     
    3738using WTF::PassRefPtr;
    3839using WTF::RefPtr;
     40using WTF::Vector;
    3941
    4042#endif // WTF_Forward_h
Note: See TracChangeset for help on using the changeset viewer.