Changeset 36016 in webkit for trunk/JavaScriptCore/kjs/JSObject.h


Ignore:
Timestamp:
Sep 1, 2008, 2:22:54 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


SunSpider says 4% faster. Tests heavy on dictionary-like access have
regressed a bit -- we have a lot of room to improve in this area,
but this patch is over-ripe as-is.


JSCells now have a StructureID that uniquely identifies their layout,
and holds their prototype.


JSValue::put takes a PropertySlot& argument, so it can fill in details
about where it put a value, for the sake of caching.

  • VM/CodeGenerator.cpp: (KJS::CodeGenerator::CodeGenerator): Avoid calling removeDirect if we can, since it disables inline caching in the global object. This can probably improve in the future.
  • kjs/JSGlobalObject.cpp: Nixed reset(), since it complicates caching, and wasn't really necessary.
  • kjs/JSObject.cpp: Tweaked getter / setter behavior not to rely on the IsGetterSetter flag, since the flag was buggy. This is necessary in order to avoid accidentally accessing a getter / setter as a normal property.


Also changed getter / setter creation to honor ReadOnly, matching Mozilla.


  • kjs/PropertyMap.cpp: Nixed clear(), since it complicates caching and isn't necessary.
  • kjs/Shell.cpp: Moved SamplingTool dumping outside the loop. This allows you to aggregate sampling of multiple files (or the same file repeatedly), which helped me track down regressions.
  • kjs/ustring.h: Moved IdentifierRepHash here to share it.

WebCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.

Updated for JavaScriptCore changes. Mostly mechanical addition of StructureIDs
to WebCore classes, and PutPropertySlot& arguments to put functions.

(WebCore::JSCSSStyleDeclaration::customPut): Be sure to play nice with
inline caching for global properties, so global assignment can be optimized.

  • ForwardingHeaders/kjs/StructureID.h: Added.
  • bindings/js/JSDOMBinding.h: (WebCore::DOMObject::DOMObject):
  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::put):
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWindowCustom.h: (WebCore::JSDOMWindow::customPut):
  • bindings/js/JSDOMWindowShell.cpp: (WebCore::JSDOMWindowShell::JSDOMWindowShell): (WebCore::JSDOMWindowShell::put):
  • bindings/js/JSDOMWindowShell.h:
  • bindings/js/JSEventTargetBase.h: (WebCore::JSEventTargetBase::put):
  • bindings/js/JSEventTargetNode.h: (WebCore::JSEventTargetNode::put):
  • bindings/js/JSHTMLAppletElementCustom.cpp: (WebCore::JSHTMLAppletElement::customPut):
  • bindings/js/JSHTMLEmbedElementCustom.cpp: (WebCore::JSHTMLEmbedElement::customPut):
  • bindings/js/JSHTMLInputElementBase.cpp: (WebCore::JSHTMLInputElementBase::put):
  • bindings/js/JSHTMLInputElementBase.h:
  • bindings/js/JSHTMLObjectElementCustom.cpp: (WebCore::JSHTMLObjectElement::customPut):
  • bindings/js/JSHistoryCustom.cpp: (WebCore::JSHistory::customPut):
  • bindings/js/JSInspectedObjectWrapper.cpp: (WebCore::JSInspectedObjectWrapper::wrap): (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
  • bindings/js/JSInspectedObjectWrapper.h:
  • bindings/js/JSInspectorCallbackWrapper.cpp: (WebCore::JSInspectorCallbackWrapper::wrap): (WebCore::JSInspectorCallbackWrapper::JSInspectorCallbackWrapper):
  • bindings/js/JSInspectorCallbackWrapper.h:
  • bindings/js/JSLocationCustom.cpp: (WebCore::JSLocation::customPut):
  • bindings/js/JSPluginElementFunctions.cpp: (WebCore::runtimeObjectCustomPut):
  • bindings/js/JSPluginElementFunctions.h:
  • bindings/js/JSQuarantinedObjectWrapper.cpp: (WebCore::JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper): (WebCore::JSQuarantinedObjectWrapper::put):
  • bindings/js/JSQuarantinedObjectWrapper.h:
  • bindings/js/JSStorageCustom.cpp: (WebCore::JSStorage::customPut):
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject setValue:forKey:]):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/NP_jsobject.cpp: (_NPN_SetProperty):
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::setMember):
  • bridge/objc/objc_class.mm: (KJS::Bindings::ObjcClass::fallbackObject):
  • bridge/objc/objc_runtime.h:
  • bridge/objc/objc_runtime.mm: (ObjcFallbackObjectImp::ObjcFallbackObjectImp): (ObjcFallbackObjectImp::put):
  • bridge/runtime.cpp: (KJS::Bindings::Instance::createRuntimeObject):
  • bridge/runtime_array.cpp: (RuntimeArray::put):
  • bridge/runtime_array.h:
  • bridge/runtime_object.cpp: (RuntimeObjectImp::RuntimeObjectImp): (RuntimeObjectImp::put):
  • bridge/runtime_object.h:

