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.cpp

    r35830 r36016  
    5757#endif
    5858
    59     JSValue* prototype = m_prototype;
    60     if (!prototype->marked())
    61         prototype->mark();
    62 
     59    m_structureID->mark();
    6360    m_propertyMap.mark();
    6461
     
    8784
    8885// ECMA 8.6.2.2
    89 void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
     86void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
    9087{
    9188    ASSERT(value);
     
    114111    JSValue* prototype;
    115112    for (JSObject* obj = this; !obj->m_propertyMap.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
    116         prototype = obj->m_prototype;
     113        prototype = obj->prototype();
    117114        if (prototype == jsNull()) {
    118             m_propertyMap.put(propertyName, value, 0, true);
     115            putDirect(propertyName, value, 0, true, slot);
    119116            return;
    120117        }
     
    126123
    127124    for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
    128         if (JSValue* gs = obj->m_propertyMap.get(propertyName, attributes)) {
    129             if (attributes & IsGetterSetter) {
     125        if (JSValue* gs = obj->m_propertyMap.get(propertyName)) {
     126            if (gs->isGetterSetter()) {
    130127                JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();       
    131128                if (!setterFunc) {
     
    147144        }
    148145
    149         prototype = obj->m_prototype;
     146        prototype = obj->prototype();
    150147        if (prototype == jsNull())
    151148            break;
    152149    }
    153    
    154     m_propertyMap.put(propertyName, value, 0, true);
     150
     151    putDirect(propertyName, value, 0, true, slot);
     152    return;
    155153}
    156154
    157155void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
    158156{
    159     put(exec, Identifier::from(exec, propertyName), value);
     157    PutPropertySlot slot;
     158    put(exec, Identifier::from(exec, propertyName), value, slot);
    160159}
    161160
     
    190189        if ((attributes & DontDelete))
    191190            return false;
    192         m_propertyMap.remove(propertyName);
    193         if (attributes & IsGetterSetter)
    194             m_propertyMap.setHasGetterSetterProperties(m_propertyMap.containsGettersOrSetters());
     191        removeDirect(propertyName);
    195192        return true;
    196193    }
    197    
     194
    198195    // Look in the static hashtable of properties
    199196    const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
     
    249246{
    250247    // Must call toString first for Date objects.
    251     if ((hint == PreferString) || (hint != PreferNumber && m_prototype == exec->lexicalGlobalObject()->datePrototype())) {
     248    if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) {
    252249        if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
    253250            return value;
     
    279276void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction)
    280277{
     278    GetterSetter* getterSetter;
     279    PutPropertySlot slot;
     280
    281281    JSValue* object = getDirect(propertyName);
    282     GetterSetter* getterSetter;
    283282    if (object && object->isGetterSetter())
    284283        getterSetter = static_cast<GetterSetter*>(object);
    285284    else {
    286285        getterSetter = new (exec) GetterSetter;
    287         putDirect(propertyName, getterSetter, IsGetterSetter);
     286        putDirect(propertyName, getterSetter, None, true, slot);
     287    }
     288
     289    // putDirect will change our StructureID if we add a new property. For
     290    // getters and setters, though, we also need to change our StructureID
     291    // if we override an existing non-getter or non-setter.
     292    if (slot.type() != PutPropertySlot::NewProperty) {
     293        if (!m_structureID->isDictionary()) {
     294            RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID);
     295            setStructureID(structureID.release());
     296        }
    288297    }
    289298
     
    294303void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction)
    295304{
     305    GetterSetter* getterSetter;
     306    PutPropertySlot slot;
     307
    296308    JSValue* object = getDirect(propertyName);
    297     GetterSetter* getterSetter;
    298309    if (object && object->isGetterSetter())
    299310        getterSetter = static_cast<GetterSetter*>(object);
    300311    else {
    301312        getterSetter = new (exec) GetterSetter;
    302         putDirect(propertyName, getterSetter, IsGetterSetter);
    303     }
    304    
     313        putDirect(propertyName, getterSetter, None, true, slot);
     314    }
     315
     316    // putDirect will change our StructureID if we add a new property. For
     317    // getters and setters, though, we also need to change our StructureID
     318    // if we override an existing non-getter or non-setter.
     319    if (slot.type() != PutPropertySlot::NewProperty) {
     320        if (!m_structureID->isDictionary()) {
     321            RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID);
     322            setStructureID(structureID.release());
     323        }
     324    }
     325
    305326    m_propertyMap.setHasGetterSetterProperties(true);
    306327    getterSetter->setSetter(setterFunction);
     
    413434    }
    414435
    415     if (m_prototype->isObject())
    416         static_cast<JSObject*>(m_prototype)->getPropertyNames(exec, propertyNames);
     436    if (prototype()->isObject())
     437        static_cast<JSObject*>(prototype())->getPropertyNames(exec, propertyNames);
    417438}
    418439
     
    456477{
    457478    m_propertyMap.remove(propertyName);
     479    if (!m_structureID->isDictionary()) {
     480        RefPtr<StructureID> structureID = StructureID::dictionaryTransition(m_structureID);
     481        setStructureID(structureID.release());
     482    }
    458483}
    459484
     
    471496}
    472497
     498PassRefPtr<StructureID> JSObject::createInheritorID()
     499{
     500    m_inheritorID = StructureID::create(this);
     501    return m_inheritorID;
     502}
     503
    473504bool JSObject::isObject() const
    474505{
Note: See TracChangeset for help on using the changeset viewer.