Ignore:
Timestamp:
May 22, 2009, 6:48:32 PM (16 years ago)
Author:
[email protected]
Message:

2009-05-21 Gavin Barraclough <[email protected]>

Reviewed by Geoff Garen.

op_method_check

Optimize method calls, by caching specific function values within the Structure.
The new opcode is used almost like an x86 opcode prefix byte to optimize op_get_by_id,
where the property access is being used to read a function to be passed to op-call (i.e.
'foo.bar();'). This patch modifies the Structure class such that when a property is
put to an object for the first time we will check if the value is a function. If it is,
we will cache the function value on the Structure. A Structure in such a state guarantees
that not only does a property with the given identifier exist on the object, but also that
its value is unchanged. Upon any further attempt to put a property with the same identifier
(but a different value) to the object, it will transition back to a normal Structure (where
it will guarantee the presence but not the value of the property).

op_method_check makes use of the new information made available by the Structure, by
augmenting the functionality of op_get_by_id. Upon generating a FunctionCallDotNode a
check will be emitted prior to the property access reading the function value, and the JIT
will generate an extra (initially unlinked but patchable) set of checks prior to the regular
JIT code for get_by_id. The new code will do inline structure and prototype structure check
(unlike a regular get_by_id, which can only handle 'self' accesses inline), and then performs
an immediate load of the function value, rather than using memory accesses to load the value
from the obejct's property storage array. If the method check fails it will revert, or if
the access is polymorphic, the op_get_by_id will continue to operate - and optimize itself -
just as any other regular op_get_by_id would.

