Changeset 38652 in webkit


Ignore:
Timestamp:
Nov 20, 2008 9:04:19 PM (15 years ago)
Author:
barraclough@apple.com
Message:

2008-11-19 Gavin Barraclough <barraclough@apple.com>

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):
Location:
trunk/JavaScriptCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r38649 r38652  
     12008-11-19  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        Add support for (really) polymorphic caching of prototype accesses.
     6       
     7        If a cached prototype access misses, cti_op_get_by_id_proto_list is called.
     8        When this occurs the Structure pointers from the instruction stream are copied
     9        off into a new ProtoStubInfo object.  A second prototype access trampoline is
     10        generated, and chained onto the first.  Subsequent missed call to
     11        cti_op_get_by_id_proto_list_append, which append futher new trampolines, up to
     12        PROTOTYPE_LIST_CACHE_SIZE (currently 4).  If any of the misses result in an
     13        access other than to a direct prototype property, list formation is halted (or
     14        for the initial miss, does not take place at all).
     15
     16        Separate fail case functions are provided for each access since this contributes
     17        to the performance progression (enables better processor branch prediction).
     18
     19        Overall this is a near 5% progression on v8, with around 10% wins on richards
     20        and deltablue.
     21
     22        * bytecode/CodeBlock.cpp:
     23        (JSC::CodeBlock::dump):
     24        (JSC::CodeBlock::derefStructures):
     25        * bytecode/Instruction.h:
     26        (JSC::ProtoStructureList::ProtoStubInfo::set):
     27        (JSC::ProtoStructureList::ProtoStructureList):
     28        (JSC::Instruction::Instruction):
     29        (JSC::Instruction::):
     30        * bytecode/Opcode.h:
     31        * interpreter/Interpreter.cpp:
     32        (JSC::Interpreter::privateExecute):
     33        (JSC::Interpreter::tryCTICacheGetByID):
     34        (JSC::Interpreter::cti_op_put_by_id_fail):
     35        (JSC::Interpreter::cti_op_get_by_id_self_fail):
     36        (JSC::Interpreter::cti_op_get_by_id_proto_list):
     37        (JSC::Interpreter::cti_op_get_by_id_proto_list_append):
     38        (JSC::Interpreter::cti_op_get_by_id_proto_list_full):
     39        (JSC::Interpreter::cti_op_get_by_id_proto_fail):
     40        (JSC::Interpreter::cti_op_get_by_id_chain_fail):
     41        (JSC::Interpreter::cti_op_get_by_id_array_fail):
     42        (JSC::Interpreter::cti_op_get_by_id_string_fail):
     43        * interpreter/Interpreter.h:
     44        * jit/JIT.cpp:
     45        (JSC::JIT::privateCompileMainPass):
     46        (JSC::JIT::privateCompileGetByIdSelf):
     47        (JSC::JIT::privateCompileGetByIdProto):
     48        (JSC::JIT::privateCompileGetByIdProtoList):
     49        (JSC::JIT::privateCompileGetByIdChain):
     50        (JSC::JIT::privateCompileCTIMachineTrampolines):
     51        (JSC::JIT::privateCompilePatchGetArrayLength):
     52        * jit/JIT.h:
     53        (JSC::JIT::compileGetByIdProtoList):
     54
    1552008-11-20  Sam Weinig  <sam@webkit.org>
    256
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r38531 r38652  
    647647            break;
    648648        }
     649        case op_get_by_id_proto_list: {
     650            printGetByIdOp(location, it, identifiers, "op_get_by_id_proto_list");
     651            break;
     652        }
    649653        case op_get_by_id_chain: {
    650654            printGetByIdOp(location, it, identifiers, "get_by_id_chain");
     
    10201024        return;
    10211025    }
    1022    
     1026    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list)) {
     1027        PrototypeStructureList* prototypeStructures = vPC[4].u.prototypeStructure;
     1028        int count = vPC[5].u.operand;
     1029        for (int i = 0; i < count; ++i) {
     1030            PrototypeStructureList::ProtoStubInfo& info = prototypeStructures->list[i];
     1031            ASSERT(info.base);
     1032            ASSERT(info.proto);
     1033            ASSERT(info.stubRoutine);
     1034            info.base->deref();
     1035            info.proto->deref();
     1036            WTF::fastFreeExecutable(info.stubRoutine);
     1037        }
     1038        return;
     1039    }
     1040
    10231041    // These instructions don't ref their Structures.
    10241042    ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
  • trunk/JavaScriptCore/bytecode/Instruction.h

    r38498 r38652  
    3434#include <wtf/VectorTraits.h>
    3535
     36#define PROTOTYPE_LIST_CACHE_SIZE 4
     37
    3638namespace JSC {
    3739
     
    3941    class Structure;
    4042    class StructureChain;
     43
     44    // Structure used by op_get_by_id_proto_list instruction to hold data off the main opcode stream.
     45    struct PrototypeStructureList {
     46        struct ProtoStubInfo {
     47            Structure* base;
     48            Structure* proto;
     49            int cachedOffset;
     50            void* stubRoutine;
     51           
     52            void set(Structure* _base, Structure* _proto, int _cachedOffset, void* _stubRoutine)
     53            {
     54                base = _base;
     55                proto = _proto;
     56                cachedOffset = _cachedOffset;
     57                stubRoutine = _stubRoutine;
     58            }
     59        } list[PROTOTYPE_LIST_CACHE_SIZE];
     60       
     61        PrototypeStructureList(Structure* firstBase, Structure* firstProto, int cachedOffset, void* stubRoutine)
     62        {
     63            list[0].set(firstBase, firstProto, cachedOffset, stubRoutine);
     64        }
     65    };
    4166
    4267    struct Instruction {
     
    5378        Instruction(StructureChain* structureChain) { u.structureChain = structureChain; }
    5479        Instruction(JSCell* jsCell) { u.jsCell = jsCell; }
     80        Instruction(PrototypeStructureList* prototypeStructure) { u.prototypeStructure = prototypeStructure; }
    5581
    5682        union {
     
    6187            JSCell* jsCell;
    6288            ResultType::Type resultType;
     89            PrototypeStructureList* prototypeStructure;
    6390        } u;
    6491    };
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r38498 r38652  
    103103        macro(op_get_by_id_self) \
    104104        macro(op_get_by_id_proto) \
     105        macro(op_get_by_id_proto_list) \
    105106        macro(op_get_by_id_chain) \
    106107        macro(op_get_by_id_generic) \
  • 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
  • trunk/JavaScriptCore/interpreter/Interpreter.h

    r38511 r38652  
    188188        static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
    189189        static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
    190         static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
     190        static JSValue* SFX_CALL cti_op_get_by_id_self_fail(CTI_ARGS);
     191        static JSValue* SFX_CALL cti_op_get_by_id_proto_list(CTI_ARGS);
     192        static JSValue* SFX_CALL cti_op_get_by_id_proto_list_full(CTI_ARGS);
     193        static JSValue* SFX_CALL cti_op_get_by_id_proto_fail(CTI_ARGS);
     194        static JSValue* SFX_CALL cti_op_get_by_id_chain_fail(CTI_ARGS);
     195        static JSValue* SFX_CALL cti_op_get_by_id_array_fail(CTI_ARGS);
     196        static JSValue* SFX_CALL cti_op_get_by_id_string_fail(CTI_ARGS);
    191197        static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
    192198        static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
  • trunk/JavaScriptCore/jit/JIT.cpp

    r38600 r38652  
    531531}
    532532
     533JmpSrc JIT::checkStructure(RegisterID reg, Structure* structure)
     534{
     535    __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), reg);
     536    return __ jne();
     537}
     538
    533539ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex)
    534540{
     
    23522358        case op_get_by_id_generic:
    23532359        case op_get_by_id_proto:
     2360        case op_get_by_id_proto_list:
    23542361        case op_get_by_id_self:
    23552362        case op_get_string_length:
     
    31173124    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    31183125    JmpSrc failureCases1 = __ jne();
    3119     __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
    3120     JmpSrc failureCases2 = __ jne();
     3126    JmpSrc failureCases2 = checkStructure(X86::eax, structure);
    31213127
    31223128    // Checks out okay! - getDirectOffset
     
    31283134    ASSERT(code);
    31293135
    3130     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3131     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
     3136    X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
     3137    X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
    31323138   
    31333139    m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
     
    31423148
    31433149    // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
    3144     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3145 
     3150#if USE(CTI_REPATCH_PIC)
     3151    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
     3152#else
     3153    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
     3154#endif
    31463155    // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
    31473156    // referencing the prototype object - let's speculatively load it's table nice and early!)
     
    31503159    __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
    31513160
    3152     // check eax is an object of the right Structure.
     3161    // Check eax is an object of the right Structure.
    31533162    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    31543163    JmpSrc failureCases1 = __ jne();
    3155     __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
    3156     JmpSrc failureCases2 = __ jne();
     3164    JmpSrc failureCases2 = checkStructure(X86::eax, structure);
    31573165
    31583166    // Check the prototype object's Structure had not changed.
    31593167    Structure** prototypeStructureAddress = &(protoObject->m_structure);
    3160     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), static_cast<void*>(prototypeStructureAddress));
     3168    __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
    31613169    JmpSrc failureCases3 = __ jne();
    31623170
     
    31763184
    31773185    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
    3178     intptr_t successDest = (intptr_t)(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
     3186    intptr_t successDest = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
    31793187    X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
    31803188
    31813189    // Track the stub we have created so that it will be deleted later.
    3182     m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
    3183 
    3184     // Finally repatch the jump to sow case back in the hot path to jump here instead.
    3185     // FIXME: should revert this repatching, on failure.
     3190    info.stubRoutine = code;
     3191
     3192    // Finally repatch the jump to slow case back in the hot path to jump here instead.
    31863193    intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
    31873194    X86Assembler::repatchBranchOffset(jmpLocation, code);
     
    31933200    __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
    31943201
    3195     // check eax is an object of the right Structure.
     3202    // Check eax is an object of the right Structure.
    31963203    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    31973204    JmpSrc failureCases1 = __ jne();
    3198     __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
    3199     JmpSrc failureCases2 = __ jne();
     3205    JmpSrc failureCases2 = checkStructure(X86::eax, structure);
     3206
     3207    // Check the prototype object's Structure had not changed.
     3208    Structure** prototypeStructureAddress = &(protoObject->m_structure);
     3209    __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
     3210    JmpSrc failureCases3 = __ jne();
     3211
     3212    // Checks out okay! - getDirectOffset
     3213    __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
     3214
     3215    __ ret();
     3216
     3217    void* code = __ executableCopy();
     3218    ASSERT(code);
     3219
     3220#if USE(CTI_REPATCH_PIC)
     3221    X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
     3222    X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
     3223    X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
     3224#else
     3225    X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
     3226    X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
     3227    X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
     3228#endif
     3229
     3230    m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
     3231
     3232    ctiRepatchCallByReturnAddress(returnAddress, code);
     3233#endif
     3234}
     3235
     3236#if USE(CTI_REPATCH_PIC)
     3237void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PrototypeStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
     3238{
     3239    // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
     3240    // referencing the prototype object - let's speculatively load it's table nice and early!)
     3241    JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
     3242    PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
     3243    __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
     3244
     3245    // Check eax is an object of the right Structure.
     3246    __ testl_i32r(JSImmediate::TagMask, X86::eax);
     3247    JmpSrc failureCases1 = __ jne();
     3248    JmpSrc failureCases2 = checkStructure(X86::eax, structure);
    32003249
    32013250    // Check the prototype object's Structure had not changed.
     
    32073256    __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
    32083257
    3209     __ ret();
     3258    JmpSrc success = __ jmp();
    32103259
    32113260    void* code = __ executableCopy();
    32123261    ASSERT(code);
    32133262
    3214     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3215     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3216     X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3217 
    3218     m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
    3219 
    3220     ctiRepatchCallByReturnAddress(returnAddress, code);
     3263    // Use the repatch information to link the failure cases back to the original slow case routine.
     3264    void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
     3265    X86Assembler::link(code, failureCases1, lastProtoBegin);
     3266    X86Assembler::link(code, failureCases2, lastProtoBegin);
     3267    X86Assembler::link(code, failureCases3, lastProtoBegin);
     3268
     3269    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     3270    intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
     3271    X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
     3272
     3273    structure->ref();
     3274    prototypeStructure->ref();
     3275    prototypeStructures->list[currentIndex].set(structure, prototypeStructure, cachedOffset, code);
     3276
     3277    // Finally repatch the jump to slow case back in the hot path to jump here instead.
     3278    intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
     3279    X86Assembler::repatchBranchOffset(jmpLocation, code);
     3280}
    32213281#endif
    3222 }
    32233282
    32243283void JIT::privateCompileGetByIdChain(Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
     
    32303289    // Check eax is an object of the right Structure.
    32313290    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    3232     bucketsOfFail.append(__ jne());
    3233     __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
    3234     bucketsOfFail.append(__ jne());
     3291    bucketsOfFail.append(checkStructure(X86::eax, structure));
    32353292
    32363293    Structure* currStructure = structure;
     
    32593316
    32603317    for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
    3261         X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
     3318        X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_chain_fail));
    32623319
    32633320    m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
     
    32683325void JIT::privateCompilePutByIdReplace(Structure* structure, size_t cachedOffset, void* returnAddress)
    32693326{
    3270     // check eax is an object of the right Structure.
     3327    // Check eax is an object of the right Structure.
    32713328    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    32723329    JmpSrc failureCases1 = __ jne();
    3273     __ cmpl_i32m(reinterpret_cast<uint32_t>(structure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
    3274     JmpSrc failureCases2 = __ jne();
     3330    JmpSrc failureCases2 = checkStructure(X86::eax, structure);
    32753331
    32763332    // checks out okay! - putDirectOffset
     
    33083364{
    33093365    Vector<JmpSrc, 16> failureCases;
    3310     // check eax is an object of the right Structure.
     3366    // Check eax is an object of the right Structure.
    33113367    __ testl_i32r(JSImmediate::TagMask, X86::eax);
    33123368    failureCases.append(__ jne());
     
    34283484    __ movl_mr(FIELD_OFFSET(ArrayStorage, m_length), X86::eax, X86::eax);
    34293485
     3486    __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::eax);
     3487    JmpSrc array_failureCases3 = __ ja();
     3488
    34303489    __ addl_rr(X86::eax, X86::eax);
    3431     JmpSrc array_failureCases3 = __ jo();
    34323490    __ addl_i8r(1, X86::eax);
    34333491   
     
    34483506    __ movl_mr(FIELD_OFFSET(UString::Rep, len), X86::eax, X86::eax);
    34493507
     3508    __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::eax);
     3509    JmpSrc string_failureCases3 = __ ja();
     3510
    34503511    __ addl_rr(X86::eax, X86::eax);
    3451     JmpSrc string_failureCases3 = __ jo();
    34523512    __ addl_i8r(1, X86::eax);
    34533513   
     
    35833643    ASSERT(code);
    35843644
    3585     X86Assembler::link(code, array_failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3586     X86Assembler::link(code, array_failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3587     X86Assembler::link(code, array_failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3588     X86Assembler::link(code, string_failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3589     X86Assembler::link(code, string_failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
    3590     X86Assembler::link(code, string_failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
     3645    X86Assembler::link(code, array_failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
     3646    X86Assembler::link(code, array_failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
     3647    X86Assembler::link(code, array_failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
     3648    X86Assembler::link(code, string_failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_string_fail));
     3649    X86Assembler::link(code, string_failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_string_fail));
     3650    X86Assembler::link(code, string_failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_string_fail));
    35913651    X86Assembler::link(code, callArityCheck1, reinterpret_cast<void*>(Interpreter::cti_op_call_arityCheck));
    35923652    X86Assembler::link(code, callArityCheck2, reinterpret_cast<void*>(Interpreter::cti_op_call_arityCheck));
     
    36413701
    36423702    // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
    3643     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_fail));
     3703    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
    36443704
    36453705    // Check eax is an array
     
    36713731
    36723732    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
    3673     intptr_t successDest = (intptr_t)(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
     3733    intptr_t successDest = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
    36743734    X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
    36753735
     
    36783738
    36793739    // Finally repatch the jump to sow case back in the hot path to jump here instead.
    3680     // FIXME: should revert this repatching, on failure.
    36813740    intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
    36823741    X86Assembler::repatchBranchOffset(jmpLocation, code);
  • trunk/JavaScriptCore/jit/JIT.h

    r38531 r38652  
    110110    struct Instruction;
    111111    struct OperandTypes;
     112    struct PrototypeStructureList;
     113    struct StructureStubInfo;
    112114
    113115    typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS);
     
    318320        }
    319321
     322#if USE(CTI_REPATCH_PIC)
     323        static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PrototypeStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset)
     324        {
     325            JIT jit(globalData, codeBlock);
     326            jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, cachedOffset, callFrame);
     327        }
     328#endif
     329
    320330        static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
    321331        {
     
    369379        void privateCompileGetByIdSelf(Structure*, size_t cachedOffset, void* returnAddress);
    370380        void privateCompileGetByIdProto(Structure*, Structure* prototypeStructure, size_t cachedOffset, void* returnAddress, CallFrame* callFrame);
     381#if USE(CTI_REPATCH_PIC)
     382        void privateCompileGetByIdProtoList(StructureStubInfo*, PrototypeStructureList*, int, Structure*, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame);
     383#endif
    371384        void privateCompileGetByIdChain(Structure*, StructureChain*, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame);
    372385        void privateCompilePutByIdReplace(Structure*, size_t cachedOffset, void* returnAddress);
     
    415428        void emitJumpSlowCaseIfNotImmNums(RegisterID, RegisterID, unsigned bytecodeIndex);
    416429
     430        JmpSrc checkStructure(RegisterID reg, Structure* structure);
     431
    417432        void emitFastArithDeTagImmediate(RegisterID);
    418433        JmpSrc emitFastArithDeTagImmediateJumpIfZero(RegisterID);
Note: See TracChangeset for help on using the changeset viewer.