LayoutTests:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


Tests for things I broke along the way.


  • fast/dom/getter-on-window-object2-expected.txt:
  • fast/js/pic: Added.
  • fast/js/pic/cached-deleted-properties-expected.txt: Added.
  • fast/js/pic/cached-deleted-properties.html: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto-expected.txt: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto.html: Added.
  • fast/js/pic/cached-getter-setter-expected.txt: Added.
  • fast/js/pic/cached-getter-setter.html: Added.
  • fast/js/pic/cached-prototype-setter-expected.txt: Added.
  • fast/js/pic/cached-prototype-setter.html: Added.
  • fast/js/pic/cached-single-entry-transition-expected.txt: Added.
  • fast/js/pic/cached-single-entry-transition.html: Added.
  • fast/js/pic/get-empty-string-expected.txt: Added.
  • fast/js/pic/get-empty-string.html: Added.
  • fast/js/pic/get-set-proxy-object-expected.txt: Added.
  • fast/js/pic/get-set-proxy-object.html: Added.
  • fast/js/pic/rehash-poisons-structure-expected.txt: Added.
  • fast/js/pic/rehash-poisons-structure.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/JSObject.h

    r35830 r36016  
    3232#include "PropertySlot.h"
    3333#include "ScopeChain.h"
     34#include "StructureID.h"
    3435
    3536namespace KJS {
     
    3738    class InternalFunction;
    3839    class PropertyNameArray;
     40    class StructureID;
    3941    struct HashEntry;
    4042    struct HashTable;
     
    4850        DontDelete   = 1 << 3,  // property can't be deleted
    4951        Function     = 1 << 4,  // property is a function - only used by static hashtables
    50         IsGetterSetter = 1 << 5 // property is a getter or setter
    5152    };
    5253
    5354    class JSObject : public JSCell {
    5455    public:
    55         /**
    56          * Creates a new JSObject with the specified prototype
    57          *
    58          * @param prototype The prototype
    59          */
    60         JSObject(JSValue* prototype);
    61 
    62         /**
    63          * Creates a new JSObject with a prototype of jsNull()
    64          * (that is, the ECMAScript "null" value, not a null object pointer).
    65          */
    66         JSObject();
     56        JSObject(PassRefPtr<StructureID>);
     57        JSObject(JSObject* prototype);
     58        virtual ~JSObject();
    6759
    6860        virtual void mark();
     
    7264        JSValue* prototype() const;
    7365        void setPrototype(JSValue* prototype);
     66       
     67        PassRefPtr<StructureID> inheritorID();
    7468
    7569        virtual UString className() const;
     
    8478        virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
    8579
    86         virtual void put(ExecState*, const Identifier& propertyName, JSValue* value);
     80        virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, PutPropertySlot&);
    8781        virtual void put(ExecState*, unsigned propertyName, JSValue* value);
    8882
     
    125119        JSValue** getDirectLocation(const Identifier& propertyName) { return m_propertyMap.getLocation(propertyName); }
    126120        JSValue** getDirectLocation(const Identifier& propertyName, bool& isWriteable) { return m_propertyMap.getLocation(propertyName, isWriteable); }
    127         void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0);
    128         void putDirect(ExecState*, const Identifier& propertyName, int value, unsigned attr = 0);
     121        size_t offsetForLocation(JSValue** location) { return m_propertyMap.offsetForLocation(location); }
    129122        void removeDirect(const Identifier& propertyName);
    130123        bool hasCustomProperties() { return !m_propertyMap.isEmpty(); }
    131 
    132         // convenience to add a function property under the function's own built-in name
    133         void putDirectFunction(ExecState*, InternalFunction*, unsigned attr = 0);
     124        bool hasGetterSetterProperties() { return m_propertyMap.hasGetterSetterProperties(); }
     125
     126        void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0);
     127        void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
     128        void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
     129
     130        // Fast access to known property offsets.
     131        JSValue* getDirectOffset(size_t offset) { return m_propertyMap.getOffset(offset); }
     132        void putDirectOffset(size_t offset, JSValue* v) { m_propertyMap.putOffset(offset, v); }
    134133
    135134        void fillGetterPropertySlot(PropertySlot&, JSValue** location);
     
    143142        virtual bool isGlobalObject() const { return false; }
    144143        virtual bool isVariableObject() const { return false; }
    145 
    146144        virtual bool isWatchdogException() const { return false; }
    147        
    148145        virtual bool isNotAnObjectErrorStub() const { return false; }
    149146
    150147    protected:
    151         PropertyMap m_propertyMap;
    152148        bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
    153149
     
    156152
    157153        const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
    158         JSValue* m_prototype;
     154        void setStructureID(PassRefPtr<StructureID>);
     155        PassRefPtr<StructureID> createInheritorID();
     156
     157        PropertyMap m_propertyMap;
     158        RefPtr<StructureID> m_inheritorID;
    159159    };
    160160
    161161  JSObject* constructEmptyObject(ExecState*);
    162162
    163 inline JSObject::JSObject(JSValue* prototype)
    164     : m_prototype(prototype)
     163inline JSObject::JSObject(JSObject* prototype)
     164    : JSCell(prototype->inheritorID().releaseRef()) // ~JSObject balances this ref()
     165{
     166    ASSERT(m_structureID);
     167    ASSERT(this->prototype());
     168    ASSERT(this->prototype() == jsNull() || Heap::heap(this) == Heap::heap(this->prototype()));
     169}
     170
     171inline JSObject::JSObject(PassRefPtr<StructureID> structureID)
     172    : JSCell(structureID.releaseRef()) // ~JSObject balances this ref()
     173{
     174    ASSERT(m_structureID);
     175}
     176
     177inline JSObject::~JSObject()
     178{
     179    ASSERT(m_structureID);
     180    m_structureID->deref();
     181}
     182
     183inline JSValue* JSObject::prototype() const
     184{
     185    return m_structureID->prototype();
     186}
     187
     188inline void JSObject::setPrototype(JSValue* prototype)
    165189{
    166190    ASSERT(prototype);
    167     ASSERT(prototype == jsNull() || Heap::heap(this) == Heap::heap(prototype));
    168 }
    169 
    170 inline JSObject::JSObject()
    171     : m_prototype(jsNull())
    172 {
    173 }
    174 
    175 inline JSValue* JSObject::prototype() const
    176 {
    177     return m_prototype;
    178 }
    179 
    180 inline void JSObject::setPrototype(JSValue* prototype)
    181 {
    182     ASSERT(prototype);
    183     m_prototype = prototype;
     191    RefPtr<StructureID> newStructureID = StructureID::changePrototypeTransition(m_structureID, prototype);
     192    setStructureID(newStructureID.release());
     193}
     194
     195inline void JSObject::setStructureID(PassRefPtr<StructureID> structureID)
     196{
     197    m_structureID->deref();
     198    m_structureID = structureID.releaseRef(); // ~JSObject balances this ref()
     199}
     200
     201inline PassRefPtr<StructureID> JSObject::inheritorID()
     202{
     203    if (m_inheritorID)
     204        return m_inheritorID.get();
     205    return createInheritorID();
    184206}
    185207
     
    226248            return true;
    227249
    228         JSValue* prototype = object->m_prototype;
     250        JSValue* prototype = object->prototype();
    229251        if (!prototype->isObject())
    230252            return false;
     
    242264            return true;
    243265
    244         JSValue* prototype = object->m_prototype;
     266        JSValue* prototype = object->prototype();
    245267        if (!prototype->isObject())
    246268            break;
     
    262284            fillGetterPropertySlot(slot, location);
    263285        } else
    264             slot.setValueSlot(location);
     286            slot.setValueSlot(this, location, offsetForLocation(location));
    265287        return true;
    266288    }
     
    268290    // non-standard Netscape extension
    269291    if (propertyName == exec->propertyNames().underscoreProto) {
    270         slot.setValueSlot(&m_prototype);
     292        slot.setValue(prototype());
    271293        slotIsWriteable = false;
    272294        return true;
     
    285307            fillGetterPropertySlot(slot, location);
    286308        else
    287             slot.setValueSlot(location);
     309            slot.setValueSlot(this, location, offsetForLocation(location));
    288310        return true;
    289311    }
     
    291313    // non-standard Netscape extension
    292314    if (propertyName == exec->propertyNames().underscoreProto) {
    293         slot.setValueSlot(&m_prototype);
     315        slot.setValue(prototype());
    294316        return true;
    295317    }
     
    300322inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr)
    301323{
     324    PutPropertySlot slot;
     325    putDirect(propertyName, value, attr, false, slot);
     326}
     327
     328inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot)
     329{
    302330    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    303 
    304     m_propertyMap.put(propertyName, value, attr);
    305 }
    306 
    307 inline void JSObject::putDirect(ExecState* exec, const Identifier& propertyName, int value, unsigned attr)
    308 {
    309     m_propertyMap.put(propertyName, jsNumber(exec, value), attr);
     331    m_propertyMap.put(propertyName, value, attr, checkReadOnly, this, slot);
     332    if (slot.type() == PutPropertySlot::NewProperty) {
     333        if (!m_structureID->isDictionary()) {
     334            RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName);
     335            setStructureID(structureID.release());
     336        }
     337    }
    310338}
    311339
     
    316344
    317345inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) const
     346{
     347    PropertySlot slot(const_cast<JSValue*>(this));
     348    return get(exec, propertyName, slot);
     349}
     350
     351inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
    318352{
    319353    if (UNLIKELY(JSImmediate::isImmediate(this))) {
    320354        JSObject* prototype = JSImmediate::prototype(this, exec);
    321         PropertySlot slot(const_cast<JSValue*>(this));
    322355        if (!prototype->getPropertySlot(exec, propertyName, slot))
    323356            return jsUndefined();
     
    325358    }
    326359    JSCell* cell = static_cast<JSCell*>(const_cast<JSValue*>(this));
    327     PropertySlot slot(cell);
    328360    while (true) {
    329361        if (cell->getOwnPropertySlot(exec, propertyName, slot))
     
    339371inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName) const
    340372{
     373    PropertySlot slot(const_cast<JSValue*>(this));
     374    return get(exec, propertyName, slot);
     375}
     376
     377inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
     378{
    341379    if (UNLIKELY(JSImmediate::isImmediate(this))) {
    342380        JSObject* prototype = JSImmediate::prototype(this, exec);
    343         PropertySlot slot(const_cast<JSValue*>(this));
    344381        if (!prototype->getPropertySlot(exec, propertyName, slot))
    345382            return jsUndefined();
     
    347384    }
    348385    JSCell* cell = const_cast<JSCell*>(asCell());
    349     PropertySlot slot(cell);
    350386    while (true) {
    351387        if (cell->getOwnPropertySlot(exec, propertyName, slot))
     
    359395}
    360396
    361 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
     397inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
     398{
     399    if (UNLIKELY(JSImmediate::isImmediate(this))) {
     400        JSImmediate::toObject(this, exec)->put(exec, propertyName, value, slot);
     401        return;
     402    }
     403    asCell()->put(exec, propertyName, value, slot);
     404}
     405
     406inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
    362407{
    363408    if (UNLIKELY(JSImmediate::isImmediate(this))) {
     
    368413}
    369414
    370 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
    371 {
    372     if (UNLIKELY(JSImmediate::isImmediate(this))) {
    373         JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
    374         return;
    375     }
    376     asCell()->put(exec, propertyName, value);
    377 }
    378 
    379415} // namespace KJS
    380416
Note: See TracChangeset for help on using the changeset viewer.