~2.5% on v8-tests, due to a ~9% progression on richards.

  • API/JSCallbackObjectFunctions.h: (JSC::::put): (JSC::::staticFunctionGetter):
  • API/JSObjectRef.cpp: (JSObjectMakeConstructor):
  • JavaScriptCore.exp:
  • assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::differenceBetween):
  • assembler/MacroAssemblerX86.h: (JSC::MacroAssemblerX86::moveWithPatch):
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • bytecode/CodeBlock.h: (JSC::getMethodCallLinkInfoReturnLocation): (JSC::CodeBlock::getMethodCallLinkInfo): (JSC::CodeBlock::addMethodCallLinkInfos): (JSC::CodeBlock::methodCallLinkInfo):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitMethodCheck):
  • bytecompiler/BytecodeGenerator.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases): (JSC::JIT::privateCompile):
  • jit/JIT.h: (JSC::MethodCallCompilationInfo::MethodCallCompilationInfo):
  • jit/JITOpcodes.cpp:
  • jit/JITPropertyAccess.cpp: (JSC::JIT::emit_op_method_check): (JSC::JIT::emitSlow_op_method_check): (JSC::JIT::emit_op_get_by_id): (JSC::JIT::emitSlow_op_get_by_id): (JSC::JIT::emit_op_put_by_id): (JSC::JIT::emitSlow_op_put_by_id): (JSC::JIT::compileGetByIdHotPath): (JSC::JIT::compileGetByIdSlowCase): (JSC::JIT::patchMethodCallProto):
  • jit/JITStubs.cpp: (JSC::JITStubs::cti_op_get_by_id_method_check): (JSC::JITStubs::cti_op_get_by_id_method_check_second):
  • jit/JITStubs.h:
  • jsc.cpp: (GlobalObject::GlobalObject):
  • parser/Nodes.cpp: (JSC::FunctionCallDotNode::emitBytecode):
  • runtime/Arguments.cpp: (JSC::Arguments::put):
  • runtime/ArrayConstructor.cpp: (JSC::ArrayConstructor::ArrayConstructor):
  • runtime/BooleanConstructor.cpp: (JSC::BooleanConstructor::BooleanConstructor):
  • runtime/DateConstructor.cpp: (JSC::DateConstructor::DateConstructor):
  • runtime/ErrorConstructor.cpp: (JSC::ErrorConstructor::ErrorConstructor): (JSC::constructError):
  • runtime/ErrorPrototype.cpp: (JSC::ErrorPrototype::ErrorPrototype):
  • runtime/FunctionConstructor.cpp: (JSC::FunctionConstructor::FunctionConstructor):
  • runtime/FunctionPrototype.cpp: (JSC::FunctionPrototype::FunctionPrototype):
  • runtime/InternalFunction.cpp: (JSC::InternalFunction::InternalFunction):
  • runtime/JSActivation.cpp: (JSC::JSActivation::put): (JSC::JSActivation::putWithAttributes):
  • runtime/JSByteArray.cpp: (JSC::JSByteArray::JSByteArray):
  • runtime/JSFunction.cpp: (JSC::JSFunction::JSFunction): (JSC::JSFunction::getOwnPropertySlot):
  • runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::putWithAttributes): (JSC::JSGlobalObject::reset): (JSC::JSGlobalObject::mark):
  • runtime/JSGlobalObject.h: (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): (JSC::JSGlobalObject::methodCallDummy):
  • runtime/JSObject.cpp: (JSC::JSObject::put): (JSC::JSObject::putWithAttributes): (JSC::JSObject::deleteProperty): (JSC::JSObject::defineGetter): (JSC::JSObject::defineSetter): (JSC::JSObject::getPropertyAttributes): (JSC::JSObject::getPropertySpecificFunction): (JSC::JSObject::putDirectFunction): (JSC::JSObject::putDirectFunctionWithoutTransition):
  • runtime/JSObject.h: (JSC::getJSFunction): (JSC::JSObject::getDirectLocation): (JSC::JSObject::putDirect): (JSC::JSObject::putDirectWithoutTransition):
  • runtime/LiteralParser.cpp: (JSC::LiteralParser::parseObject):
  • runtime/Lookup.cpp: (JSC::setUpStaticFunctionSlot):
  • runtime/Lookup.h: (JSC::lookupPut):
  • runtime/MathObject.cpp: (JSC::MathObject::MathObject):
  • runtime/NativeErrorConstructor.cpp: (JSC::NativeErrorConstructor::NativeErrorConstructor): (JSC::NativeErrorConstructor::construct):
  • runtime/NativeErrorPrototype.cpp: (JSC::NativeErrorPrototype::NativeErrorPrototype):
  • runtime/NumberConstructor.cpp: (JSC::NumberConstructor::NumberConstructor):
  • runtime/ObjectConstructor.cpp: (JSC::ObjectConstructor::ObjectConstructor):
  • runtime/PropertyMapHashTable.h: (JSC::PropertyMapEntry::PropertyMapEntry):
  • runtime/PrototypeFunction.cpp: (JSC::PrototypeFunction::PrototypeFunction):
  • runtime/PutPropertySlot.h: (JSC::PutPropertySlot::): (JSC::PutPropertySlot::PutPropertySlot): (JSC::PutPropertySlot::setNewProperty): (JSC::PutPropertySlot::setDespecifyFunctionProperty): (JSC::PutPropertySlot::isCacheable): (JSC::PutPropertySlot::cachedOffset):
  • runtime/RegExpConstructor.cpp: (JSC::RegExpConstructor::RegExpConstructor):
  • runtime/StringConstructor.cpp: (JSC::StringConstructor::StringConstructor):
  • runtime/StringPrototype.cpp: (JSC::StringPrototype::StringPrototype):
  • runtime/Structure.cpp: (JSC::Structure::Structure): (JSC::Structure::~Structure): (JSC::Structure::materializePropertyMap): (JSC::Structure::addPropertyTransitionToExistingStructure): (JSC::Structure::addPropertyTransition): (JSC::Structure::changeFunctionTransition): (JSC::Structure::addPropertyWithoutTransition): (JSC::Structure::get): (JSC::Structure::despecifyFunction): (JSC::Structure::put): (JSC::Structure::remove):
  • runtime/Structure.h: (JSC::Structure::get): (JSC::Structure::specificFunction):
  • runtime/StructureTransitionTable.h: (JSC::StructureTransitionTableHashTraits::emptyValue):
  • wtf/Platform.h:
File:
1 edited

