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


Ignore:
Timestamp:
Nov 25, 2008, 3:07:30 PM (17 years ago)
Author:
[email protected]
Message:

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

Reviewed by Geoff Garen.

Polymorpic caching for get by id chain. Similar to the polymorphic caching already implemented
for self and proto accesses (implemented by allowing multiple trampolines to be JIT genertaed,
and linked together) - the get by id chain caching is implemented as a genericization of the
proto list caching, allowing cached access lists to contain a mix of proto and proto chain
accesses (since in JS style inheritance hierarchies you may commonly see a mix of properties
being overridden on the direct prototype, or higher up its prototype chain).

In order to allow this patch to compile there is a fix to appease gcc 4.2 compiler issues
(removing the jumps between fall-through cases in privateExecute).


This patch also removes redundant immediate checking from the reptach code, and fixes a related
memory leak (failure to deallocate trampolines).

~2% progression on v8 tests (bulk on the win on deltablue)

  • bytecode/Instruction.h: (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::): (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set): (JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList): (JSC::PolymorphicAccessStructureList::derefStructures):
  • interpreter/Interpreter.cpp: (JSC::countPrototypeChainEntriesAndCheckForProxies): (JSC::Interpreter::tryCacheGetByID): (JSC::Interpreter::privateExecute): (JSC::Interpreter::tryCTICacheGetByID): (JSC::Interpreter::cti_op_get_by_id_self_fail): (JSC::getPolymorphicAccessStructureListSlot): (JSC::Interpreter::cti_op_get_by_id_proto_list):
  • interpreter/Interpreter.h:
  • jit/JIT.cpp: (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain): (JSC::JIT::privateCompilePatchGetArrayLength):
  • jit/JIT.h: (JSC::JIT::compileGetByIdChainList):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/jit/JIT.cpp

    r38700 r38763  
    31563156
    31573157    // Check eax is an object of the right Structure.
    3158     __ testl_i32r(JSImmediate::TagMask, X86::eax);
    3159     JmpSrc failureCases1 = __ jne();
    3160     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
     3158    JmpSrc failureCases1 = checkStructure(X86::eax, structure);
    31613159
    31623160    // Check the prototype object's Structure had not changed.
    31633161    Structure** prototypeStructureAddress = &(protoObject->m_structure);
    31643162    __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
    3165     JmpSrc failureCases3 = __ jne();
     3163    JmpSrc failureCases2 = __ jne();
    31663164
    31673165    // Checks out okay! - getDirectOffset
     
    31763174    X86Assembler::link(code, failureCases1, slowCaseBegin);
    31773175    X86Assembler::link(code, failureCases2, slowCaseBegin);
    3178     X86Assembler::link(code, failureCases3, slowCaseBegin);
    31793176
    31803177    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     
    32453242
    32463243    structure->ref();
    3247     polymorphicStructures->list[currentIndex].set(structure, 0, cachedOffset, 0/*code*/);
     3244    polymorphicStructures->list[currentIndex].set(cachedOffset, code, structure);
    32483245
    32493246    // Finally repatch the jump to slow case back in the hot path to jump here instead.
     
    32613258
    32623259    // Check eax is an object of the right Structure.
    3263     __ testl_i32r(JSImmediate::TagMask, X86::eax);
    3264     JmpSrc failureCases1 = __ jne();
    3265     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
     3260    JmpSrc failureCases1 = checkStructure(X86::eax, structure);
    32663261
    32673262    // Check the prototype object's Structure had not changed.
    32683263    Structure** prototypeStructureAddress = &(protoObject->m_structure);
    3269     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), static_cast<void*>(prototypeStructureAddress));
    3270     JmpSrc failureCases3 = __ jne();
     3264    __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
     3265    JmpSrc failureCases2 = __ jne();
    32713266
    32723267    // Checks out okay! - getDirectOffset
     
    32813276    X86Assembler::link(code, failureCases1, lastProtoBegin);
    32823277    X86Assembler::link(code, failureCases2, lastProtoBegin);
    3283     X86Assembler::link(code, failureCases3, lastProtoBegin);
    32843278
    32853279    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     
    32893283    structure->ref();
    32903284    prototypeStructure->ref();
    3291     prototypeStructures->list[currentIndex].set(structure, prototypeStructure, cachedOffset, code);
     3285    prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, prototypeStructure);
    32923286
    32933287    // Finally repatch the jump to slow case back in the hot path to jump here instead.
     
    32953289    X86Assembler::repatchBranchOffset(jmpLocation, code);
    32963290}
    3297 #endif
    3298 
    3299 void JIT::privateCompileGetByIdChain(Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
    3300 {
    3301 #if USE(CTI_REPATCH_PIC)
    3302     StructureStubInfo& info = m_codeBlock->getStubInfo(returnAddress);
    3303 
    3304     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
    3305     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_generic));
    3306 
     3291
     3292void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, CallFrame* callFrame)
     3293{
    33073294    ASSERT(count);
    33083295   
     
    33103297
    33113298    // Check eax is an object of the right Structure.
    3312     __ testl_i32r(JSImmediate::TagMask, X86::eax);
    3313     bucketsOfFail.append(__ jne());
    33143299    bucketsOfFail.append(checkStructure(X86::eax, structure));
    33153300
     
    33233308        // Check the prototype object's Structure had not changed.
    33243309        Structure** prototypeStructureAddress = &(protoObject->m_structure);
    3325         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), static_cast<void*>(prototypeStructureAddress));
     3310        __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
     3311        bucketsOfFail.append(__ jne());
     3312    }
     3313    ASSERT(protoObject);
     3314
     3315    PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
     3316    __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
     3317    __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
     3318    JmpSrc success = __ jmp();
     3319
     3320    void* code = __ executableCopy();
     3321
     3322    // Use the repatch information to link the failure cases back to the original slow case routine.
     3323    void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
     3324
     3325    for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
     3326        X86Assembler::link(code, bucketsOfFail[i], lastProtoBegin);
     3327
     3328    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     3329    intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
     3330    X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
     3331
     3332    // Track the stub we have created so that it will be deleted later.
     3333    structure->ref();
     3334    chain->ref();
     3335    prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, chain);
     3336
     3337    // Finally repatch the jump to slow case back in the hot path to jump here instead.
     3338    intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
     3339    X86Assembler::repatchBranchOffset(jmpLocation, code);
     3340}
     3341#endif
     3342
     3343void JIT::privateCompileGetByIdChain(Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
     3344{
     3345#if USE(CTI_REPATCH_PIC)
     3346    StructureStubInfo& info = m_codeBlock->getStubInfo(returnAddress);
     3347
     3348    // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
     3349    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
     3350
     3351    ASSERT(count);
     3352   
     3353    Vector<JmpSrc> bucketsOfFail;
     3354
     3355    // Check eax is an object of the right Structure.
     3356    bucketsOfFail.append(checkStructure(X86::eax, structure));
     3357
     3358    Structure* currStructure = structure;
     3359    RefPtr<Structure>* chainEntries = chain->head();
     3360    JSObject* protoObject = 0;
     3361    for (unsigned i = 0; i < count; ++i) {
     3362        protoObject = asObject(currStructure->prototypeForLookup(callFrame));
     3363        currStructure = chainEntries[i].get();
     3364
     3365        // Check the prototype object's Structure had not changed.
     3366        Structure** prototypeStructureAddress = &(protoObject->m_structure);
     3367        __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
    33263368        bucketsOfFail.append(__ jne());
    33273369    }
     
    33703412        // Check the prototype object's Structure had not changed.
    33713413        Structure** prototypeStructureAddress = &(protoObject->m_structure);
    3372         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), static_cast<void*>(prototypeStructureAddress));
     3414        __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
    33733415        bucketsOfFail.append(__ jne());
    33743416    }
     
    33833425
    33843426    for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
    3385         X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_chain_fail));
     3427        X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
    33863428
    33873429    m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
     
    37693811
    37703812    // Check eax is an array
    3771     __ testl_i32r(JSImmediate::TagMask, X86::eax);
     3813    __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsArrayVptr), X86::eax);
    37723814    JmpSrc failureCases1 = __ jne();
    3773     __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsArrayVptr), X86::eax);
    3774     JmpSrc failureCases2 = __ jne();
    37753815
    37763816    // Checks out okay! - get the length from the storage
     
    37793819
    37803820    __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::ecx);
    3781     JmpSrc failureCases3 = __ ja();
     3821    JmpSrc failureCases2 = __ ja();
    37823822
    37833823    __ addl_rr(X86::ecx, X86::ecx);
     
    37923832    X86Assembler::link(code, failureCases1, slowCaseBegin);
    37933833    X86Assembler::link(code, failureCases2, slowCaseBegin);
    3794     X86Assembler::link(code, failureCases3, slowCaseBegin);
    37953834
    37963835    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
Note: See TracChangeset for help on using the changeset viewer.