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/jit/JITStubs.cpp

    r44030 r44076  
    688688
    689689    CHECK_FOR_EXCEPTION_AT_END();
     690    return JSValue::encode(result);
     691}
     692
     693EncodedJSValue JITStubs::cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION)
     694{
     695    STUB_INIT_STACK_FRAME(stackFrame);
     696
     697    CallFrame* callFrame = stackFrame.callFrame;
     698    Identifier& ident = stackFrame.args[1].identifier();
     699
     700    JSValue baseValue = stackFrame.args[0].jsValue();
     701    PropertySlot slot(baseValue);
     702    JSValue result = baseValue.get(callFrame, ident, slot);
     703
     704    ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_method_check_second));
     705
     706    CHECK_FOR_EXCEPTION_AT_END();
     707    return JSValue::encode(result);
     708}
     709
     710EncodedJSValue JITStubs::cti_op_get_by_id_method_check_second(STUB_ARGS_DECLARATION)
     711{
     712    STUB_INIT_STACK_FRAME(stackFrame);
     713
     714    CallFrame* callFrame = stackFrame.callFrame;
     715    Identifier& ident = stackFrame.args[1].identifier();
     716
     717    JSValue baseValue = stackFrame.args[0].jsValue();
     718    PropertySlot slot(baseValue);
     719    JSValue result = baseValue.get(callFrame, ident, slot);
     720
     721    CHECK_FOR_EXCEPTION();
     722
     723    // If we successfully got something, then the base from which it is being accessed must
     724    // be an object.  (Assertion to ensure asObject() call below is safe, which comes after
     725    // an isCacheable() chceck.
     726    ASSERT(!slot.isCacheable() || slot.slotBase().isObject());
     727
     728    // Check that:
     729    //   * We're dealing with a JSCell,
     730    //   * the property is cachable,
     731    //   * it's not a dictionary
     732    //   * there is a function cached.
     733    Structure* structure;
     734    JSCell* specific;
     735    if (baseValue.isCell()
     736        && slot.isCacheable()
     737        && !(structure = asCell(baseValue)->structure())->isDictionary()
     738        && asObject(slot.slotBase())->getPropertySpecificValue(callFrame, ident, specific)
     739        && specific
     740        ) {
     741
     742        JSFunction* callee = (JSFunction*)specific;
     743
     744        // The result fetched should always be the callee!
     745        ASSERT(result == JSValue(callee));
     746        MethodCallLinkInfo& methodCallLinkInfo = callFrame->codeBlock()->getMethodCallLinkInfo(STUB_RETURN_ADDRESS);
     747
     748        // Check to see if the function is on the object's prototype.  Patch up the code to optimize.
     749        if (slot.slotBase() == structure->prototypeForLookup(callFrame))
     750            JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, asObject(slot.slotBase()));
     751        // Check to see if the function is on the object itself.
     752        // Since we generate the method-check to check both the structure and a prototype-structure (since this
     753        // is the common case) we have a problem - we need to patch the prototype structure check to do something
     754        // useful.  We could try to nop it out altogether, but that's a little messy, so lets do something simpler
     755        // for now.  For now it performs a check on a special object on the global object only used for this
     756        // purpose.  The object is in no way exposed, and as such the check will always pass.
     757        else if (slot.slotBase() == baseValue)
     758            JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy());
     759
     760        // For now let any other case be cached as a normal get_by_id.
     761    }
     762
     763    // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to.
     764    ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id));
     765
    690766    return JSValue::encode(result);
    691767}
Note: See TracChangeset for help on using the changeset viewer.