Changeset 90950 in webkit
- Timestamp:
- Jul 13, 2011 2:44:42 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r90940 r90950 1 2011-07-13 Filip Pizlo <fpizlo@apple.com> 2 3 DFG JIT does not implement prototype chain or list caching for get_by_id. 4 https://bugs.webkit.org/show_bug.cgi?id=64147 5 6 Reviewed by Gavin Barraclough. 7 8 This implements unified support for prototype caching, prototype chain 9 caching, and polymorphic (i.e. list) prototype and prototype chain 10 caching. This is done by creating common code for emitting prototype 11 or chain access stubs, and having it factored out into 12 generateProtoChainAccessStub(). This function is called by 13 tryCacheGetByID once the latter determines that some form of prototype 14 access caching is necessary (i.e. the slot being accessed is not on the 15 base value but on some other object). 16 17 Direct prototype list, and prototype chain list, caching is implemented by 18 linking the slow path to operationGetByIdProtoBuildList(), which uses the 19 same helper function (generateProtoChainAccessStub()) as tryCacheGetByID. 20 21 This change required ensuring that the value in the scratchGPR field in 22 StructureStubInfo is preserved even after the stub info is in the 23 chain, or proto_list, states. Hence scratchGPR was moved out of the union 24 and into the top-level of StructureStubInfo. 25 26 * bytecode/StructureStubInfo.h: 27 * dfg/DFGJITCompiler.cpp: 28 (JSC::DFG::JITCompiler::compileFunction): 29 * dfg/DFGOperations.cpp: 30 * dfg/DFGOperations.h: 31 * dfg/DFGRepatch.cpp: 32 (JSC::DFG::emitRestoreScratch): 33 (JSC::DFG::linkRestoreScratch): 34 (JSC::DFG::generateProtoChainAccessStub): 35 (JSC::DFG::tryCacheGetByID): 36 (JSC::DFG::tryBuildGetByIDProtoList): 37 (JSC::DFG::dfgBuildGetByIDProtoList): 38 (JSC::DFG::tryCachePutByID): 39 * dfg/DFGRepatch.h: 40 1 41 2011-07-12 Brent Fulgham <bfulgham@webkit.org> 2 42 -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h
r90035 r90950 134 134 int8_t baseGPR; 135 135 int8_t valueGPR; 136 int8_t scratchGPR; 136 137 int8_t deltaCallToDone; 137 138 int8_t deltaCallToStructCheck; … … 143 144 int8_t deltaCheckImmToCall; 144 145 int8_t deltaCallToLoadOrStore; 145 int8_t scratchGPR;146 146 } unset; 147 147 struct { -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r90529 r90950 399 399 info.baseGPR = m_propertyAccesses[i].m_baseGPR; 400 400 info.valueGPR = m_propertyAccesses[i].m_valueGPR; 401 info. u.unset.scratchGPR = m_propertyAccesses[i].m_scratchGPR;401 info.scratchGPR = m_propertyAccesses[i].m_scratchGPR; 402 402 } 403 403 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r90877 r90950 260 260 } 261 261 262 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr); 263 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdProtoBuildList); 264 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress) 265 { 266 JSValue baseValue = JSValue::decode(encodedBase); 267 PropertySlot slot(baseValue); 268 JSValue result = baseValue.get(exec, *propertyName, slot); 269 270 StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); 271 dfgBuildGetByIDProtoList(exec, baseValue, *propertyName, slot, stubInfo); 272 273 return JSValue::encode(result); 274 } 275 262 276 EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr); 263 277 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize); -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r90877 r90950 62 62 EncodedJSValue operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*); 63 63 EncodedJSValue operationGetByIdBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*); 64 EncodedJSValue operationGetByIdProtoBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*); 64 65 EncodedJSValue operationGetByIdOptimize(ExecState*, EncodedJSValue encodedBase, Identifier*); 65 66 EncodedJSValue operationGetMethodOptimize(ExecState*, EncodedJSValue encodedBase, Identifier*); -
trunk/Source/JavaScriptCore/dfg/DFGRepatch.cpp
r90877 r90950 57 57 } 58 58 59 static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases) 60 { 61 if (needToRestoreScratch) { 62 stubJit.pop(scratchGPR); 63 64 success = stubJit.jump(); 65 66 // link failure cases here, so we can pop scratchGPR, and then jump back. 67 failureCases.link(&stubJit); 68 69 stubJit.pop(scratchGPR); 70 71 fail = stubJit.jump(); 72 return; 73 } 74 75 success = stubJit.jump(); 76 } 77 78 static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratch, MacroAssembler::Jump success, MacroAssembler::Jump fail, MacroAssembler::JumpList failureCases, CodeLocationLabel successLabel, CodeLocationLabel slowCaseBegin) 79 { 80 patchBuffer.link(success, successLabel); 81 82 if (needToRestoreScratch) { 83 patchBuffer.link(fail, slowCaseBegin); 84 return; 85 } 86 87 // link failure cases directly back to normal path 88 patchBuffer.link(failureCases, slowCaseBegin); 89 } 90 91 static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratch, StructureStubInfo& stubInfo, MacroAssembler::Jump success, MacroAssembler::Jump fail, MacroAssembler::JumpList failureCases) 92 { 93 linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)); 94 } 95 96 static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, size_t offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, CodeLocationLabel& stubRoutine) 97 { 98 JSGlobalData* globalData = &exec->globalData(); 99 100 MacroAssembler stubJit; 101 102 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR); 103 GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR); 104 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR); 105 bool needToRestoreScratch = false; 106 107 if (scratchGPR == InvalidGPRReg) { 108 scratchGPR = JITCodeGenerator::selectScratchGPR(baseGPR, resultGPR); 109 stubJit.push(scratchGPR); 110 needToRestoreScratch = true; 111 } 112 113 MacroAssembler::JumpList failureCases; 114 115 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(structure))); 116 117 Structure* currStructure = structure; 118 WriteBarrier<Structure>* it = chain->head(); 119 JSObject* protoObject = 0; 120 for (unsigned i = 0; i < count; ++i, ++it) { 121 protoObject = asObject(currStructure->prototypeForLookup(exec)); 122 stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR); 123 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(protoObject->structure()))); 124 currStructure = it->get(); 125 } 126 127 if (protoObject->structure()->isUsingInlineStorage()) 128 stubJit.loadPtr(MacroAssembler::Address(scratchGPR, JSObject::offsetOfInlineStorage() + offset * sizeof(JSValue)), resultGPR); 129 else 130 stubJit.loadPtr(protoObject->addressOfPropertyAtOffset(offset), resultGPR); 131 132 MacroAssembler::Jump success, fail; 133 134 emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases); 135 136 LinkBuffer patchBuffer(*globalData, &stubJit, exec->codeBlock()->executablePool()); 137 138 linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel); 139 140 stubRoutine = patchBuffer.finalizeCodeAddendum(); 141 } 142 59 143 static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo) 60 144 { … … 68 152 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR); 69 153 GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR); 70 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo. u.unset.scratchGPR);154 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR); 71 155 bool needToRestoreScratch = false; 72 156 … … 79 163 } 80 164 81 MacroAssembler::Jump failureCase1 = stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(globalData->jsArrayVPtr)); 165 MacroAssembler::JumpList failureCases; 166 167 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(globalData->jsArrayVPtr))); 82 168 83 169 stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), scratchGPR); 84 170 stubJit.load32(MacroAssembler::Address(scratchGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), scratchGPR); 85 MacroAssembler::Jump failureCase2 = stubJit.branch32(MacroAssembler::LessThan, scratchGPR, MacroAssembler::TrustedImm32(0));171 failureCases.append(stubJit.branch32(MacroAssembler::LessThan, scratchGPR, MacroAssembler::TrustedImm32(0))); 86 172 87 173 stubJit.orPtr(GPRInfo::tagTypeNumberRegister, scratchGPR, resultGPR); … … 89 175 MacroAssembler::Jump success, fail; 90 176 91 if (needToRestoreScratch) { 92 stubJit.pop(scratchGPR); 93 94 success = stubJit.jump(); 95 96 // link failure cases here, so we can pop scratchGPR, and then jump back. 97 failureCase1.link(&stubJit); 98 failureCase2.link(&stubJit); 99 100 stubJit.pop(scratchGPR); 101 102 fail = stubJit.jump(); 103 } else 104 success = stubJit.jump(); 177 emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases); 105 178 106 179 LinkBuffer patchBuffer(*globalData, &stubJit, codeBlock->executablePool()); 107 180 108 CodeLocationLabel slowCaseBegin = stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase); 109 110 patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone)); 111 112 if (needToRestoreScratch) 113 patchBuffer.link(fail, slowCaseBegin); 114 else { 115 // link failure cases directly back to normal path 116 patchBuffer.link(failureCase1, slowCaseBegin); 117 patchBuffer.link(failureCase2, slowCaseBegin); 118 } 181 linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases); 119 182 120 183 CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 121 184 stubInfo.stubRoutine = entryLabel; 122 185 123 CodeLocationLabel hotPathBegin = stubInfo.hotPathBegin;124 186 RepatchBuffer repatchBuffer(codeBlock); 125 187 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), entryLabel); … … 138 200 if (!slot.isCacheable()) 139 201 return false; 140 if (structure->isUncacheableDictionary() )202 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) 141 203 return false; 142 204 … … 151 213 } 152 214 153 // FIXME: should support prototype & chain accesses! 154 return false; 215 if (structure->isDictionary()) 216 return false; 217 218 // FIXME: optimize getters and setters 219 if (slot.cachedPropertyType() != PropertySlot::Value) 220 return false; 221 222 size_t offset = slot.cachedOffset(); 223 size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset); 224 if (!count) 225 return false; 226 227 StructureChain* prototypeChain = structure->prototypeChain(exec); 228 229 ASSERT(slot.slotBase().isObject()); 230 231 generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase), stubInfo.stubRoutine); 232 233 RepatchBuffer repatchBuffer(codeBlock); 234 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), stubInfo.stubRoutine); 235 repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList); 236 237 stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain); 238 return true; 155 239 } 156 240 … … 297 381 } 298 382 383 static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo) 384 { 385 if (!baseValue.isCell() 386 || !slot.isCacheable() 387 || baseValue.asCell()->structure()->isDictionary() 388 || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching() 389 || slot.slotBase() == baseValue 390 || slot.cachedPropertyType() != PropertySlot::Value) 391 return false; 392 393 ASSERT(slot.slotBase().isObject()); 394 395 size_t offset = slot.cachedOffset(); 396 size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset); 397 if (!count) 398 return false; 399 400 Structure* structure = baseValue.asCell()->structure(); 401 StructureChain* prototypeChain = structure->prototypeChain(exec); 402 CodeBlock* codeBlock = exec->codeBlock(); 403 JSGlobalData* globalData = &exec->globalData(); 404 405 PolymorphicAccessStructureList* polymorphicStructureList; 406 int listIndex = 1; 407 408 if (stubInfo.accessType == access_get_by_id_chain) { 409 ASSERT(!!stubInfo.stubRoutine); 410 polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get()); 411 stubInfo.stubRoutine = CodeLocationLabel(); 412 stubInfo.initGetByIdProtoList(polymorphicStructureList, 1); 413 } else { 414 ASSERT(stubInfo.accessType = access_get_by_id_proto_list); 415 polymorphicStructureList = stubInfo.u.getByIdProtoList.structureList; 416 listIndex = stubInfo.u.getByIdProtoList.listSize; 417 } 418 419 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 420 stubInfo.u.getByIdProtoList.listSize++; 421 422 CodeLocationLabel lastProtoBegin = polymorphicStructureList->list[listIndex - 1].stubRoutine; 423 ASSERT(!!lastProtoBegin); 424 425 CodeLocationLabel entryLabel; 426 427 generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), lastProtoBegin, entryLabel); 428 429 polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), entryLabel, structure); 430 431 CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck); 432 RepatchBuffer repatchBuffer(codeBlock); 433 repatchBuffer.relink(jumpLocation, entryLabel); 434 435 if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 436 return true; 437 } 438 439 return false; 440 } 441 442 void dfgBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo) 443 { 444 bool dontChangeCall = tryBuildGetByIDProtoList(exec, baseValue, propertyName, slot, stubInfo); 445 if (!dontChangeCall) 446 dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById); 447 } 448 299 449 static V_DFGOperation_EJJI appropriatePutByIdFunction(const PutPropertySlot &slot, PutKind putKind) 300 450 { … … 352 502 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR); 353 503 GPRReg valueGPR = static_cast<GPRReg>(stubInfo.valueGPR); 354 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo. u.unset.scratchGPR);504 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR); 355 505 bool needToRestoreScratch = false; 356 506 … … 409 559 stubInfo.stubRoutine = entryLabel; 410 560 411 CodeLocationLabel hotPathBegin = stubInfo.hotPathBegin;412 561 RepatchBuffer repatchBuffer(codeBlock); 413 562 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), entryLabel); -
trunk/Source/JavaScriptCore/dfg/DFGRepatch.h
r90877 r90950 37 37 void dfgRepatchGetMethod(ExecState*, JSValue, const Identifier&, const PropertySlot&, MethodCallLinkInfo&); 38 38 void dfgBuildGetByIDList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&); 39 void dfgBuildGetByIDProtoList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&); 39 40 void dfgRepatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind); 40 41 void dfgLinkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr, CodeSpecializationKind); -
trunk/Source/JavaScriptCore/runtime/JSObject.h
r90673 r90950 221 221 bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage) == static_cast<const void*>(this + 1); } 222 222 223 void* addressOfPropertyAtOffset(size_t offset) 224 { 225 return static_cast<void*>(&m_propertyStorage[offset]); 226 } 227 223 228 static const unsigned baseExternalStorageCapacity = 16; 224 229
Note: See TracChangeset
for help on using the changeset viewer.