Ignore:
Timestamp:
Nov 20, 2008, 9:04:19 PM (17 years ago)
Author:
[email protected]
Message:

2008-11-19 Gavin Barraclough <[email protected]>

Reviewed by Darin Adler.

Add support for (really) polymorphic caching of prototype accesses.


If a cached prototype access misses, cti_op_get_by_id_proto_list is called.
When this occurs the Structure pointers from the instruction stream are copied
off into a new ProtoStubInfo object. A second prototype access trampoline is
generated, and chained onto the first. Subsequent missed call to
cti_op_get_by_id_proto_list_append, which append futher new trampolines, up to
PROTOTYPE_LIST_CACHE_SIZE (currently 4). If any of the misses result in an
access other than to a direct prototype property, list formation is halted (or
for the initial miss, does not take place at all).

Separate fail case functions are provided for each access since this contributes
to the performance progression (enables better processor branch prediction).

Overall this is a near 5% progression on v8, with around 10% wins on richards
and deltablue.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures):
  • bytecode/Instruction.h: (JSC::ProtoStructureList::ProtoStubInfo::set): (JSC::ProtoStructureList::ProtoStructureList): (JSC::Instruction::Instruction): (JSC::Instruction::):
  • bytecode/Opcode.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): (JSC::Interpreter::tryCTICacheGetByID): (JSC::Interpreter::cti_op_put_by_id_fail): (JSC::Interpreter::cti_op_get_by_id_self_fail): (JSC::Interpreter::cti_op_get_by_id_proto_list): (JSC::Interpreter::cti_op_get_by_id_proto_list_append): (JSC::Interpreter::cti_op_get_by_id_proto_list_full): (JSC::Interpreter::cti_op_get_by_id_proto_fail): (JSC::Interpreter::cti_op_get_by_id_chain_fail): (JSC::Interpreter::cti_op_get_by_id_array_fail): (JSC::Interpreter::cti_op_get_by_id_string_fail):
  • interpreter/Interpreter.h:
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileGetByIdSelf): (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChain): (JSC::JIT::privateCompileCTIMachineTrampolines): (JSC::JIT::privateCompilePatchGetArrayLength):
  • jit/JIT.h: (JSC::JIT::compileGetByIdProtoList):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r38576 r38652  
    25872587        NEXT_INSTRUCTION();
    25882588    }
     2589    DEFINE_OPCODE(op_get_by_id_proto_list) {
     2590        // Polymorphic prototype access caching currently only supported when JITting.
     2591        ASSERT_NOT_REACHED();
     2592        // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
     2593        vPC += 8;
     2594        NEXT_INSTRUCTION();
     2595    }
    25892596    DEFINE_OPCODE(op_get_by_id_chain) {
    25902597        /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
     
    45244531    ARG_src1->put(callFrame, ident, ARG_src3, slot);
    45254532
    4526     // should probably uncachePutByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
    4527     ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_put_by_id_generic));
    4528 
    45294533    CHECK_FOR_EXCEPTION_AT_END();
    45304534}
     
    45794583}
    45804584
    4581 JSValue* Interpreter::cti_op_get_by_id_fail(CTI_ARGS)
     4585JSValue* Interpreter::cti_op_get_by_id_self_fail(CTI_ARGS)
    45824586{
    45834587    CTI_STACK_HACK();
     
    45904594    JSValue* result = baseValue->get(callFrame, ident, slot);
    45914595
    4592     // should probably uncacheGetByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
    4593     ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
     4596    CHECK_FOR_EXCEPTION_AT_END();
     4597    return result;
     4598}
     4599
     4600JSValue* Interpreter::cti_op_get_by_id_proto_list(CTI_ARGS)
     4601{
     4602    CTI_STACK_HACK();
     4603
     4604    CallFrame* callFrame = ARG_callFrame;
     4605
     4606    JSValue* baseValue = ARG_src1;
     4607    PropertySlot slot(baseValue);
     4608    JSValue* result = baseValue->get(callFrame, *ARG_id2, slot);
     4609
     4610    CHECK_FOR_EXCEPTION();
     4611
     4612    if (baseValue->isObject()
     4613        && slot.isCacheable()
     4614        && !asCell(baseValue)->structure()->isDictionary()
     4615        && slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
     4616
     4617        JSCell* baseCell = asCell(baseValue);
     4618        Structure* structure = baseCell->structure();
     4619        CodeBlock* codeBlock = callFrame->codeBlock();
     4620        unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
     4621        Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
     4622
     4623        ASSERT(slot.slotBase()->isObject());
     4624
     4625        JSObject* slotBaseObject = asObject(slot.slotBase());
     4626
     4627        // Heavy access to a prototype is a good indication that it's not being
     4628        // used as a dictionary.
     4629        if (slotBaseObject->structure()->isDictionary()) {
     4630            RefPtr<Structure> transition = Structure::fromDictionaryTransition(slotBaseObject->structure());
     4631            slotBaseObject->setStructure(transition.release());
     4632            asObject(baseValue)->structure()->setCachedPrototypeChain(0);
     4633        }
     4634
     4635        StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
     4636
     4637        PrototypeStructureList* prototypeStructureList;
     4638        int listIndex = 1;
     4639
     4640        if (vPC[0].u.opcode == ARG_globalData->interpreter->getOpcode(op_get_by_id_proto)) {
     4641            prototypeStructureList = new PrototypeStructureList(vPC[4].u.structure, vPC[5].u.structure, vPC[6].u.operand, stubInfo->stubRoutine);
     4642            stubInfo->stubRoutine = 0;
     4643
     4644            vPC[0] = ARG_globalData->interpreter->getOpcode(op_get_by_id_proto_list);
     4645            vPC[4] = prototypeStructureList;
     4646            vPC[5] = 2;
     4647        } else {
     4648            prototypeStructureList = vPC[4].u.prototypeStructure;
     4649            listIndex = vPC[5].u.operand;
     4650
     4651            vPC[5] = listIndex + 1;
     4652        }
     4653
     4654        JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset());
     4655
     4656        if (listIndex == (PROTOTYPE_LIST_CACHE_SIZE - 1))
     4657            ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
     4658    } else {
     4659        ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
     4660    }
     4661    return result;
     4662}
     4663
     4664JSValue* Interpreter::cti_op_get_by_id_proto_list_full(CTI_ARGS)
     4665{
     4666    CTI_STACK_HACK();
     4667
     4668    JSValue* baseValue = ARG_src1;
     4669    PropertySlot slot(baseValue);
     4670    JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
     4671
     4672    CHECK_FOR_EXCEPTION_AT_END();
     4673    return result;
     4674}
     4675
     4676JSValue* Interpreter::cti_op_get_by_id_proto_fail(CTI_ARGS)
     4677{
     4678    CTI_STACK_HACK();
     4679
     4680    JSValue* baseValue = ARG_src1;
     4681    PropertySlot slot(baseValue);
     4682    JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
     4683
     4684    CHECK_FOR_EXCEPTION_AT_END();
     4685    return result;
     4686}
     4687
     4688JSValue* Interpreter::cti_op_get_by_id_chain_fail(CTI_ARGS)
     4689{
     4690    CTI_STACK_HACK();
     4691
     4692    JSValue* baseValue = ARG_src1;
     4693    PropertySlot slot(baseValue);
     4694    JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
     4695
     4696    CHECK_FOR_EXCEPTION_AT_END();
     4697    return result;
     4698}
     4699
     4700JSValue* Interpreter::cti_op_get_by_id_array_fail(CTI_ARGS)
     4701{
     4702    CTI_STACK_HACK();
     4703
     4704    JSValue* baseValue = ARG_src1;
     4705    PropertySlot slot(baseValue);
     4706    JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
     4707
     4708    CHECK_FOR_EXCEPTION_AT_END();
     4709    return result;
     4710}
     4711
     4712JSValue* Interpreter::cti_op_get_by_id_string_fail(CTI_ARGS)
     4713{
     4714    CTI_STACK_HACK();
     4715
     4716    JSValue* baseValue = ARG_src1;
     4717    PropertySlot slot(baseValue);
     4718    JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
    45944719
    45954720    CHECK_FOR_EXCEPTION_AT_END();
     
    46424767
    46434768    CallFrame* callFrame = ARG_callFrame;
    4644     Identifier& ident = *ARG_id2;
    46454769   
    46464770    JSObject* baseObj = ARG_src1->toObject(callFrame);
    46474771
    4648     JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
     4772    JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, *ARG_id2));
    46494773    CHECK_FOR_EXCEPTION_AT_END();
    46504774    return result;
     
    58916015    ASSERT(ARG_src1->isObject());
    58926016    JSObject* baseObj = asObject(ARG_src1);
    5893     Identifier& ident = *ARG_id2;
    58946017    ASSERT(ARG_src3->isObject());
    5895     baseObj->defineGetter(callFrame, ident, asObject(ARG_src3));
     6018    baseObj->defineGetter(callFrame, *ARG_id2, asObject(ARG_src3));
    58966019}
    58976020
     
    59046027    ASSERT(ARG_src1->isObject());
    59056028    JSObject* baseObj = asObject(ARG_src1);
    5906     Identifier& ident = *ARG_id2;
    59076029    ASSERT(ARG_src3->isObject());
    5908     baseObj->defineSetter(callFrame, ident, asObject(ARG_src3));
     6030    baseObj->defineSetter(callFrame, *ARG_id2, asObject(ARG_src3));
    59096031}
    59106032
Note: See TracChangeset for help on using the changeset viewer.