Changeset 66150 in webkit for trunk/JavaScriptCore/jit/JITStubs.cpp
- Timestamp:
- Aug 26, 2010, 4:21:24 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/jit/JITStubs.cpp
r65866 r66150 825 825 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 826 826 827 NEVER_INLINE boolJITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct)827 NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) 828 828 { 829 829 // The interpreter checks for recursion here; I do not believe this can occur in CTI. 830 830 831 831 if (!baseValue.isCell()) 832 return false;832 return; 833 833 834 834 // Uncacheable: give up. 835 if (!slot.isCacheable()) 836 return false; 835 if (!slot.isCacheable()) { 836 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 837 return; 838 } 837 839 838 840 JSCell* baseCell = asCell(baseValue); 839 841 Structure* structure = baseCell->structure(); 840 842 841 if (structure->isUncacheableDictionary()) 842 return false; 843 if (structure->isUncacheableDictionary()) { 844 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 845 return; 846 } 843 847 844 848 // If baseCell != base, then baseCell must be a proxy for another object. 845 if (baseCell != slot.base()) 846 return false; 849 if (baseCell != slot.base()) { 850 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 851 return; 852 } 847 853 848 854 // Cache hit: Specialize instruction and ref Structures. … … 850 856 // Structure transition, cache transition info 851 857 if (slot.type() == PutPropertySlot::NewProperty) { 852 if (structure->isDictionary()) 853 return false; 858 if (structure->isDictionary()) { 859 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 860 return; 861 } 854 862 855 863 // put_by_id_transition checks the prototype chain for setters. … … 857 865 858 866 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 859 return JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); 860 } 867 stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); 868 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); 869 return; 870 } 871 872 stubInfo->initPutByIdReplace(structure); 861 873 862 874 JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); 863 stubInfo->initPutByIdReplace(structure); 864 return true; 865 } 866 867 NEVER_INLINE bool JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) 875 } 876 877 NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) 868 878 { 869 879 // FIXME: Write a test that proves we need to check for recursion here just … … 871 881 872 882 // FIXME: Cache property access for immediates. 873 if (!baseValue.isCell()) 874 return false; 883 if (!baseValue.isCell()) { 884 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 885 return; 886 } 875 887 876 888 JSGlobalData* globalData = &callFrame->globalData(); 877 889 878 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) 879 return JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, stubInfo, returnAddress); 890 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { 891 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress); 892 return; 893 } 880 894 881 895 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { … … 883 897 // to pay off, so we currently only do this for arrays. 884 898 ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline()); 885 return true;899 return; 886 900 } 887 901 888 902 // Uncacheable: give up. 889 if (!slot.isCacheable()) 890 return false; 903 if (!slot.isCacheable()) { 904 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 905 return; 906 } 891 907 892 908 JSCell* baseCell = asCell(baseValue); 893 909 Structure* structure = baseCell->structure(); 894 910 895 if (structure->isUncacheableDictionary()) 896 return false; 911 if (structure->isUncacheableDictionary()) { 912 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 913 return; 914 } 897 915 898 916 // Cache hit: Specialize instruction and ref Structures. 899 917 900 918 if (slot.slotBase() == baseValue) { 919 // set this up, so derefStructures can do it's job. 920 stubInfo->initGetByIdSelf(structure); 901 921 if (slot.cachedPropertyType() != PropertySlot::Value) 902 return false; 903 JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); 904 stubInfo->initGetByIdSelf(structure); 905 return true; 906 } 907 908 if (structure->isDictionary()) 909 return false; 922 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); 923 else 924 JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); 925 return; 926 } 927 928 if (structure->isDictionary()) { 929 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 930 return; 931 } 910 932 911 933 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { … … 921 943 offset = slotBaseObject->structure()->get(propertyName); 922 944 } 945 946 stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); 947 923 948 ASSERT(!structure->isDictionary()); 924 949 ASSERT(!slotBaseObject->structure()->isDictionary()); 925 return JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); 950 JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); 951 return; 926 952 } 927 953 … … 930 956 if (!count) { 931 957 stubInfo->accessType = access_get_by_id_generic; 932 return true;958 return; 933 959 } 934 960 935 961 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 936 return JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); 962 stubInfo->initGetByIdChain(structure, prototypeChain); 963 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); 937 964 } 938 965 … … 1387 1414 if (!stubInfo->seenOnce()) 1388 1415 stubInfo->setSeen(); 1389 else { 1390 JSValue baseValue = stackFrame.args[0].jsValue(); 1391 bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, false); 1392 if (!cached && baseValue.isCell()) 1393 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_generic)); 1394 } 1395 1416 else 1417 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false); 1418 1396 1419 CHECK_FOR_EXCEPTION_AT_END(); 1397 1420 } … … 1410 1433 if (!stubInfo->seenOnce()) 1411 1434 stubInfo->setSeen(); 1412 else { 1413 JSValue baseValue = stackFrame.args[0].jsValue(); 1414 bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, true); 1415 if (!cached && baseValue.isCell()) 1416 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_direct_generic)); 1417 } 1418 1435 else 1436 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); 1437 1419 1438 CHECK_FOR_EXCEPTION_AT_END(); 1420 1439 } … … 1548 1567 if (!stubInfo->seenOnce()) 1549 1568 stubInfo->setSeen(); 1550 else { 1551 bool cached = JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); 1552 if (!cached) 1553 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1554 } 1569 else 1570 JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); 1555 1571 1556 1572 CHECK_FOR_EXCEPTION_AT_END(); … … 1581 1597 ASSERT(slot.slotBase().isObject()); 1582 1598 1583 // If this is a regular self access (not yet upgraded to list), then switch the stubInfo over. 1584 if (stubInfo->accessType == access_get_by_id_self) 1585 stubInfo->initGetByIdSelfList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdSelf.baseObjectStructure)); 1586 1587 // If there is room in the list, try to add a cached entry. 1588 if (stubInfo->u.getByIdSelfList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { 1589 bool cached = JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset()); 1590 if (cached) 1591 return JSValue::encode(result); 1592 } 1593 } 1594 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1595 return JSValue::encode(result); 1596 } 1597 1598 static void setupPolymorphicProtoList(StructureStubInfo* stubInfo) 1599 { 1600 if (stubInfo->accessType == access_get_by_id_proto) 1601 stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure)); 1602 else if (stubInfo->accessType == access_get_by_id_chain) 1603 stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain)); 1604 ASSERT(stubInfo->accessType == access_get_by_id_proto_list); 1599 PolymorphicAccessStructureList* polymorphicStructureList; 1600 int listIndex = 1; 1601 1602 if (stubInfo->accessType == access_get_by_id_self) { 1603 ASSERT(!stubInfo->stubRoutine); 1604 polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); 1605 stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); 1606 } else { 1607 polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; 1608 listIndex = stubInfo->u.getByIdSelfList.listSize; 1609 } 1610 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1611 stubInfo->u.getByIdSelfList.listSize++; 1612 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset()); 1613 1614 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1615 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1616 } 1617 } else 1618 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1619 return JSValue::encode(result); 1620 } 1621 1622 static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex) 1623 { 1624 PolymorphicAccessStructureList* prototypeStructureList = 0; 1625 listIndex = 1; 1626 1627 switch (stubInfo->accessType) { 1628 case access_get_by_id_proto: 1629 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); 1630 stubInfo->stubRoutine = CodeLocationLabel(); 1631 stubInfo->initGetByIdProtoList(prototypeStructureList, 2); 1632 break; 1633 case access_get_by_id_chain: 1634 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); 1635 stubInfo->stubRoutine = CodeLocationLabel(); 1636 stubInfo->initGetByIdProtoList(prototypeStructureList, 2); 1637 break; 1638 case access_get_by_id_proto_list: 1639 prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; 1640 listIndex = stubInfo->u.getByIdProtoList.listSize; 1641 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) 1642 stubInfo->u.getByIdProtoList.listSize++; 1643 break; 1644 default: 1645 ASSERT_NOT_REACHED(); 1646 } 1647 1648 ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); 1649 return prototypeStructureList; 1605 1650 } 1606 1651 … … 1663 1708 size_t offset = slot.cachedOffset(); 1664 1709 1665 // Don't mix self & proto/chain accesses in the same list 1666 if (slot.slotBase() != baseValue) { 1667 if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { 1668 ASSERT(!asCell(baseValue)->structure()->isDictionary()); 1669 // Since we're accessing a prototype in a loop, it's a good bet that it 1670 // should not be treated as a dictionary. 1671 if (slotBaseObject->structure()->isDictionary()) { 1672 slotBaseObject->flattenDictionaryObject(); 1673 offset = slotBaseObject->structure()->get(propertyName); 1674 } 1675 1676 setupPolymorphicProtoList(stubInfo); 1677 if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { 1678 bool cached = JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset); 1679 if (cached) 1680 return JSValue::encode(result); 1681 } 1682 } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { 1683 ASSERT(!asCell(baseValue)->structure()->isDictionary()); 1684 1685 setupPolymorphicProtoList(stubInfo); 1686 if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { 1687 bool cached = JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, structure->prototypeChain(callFrame), count, propertyName, slot, offset); 1688 if (cached) 1689 return JSValue::encode(result); 1690 } 1691 } 1692 } 1693 1694 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1710 if (slot.slotBase() == baseValue) 1711 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1712 else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { 1713 ASSERT(!asCell(baseValue)->structure()->isDictionary()); 1714 // Since we're accessing a prototype in a loop, it's a good bet that it 1715 // should not be treated as a dictionary. 1716 if (slotBaseObject->structure()->isDictionary()) { 1717 slotBaseObject->flattenDictionaryObject(); 1718 offset = slotBaseObject->structure()->get(propertyName); 1719 } 1720 1721 int listIndex; 1722 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); 1723 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1724 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset); 1725 1726 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1727 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); 1728 } 1729 } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { 1730 ASSERT(!asCell(baseValue)->structure()->isDictionary()); 1731 int listIndex; 1732 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); 1733 1734 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1735 StructureChain* protoChain = structure->prototypeChain(callFrame); 1736 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset); 1737 1738 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1739 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); 1740 } 1741 } else 1742 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1743 1695 1744 return JSValue::encode(result); 1696 1745 }
Note:
See TracChangeset
for help on using the changeset viewer.