Changeset 95388 in webkit
- Timestamp:
- Sep 17, 2011 4:33:01 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r95364 r95388 1 2011-09-16 Filip Pizlo <fpizlo@apple.com> 2 3 method_check should repatch itself if it finds that the new structure(s) 4 are the result of transitions from the old structure(s) 5 https://bugs.webkit.org/show_bug.cgi?id=68294 6 7 Reviewed by Gavin Barraclough. 8 9 Previously a patched method_check would slow-path to get_by_id. Now it 10 slow-paths to method_check_update, which attempts to correct the 11 method_check due to structure transitions before bailing to get_by_id. 12 13 This is a 1-2% speed-up on some benchmarks and is not a slow-down 14 anywhere, leading to a 0.6% speed-up on the Kraken geomean. 15 16 * jit/JITPropertyAccess.cpp: 17 (JSC::JIT::patchMethodCallProto): 18 * jit/JITStubs.cpp: 19 (JSC::DEFINE_STUB_FUNCTION): 20 * jit/JITStubs.h: 21 * runtime/Structure.h: 22 (JSC::Structure::transitivelyTransitionedFrom): 23 1 24 2011-09-16 Ryosuke Niwa <rniwa@webkit.org> 2 25 -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r95273 r95388 1052 1052 RepatchBuffer repatchBuffer(codeBlock); 1053 1053 1054 ASSERT(!methodCallLinkInfo.cachedStructure);1055 1054 CodeLocationDataLabelPtr structureLocation = methodCallLinkInfo.cachedStructure.location(); 1056 1055 methodCallLinkInfo.cachedStructure.set(globalData, structureLocation, codeBlock->ownerExecutable(), structure); … … 1060 1059 methodCallLinkInfo.cachedPrototype.set(globalData, structureLocation.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), codeBlock->ownerExecutable(), proto); 1061 1060 methodCallLinkInfo.cachedFunction.set(globalData, structureLocation.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction), codeBlock->ownerExecutable(), callee); 1062 repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id ));1061 repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_method_check_update)); 1063 1062 } 1064 1063 -
trunk/Source/JavaScriptCore/jit/JITStubs.cpp
r95340 r95388 1558 1558 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. 1559 1559 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); 1560 return JSValue::encode(result); 1561 } 1562 1563 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_update) 1564 { 1565 STUB_INIT_STACK_FRAME(stackFrame); 1566 1567 CallFrame* callFrame = stackFrame.callFrame; 1568 Identifier& ident = stackFrame.args[1].identifier(); 1569 1570 JSValue baseValue = stackFrame.args[0].jsValue(); 1571 PropertySlot slot(baseValue); 1572 JSValue result = baseValue.get(callFrame, ident, slot); 1573 CHECK_FOR_EXCEPTION(); 1574 1575 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); 1576 MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); 1577 1578 ASSERT(methodCallLinkInfo.seenOnce()); 1579 1580 // If we successfully got something, then the base from which it is being accessed must 1581 // be an object. (Assertion to ensure asObject() call below is safe, which comes after 1582 // an isCacheable() chceck. 1583 ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); 1584 1585 // Check that: 1586 // * We're dealing with a JSCell, 1587 // * the property is cachable, 1588 // * it's not a dictionary 1589 // * there is a function cached. 1590 Structure* structure; 1591 JSCell* specific; 1592 JSObject* slotBaseObject; 1593 if (!(baseValue.isCell() 1594 && slot.isCacheableValue() 1595 && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() 1596 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) 1597 && specific 1598 ) 1599 || (slot.slotBase() != structure->prototypeForLookup(callFrame) 1600 && slot.slotBase() != baseValue)) { 1601 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. 1602 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); 1603 return JSValue::encode(result); 1604 } 1605 1606 // Now check if the situation has changed sufficiently that we should bail out of 1607 // doing method_check optimizations entirely, or if it changed only slightly, in 1608 // which case we can just repatch. 1609 1610 JSValue proto = structure->prototypeForLookup(callFrame); 1611 1612 bool previousWasProto = methodCallLinkInfo.cachedPrototype.get() != codeBlock->globalObject()->methodCallDummy(); 1613 bool currentIsProto = slot.slotBase() == proto; 1614 1615 JSObject* callee = asObject(specific); 1616 1617 if (previousWasProto != currentIsProto 1618 || !structure->transitivelyTransitionedFrom(methodCallLinkInfo.cachedStructure.get()) 1619 || (previousWasProto && !slotBaseObject->structure()->transitivelyTransitionedFrom(methodCallLinkInfo.cachedPrototypeStructure.get())) 1620 || specific != methodCallLinkInfo.cachedFunction.get()) { 1621 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); 1622 return JSValue::encode(result); 1623 } 1624 1625 // It makes sense to simply repatch the method_check. 1626 1627 // Since we're accessing a prototype in a loop, it's a good bet that it 1628 // should not be treated as a dictionary. 1629 if (slotBaseObject->structure()->isDictionary()) 1630 slotBaseObject->flattenDictionaryObject(callFrame->globalData()); 1631 1632 // The result fetched should always be the callee! 1633 ASSERT(result == JSValue(callee)); 1634 1635 // Check to see if the function is on the object's prototype. Patch up the code to optimize. 1636 if (slot.slotBase() == proto) { 1637 JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); 1638 return JSValue::encode(result); 1639 } 1640 1641 ASSERT(slot.slotBase() == baseValue); 1642 1643 // Since we generate the method-check to check both the structure and a prototype-structure (since this 1644 // is the common case) we have a problem - we need to patch the prototype structure check to do something 1645 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler 1646 // for now. For now it performs a check on a special object on the global object only used for this 1647 // purpose. The object is in no way exposed, and as such the check will always pass. 1648 JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); 1560 1649 return JSValue::encode(result); 1561 1650 } -
trunk/Source/JavaScriptCore/jit/JITStubs.h
r95310 r95388 335 335 EncodedJSValue JIT_STUB cti_op_get_by_id_getter_stub(STUB_ARGS_DECLARATION); 336 336 EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION); 337 EncodedJSValue JIT_STUB cti_op_get_by_id_method_check_update(STUB_ARGS_DECLARATION); 337 338 EncodedJSValue JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS_DECLARATION); 338 339 EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS_DECLARATION); -
trunk/Source/JavaScriptCore/runtime/Structure.h
r95358 r95388 134 134 135 135 Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); } 136 bool transitivelyTransitionedFrom(Structure* structureToFind); 136 137 137 138 void growPropertyStorageCapacity(); … … 353 354 } 354 355 356 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind) 357 { 358 for (Structure* current = this; current; current = current->previousID()) { 359 if (current == structureToFind) 360 return true; 361 } 362 return false; 363 } 364 355 365 } // namespace JSC 356 366
Note: See TracChangeset
for help on using the changeset viewer.