Changeset 38652 in webkit
- Timestamp:
- Nov 20, 2008 9:04:19 PM (15 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r38649 r38652 1 2008-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 1 55 2008-11-20 Sam Weinig <sam@webkit.org> 2 56 -
trunk/JavaScriptCore/bytecode/CodeBlock.cpp
r38531 r38652 647 647 break; 648 648 } 649 case op_get_by_id_proto_list: { 650 printGetByIdOp(location, it, identifiers, "op_get_by_id_proto_list"); 651 break; 652 } 649 653 case op_get_by_id_chain: { 650 654 printGetByIdOp(location, it, identifiers, "get_by_id_chain"); … … 1020 1024 return; 1021 1025 } 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 1023 1041 // These instructions don't ref their Structures. 1024 1042 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 34 34 #include <wtf/VectorTraits.h> 35 35 36 #define PROTOTYPE_LIST_CACHE_SIZE 4 37 36 38 namespace JSC { 37 39 … … 39 41 class Structure; 40 42 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 }; 41 66 42 67 struct Instruction { … … 53 78 Instruction(StructureChain* structureChain) { u.structureChain = structureChain; } 54 79 Instruction(JSCell* jsCell) { u.jsCell = jsCell; } 80 Instruction(PrototypeStructureList* prototypeStructure) { u.prototypeStructure = prototypeStructure; } 55 81 56 82 union { … … 61 87 JSCell* jsCell; 62 88 ResultType::Type resultType; 89 PrototypeStructureList* prototypeStructure; 63 90 } u; 64 91 }; -
trunk/JavaScriptCore/bytecode/Opcode.h
r38498 r38652 103 103 macro(op_get_by_id_self) \ 104 104 macro(op_get_by_id_proto) \ 105 macro(op_get_by_id_proto_list) \ 105 106 macro(op_get_by_id_chain) \ 106 107 macro(op_get_by_id_generic) \ -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r38576 r38652 2587 2587 NEXT_INSTRUCTION(); 2588 2588 } 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 } 2589 2596 DEFINE_OPCODE(op_get_by_id_chain) { 2590 2597 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n) … … 4524 4531 ARG_src1->put(callFrame, ident, ARG_src3, slot); 4525 4532 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 4529 4533 CHECK_FOR_EXCEPTION_AT_END(); 4530 4534 } … … 4579 4583 } 4580 4584 4581 JSValue* Interpreter::cti_op_get_by_id_ fail(CTI_ARGS)4585 JSValue* Interpreter::cti_op_get_by_id_self_fail(CTI_ARGS) 4582 4586 { 4583 4587 CTI_STACK_HACK(); … … 4590 4594 JSValue* result = baseValue->get(callFrame, ident, slot); 4591 4595 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 4600 JSValue* 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 4664 JSValue* 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 4676 JSValue* 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 4688 JSValue* 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 4700 JSValue* 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 4712 JSValue* 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); 4594 4719 4595 4720 CHECK_FOR_EXCEPTION_AT_END(); … … 4642 4767 4643 4768 CallFrame* callFrame = ARG_callFrame; 4644 Identifier& ident = *ARG_id2;4645 4769 4646 4770 JSObject* baseObj = ARG_src1->toObject(callFrame); 4647 4771 4648 JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, ident));4772 JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, *ARG_id2)); 4649 4773 CHECK_FOR_EXCEPTION_AT_END(); 4650 4774 return result; … … 5891 6015 ASSERT(ARG_src1->isObject()); 5892 6016 JSObject* baseObj = asObject(ARG_src1); 5893 Identifier& ident = *ARG_id2;5894 6017 ASSERT(ARG_src3->isObject()); 5895 baseObj->defineGetter(callFrame, ident, asObject(ARG_src3));6018 baseObj->defineGetter(callFrame, *ARG_id2, asObject(ARG_src3)); 5896 6019 } 5897 6020 … … 5904 6027 ASSERT(ARG_src1->isObject()); 5905 6028 JSObject* baseObj = asObject(ARG_src1); 5906 Identifier& ident = *ARG_id2;5907 6029 ASSERT(ARG_src3->isObject()); 5908 baseObj->defineSetter(callFrame, ident, asObject(ARG_src3));6030 baseObj->defineSetter(callFrame, *ARG_id2, asObject(ARG_src3)); 5909 6031 } 5910 6032 -
trunk/JavaScriptCore/interpreter/Interpreter.h
r38511 r38652 188 188 static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS); 189 189 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); 191 197 static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS); 192 198 static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS); -
trunk/JavaScriptCore/jit/JIT.cpp
r38600 r38652 531 531 } 532 532 533 JmpSrc 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 533 539 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex) 534 540 { … … 2352 2358 case op_get_by_id_generic: 2353 2359 case op_get_by_id_proto: 2360 case op_get_by_id_proto_list: 2354 2361 case op_get_by_id_self: 2355 2362 case op_get_string_length: … … 3117 3124 __ testl_i32r(JSImmediate::TagMask, X86::eax); 3118 3125 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); 3121 3127 3122 3128 // Checks out okay! - getDirectOffset … … 3128 3134 ASSERT(code); 3129 3135 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)); 3132 3138 3133 3139 m_codeBlock->getStubInfo(returnAddress).stubRoutine = code; … … 3142 3148 3143 3149 // 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 3146 3155 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is 3147 3156 // referencing the prototype object - let's speculatively load it's table nice and early!) … … 3150 3159 __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx); 3151 3160 3152 // check eax is an object of the right Structure.3161 // Check eax is an object of the right Structure. 3153 3162 __ testl_i32r(JSImmediate::TagMask, X86::eax); 3154 3163 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); 3157 3165 3158 3166 // Check the prototype object's Structure had not changed. 3159 3167 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); 3161 3169 JmpSrc failureCases3 = __ jne(); 3162 3170 … … 3176 3184 3177 3185 // 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; 3179 3187 X86Assembler::link(code, success, reinterpret_cast<void*>(successDest)); 3180 3188 3181 3189 // 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. 3186 3193 intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase; 3187 3194 X86Assembler::repatchBranchOffset(jmpLocation, code); … … 3193 3200 __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx); 3194 3201 3195 // check eax is an object of the right Structure.3202 // Check eax is an object of the right Structure. 3196 3203 __ testl_i32r(JSImmediate::TagMask, X86::eax); 3197 3204 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) 3237 void 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); 3200 3249 3201 3250 // Check the prototype object's Structure had not changed. … … 3207 3256 __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax); 3208 3257 3209 __ ret();3258 JmpSrc success = __ jmp(); 3210 3259 3211 3260 void* code = __ executableCopy(); 3212 3261 ASSERT(code); 3213 3262 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 } 3221 3281 #endif 3222 }3223 3282 3224 3283 void JIT::privateCompileGetByIdChain(Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame) … … 3230 3289 // Check eax is an object of the right Structure. 3231 3290 __ 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)); 3235 3292 3236 3293 Structure* currStructure = structure; … … 3259 3316 3260 3317 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)); 3262 3319 3263 3320 m_codeBlock->getStubInfo(returnAddress).stubRoutine = code; … … 3268 3325 void JIT::privateCompilePutByIdReplace(Structure* structure, size_t cachedOffset, void* returnAddress) 3269 3326 { 3270 // check eax is an object of the right Structure.3327 // Check eax is an object of the right Structure. 3271 3328 __ testl_i32r(JSImmediate::TagMask, X86::eax); 3272 3329 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); 3275 3331 3276 3332 // checks out okay! - putDirectOffset … … 3308 3364 { 3309 3365 Vector<JmpSrc, 16> failureCases; 3310 // check eax is an object of the right Structure.3366 // Check eax is an object of the right Structure. 3311 3367 __ testl_i32r(JSImmediate::TagMask, X86::eax); 3312 3368 failureCases.append(__ jne()); … … 3428 3484 __ movl_mr(FIELD_OFFSET(ArrayStorage, m_length), X86::eax, X86::eax); 3429 3485 3486 __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::eax); 3487 JmpSrc array_failureCases3 = __ ja(); 3488 3430 3489 __ addl_rr(X86::eax, X86::eax); 3431 JmpSrc array_failureCases3 = __ jo();3432 3490 __ addl_i8r(1, X86::eax); 3433 3491 … … 3448 3506 __ movl_mr(FIELD_OFFSET(UString::Rep, len), X86::eax, X86::eax); 3449 3507 3508 __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::eax); 3509 JmpSrc string_failureCases3 = __ ja(); 3510 3450 3511 __ addl_rr(X86::eax, X86::eax); 3451 JmpSrc string_failureCases3 = __ jo();3452 3512 __ addl_i8r(1, X86::eax); 3453 3513 … … 3583 3643 ASSERT(code); 3584 3644 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)); 3591 3651 X86Assembler::link(code, callArityCheck1, reinterpret_cast<void*>(Interpreter::cti_op_call_arityCheck)); 3592 3652 X86Assembler::link(code, callArityCheck2, reinterpret_cast<void*>(Interpreter::cti_op_call_arityCheck)); … … 3641 3701 3642 3702 // 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)); 3644 3704 3645 3705 // Check eax is an array … … 3671 3731 3672 3732 // 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; 3674 3734 X86Assembler::link(code, success, reinterpret_cast<void*>(successDest)); 3675 3735 … … 3678 3738 3679 3739 // Finally repatch the jump to sow case back in the hot path to jump here instead. 3680 // FIXME: should revert this repatching, on failure.3681 3740 intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase; 3682 3741 X86Assembler::repatchBranchOffset(jmpLocation, code); -
trunk/JavaScriptCore/jit/JIT.h
r38531 r38652 110 110 struct Instruction; 111 111 struct OperandTypes; 112 struct PrototypeStructureList; 113 struct StructureStubInfo; 112 114 113 115 typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS); … … 318 320 } 319 321 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 320 330 static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress) 321 331 { … … 369 379 void privateCompileGetByIdSelf(Structure*, size_t cachedOffset, void* returnAddress); 370 380 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 371 384 void privateCompileGetByIdChain(Structure*, StructureChain*, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame); 372 385 void privateCompilePutByIdReplace(Structure*, size_t cachedOffset, void* returnAddress); … … 415 428 void emitJumpSlowCaseIfNotImmNums(RegisterID, RegisterID, unsigned bytecodeIndex); 416 429 430 JmpSrc checkStructure(RegisterID reg, Structure* structure); 431 417 432 void emitFastArithDeTagImmediate(RegisterID); 418 433 JmpSrc emitFastArithDeTagImmediateJumpIfZero(RegisterID);
Note: See TracChangeset
for help on using the changeset viewer.