Legend:

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

    r43692 r44076  
    3333#include "ScopeChain.h"
    3434#include "Structure.h"
     35#include "JSGlobalData.h"
    3536
    3637namespace JSC {
     38
     39    inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
     40    {
     41        if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
     42            return value.asCell();
     43        return 0;
     44    }
    3745
    3846    class InternalFunction;
     
    94102        virtual void put(ExecState*, unsigned propertyName, JSValue value);
    95103
     104        virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
    96105        virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
    97106        virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
     
    123132
    124133        virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
     134        bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
    125135
    126136        // This get function only looks at the property map.
     
    144154        JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
    145155        {
    146             size_t offset = m_structure->get(propertyName, attributes);
     156            JSCell* specificFunction;
     157            size_t offset = m_structure->get(propertyName, attributes, specificFunction);
    147158            return offset != WTF::notFound ? locationForOffset(offset) : 0;
    148159        }
     
    169180        bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
    170181
     182        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
    171183        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
    172         void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
     184
     185        void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
     186        void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
    173187        void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
     188
    174189        void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
     190        void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
    175191        void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
    176192
     
    208224
    209225    private:
     226        void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
     227        void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
     228        void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
     229
    210230        bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    211231
     
    397417}
    398418
    399 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attr)
    400 {
    401     PutPropertySlot slot;
    402     putDirect(propertyName, value, attr, false, slot);
    403 }
    404 
    405 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
     419inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
    406420{
    407421    ASSERT(value);
     
    410424    if (m_structure->isDictionary()) {
    411425        unsigned currentAttributes;
    412         size_t offset = m_structure->get(propertyName, currentAttributes);
     426        JSCell* currentSpecificFunction;
     427        size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
    413428        if (offset != WTF::notFound) {
    414429            if (checkReadOnly && currentAttributes & ReadOnly)
     
    420435
    421436        size_t currentCapacity = m_structure->propertyStorageCapacity();
    422         offset = m_structure->addPropertyWithoutTransition(propertyName, attributes);
     437        offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
    423438        if (currentCapacity != m_structure->propertyStorageCapacity())
    424439            allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
     
    426441        ASSERT(offset < m_structure->propertyStorageCapacity());
    427442        putDirectOffset(offset, value);
    428         slot.setNewProperty(this, offset);
     443        // See comment on setNewProperty call below.
     444        if (!specificFunction)
     445            slot.setNewProperty(this, offset);
    429446        return;
    430447    }
     
    432449    size_t offset;
    433450    size_t currentCapacity = m_structure->propertyStorageCapacity();
    434     if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, offset)) {
     451    if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {   
    435452        if (currentCapacity != structure->propertyStorageCapacity())
    436453            allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
     
    439456        setStructure(structure.release());
    440457        putDirectOffset(offset, value);
    441         slot.setNewProperty(this, offset);
    442         slot.setWasTransition(true);
     458        // See comment on setNewProperty call below.
     459        if (!specificFunction)
     460            slot.setNewProperty(this, offset);
    443461        return;
    444462    }
    445463
    446464    unsigned currentAttributes;
    447     offset = m_structure->get(propertyName, currentAttributes);
     465    JSCell* currentSpecificFunction;
     466    offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
    448467    if (offset != WTF::notFound) {
    449468        if (checkReadOnly && currentAttributes & ReadOnly)
    450469            return;
     470
     471        if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) {
     472            setStructure(Structure::changeFunctionTransition(m_structure, propertyName));
     473            putDirectOffset(offset, value);
     474            // Function transitions are not currently cachable, so leave the slot in an uncachable state.
     475            return;
     476        }
    451477        putDirectOffset(offset, value);
    452478        slot.setExistingProperty(this, offset);
     
    454480    }
    455481
    456     RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, offset);
     482    RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
    457483    if (currentCapacity != structure->propertyStorageCapacity())
    458484        allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
     
    461487    setStructure(structure.release());
    462488    putDirectOffset(offset, value);
    463     slot.setNewProperty(this, offset);
    464     slot.setWasTransition(true);
     489    // Function transitions are not currently cachable, so leave the slot in an uncachable state.
     490    if (!specificFunction)
     491        slot.setNewProperty(this, offset);
     492}
     493
     494inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
     495{
     496    ASSERT(value);
     497    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
     498
     499    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
     500}
     501
     502inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
     503{
     504    PutPropertySlot slot;
     505    putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
     506}
     507
     508inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
     509{
     510    ASSERT(value);
     511    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
     512
     513    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
     514}
     515
     516inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
     517{
     518    PutPropertySlot slot;
     519    putDirectInternal(propertyName, value, attributes, false, slot, 0);
     520}
     521
     522inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
     523{
     524    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
     525}
     526
     527inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
     528{
     529    PutPropertySlot slot;
     530    putDirectInternal(propertyName, value, attr, false, slot, value);
    465531}
    466532
     
    468534{
    469535    size_t currentCapacity = m_structure->propertyStorageCapacity();
    470     size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes);
     536    size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
     537    if (currentCapacity != m_structure->propertyStorageCapacity())
     538        allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
     539    putDirectOffset(offset, value);
     540}
     541
     542inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
     543{
     544    size_t currentCapacity = m_structure->propertyStorageCapacity();
     545    size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
    471546    if (currentCapacity != m_structure->propertyStorageCapacity())
    472547        allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
Note: See TracChangeset for help on using the changeset viewer.