Changeset 38652 in webkit for trunk/JavaScriptCore/jit/JIT.cpp


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/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);
Note: See TracChangeset for help on using the changeset viewer.