OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #ifndef VM_OBJECT_H_ | 5 #ifndef VM_OBJECT_H_ |
6 #define VM_OBJECT_H_ | 6 #define VM_OBJECT_H_ |
7 | 7 |
8 #include "include/dart_api.h" | 8 #include "include/dart_api.h" |
9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
10 #include "platform/utils.h" | 10 #include "platform/utils.h" |
(...skipping 1688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1699 void set_patched_class(const Class& value) const; | 1699 void set_patched_class(const Class& value) const; |
1700 void set_source_class(const Class& value) const; | 1700 void set_source_class(const Class& value) const; |
1701 | 1701 |
1702 static RawPatchClass* New(); | 1702 static RawPatchClass* New(); |
1703 | 1703 |
1704 FINAL_HEAP_OBJECT_IMPLEMENTATION(PatchClass, Object); | 1704 FINAL_HEAP_OBJECT_IMPLEMENTATION(PatchClass, Object); |
1705 friend class Class; | 1705 friend class Class; |
1706 }; | 1706 }; |
1707 | 1707 |
1708 | 1708 |
1709 // Object holding information about an IC: test classes and their | |
Florian Schneider
2015/06/01 07:50:16
Is there any diff here or did you just move class
srdjan
2015/06/01 15:23:40
Done.
No diffs, ICData moved ahead of class Functi
| |
1710 // corresponding targets. | |
1711 class ICData : public Object { | |
1712 public: | |
1713 RawFunction* owner() const { | |
1714 return raw_ptr()->owner_; | |
1715 } | |
1716 | |
1717 RawString* target_name() const { | |
1718 return raw_ptr()->target_name_; | |
1719 } | |
1720 | |
1721 RawArray* arguments_descriptor() const { | |
1722 return raw_ptr()->args_descriptor_; | |
1723 } | |
1724 | |
1725 intptr_t NumArgsTested() const; | |
1726 | |
1727 intptr_t deopt_id() const { | |
1728 return raw_ptr()->deopt_id_; | |
1729 } | |
1730 | |
1731 // Note: only deopts with reasons before Unknown in this list are recorded in | |
1732 // the ICData. All other reasons are used purely for informational messages | |
1733 // printed during deoptimization itself. | |
1734 #define DEOPT_REASONS(V) \ | |
1735 V(BinarySmiOp) \ | |
1736 V(BinaryMintOp) \ | |
1737 V(DoubleToSmi) \ | |
1738 V(CheckSmi) \ | |
1739 V(Unknown) \ | |
1740 V(PolymorphicInstanceCallTestFail) \ | |
1741 V(UnaryMintOp) \ | |
1742 V(BinaryDoubleOp) \ | |
1743 V(UnaryOp) \ | |
1744 V(UnboxInteger) \ | |
1745 V(CheckClass) \ | |
1746 V(CheckArrayBound) \ | |
1747 V(AtCall) \ | |
1748 V(Uint32Load) \ | |
1749 V(GuardField) \ | |
1750 V(TestCids) \ | |
1751 V(NumReasons) \ | |
1752 | |
1753 enum DeoptReasonId { | |
1754 #define DEFINE_ENUM_LIST(name) kDeopt##name, | |
1755 DEOPT_REASONS(DEFINE_ENUM_LIST) | |
1756 #undef DEFINE_ENUM_LIST | |
1757 }; | |
1758 | |
1759 static const intptr_t kLastRecordedDeoptReason = kDeoptUnknown - 1; | |
1760 | |
1761 enum DeoptFlags { | |
1762 // Deoptimization is caused by an optimistically hoisted instruction. | |
1763 kHoisted = 1 << 0, | |
1764 | |
1765 // Deoptimization is caused by an optimistically generalized bounds check. | |
1766 kGeneralized = 1 << 1 | |
1767 }; | |
1768 | |
1769 bool HasDeoptReasons() const { return DeoptReasons() != 0; } | |
1770 uint32_t DeoptReasons() const; | |
1771 void SetDeoptReasons(uint32_t reasons) const; | |
1772 | |
1773 bool HasDeoptReason(ICData::DeoptReasonId reason) const; | |
1774 void AddDeoptReason(ICData::DeoptReasonId reason) const; | |
1775 | |
1776 bool IssuedJSWarning() const; | |
1777 void SetIssuedJSWarning() const; | |
1778 | |
1779 // Return true if the target function of this IC data may check for (and | |
1780 // possibly issue) a Javascript compatibility warning. | |
1781 bool MayCheckForJSWarning() const; | |
1782 | |
1783 intptr_t NumberOfChecks() const; | |
1784 | |
1785 // Discounts any checks with usage of zero. | |
1786 intptr_t NumberOfUsedChecks() const; | |
1787 | |
1788 static intptr_t InstanceSize() { | |
1789 return RoundedAllocationSize(sizeof(RawICData)); | |
1790 } | |
1791 | |
1792 static intptr_t target_name_offset() { | |
1793 return OFFSET_OF(RawICData, target_name_); | |
1794 } | |
1795 | |
1796 static intptr_t state_bits_offset() { | |
1797 return OFFSET_OF(RawICData, state_bits_); | |
1798 } | |
1799 | |
1800 static intptr_t NumArgsTestedShift() { | |
1801 return kNumArgsTestedPos; | |
1802 } | |
1803 | |
1804 static intptr_t NumArgsTestedMask() { | |
1805 return ((1 << kNumArgsTestedSize) - 1) << kNumArgsTestedPos; | |
1806 } | |
1807 | |
1808 static intptr_t arguments_descriptor_offset() { | |
1809 return OFFSET_OF(RawICData, args_descriptor_); | |
1810 } | |
1811 | |
1812 static intptr_t ic_data_offset() { | |
1813 return OFFSET_OF(RawICData, ic_data_); | |
1814 } | |
1815 | |
1816 static intptr_t owner_offset() { | |
1817 return OFFSET_OF(RawICData, owner_); | |
1818 } | |
1819 | |
1820 // Used for unoptimized static calls when no class-ids are checked. | |
1821 void AddTarget(const Function& target) const; | |
1822 | |
1823 // Adding checks. | |
1824 | |
1825 // Adds one more class test to ICData. Length of 'classes' must be equal to | |
1826 // the number of arguments tested. Use only for num_args_tested > 1. | |
1827 void AddCheck(const GrowableArray<intptr_t>& class_ids, | |
1828 const Function& target) const; | |
1829 // Adds sorted so that Smi is the first class-id. Use only for | |
1830 // num_args_tested == 1. | |
1831 void AddReceiverCheck(intptr_t receiver_class_id, | |
1832 const Function& target, | |
1833 intptr_t count = 1) const; | |
1834 | |
1835 // Retrieving checks. | |
1836 | |
1837 // TODO(srdjan): GetCheckAt without target. | |
1838 void GetCheckAt(intptr_t index, | |
1839 GrowableArray<intptr_t>* class_ids, | |
1840 Function* target) const; | |
1841 // Only for 'num_args_checked == 1'. | |
1842 void GetOneClassCheckAt(intptr_t index, | |
1843 intptr_t* class_id, | |
1844 Function* target) const; | |
1845 // Only for 'num_args_checked == 1'. | |
1846 intptr_t GetCidAt(intptr_t index) const; | |
1847 | |
1848 intptr_t GetReceiverClassIdAt(intptr_t index) const; | |
1849 intptr_t GetClassIdAt(intptr_t index, intptr_t arg_nr) const; | |
1850 | |
1851 RawFunction* GetTargetAt(intptr_t index) const; | |
1852 RawFunction* GetTargetForReceiverClassId(intptr_t class_id) const; | |
1853 | |
1854 void IncrementCountAt(intptr_t index, intptr_t value) const; | |
1855 void SetCountAt(intptr_t index, intptr_t value) const; | |
1856 intptr_t GetCountAt(intptr_t index) const; | |
1857 intptr_t AggregateCount() const; | |
1858 | |
1859 // Returns this->raw() if num_args_tested == 1 and arg_nr == 1, otherwise | |
1860 // returns a new ICData object containing only unique arg_nr checks. | |
1861 // Returns only used entries. | |
1862 RawICData* AsUnaryClassChecksForArgNr(intptr_t arg_nr) const; | |
1863 RawICData* AsUnaryClassChecks() const { | |
1864 return AsUnaryClassChecksForArgNr(0); | |
1865 } | |
1866 RawICData* AsUnaryClassChecksForCid( | |
1867 intptr_t cid, const Function& target) const; | |
1868 | |
1869 // Consider only used entries. | |
1870 bool AllTargetsHaveSameOwner(intptr_t owner_cid) const; | |
1871 bool AllReceiversAreNumbers() const; | |
1872 bool HasOneTarget() const; | |
1873 bool HasReceiverClassId(intptr_t class_id) const; | |
1874 | |
1875 static RawICData* New(const Function& owner, | |
1876 const String& target_name, | |
1877 const Array& arguments_descriptor, | |
1878 intptr_t deopt_id, | |
1879 intptr_t num_args_tested); | |
1880 static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested); | |
1881 | |
1882 static intptr_t TestEntryLengthFor(intptr_t num_args); | |
1883 | |
1884 static intptr_t TargetIndexFor(intptr_t num_args) { | |
1885 return num_args; | |
1886 } | |
1887 | |
1888 static intptr_t CountIndexFor(intptr_t num_args) { | |
1889 return (num_args + 1); | |
1890 } | |
1891 | |
1892 bool IsUsedAt(intptr_t i) const; | |
1893 | |
1894 void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first, | |
1895 GrowableArray<intptr_t>* second) const; | |
1896 | |
1897 // Range feedback tracking functionality. | |
1898 | |
1899 // For arithmetic operations we store range information for inputs and the | |
1900 // result. The goal is to discover: | |
1901 // | |
1902 // - on 32-bit platforms: | |
1903 // - when Mint operation is actually a int32/uint32 operation; | |
1904 // - when Smi operation produces non-smi results; | |
1905 // | |
1906 // - on 64-bit platforms: | |
1907 // - when Smi operation is actually int32/uint32 operation; | |
1908 // - when Mint operation produces non-smi results; | |
1909 // | |
1910 enum RangeFeedback { | |
1911 kSmiRange, | |
1912 kInt32Range, | |
1913 kUint32Range, | |
1914 kInt64Range | |
1915 }; | |
1916 | |
1917 // We use 4 bits per operand/result feedback. Our lattice allows us to | |
1918 // express the following states: | |
1919 // | |
1920 // - usmi 0000 [used only on 32bit platforms] | |
1921 // - smi 0001 | |
1922 // - uint31 0010 | |
1923 // - int32 0011 | |
1924 // - uint32 0100 | |
1925 // - int33 x1x1 | |
1926 // - int64 1xxx | |
1927 // | |
1928 // DecodeRangeFeedbackAt() helper maps these states into the RangeFeedback | |
1929 // enumeration. | |
1930 enum RangeFeedbackLatticeBits { | |
1931 kSignedRangeBit = 1 << 0, | |
1932 kInt32RangeBit = 1 << 1, | |
1933 kUint32RangeBit = 1 << 2, | |
1934 kInt64RangeBit = 1 << 3, | |
1935 kBitsPerRangeFeedback = 4, | |
1936 kRangeFeedbackMask = (1 << kBitsPerRangeFeedback) - 1, | |
1937 kRangeFeedbackSlots = 3 | |
1938 }; | |
1939 | |
1940 static bool IsValidRangeFeedbackIndex(intptr_t index) { | |
1941 return (0 <= index) && (index < kRangeFeedbackSlots); | |
1942 } | |
1943 | |
1944 static intptr_t RangeFeedbackShift(intptr_t index) { | |
1945 return (index * kBitsPerRangeFeedback) + kRangeFeedbackPos; | |
1946 } | |
1947 | |
1948 static const char* RangeFeedbackToString(RangeFeedback feedback) { | |
1949 switch (feedback) { | |
1950 case kSmiRange: | |
1951 return "smi"; | |
1952 case kInt32Range: | |
1953 return "int32"; | |
1954 case kUint32Range: | |
1955 return "uint32"; | |
1956 case kInt64Range: | |
1957 return "int64"; | |
1958 default: | |
1959 UNREACHABLE(); | |
1960 return "?"; | |
1961 } | |
1962 } | |
1963 | |
1964 // It is only meaningful to interptret range feedback stored in the ICData | |
1965 // when all checks are Mint or Smi. | |
1966 bool HasRangeFeedback() const; | |
1967 RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const; | |
1968 | |
1969 void PrintToJSONArray(const JSONArray& jsarray, | |
1970 intptr_t token_pos, | |
1971 bool is_static_call) const; | |
1972 | |
1973 private: | |
1974 RawArray* ic_data() const { | |
1975 return raw_ptr()->ic_data_; | |
1976 } | |
1977 | |
1978 void set_owner(const Function& value) const; | |
1979 void set_target_name(const String& value) const; | |
1980 void set_arguments_descriptor(const Array& value) const; | |
1981 void set_deopt_id(intptr_t value) const; | |
1982 void SetNumArgsTested(intptr_t value) const; | |
1983 void set_ic_data(const Array& value) const; | |
1984 void set_state_bits(uint32_t bits) const; | |
1985 | |
1986 enum { | |
1987 kNumArgsTestedPos = 0, | |
1988 kNumArgsTestedSize = 2, | |
1989 kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize, | |
1990 kDeoptReasonSize = kLastRecordedDeoptReason + 1, | |
1991 kIssuedJSWarningBit = kDeoptReasonPos + kDeoptReasonSize, | |
1992 kRangeFeedbackPos = kIssuedJSWarningBit + 1, | |
1993 kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots | |
1994 }; | |
1995 | |
1996 class NumArgsTestedBits : public BitField<uint32_t, | |
1997 kNumArgsTestedPos, kNumArgsTestedSize> {}; // NOLINT | |
1998 class DeoptReasonBits : public BitField<uint32_t, | |
1999 ICData::kDeoptReasonPos, ICData::kDeoptReasonSize> {}; // NOLINT | |
2000 class IssuedJSWarningBit : public BitField<bool, kIssuedJSWarningBit, 1> {}; | |
2001 class RangeFeedbackBits : public BitField<uint32_t, | |
2002 ICData::kRangeFeedbackPos, ICData::kRangeFeedbackSize> {}; // NOLINT | |
2003 | |
2004 #if defined(DEBUG) | |
2005 // Used in asserts to verify that a check is not added twice. | |
2006 bool HasCheck(const GrowableArray<intptr_t>& cids) const; | |
2007 #endif // DEBUG | |
2008 | |
2009 intptr_t TestEntryLength() const; | |
2010 void WriteSentinel(const Array& data) const; | |
2011 | |
2012 FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object); | |
2013 friend class Class; | |
2014 }; | |
2015 | |
2016 | |
1709 class Function : public Object { | 2017 class Function : public Object { |
1710 public: | 2018 public: |
1711 RawString* name() const { return raw_ptr()->name_; } | 2019 RawString* name() const { return raw_ptr()->name_; } |
1712 RawString* PrettyName() const; | 2020 RawString* PrettyName() const; |
1713 RawString* UserVisibleName() const; | 2021 RawString* UserVisibleName() const; |
1714 RawString* QualifiedPrettyName() const; | 2022 RawString* QualifiedPrettyName() const; |
1715 RawString* QualifiedUserVisibleName() const; | 2023 RawString* QualifiedUserVisibleName() const; |
1716 virtual RawString* DictionaryName() const { return name(); } | 2024 virtual RawString* DictionaryName() const { return name(); } |
1717 | 2025 |
1718 RawString* GetSource() const; | 2026 RawString* GetSource() const; |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2224 // Return false and report an error if the fingerprint does not match. | 2532 // Return false and report an error if the fingerprint does not match. |
2225 bool CheckSourceFingerprint(const char* prefix, int32_t fp) const; | 2533 bool CheckSourceFingerprint(const char* prefix, int32_t fp) const; |
2226 | 2534 |
2227 // Works with map [deopt-id] -> ICData. | 2535 // Works with map [deopt-id] -> ICData. |
2228 void SaveICDataMap( | 2536 void SaveICDataMap( |
2229 const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data) const; | 2537 const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data) const; |
2230 void RestoreICDataMap( | 2538 void RestoreICDataMap( |
2231 ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data) const; | 2539 ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data) const; |
2232 | 2540 |
2233 RawArray* ic_data_array() const; | 2541 RawArray* ic_data_array() const; |
2234 void ClearICData() const; | 2542 void ClearICDataArray() const; |
2543 | |
2544 // Sets deopt reason in all ICData-s with given deopt_id. | |
2545 void SetDeoptReasonForAll(intptr_t deopt_id, ICData::DeoptReasonId reason); | |
2235 | 2546 |
2236 static const int kCtorPhaseInit = 1 << 0; | 2547 static const int kCtorPhaseInit = 1 << 0; |
2237 static const int kCtorPhaseBody = 1 << 1; | 2548 static const int kCtorPhaseBody = 1 << 1; |
2238 static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody); | 2549 static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody); |
2239 | 2550 |
2240 void set_modifier(RawFunction::AsyncModifier value) const; | 2551 void set_modifier(RawFunction::AsyncModifier value) const; |
2241 | 2552 |
2242 // static: Considered during class-side or top-level resolution rather than | 2553 // static: Considered during class-side or top-level resolution rather than |
2243 // instance-side resolution. | 2554 // instance-side resolution. |
2244 // const: Valid target of a const constructor call. | 2555 // const: Valid target of a const constructor call. |
(...skipping 1299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3544 | 3855 |
3545 | 3856 |
3546 private: | 3857 private: |
3547 static void UnpackInto(const Array& table, | 3858 static void UnpackInto(const Array& table, |
3548 const TypedData& packed, | 3859 const TypedData& packed, |
3549 GrowableArray<DeoptInstr*>* instructions, | 3860 GrowableArray<DeoptInstr*>* instructions, |
3550 intptr_t length); | 3861 intptr_t length); |
3551 }; | 3862 }; |
3552 | 3863 |
3553 | 3864 |
3554 // Object holding information about an IC: test classes and their | |
3555 // corresponding targets. | |
3556 class ICData : public Object { | |
3557 public: | |
3558 RawFunction* owner() const { | |
3559 return raw_ptr()->owner_; | |
3560 } | |
3561 | |
3562 RawString* target_name() const { | |
3563 return raw_ptr()->target_name_; | |
3564 } | |
3565 | |
3566 RawArray* arguments_descriptor() const { | |
3567 return raw_ptr()->args_descriptor_; | |
3568 } | |
3569 | |
3570 intptr_t NumArgsTested() const; | |
3571 | |
3572 intptr_t deopt_id() const { | |
3573 return raw_ptr()->deopt_id_; | |
3574 } | |
3575 | |
3576 // Note: only deopts with reasons before Unknown in this list are recorded in | |
3577 // the ICData. All other reasons are used purely for informational messages | |
3578 // printed during deoptimization itself. | |
3579 #define DEOPT_REASONS(V) \ | |
3580 V(BinarySmiOp) \ | |
3581 V(BinaryMintOp) \ | |
3582 V(DoubleToSmi) \ | |
3583 V(Unknown) \ | |
3584 V(PolymorphicInstanceCallTestFail) \ | |
3585 V(UnaryMintOp) \ | |
3586 V(BinaryDoubleOp) \ | |
3587 V(UnaryOp) \ | |
3588 V(UnboxInteger) \ | |
3589 V(CheckClass) \ | |
3590 V(CheckSmi) \ | |
3591 V(CheckArrayBound) \ | |
3592 V(AtCall) \ | |
3593 V(Uint32Load) \ | |
3594 V(GuardField) \ | |
3595 V(TestCids) \ | |
3596 V(NumReasons) \ | |
3597 | |
3598 enum DeoptReasonId { | |
3599 #define DEFINE_ENUM_LIST(name) kDeopt##name, | |
3600 DEOPT_REASONS(DEFINE_ENUM_LIST) | |
3601 #undef DEFINE_ENUM_LIST | |
3602 }; | |
3603 | |
3604 static const intptr_t kLastRecordedDeoptReason = kDeoptUnknown - 1; | |
3605 | |
3606 enum DeoptFlags { | |
3607 // Deoptimization is caused by an optimistically hoisted instruction. | |
3608 kHoisted = 1 << 0, | |
3609 | |
3610 // Deoptimization is caused by an optimistically generalized bounds check. | |
3611 kGeneralized = 1 << 1 | |
3612 }; | |
3613 | |
3614 bool HasDeoptReasons() const { return DeoptReasons() != 0; } | |
3615 uint32_t DeoptReasons() const; | |
3616 void SetDeoptReasons(uint32_t reasons) const; | |
3617 | |
3618 bool HasDeoptReason(ICData::DeoptReasonId reason) const; | |
3619 void AddDeoptReason(ICData::DeoptReasonId reason) const; | |
3620 | |
3621 bool IssuedJSWarning() const; | |
3622 void SetIssuedJSWarning() const; | |
3623 | |
3624 // Return true if the target function of this IC data may check for (and | |
3625 // possibly issue) a Javascript compatibility warning. | |
3626 bool MayCheckForJSWarning() const; | |
3627 | |
3628 intptr_t NumberOfChecks() const; | |
3629 | |
3630 // Discounts any checks with usage of zero. | |
3631 intptr_t NumberOfUsedChecks() const; | |
3632 | |
3633 static intptr_t InstanceSize() { | |
3634 return RoundedAllocationSize(sizeof(RawICData)); | |
3635 } | |
3636 | |
3637 static intptr_t target_name_offset() { | |
3638 return OFFSET_OF(RawICData, target_name_); | |
3639 } | |
3640 | |
3641 static intptr_t state_bits_offset() { | |
3642 return OFFSET_OF(RawICData, state_bits_); | |
3643 } | |
3644 | |
3645 static intptr_t NumArgsTestedShift() { | |
3646 return kNumArgsTestedPos; | |
3647 } | |
3648 | |
3649 static intptr_t NumArgsTestedMask() { | |
3650 return ((1 << kNumArgsTestedSize) - 1) << kNumArgsTestedPos; | |
3651 } | |
3652 | |
3653 static intptr_t arguments_descriptor_offset() { | |
3654 return OFFSET_OF(RawICData, args_descriptor_); | |
3655 } | |
3656 | |
3657 static intptr_t ic_data_offset() { | |
3658 return OFFSET_OF(RawICData, ic_data_); | |
3659 } | |
3660 | |
3661 static intptr_t owner_offset() { | |
3662 return OFFSET_OF(RawICData, owner_); | |
3663 } | |
3664 | |
3665 // Used for unoptimized static calls when no class-ids are checked. | |
3666 void AddTarget(const Function& target) const; | |
3667 | |
3668 // Adding checks. | |
3669 | |
3670 // Adds one more class test to ICData. Length of 'classes' must be equal to | |
3671 // the number of arguments tested. Use only for num_args_tested > 1. | |
3672 void AddCheck(const GrowableArray<intptr_t>& class_ids, | |
3673 const Function& target) const; | |
3674 // Adds sorted so that Smi is the first class-id. Use only for | |
3675 // num_args_tested == 1. | |
3676 void AddReceiverCheck(intptr_t receiver_class_id, | |
3677 const Function& target, | |
3678 intptr_t count = 1) const; | |
3679 | |
3680 // Retrieving checks. | |
3681 | |
3682 // TODO(srdjan): GetCheckAt without target. | |
3683 void GetCheckAt(intptr_t index, | |
3684 GrowableArray<intptr_t>* class_ids, | |
3685 Function* target) const; | |
3686 // Only for 'num_args_checked == 1'. | |
3687 void GetOneClassCheckAt(intptr_t index, | |
3688 intptr_t* class_id, | |
3689 Function* target) const; | |
3690 // Only for 'num_args_checked == 1'. | |
3691 intptr_t GetCidAt(intptr_t index) const; | |
3692 | |
3693 intptr_t GetReceiverClassIdAt(intptr_t index) const; | |
3694 intptr_t GetClassIdAt(intptr_t index, intptr_t arg_nr) const; | |
3695 | |
3696 RawFunction* GetTargetAt(intptr_t index) const; | |
3697 RawFunction* GetTargetForReceiverClassId(intptr_t class_id) const; | |
3698 | |
3699 void IncrementCountAt(intptr_t index, intptr_t value) const; | |
3700 void SetCountAt(intptr_t index, intptr_t value) const; | |
3701 intptr_t GetCountAt(intptr_t index) const; | |
3702 intptr_t AggregateCount() const; | |
3703 | |
3704 // Returns this->raw() if num_args_tested == 1 and arg_nr == 1, otherwise | |
3705 // returns a new ICData object containing only unique arg_nr checks. | |
3706 // Returns only used entries. | |
3707 RawICData* AsUnaryClassChecksForArgNr(intptr_t arg_nr) const; | |
3708 RawICData* AsUnaryClassChecks() const { | |
3709 return AsUnaryClassChecksForArgNr(0); | |
3710 } | |
3711 RawICData* AsUnaryClassChecksForCid( | |
3712 intptr_t cid, const Function& target) const; | |
3713 | |
3714 // Consider only used entries. | |
3715 bool AllTargetsHaveSameOwner(intptr_t owner_cid) const; | |
3716 bool AllReceiversAreNumbers() const; | |
3717 bool HasOneTarget() const; | |
3718 bool HasReceiverClassId(intptr_t class_id) const; | |
3719 | |
3720 static RawICData* New(const Function& owner, | |
3721 const String& target_name, | |
3722 const Array& arguments_descriptor, | |
3723 intptr_t deopt_id, | |
3724 intptr_t num_args_tested); | |
3725 static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested); | |
3726 | |
3727 static intptr_t TestEntryLengthFor(intptr_t num_args); | |
3728 | |
3729 static intptr_t TargetIndexFor(intptr_t num_args) { | |
3730 return num_args; | |
3731 } | |
3732 | |
3733 static intptr_t CountIndexFor(intptr_t num_args) { | |
3734 return (num_args + 1); | |
3735 } | |
3736 | |
3737 bool IsUsedAt(intptr_t i) const; | |
3738 | |
3739 void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first, | |
3740 GrowableArray<intptr_t>* second) const; | |
3741 | |
3742 // Range feedback tracking functionality. | |
3743 | |
3744 // For arithmetic operations we store range information for inputs and the | |
3745 // result. The goal is to discover: | |
3746 // | |
3747 // - on 32-bit platforms: | |
3748 // - when Mint operation is actually a int32/uint32 operation; | |
3749 // - when Smi operation produces non-smi results; | |
3750 // | |
3751 // - on 64-bit platforms: | |
3752 // - when Smi operation is actually int32/uint32 operation; | |
3753 // - when Mint operation produces non-smi results; | |
3754 // | |
3755 enum RangeFeedback { | |
3756 kSmiRange, | |
3757 kInt32Range, | |
3758 kUint32Range, | |
3759 kInt64Range | |
3760 }; | |
3761 | |
3762 // We use 4 bits per operand/result feedback. Our lattice allows us to | |
3763 // express the following states: | |
3764 // | |
3765 // - usmi 0000 [used only on 32bit platforms] | |
3766 // - smi 0001 | |
3767 // - uint31 0010 | |
3768 // - int32 0011 | |
3769 // - uint32 0100 | |
3770 // - int33 x1x1 | |
3771 // - int64 1xxx | |
3772 // | |
3773 // DecodeRangeFeedbackAt() helper maps these states into the RangeFeedback | |
3774 // enumeration. | |
3775 enum RangeFeedbackLatticeBits { | |
3776 kSignedRangeBit = 1 << 0, | |
3777 kInt32RangeBit = 1 << 1, | |
3778 kUint32RangeBit = 1 << 2, | |
3779 kInt64RangeBit = 1 << 3, | |
3780 kBitsPerRangeFeedback = 4, | |
3781 kRangeFeedbackMask = (1 << kBitsPerRangeFeedback) - 1, | |
3782 kRangeFeedbackSlots = 3 | |
3783 }; | |
3784 | |
3785 static bool IsValidRangeFeedbackIndex(intptr_t index) { | |
3786 return (0 <= index) && (index < kRangeFeedbackSlots); | |
3787 } | |
3788 | |
3789 static intptr_t RangeFeedbackShift(intptr_t index) { | |
3790 return (index * kBitsPerRangeFeedback) + kRangeFeedbackPos; | |
3791 } | |
3792 | |
3793 static const char* RangeFeedbackToString(RangeFeedback feedback) { | |
3794 switch (feedback) { | |
3795 case kSmiRange: | |
3796 return "smi"; | |
3797 case kInt32Range: | |
3798 return "int32"; | |
3799 case kUint32Range: | |
3800 return "uint32"; | |
3801 case kInt64Range: | |
3802 return "int64"; | |
3803 default: | |
3804 UNREACHABLE(); | |
3805 return "?"; | |
3806 } | |
3807 } | |
3808 | |
3809 // It is only meaningful to interptret range feedback stored in the ICData | |
3810 // when all checks are Mint or Smi. | |
3811 bool HasRangeFeedback() const; | |
3812 RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const; | |
3813 | |
3814 void PrintToJSONArray(const JSONArray& jsarray, | |
3815 intptr_t token_pos, | |
3816 bool is_static_call) const; | |
3817 | |
3818 private: | |
3819 RawArray* ic_data() const { | |
3820 return raw_ptr()->ic_data_; | |
3821 } | |
3822 | |
3823 void set_owner(const Function& value) const; | |
3824 void set_target_name(const String& value) const; | |
3825 void set_arguments_descriptor(const Array& value) const; | |
3826 void set_deopt_id(intptr_t value) const; | |
3827 void SetNumArgsTested(intptr_t value) const; | |
3828 void set_ic_data(const Array& value) const; | |
3829 void set_state_bits(uint32_t bits) const; | |
3830 | |
3831 enum { | |
3832 kNumArgsTestedPos = 0, | |
3833 kNumArgsTestedSize = 2, | |
3834 kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize, | |
3835 kDeoptReasonSize = kLastRecordedDeoptReason + 1, | |
3836 kIssuedJSWarningBit = kDeoptReasonPos + kDeoptReasonSize, | |
3837 kRangeFeedbackPos = kIssuedJSWarningBit + 1, | |
3838 kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots | |
3839 }; | |
3840 | |
3841 class NumArgsTestedBits : public BitField<uint32_t, | |
3842 kNumArgsTestedPos, kNumArgsTestedSize> {}; // NOLINT | |
3843 class DeoptReasonBits : public BitField<uint32_t, | |
3844 ICData::kDeoptReasonPos, ICData::kDeoptReasonSize> {}; // NOLINT | |
3845 class IssuedJSWarningBit : public BitField<bool, kIssuedJSWarningBit, 1> {}; | |
3846 class RangeFeedbackBits : public BitField<uint32_t, | |
3847 ICData::kRangeFeedbackPos, ICData::kRangeFeedbackSize> {}; // NOLINT | |
3848 | |
3849 #if defined(DEBUG) | |
3850 // Used in asserts to verify that a check is not added twice. | |
3851 bool HasCheck(const GrowableArray<intptr_t>& cids) const; | |
3852 #endif // DEBUG | |
3853 | |
3854 intptr_t TestEntryLength() const; | |
3855 void WriteSentinel(const Array& data) const; | |
3856 | |
3857 FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object); | |
3858 friend class Class; | |
3859 }; | |
3860 | |
3861 | |
3862 class Code : public Object { | 3865 class Code : public Object { |
3863 public: | 3866 public: |
3864 RawInstructions* instructions() const { return raw_ptr()->instructions_; } | 3867 RawInstructions* instructions() const { return raw_ptr()->instructions_; } |
3865 static intptr_t instructions_offset() { | 3868 static intptr_t instructions_offset() { |
3866 return OFFSET_OF(RawCode, instructions_); | 3869 return OFFSET_OF(RawCode, instructions_); |
3867 } | 3870 } |
3868 intptr_t pointer_offsets_length() const { | 3871 intptr_t pointer_offsets_length() const { |
3869 return PtrOffBits::decode(raw_ptr()->state_bits_); | 3872 return PtrOffBits::decode(raw_ptr()->state_bits_); |
3870 } | 3873 } |
3871 | 3874 |
(...skipping 3917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7789 | 7792 |
7790 | 7793 |
7791 RawObject* MegamorphicCache::GetTargetFunction(const Array& array, | 7794 RawObject* MegamorphicCache::GetTargetFunction(const Array& array, |
7792 intptr_t index) { | 7795 intptr_t index) { |
7793 return array.At((index * kEntryLength) + kTargetFunctionIndex); | 7796 return array.At((index * kEntryLength) + kTargetFunctionIndex); |
7794 } | 7797 } |
7795 | 7798 |
7796 } // namespace dart | 7799 } // namespace dart |
7797 | 7800 |
7798 #endif // VM_OBJECT_H_ | 7801 #endif // VM_OBJECT_H_ |
OLD | NEW |