Chromium Code Reviews| 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 |