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 #include "vm/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 10583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10594 | 10594 |
10595 | 10595 |
10596 void DeoptInfo::SetAt(intptr_t index, | 10596 void DeoptInfo::SetAt(intptr_t index, |
10597 intptr_t instr_kind, | 10597 intptr_t instr_kind, |
10598 intptr_t from_index) const { | 10598 intptr_t from_index) const { |
10599 *(EntryAddr(index, kInstruction)) = instr_kind; | 10599 *(EntryAddr(index, kInstruction)) = instr_kind; |
10600 *(EntryAddr(index, kFromIndex)) = from_index; | 10600 *(EntryAddr(index, kFromIndex)) = from_index; |
10601 } | 10601 } |
10602 | 10602 |
10603 | 10603 |
| 10604 const char* ICData::ToCString() const { |
| 10605 const char* kFormat = "ICData target:'%s' num-args: %" Pd |
| 10606 " num-checks: %" Pd ""; |
| 10607 const String& name = String::Handle(target_name()); |
| 10608 const intptr_t num_args = NumArgsTested(); |
| 10609 const intptr_t num_checks = NumberOfChecks(); |
| 10610 intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString(), |
| 10611 num_args, num_checks) + 1; |
| 10612 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 10613 OS::SNPrint(chars, len, kFormat, name.ToCString(), num_args, num_checks); |
| 10614 return chars; |
| 10615 } |
| 10616 |
| 10617 |
| 10618 void ICData::set_owner(const Function& value) const { |
| 10619 ASSERT(!value.IsNull()); |
| 10620 StorePointer(&raw_ptr()->owner_, value.raw()); |
| 10621 } |
| 10622 |
| 10623 |
| 10624 void ICData::set_target_name(const String& value) const { |
| 10625 ASSERT(!value.IsNull()); |
| 10626 StorePointer(&raw_ptr()->target_name_, value.raw()); |
| 10627 } |
| 10628 |
| 10629 |
| 10630 void ICData::set_arguments_descriptor(const Array& value) const { |
| 10631 ASSERT(!value.IsNull()); |
| 10632 StorePointer(&raw_ptr()->args_descriptor_, value.raw()); |
| 10633 } |
| 10634 |
| 10635 void ICData::set_deopt_id(intptr_t value) const { |
| 10636 ASSERT(value <= kMaxInt32); |
| 10637 raw_ptr()->deopt_id_ = value; |
| 10638 } |
| 10639 |
| 10640 |
| 10641 void ICData::set_ic_data(const Array& value) const { |
| 10642 ASSERT(!value.IsNull()); |
| 10643 StorePointer(&raw_ptr()->ic_data_, value.raw()); |
| 10644 } |
| 10645 |
| 10646 |
| 10647 intptr_t ICData::NumArgsTested() const { |
| 10648 return NumArgsTestedBits::decode(raw_ptr()->state_bits_); |
| 10649 } |
| 10650 |
| 10651 |
| 10652 void ICData::SetNumArgsTested(intptr_t value) const { |
| 10653 ASSERT(Utils::IsUint(2, value)); |
| 10654 raw_ptr()->state_bits_ = |
| 10655 NumArgsTestedBits::update(value, raw_ptr()->state_bits_); |
| 10656 } |
| 10657 |
| 10658 |
| 10659 uint32_t ICData::DeoptReasons() const { |
| 10660 return DeoptReasonBits::decode(raw_ptr()->state_bits_); |
| 10661 } |
| 10662 |
| 10663 |
| 10664 void ICData::SetDeoptReasons(uint32_t reasons) const { |
| 10665 raw_ptr()->state_bits_ = |
| 10666 DeoptReasonBits::update(reasons, raw_ptr()->state_bits_); |
| 10667 } |
| 10668 |
| 10669 |
| 10670 bool ICData::HasDeoptReason(DeoptReasonId reason) const { |
| 10671 return (DeoptReasons() & (1 << reason)) != 0; |
| 10672 } |
| 10673 |
| 10674 |
| 10675 void ICData::AddDeoptReason(DeoptReasonId reason) const { |
| 10676 SetDeoptReasons(DeoptReasons() | (1 << reason)); |
| 10677 } |
| 10678 |
| 10679 |
| 10680 bool ICData::IssuedJSWarning() const { |
| 10681 return IssuedJSWarningBit::decode(raw_ptr()->state_bits_); |
| 10682 } |
| 10683 |
| 10684 |
| 10685 void ICData::SetIssuedJSWarning() const { |
| 10686 raw_ptr()->state_bits_ = |
| 10687 IssuedJSWarningBit::update(true, raw_ptr()->state_bits_); |
| 10688 } |
| 10689 |
| 10690 |
| 10691 bool ICData::IsClosureCall() const { |
| 10692 return IsClosureCallBit::decode(raw_ptr()->state_bits_); |
| 10693 } |
| 10694 |
| 10695 |
| 10696 void ICData::SetIsClosureCall() const { |
| 10697 raw_ptr()->state_bits_ = |
| 10698 IsClosureCallBit::update(true, raw_ptr()->state_bits_); |
| 10699 } |
| 10700 |
| 10701 |
| 10702 void ICData::set_state_bits(uint32_t bits) const { |
| 10703 raw_ptr()->state_bits_ = bits; |
| 10704 } |
| 10705 |
| 10706 |
| 10707 intptr_t ICData::TestEntryLengthFor(intptr_t num_args) { |
| 10708 return num_args + 1 /* target function*/ + 1 /* frequency */; |
| 10709 } |
| 10710 |
| 10711 |
| 10712 intptr_t ICData::TestEntryLength() const { |
| 10713 return TestEntryLengthFor(NumArgsTested()); |
| 10714 } |
| 10715 |
| 10716 |
| 10717 intptr_t ICData::NumberOfChecks() const { |
| 10718 // Do not count the sentinel; |
| 10719 return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength()) - 1; |
| 10720 } |
| 10721 |
| 10722 |
| 10723 void ICData::WriteSentinel(const Array& data) const { |
| 10724 ASSERT(!data.IsNull()); |
| 10725 for (intptr_t i = 1; i <= TestEntryLength(); i++) { |
| 10726 data.SetAt(data.Length() - i, smi_illegal_cid()); |
| 10727 } |
| 10728 } |
| 10729 |
| 10730 |
| 10731 #if defined(DEBUG) |
| 10732 // Used in asserts to verify that a check is not added twice. |
| 10733 bool ICData::HasCheck(const GrowableArray<intptr_t>& cids) const { |
| 10734 const intptr_t len = NumberOfChecks(); |
| 10735 for (intptr_t i = 0; i < len; i++) { |
| 10736 GrowableArray<intptr_t> class_ids; |
| 10737 Function& target = Function::Handle(); |
| 10738 GetCheckAt(i, &class_ids, &target); |
| 10739 bool matches = true; |
| 10740 for (intptr_t k = 0; k < class_ids.length(); k++) { |
| 10741 if (class_ids[k] != cids[k]) { |
| 10742 matches = false; |
| 10743 break; |
| 10744 } |
| 10745 } |
| 10746 if (matches) { |
| 10747 return true; |
| 10748 } |
| 10749 } |
| 10750 return false; |
| 10751 } |
| 10752 #endif // DEBUG |
| 10753 |
| 10754 |
| 10755 // Used for unoptimized static calls when no class-ids are checked. |
| 10756 void ICData::AddTarget(const Function& target) const { |
| 10757 ASSERT(!target.IsNull()); |
| 10758 if (NumArgsTested() > 0) { |
| 10759 // Create a fake cid entry, so that we can store the target. |
| 10760 GrowableArray<intptr_t> class_ids(NumArgsTested()); |
| 10761 for (intptr_t i = 0; i < NumArgsTested(); i++) { |
| 10762 class_ids.Add(kObjectCid); |
| 10763 } |
| 10764 AddCheck(class_ids, target); |
| 10765 return; |
| 10766 } |
| 10767 ASSERT(NumArgsTested() >= 0); |
| 10768 // Can add only once. |
| 10769 const intptr_t old_num = NumberOfChecks(); |
| 10770 ASSERT(old_num == 0); |
| 10771 Array& data = Array::Handle(ic_data()); |
| 10772 const intptr_t new_len = data.Length() + TestEntryLength(); |
| 10773 data = Array::Grow(data, new_len, Heap::kOld); |
| 10774 set_ic_data(data); |
| 10775 WriteSentinel(data); |
| 10776 intptr_t data_pos = old_num * TestEntryLength(); |
| 10777 ASSERT(!target.IsNull()); |
| 10778 data.SetAt(data_pos++, target); |
| 10779 const Smi& value = Smi::Handle(Smi::New(0)); |
| 10780 data.SetAt(data_pos, value); |
| 10781 } |
| 10782 |
| 10783 |
| 10784 void ICData::AddCheck(const GrowableArray<intptr_t>& class_ids, |
| 10785 const Function& target) const { |
| 10786 ASSERT(!target.IsNull()); |
| 10787 DEBUG_ASSERT(!HasCheck(class_ids)); |
| 10788 ASSERT(NumArgsTested() > 1); // Otherwise use 'AddReceiverCheck'. |
| 10789 ASSERT(class_ids.length() == NumArgsTested()); |
| 10790 const intptr_t old_num = NumberOfChecks(); |
| 10791 Array& data = Array::Handle(ic_data()); |
| 10792 // ICData of static calls with NumArgsTested() > 0 have initially a |
| 10793 // dummy set of cids entered (see ICData::AddTarget). That entry is |
| 10794 // overwritten by first real type feedback data. |
| 10795 if (old_num == 1) { |
| 10796 bool has_dummy_entry = true; |
| 10797 for (intptr_t i = 0; i < NumArgsTested(); i++) { |
| 10798 if (Smi::Value(Smi::RawCast(data.At(i))) != kObjectCid) { |
| 10799 has_dummy_entry = false; |
| 10800 break; |
| 10801 } |
| 10802 } |
| 10803 if (has_dummy_entry) { |
| 10804 ASSERT(target.raw() == data.At(NumArgsTested())); |
| 10805 // Replace dummy entry. |
| 10806 Smi& value = Smi::Handle(); |
| 10807 for (intptr_t i = 0; i < NumArgsTested(); i++) { |
| 10808 ASSERT(class_ids[i] != kIllegalCid); |
| 10809 value = Smi::New(class_ids[i]); |
| 10810 data.SetAt(i, value); |
| 10811 } |
| 10812 return; |
| 10813 } |
| 10814 } |
| 10815 const intptr_t new_len = data.Length() + TestEntryLength(); |
| 10816 data = Array::Grow(data, new_len, Heap::kOld); |
| 10817 set_ic_data(data); |
| 10818 WriteSentinel(data); |
| 10819 intptr_t data_pos = old_num * TestEntryLength(); |
| 10820 Smi& value = Smi::Handle(); |
| 10821 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 10822 // kIllegalCid is used as terminating value, do not add it. |
| 10823 ASSERT(class_ids[i] != kIllegalCid); |
| 10824 value = Smi::New(class_ids[i]); |
| 10825 data.SetAt(data_pos++, value); |
| 10826 } |
| 10827 ASSERT(!target.IsNull()); |
| 10828 data.SetAt(data_pos++, target); |
| 10829 value = Smi::New(1); |
| 10830 data.SetAt(data_pos, value); |
| 10831 } |
| 10832 |
| 10833 |
| 10834 void ICData::AddReceiverCheck(intptr_t receiver_class_id, |
| 10835 const Function& target, |
| 10836 intptr_t count) const { |
| 10837 #if defined(DEBUG) |
| 10838 GrowableArray<intptr_t> class_ids(1); |
| 10839 class_ids.Add(receiver_class_id); |
| 10840 ASSERT(!HasCheck(class_ids)); |
| 10841 #endif // DEBUG |
| 10842 ASSERT(!target.IsNull()); |
| 10843 ASSERT(NumArgsTested() == 1); // Otherwise use 'AddCheck'. |
| 10844 ASSERT(receiver_class_id != kIllegalCid); |
| 10845 |
| 10846 const intptr_t old_num = NumberOfChecks(); |
| 10847 Array& data = Array::Handle(ic_data()); |
| 10848 const intptr_t new_len = data.Length() + TestEntryLength(); |
| 10849 data = Array::Grow(data, new_len, Heap::kOld); |
| 10850 set_ic_data(data); |
| 10851 WriteSentinel(data); |
| 10852 intptr_t data_pos = old_num * TestEntryLength(); |
| 10853 if ((receiver_class_id == kSmiCid) && (data_pos > 0)) { |
| 10854 ASSERT(GetReceiverClassIdAt(0) != kSmiCid); |
| 10855 // Move class occupying position 0 to the data_pos. |
| 10856 for (intptr_t i = 0; i < TestEntryLength(); i++) { |
| 10857 data.SetAt(data_pos + i, Object::Handle(data.At(i))); |
| 10858 } |
| 10859 // Insert kSmiCid in position 0. |
| 10860 data_pos = 0; |
| 10861 } |
| 10862 data.SetAt(data_pos, Smi::Handle(Smi::New(receiver_class_id))); |
| 10863 data.SetAt(data_pos + 1, target); |
| 10864 data.SetAt(data_pos + 2, Smi::Handle(Smi::New(count))); |
| 10865 } |
| 10866 |
| 10867 |
| 10868 void ICData::GetCheckAt(intptr_t index, |
| 10869 GrowableArray<intptr_t>* class_ids, |
| 10870 Function* target) const { |
| 10871 ASSERT(index < NumberOfChecks()); |
| 10872 ASSERT(class_ids != NULL); |
| 10873 ASSERT(target != NULL); |
| 10874 class_ids->Clear(); |
| 10875 const Array& data = Array::Handle(ic_data()); |
| 10876 intptr_t data_pos = index * TestEntryLength(); |
| 10877 for (intptr_t i = 0; i < NumArgsTested(); i++) { |
| 10878 class_ids->Add(Smi::Value(Smi::RawCast(data.At(data_pos++)))); |
| 10879 } |
| 10880 (*target) ^= data.At(data_pos++); |
| 10881 } |
| 10882 |
| 10883 |
| 10884 void ICData::GetOneClassCheckAt(intptr_t index, |
| 10885 intptr_t* class_id, |
| 10886 Function* target) const { |
| 10887 ASSERT(class_id != NULL); |
| 10888 ASSERT(target != NULL); |
| 10889 ASSERT(NumArgsTested() == 1); |
| 10890 const Array& data = Array::Handle(ic_data()); |
| 10891 const intptr_t data_pos = index * TestEntryLength(); |
| 10892 *class_id = Smi::Value(Smi::RawCast(data.At(data_pos))); |
| 10893 *target ^= data.At(data_pos + 1); |
| 10894 } |
| 10895 |
| 10896 |
| 10897 intptr_t ICData::GetCidAt(intptr_t index) const { |
| 10898 ASSERT(NumArgsTested() == 1); |
| 10899 const Array& data = Array::Handle(ic_data()); |
| 10900 const intptr_t data_pos = index * TestEntryLength(); |
| 10901 return Smi::Value(Smi::RawCast(data.At(data_pos))); |
| 10902 } |
| 10903 |
| 10904 |
| 10905 intptr_t ICData::GetClassIdAt(intptr_t index, intptr_t arg_nr) const { |
| 10906 GrowableArray<intptr_t> class_ids; |
| 10907 Function& target = Function::Handle(); |
| 10908 GetCheckAt(index, &class_ids, &target); |
| 10909 return class_ids[arg_nr]; |
| 10910 } |
| 10911 |
| 10912 |
| 10913 intptr_t ICData::GetReceiverClassIdAt(intptr_t index) const { |
| 10914 ASSERT(index < NumberOfChecks()); |
| 10915 const Array& data = Array::Handle(ic_data()); |
| 10916 const intptr_t data_pos = index * TestEntryLength(); |
| 10917 return Smi::Value(Smi::RawCast(data.At(data_pos))); |
| 10918 } |
| 10919 |
| 10920 |
| 10921 RawFunction* ICData::GetTargetAt(intptr_t index) const { |
| 10922 const intptr_t data_pos = index * TestEntryLength() + NumArgsTested(); |
| 10923 ASSERT(Object::Handle(Array::Handle(ic_data()).At(data_pos)).IsFunction()); |
| 10924 |
| 10925 NoGCScope no_gc; |
| 10926 RawArray* raw_data = ic_data(); |
| 10927 return reinterpret_cast<RawFunction*>(raw_data->ptr()->data()[data_pos]); |
| 10928 } |
| 10929 |
| 10930 |
| 10931 void ICData::IncrementCountAt(intptr_t index, intptr_t value) const { |
| 10932 ASSERT(0 <= value); |
| 10933 ASSERT(value <= Smi::kMaxValue); |
| 10934 SetCountAt(index, Utils::Minimum(GetCountAt(index) + value, Smi::kMaxValue)); |
| 10935 } |
| 10936 |
| 10937 |
| 10938 void ICData::SetCountAt(intptr_t index, intptr_t value) const { |
| 10939 ASSERT(0 <= value); |
| 10940 ASSERT(value <= Smi::kMaxValue); |
| 10941 |
| 10942 const Array& data = Array::Handle(ic_data()); |
| 10943 const intptr_t data_pos = index * TestEntryLength() + |
| 10944 CountIndexFor(NumArgsTested()); |
| 10945 data.SetAt(data_pos, Smi::Handle(Smi::New(value))); |
| 10946 } |
| 10947 |
| 10948 |
| 10949 intptr_t ICData::GetCountAt(intptr_t index) const { |
| 10950 const Array& data = Array::Handle(ic_data()); |
| 10951 const intptr_t data_pos = index * TestEntryLength() + |
| 10952 CountIndexFor(NumArgsTested()); |
| 10953 return Smi::Value(Smi::RawCast(data.At(data_pos))); |
| 10954 } |
| 10955 |
| 10956 |
| 10957 intptr_t ICData::AggregateCount() const { |
| 10958 if (IsNull()) return 0; |
| 10959 const intptr_t len = NumberOfChecks(); |
| 10960 intptr_t count = 0; |
| 10961 for (intptr_t i = 0; i < len; i++) { |
| 10962 count += GetCountAt(i); |
| 10963 } |
| 10964 return count; |
| 10965 } |
| 10966 |
| 10967 |
| 10968 RawFunction* ICData::GetTargetForReceiverClassId(intptr_t class_id) const { |
| 10969 const intptr_t len = NumberOfChecks(); |
| 10970 for (intptr_t i = 0; i < len; i++) { |
| 10971 if (GetReceiverClassIdAt(i) == class_id) { |
| 10972 return GetTargetAt(i); |
| 10973 } |
| 10974 } |
| 10975 return Function::null(); |
| 10976 } |
| 10977 |
| 10978 |
| 10979 RawICData* ICData::AsUnaryClassChecksForArgNr(intptr_t arg_nr) const { |
| 10980 ASSERT(!IsNull()); |
| 10981 ASSERT(NumArgsTested() > arg_nr); |
| 10982 if ((arg_nr == 0) && (NumArgsTested() == 1)) { |
| 10983 // Frequent case. |
| 10984 return raw(); |
| 10985 } |
| 10986 const intptr_t kNumArgsTested = 1; |
| 10987 ICData& result = ICData::Handle(ICData::New( |
| 10988 Function::Handle(owner()), |
| 10989 String::Handle(target_name()), |
| 10990 Array::Handle(arguments_descriptor()), |
| 10991 deopt_id(), |
| 10992 kNumArgsTested)); |
| 10993 const intptr_t len = NumberOfChecks(); |
| 10994 for (intptr_t i = 0; i < len; i++) { |
| 10995 const intptr_t class_id = GetClassIdAt(i, arg_nr); |
| 10996 const intptr_t count = GetCountAt(i); |
| 10997 intptr_t duplicate_class_id = -1; |
| 10998 const intptr_t result_len = result.NumberOfChecks(); |
| 10999 for (intptr_t k = 0; k < result_len; k++) { |
| 11000 if (class_id == result.GetReceiverClassIdAt(k)) { |
| 11001 duplicate_class_id = k; |
| 11002 break; |
| 11003 } |
| 11004 } |
| 11005 if (duplicate_class_id >= 0) { |
| 11006 // This check is valid only when checking the receiver. |
| 11007 ASSERT((arg_nr != 0) || |
| 11008 (result.GetTargetAt(duplicate_class_id) == GetTargetAt(i))); |
| 11009 result.IncrementCountAt(duplicate_class_id, count); |
| 11010 } else { |
| 11011 // This will make sure that Smi is first if it exists. |
| 11012 result.AddReceiverCheck(class_id, |
| 11013 Function::Handle(GetTargetAt(i)), |
| 11014 count); |
| 11015 } |
| 11016 } |
| 11017 // Copy deoptimization reasons. |
| 11018 result.SetDeoptReasons(DeoptReasons()); |
| 11019 |
| 11020 return result.raw(); |
| 11021 } |
| 11022 |
| 11023 |
| 11024 bool ICData::AllTargetsHaveSameOwner(intptr_t owner_cid) const { |
| 11025 if (NumberOfChecks() == 0) return false; |
| 11026 Class& cls = Class::Handle(); |
| 11027 const intptr_t len = NumberOfChecks(); |
| 11028 for (intptr_t i = 0; i < len; i++) { |
| 11029 cls = Function::Handle(GetTargetAt(i)).Owner(); |
| 11030 if (cls.id() != owner_cid) { |
| 11031 return false; |
| 11032 } |
| 11033 } |
| 11034 return true; |
| 11035 } |
| 11036 |
| 11037 |
| 11038 bool ICData::AllReceiversAreNumbers() const { |
| 11039 if (NumberOfChecks() == 0) return false; |
| 11040 Class& cls = Class::Handle(); |
| 11041 const intptr_t len = NumberOfChecks(); |
| 11042 for (intptr_t i = 0; i < len; i++) { |
| 11043 cls = Function::Handle(GetTargetAt(i)).Owner(); |
| 11044 const intptr_t cid = cls.id(); |
| 11045 if ((cid != kSmiCid) && |
| 11046 (cid != kMintCid) && |
| 11047 (cid != kBigintCid) && |
| 11048 (cid != kDoubleCid)) { |
| 11049 return false; |
| 11050 } |
| 11051 } |
| 11052 return true; |
| 11053 } |
| 11054 |
| 11055 |
| 11056 bool ICData::HasReceiverClassId(intptr_t class_id) const { |
| 11057 ASSERT(NumArgsTested() > 0); |
| 11058 const intptr_t len = NumberOfChecks(); |
| 11059 for (intptr_t i = 0; i < len; i++) { |
| 11060 const intptr_t test_class_id = GetReceiverClassIdAt(i); |
| 11061 if (test_class_id == class_id) { |
| 11062 return true; |
| 11063 } |
| 11064 } |
| 11065 return false; |
| 11066 } |
| 11067 |
| 11068 |
| 11069 // Returns true if all targets are the same. |
| 11070 // TODO(srdjan): if targets are native use their C_function to compare. |
| 11071 bool ICData::HasOneTarget() const { |
| 11072 ASSERT(NumberOfChecks() > 0); |
| 11073 const Function& first_target = Function::Handle(GetTargetAt(0)); |
| 11074 const intptr_t len = NumberOfChecks(); |
| 11075 for (intptr_t i = 1; i < len; i++) { |
| 11076 if (GetTargetAt(i) != first_target.raw()) { |
| 11077 return false; |
| 11078 } |
| 11079 } |
| 11080 return true; |
| 11081 } |
| 11082 |
| 11083 |
| 11084 RawICData* ICData::New(const Function& owner, |
| 11085 const String& target_name, |
| 11086 const Array& arguments_descriptor, |
| 11087 intptr_t deopt_id, |
| 11088 intptr_t num_args_tested) { |
| 11089 ASSERT(!owner.IsNull()); |
| 11090 ASSERT(!target_name.IsNull()); |
| 11091 ASSERT(!arguments_descriptor.IsNull()); |
| 11092 ASSERT(Object::icdata_class() != Class::null()); |
| 11093 ASSERT(num_args_tested >= 0); |
| 11094 ICData& result = ICData::Handle(); |
| 11095 { |
| 11096 // IC data objects are long living objects, allocate them in old generation. |
| 11097 RawObject* raw = Object::Allocate(ICData::kClassId, |
| 11098 ICData::InstanceSize(), |
| 11099 Heap::kOld); |
| 11100 NoGCScope no_gc; |
| 11101 result ^= raw; |
| 11102 } |
| 11103 result.set_owner(owner); |
| 11104 result.set_target_name(target_name); |
| 11105 result.set_arguments_descriptor(arguments_descriptor); |
| 11106 result.set_deopt_id(deopt_id); |
| 11107 result.set_state_bits(0); |
| 11108 result.SetNumArgsTested(num_args_tested); |
| 11109 // Number of array elements in one test entry. |
| 11110 intptr_t len = result.TestEntryLength(); |
| 11111 // IC data array must be null terminated (sentinel entry). |
| 11112 const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld)); |
| 11113 result.set_ic_data(ic_data); |
| 11114 result.WriteSentinel(ic_data); |
| 11115 return result.raw(); |
| 11116 } |
| 11117 |
| 11118 |
| 11119 void ICData::PrintToJSONStream(JSONStream* stream, bool ref) const { |
| 11120 Object::PrintToJSONStream(stream, ref); |
| 11121 } |
| 11122 |
| 11123 |
10604 Code::Comments& Code::Comments::New(intptr_t count) { | 11124 Code::Comments& Code::Comments::New(intptr_t count) { |
10605 Comments* comments; | 11125 Comments* comments; |
10606 if (count < 0 || count > (kIntptrMax / kNumberOfEntries)) { | 11126 if (count < 0 || count > (kIntptrMax / kNumberOfEntries)) { |
10607 // This should be caught before we reach here. | 11127 // This should be caught before we reach here. |
10608 FATAL1("Fatal error in Code::Comments::New: invalid count %" Pd "\n", | 11128 FATAL1("Fatal error in Code::Comments::New: invalid count %" Pd "\n", |
10609 count); | 11129 count); |
10610 } | 11130 } |
10611 if (count == 0) { | 11131 if (count == 0) { |
10612 comments = new Comments(Object::empty_array()); | 11132 comments = new Comments(Object::empty_array()); |
10613 } else { | 11133 } else { |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10701 } | 11221 } |
10702 #endif // DEBUG | 11222 #endif // DEBUG |
10703 } | 11223 } |
10704 | 11224 |
10705 | 11225 |
10706 bool Code::HasBreakpoint() const { | 11226 bool Code::HasBreakpoint() const { |
10707 return Isolate::Current()->debugger()->HasBreakpoint(*this); | 11227 return Isolate::Current()->debugger()->HasBreakpoint(*this); |
10708 } | 11228 } |
10709 | 11229 |
10710 | 11230 |
10711 RawDeoptInfo* Code::GetDeoptInfoAtPc(uword pc, intptr_t* deopt_reason) const { | 11231 RawDeoptInfo* Code::GetDeoptInfoAtPc( |
| 11232 uword pc, ICData::DeoptReasonId* deopt_reason) const { |
10712 ASSERT(is_optimized()); | 11233 ASSERT(is_optimized()); |
10713 const Instructions& instrs = Instructions::Handle(instructions()); | 11234 const Instructions& instrs = Instructions::Handle(instructions()); |
10714 uword code_entry = instrs.EntryPoint(); | 11235 uword code_entry = instrs.EntryPoint(); |
10715 const Array& table = Array::Handle(deopt_info_array()); | 11236 const Array& table = Array::Handle(deopt_info_array()); |
10716 ASSERT(!table.IsNull()); | 11237 ASSERT(!table.IsNull()); |
10717 // Linear search for the PC offset matching the target PC. | 11238 // Linear search for the PC offset matching the target PC. |
10718 intptr_t length = DeoptTable::GetLength(table); | 11239 intptr_t length = DeoptTable::GetLength(table); |
10719 Smi& offset = Smi::Handle(); | 11240 Smi& offset = Smi::Handle(); |
10720 Smi& reason = Smi::Handle(); | 11241 Smi& reason = Smi::Handle(); |
10721 DeoptInfo& info = DeoptInfo::Handle(); | 11242 DeoptInfo& info = DeoptInfo::Handle(); |
10722 for (intptr_t i = 0; i < length; ++i) { | 11243 for (intptr_t i = 0; i < length; ++i) { |
10723 DeoptTable::GetEntry(table, i, &offset, &info, &reason); | 11244 DeoptTable::GetEntry(table, i, &offset, &info, &reason); |
10724 if (pc == (code_entry + offset.Value())) { | 11245 if (pc == (code_entry + offset.Value())) { |
10725 ASSERT(!info.IsNull()); | 11246 ASSERT(!info.IsNull()); |
10726 *deopt_reason = reason.Value(); | 11247 ASSERT((0 <= reason.Value()) && |
| 11248 (reason.Value() < ICData::kDeoptNumReasons)); |
| 11249 *deopt_reason = static_cast<ICData::DeoptReasonId>(reason.Value()); |
10727 return info.raw(); | 11250 return info.raw(); |
10728 } | 11251 } |
10729 } | 11252 } |
10730 *deopt_reason = kDeoptUnknown; | 11253 *deopt_reason = ICData::kDeoptUnknown; |
10731 return DeoptInfo::null(); | 11254 return DeoptInfo::null(); |
10732 } | 11255 } |
10733 | 11256 |
10734 | 11257 |
10735 intptr_t Code::BinarySearchInSCallTable(uword pc) const { | 11258 intptr_t Code::BinarySearchInSCallTable(uword pc) const { |
10736 NoGCScope no_gc; | 11259 NoGCScope no_gc; |
10737 const Array& table = Array::Handle(raw_ptr()->static_calls_target_table_); | 11260 const Array& table = Array::Handle(raw_ptr()->static_calls_target_table_); |
10738 RawObject* key = reinterpret_cast<RawObject*>(Smi::New(pc - EntryPoint())); | 11261 RawObject* key = reinterpret_cast<RawObject*>(Smi::New(pc - EntryPoint())); |
10739 intptr_t imin = 0; | 11262 intptr_t imin = 0; |
10740 intptr_t imax = table.Length() / kSCallTableEntryLength; | 11263 intptr_t imax = table.Length() / kSCallTableEntryLength; |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11406 const char* ContextScope::ToCString() const { | 11929 const char* ContextScope::ToCString() const { |
11407 return "ContextScope"; | 11930 return "ContextScope"; |
11408 } | 11931 } |
11409 | 11932 |
11410 | 11933 |
11411 void ContextScope::PrintToJSONStream(JSONStream* stream, bool ref) const { | 11934 void ContextScope::PrintToJSONStream(JSONStream* stream, bool ref) const { |
11412 Object::PrintToJSONStream(stream, ref); | 11935 Object::PrintToJSONStream(stream, ref); |
11413 } | 11936 } |
11414 | 11937 |
11415 | 11938 |
11416 const char* ICData::ToCString() const { | |
11417 const char* kFormat = "ICData target:'%s' num-args: %" Pd | |
11418 " num-checks: %" Pd ""; | |
11419 const String& name = String::Handle(target_name()); | |
11420 const intptr_t num_args = num_args_tested(); | |
11421 const intptr_t num_checks = NumberOfChecks(); | |
11422 intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString(), | |
11423 num_args, num_checks) + 1; | |
11424 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | |
11425 OS::SNPrint(chars, len, kFormat, name.ToCString(), num_args, num_checks); | |
11426 return chars; | |
11427 } | |
11428 | |
11429 | |
11430 void ICData::set_function(const Function& value) const { | |
11431 ASSERT(!value.IsNull()); | |
11432 StorePointer(&raw_ptr()->function_, value.raw()); | |
11433 } | |
11434 | |
11435 | |
11436 void ICData::set_target_name(const String& value) const { | |
11437 ASSERT(!value.IsNull()); | |
11438 StorePointer(&raw_ptr()->target_name_, value.raw()); | |
11439 } | |
11440 | |
11441 | |
11442 void ICData::set_arguments_descriptor(const Array& value) const { | |
11443 ASSERT(!value.IsNull()); | |
11444 StorePointer(&raw_ptr()->args_descriptor_, value.raw()); | |
11445 } | |
11446 | |
11447 void ICData::set_deopt_id(intptr_t value) const { | |
11448 raw_ptr()->deopt_id_ = value; | |
11449 } | |
11450 | |
11451 | |
11452 void ICData::set_num_args_tested(intptr_t value) const { | |
11453 raw_ptr()->num_args_tested_ = value; | |
11454 } | |
11455 | |
11456 | |
11457 void ICData::set_ic_data(const Array& value) const { | |
11458 ASSERT(!value.IsNull()); | |
11459 StorePointer(&raw_ptr()->ic_data_, value.raw()); | |
11460 } | |
11461 | |
11462 | |
11463 void ICData::set_deopt_reason(intptr_t deopt_reason) const { | |
11464 raw_ptr()->deopt_reason_ = deopt_reason; | |
11465 } | |
11466 | |
11467 void ICData::set_is_closure_call(bool value) const { | |
11468 raw_ptr()->is_closure_call_ = value ? 1 : 0; | |
11469 } | |
11470 | |
11471 | |
11472 intptr_t ICData::TestEntryLengthFor(intptr_t num_args) { | |
11473 return num_args + 1 /* target function*/ + 1 /* frequency */; | |
11474 } | |
11475 | |
11476 | |
11477 intptr_t ICData::TestEntryLength() const { | |
11478 return TestEntryLengthFor(num_args_tested()); | |
11479 } | |
11480 | |
11481 | |
11482 intptr_t ICData::NumberOfChecks() const { | |
11483 // Do not count the sentinel; | |
11484 return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength()) - 1; | |
11485 } | |
11486 | |
11487 | |
11488 void ICData::WriteSentinel(const Array& data) const { | |
11489 ASSERT(!data.IsNull()); | |
11490 for (intptr_t i = 1; i <= TestEntryLength(); i++) { | |
11491 data.SetAt(data.Length() - i, smi_illegal_cid()); | |
11492 } | |
11493 } | |
11494 | |
11495 | |
11496 #if defined(DEBUG) | |
11497 // Used in asserts to verify that a check is not added twice. | |
11498 bool ICData::HasCheck(const GrowableArray<intptr_t>& cids) const { | |
11499 const intptr_t len = NumberOfChecks(); | |
11500 for (intptr_t i = 0; i < len; i++) { | |
11501 GrowableArray<intptr_t> class_ids; | |
11502 Function& target = Function::Handle(); | |
11503 GetCheckAt(i, &class_ids, &target); | |
11504 bool matches = true; | |
11505 for (intptr_t k = 0; k < class_ids.length(); k++) { | |
11506 if (class_ids[k] != cids[k]) { | |
11507 matches = false; | |
11508 break; | |
11509 } | |
11510 } | |
11511 if (matches) { | |
11512 return true; | |
11513 } | |
11514 } | |
11515 return false; | |
11516 } | |
11517 #endif // DEBUG | |
11518 | |
11519 | |
11520 // Used for unoptimized static calls when no class-ids are checked. | |
11521 void ICData::AddTarget(const Function& target) const { | |
11522 ASSERT(!target.IsNull()); | |
11523 if (num_args_tested() > 0) { | |
11524 // Create a fake cid entry, so that we can store the target. | |
11525 GrowableArray<intptr_t> class_ids(num_args_tested()); | |
11526 for (intptr_t i = 0; i < num_args_tested(); i++) { | |
11527 class_ids.Add(kObjectCid); | |
11528 } | |
11529 AddCheck(class_ids, target); | |
11530 return; | |
11531 } | |
11532 ASSERT(num_args_tested() >= 0); | |
11533 // Can add only once. | |
11534 const intptr_t old_num = NumberOfChecks(); | |
11535 ASSERT(old_num == 0); | |
11536 Array& data = Array::Handle(ic_data()); | |
11537 const intptr_t new_len = data.Length() + TestEntryLength(); | |
11538 data = Array::Grow(data, new_len, Heap::kOld); | |
11539 set_ic_data(data); | |
11540 WriteSentinel(data); | |
11541 intptr_t data_pos = old_num * TestEntryLength(); | |
11542 ASSERT(!target.IsNull()); | |
11543 data.SetAt(data_pos++, target); | |
11544 const Smi& value = Smi::Handle(Smi::New(0)); | |
11545 data.SetAt(data_pos, value); | |
11546 } | |
11547 | |
11548 | |
11549 void ICData::AddCheck(const GrowableArray<intptr_t>& class_ids, | |
11550 const Function& target) const { | |
11551 ASSERT(!target.IsNull()); | |
11552 DEBUG_ASSERT(!HasCheck(class_ids)); | |
11553 ASSERT(num_args_tested() > 1); // Otherwise use 'AddReceiverCheck'. | |
11554 ASSERT(class_ids.length() == num_args_tested()); | |
11555 const intptr_t old_num = NumberOfChecks(); | |
11556 Array& data = Array::Handle(ic_data()); | |
11557 // ICData of static calls with num_args_tested() > 0 have initially a | |
11558 // dummy set of cids entered (see ICData::AddTarget). That entry is | |
11559 // overwritten by first real type feedback data. | |
11560 if (old_num == 1) { | |
11561 bool has_dummy_entry = true; | |
11562 for (intptr_t i = 0; i < num_args_tested(); i++) { | |
11563 if (Smi::Value(Smi::RawCast(data.At(i))) != kObjectCid) { | |
11564 has_dummy_entry = false; | |
11565 break; | |
11566 } | |
11567 } | |
11568 if (has_dummy_entry) { | |
11569 ASSERT(target.raw() == data.At(num_args_tested())); | |
11570 // Replace dummy entry. | |
11571 Smi& value = Smi::Handle(); | |
11572 for (intptr_t i = 0; i < num_args_tested(); i++) { | |
11573 ASSERT(class_ids[i] != kIllegalCid); | |
11574 value = Smi::New(class_ids[i]); | |
11575 data.SetAt(i, value); | |
11576 } | |
11577 return; | |
11578 } | |
11579 } | |
11580 const intptr_t new_len = data.Length() + TestEntryLength(); | |
11581 data = Array::Grow(data, new_len, Heap::kOld); | |
11582 set_ic_data(data); | |
11583 WriteSentinel(data); | |
11584 intptr_t data_pos = old_num * TestEntryLength(); | |
11585 Smi& value = Smi::Handle(); | |
11586 for (intptr_t i = 0; i < class_ids.length(); i++) { | |
11587 // kIllegalCid is used as terminating value, do not add it. | |
11588 ASSERT(class_ids[i] != kIllegalCid); | |
11589 value = Smi::New(class_ids[i]); | |
11590 data.SetAt(data_pos++, value); | |
11591 } | |
11592 ASSERT(!target.IsNull()); | |
11593 data.SetAt(data_pos++, target); | |
11594 value = Smi::New(1); | |
11595 data.SetAt(data_pos, value); | |
11596 } | |
11597 | |
11598 | |
11599 void ICData::AddReceiverCheck(intptr_t receiver_class_id, | |
11600 const Function& target, | |
11601 intptr_t count) const { | |
11602 #if defined(DEBUG) | |
11603 GrowableArray<intptr_t> class_ids(1); | |
11604 class_ids.Add(receiver_class_id); | |
11605 ASSERT(!HasCheck(class_ids)); | |
11606 #endif // DEBUG | |
11607 ASSERT(!target.IsNull()); | |
11608 ASSERT(num_args_tested() == 1); // Otherwise use 'AddCheck'. | |
11609 ASSERT(receiver_class_id != kIllegalCid); | |
11610 | |
11611 const intptr_t old_num = NumberOfChecks(); | |
11612 Array& data = Array::Handle(ic_data()); | |
11613 const intptr_t new_len = data.Length() + TestEntryLength(); | |
11614 data = Array::Grow(data, new_len, Heap::kOld); | |
11615 set_ic_data(data); | |
11616 WriteSentinel(data); | |
11617 intptr_t data_pos = old_num * TestEntryLength(); | |
11618 if ((receiver_class_id == kSmiCid) && (data_pos > 0)) { | |
11619 ASSERT(GetReceiverClassIdAt(0) != kSmiCid); | |
11620 // Move class occupying position 0 to the data_pos. | |
11621 for (intptr_t i = 0; i < TestEntryLength(); i++) { | |
11622 data.SetAt(data_pos + i, Object::Handle(data.At(i))); | |
11623 } | |
11624 // Insert kSmiCid in position 0. | |
11625 data_pos = 0; | |
11626 } | |
11627 data.SetAt(data_pos, Smi::Handle(Smi::New(receiver_class_id))); | |
11628 data.SetAt(data_pos + 1, target); | |
11629 data.SetAt(data_pos + 2, Smi::Handle(Smi::New(count))); | |
11630 } | |
11631 | |
11632 | |
11633 void ICData::GetCheckAt(intptr_t index, | |
11634 GrowableArray<intptr_t>* class_ids, | |
11635 Function* target) const { | |
11636 ASSERT(index < NumberOfChecks()); | |
11637 ASSERT(class_ids != NULL); | |
11638 ASSERT(target != NULL); | |
11639 class_ids->Clear(); | |
11640 const Array& data = Array::Handle(ic_data()); | |
11641 intptr_t data_pos = index * TestEntryLength(); | |
11642 for (intptr_t i = 0; i < num_args_tested(); i++) { | |
11643 class_ids->Add(Smi::Value(Smi::RawCast(data.At(data_pos++)))); | |
11644 } | |
11645 (*target) ^= data.At(data_pos++); | |
11646 } | |
11647 | |
11648 | |
11649 void ICData::GetOneClassCheckAt(intptr_t index, | |
11650 intptr_t* class_id, | |
11651 Function* target) const { | |
11652 ASSERT(class_id != NULL); | |
11653 ASSERT(target != NULL); | |
11654 ASSERT(num_args_tested() == 1); | |
11655 const Array& data = Array::Handle(ic_data()); | |
11656 const intptr_t data_pos = index * TestEntryLength(); | |
11657 *class_id = Smi::Value(Smi::RawCast(data.At(data_pos))); | |
11658 *target ^= data.At(data_pos + 1); | |
11659 } | |
11660 | |
11661 | |
11662 intptr_t ICData::GetCidAt(intptr_t index) const { | |
11663 ASSERT(num_args_tested() == 1); | |
11664 const Array& data = Array::Handle(ic_data()); | |
11665 const intptr_t data_pos = index * TestEntryLength(); | |
11666 return Smi::Value(Smi::RawCast(data.At(data_pos))); | |
11667 } | |
11668 | |
11669 | |
11670 intptr_t ICData::GetClassIdAt(intptr_t index, intptr_t arg_nr) const { | |
11671 GrowableArray<intptr_t> class_ids; | |
11672 Function& target = Function::Handle(); | |
11673 GetCheckAt(index, &class_ids, &target); | |
11674 return class_ids[arg_nr]; | |
11675 } | |
11676 | |
11677 | |
11678 intptr_t ICData::GetReceiverClassIdAt(intptr_t index) const { | |
11679 ASSERT(index < NumberOfChecks()); | |
11680 const Array& data = Array::Handle(ic_data()); | |
11681 const intptr_t data_pos = index * TestEntryLength(); | |
11682 return Smi::Value(Smi::RawCast(data.At(data_pos))); | |
11683 } | |
11684 | |
11685 | |
11686 RawFunction* ICData::GetTargetAt(intptr_t index) const { | |
11687 const intptr_t data_pos = index * TestEntryLength() + num_args_tested(); | |
11688 ASSERT(Object::Handle(Array::Handle(ic_data()).At(data_pos)).IsFunction()); | |
11689 | |
11690 NoGCScope no_gc; | |
11691 RawArray* raw_data = ic_data(); | |
11692 return reinterpret_cast<RawFunction*>(raw_data->ptr()->data()[data_pos]); | |
11693 } | |
11694 | |
11695 | |
11696 void ICData::IncrementCountAt(intptr_t index, intptr_t value) const { | |
11697 ASSERT(0 <= value); | |
11698 ASSERT(value <= Smi::kMaxValue); | |
11699 SetCountAt(index, Utils::Minimum(GetCountAt(index) + value, Smi::kMaxValue)); | |
11700 } | |
11701 | |
11702 | |
11703 void ICData::SetCountAt(intptr_t index, intptr_t value) const { | |
11704 ASSERT(0 <= value); | |
11705 ASSERT(value <= Smi::kMaxValue); | |
11706 | |
11707 const Array& data = Array::Handle(ic_data()); | |
11708 const intptr_t data_pos = index * TestEntryLength() + | |
11709 CountIndexFor(num_args_tested()); | |
11710 data.SetAt(data_pos, Smi::Handle(Smi::New(value))); | |
11711 } | |
11712 | |
11713 | |
11714 intptr_t ICData::GetCountAt(intptr_t index) const { | |
11715 const Array& data = Array::Handle(ic_data()); | |
11716 const intptr_t data_pos = index * TestEntryLength() + | |
11717 CountIndexFor(num_args_tested()); | |
11718 return Smi::Value(Smi::RawCast(data.At(data_pos))); | |
11719 } | |
11720 | |
11721 | |
11722 intptr_t ICData::AggregateCount() const { | |
11723 if (IsNull()) return 0; | |
11724 const intptr_t len = NumberOfChecks(); | |
11725 intptr_t count = 0; | |
11726 for (intptr_t i = 0; i < len; i++) { | |
11727 count += GetCountAt(i); | |
11728 } | |
11729 return count; | |
11730 } | |
11731 | |
11732 | |
11733 RawFunction* ICData::GetTargetForReceiverClassId(intptr_t class_id) const { | |
11734 const intptr_t len = NumberOfChecks(); | |
11735 for (intptr_t i = 0; i < len; i++) { | |
11736 if (GetReceiverClassIdAt(i) == class_id) { | |
11737 return GetTargetAt(i); | |
11738 } | |
11739 } | |
11740 return Function::null(); | |
11741 } | |
11742 | |
11743 | |
11744 RawICData* ICData::AsUnaryClassChecksForArgNr(intptr_t arg_nr) const { | |
11745 ASSERT(!IsNull()); | |
11746 ASSERT(num_args_tested() > arg_nr); | |
11747 if ((arg_nr == 0) && (num_args_tested() == 1)) { | |
11748 // Frequent case. | |
11749 return raw(); | |
11750 } | |
11751 const intptr_t kNumArgsTested = 1; | |
11752 ICData& result = ICData::Handle(ICData::New( | |
11753 Function::Handle(function()), | |
11754 String::Handle(target_name()), | |
11755 Array::Handle(arguments_descriptor()), | |
11756 deopt_id(), | |
11757 kNumArgsTested)); | |
11758 const intptr_t len = NumberOfChecks(); | |
11759 for (intptr_t i = 0; i < len; i++) { | |
11760 const intptr_t class_id = GetClassIdAt(i, arg_nr); | |
11761 const intptr_t count = GetCountAt(i); | |
11762 intptr_t duplicate_class_id = -1; | |
11763 const intptr_t result_len = result.NumberOfChecks(); | |
11764 for (intptr_t k = 0; k < result_len; k++) { | |
11765 if (class_id == result.GetReceiverClassIdAt(k)) { | |
11766 duplicate_class_id = k; | |
11767 break; | |
11768 } | |
11769 } | |
11770 if (duplicate_class_id >= 0) { | |
11771 // This check is valid only when checking the receiver. | |
11772 ASSERT((arg_nr != 0) || | |
11773 (result.GetTargetAt(duplicate_class_id) == GetTargetAt(i))); | |
11774 result.IncrementCountAt(duplicate_class_id, count); | |
11775 } else { | |
11776 // This will make sure that Smi is first if it exists. | |
11777 result.AddReceiverCheck(class_id, | |
11778 Function::Handle(GetTargetAt(i)), | |
11779 count); | |
11780 } | |
11781 } | |
11782 // Copy deoptimization reason. | |
11783 result.set_deopt_reason(deopt_reason()); | |
11784 | |
11785 return result.raw(); | |
11786 } | |
11787 | |
11788 | |
11789 bool ICData::AllTargetsHaveSameOwner(intptr_t owner_cid) const { | |
11790 if (NumberOfChecks() == 0) return false; | |
11791 Class& cls = Class::Handle(); | |
11792 const intptr_t len = NumberOfChecks(); | |
11793 for (intptr_t i = 0; i < len; i++) { | |
11794 cls = Function::Handle(GetTargetAt(i)).Owner(); | |
11795 if (cls.id() != owner_cid) { | |
11796 return false; | |
11797 } | |
11798 } | |
11799 return true; | |
11800 } | |
11801 | |
11802 | |
11803 bool ICData::AllReceiversAreNumbers() const { | |
11804 if (NumberOfChecks() == 0) return false; | |
11805 Class& cls = Class::Handle(); | |
11806 const intptr_t len = NumberOfChecks(); | |
11807 for (intptr_t i = 0; i < len; i++) { | |
11808 cls = Function::Handle(GetTargetAt(i)).Owner(); | |
11809 const intptr_t cid = cls.id(); | |
11810 if ((cid != kSmiCid) && | |
11811 (cid != kMintCid) && | |
11812 (cid != kBigintCid) && | |
11813 (cid != kDoubleCid)) { | |
11814 return false; | |
11815 } | |
11816 } | |
11817 return true; | |
11818 } | |
11819 | |
11820 | |
11821 bool ICData::HasReceiverClassId(intptr_t class_id) const { | |
11822 ASSERT(num_args_tested() > 0); | |
11823 const intptr_t len = NumberOfChecks(); | |
11824 for (intptr_t i = 0; i < len; i++) { | |
11825 const intptr_t test_class_id = GetReceiverClassIdAt(i); | |
11826 if (test_class_id == class_id) { | |
11827 return true; | |
11828 } | |
11829 } | |
11830 return false; | |
11831 } | |
11832 | |
11833 | |
11834 // Returns true if all targets are the same. | |
11835 // TODO(srdjan): if targets are native use their C_function to compare. | |
11836 bool ICData::HasOneTarget() const { | |
11837 ASSERT(NumberOfChecks() > 0); | |
11838 const Function& first_target = Function::Handle(GetTargetAt(0)); | |
11839 const intptr_t len = NumberOfChecks(); | |
11840 for (intptr_t i = 1; i < len; i++) { | |
11841 if (GetTargetAt(i) != first_target.raw()) { | |
11842 return false; | |
11843 } | |
11844 } | |
11845 return true; | |
11846 } | |
11847 | |
11848 | |
11849 RawICData* ICData::New(const Function& caller_function, | |
11850 const String& target_name, | |
11851 const Array& arguments_descriptor, | |
11852 intptr_t deopt_id, | |
11853 intptr_t num_args_tested) { | |
11854 ASSERT(!caller_function.IsNull()); | |
11855 ASSERT(!target_name.IsNull()); | |
11856 ASSERT(!arguments_descriptor.IsNull()); | |
11857 ASSERT(Object::icdata_class() != Class::null()); | |
11858 ASSERT(num_args_tested >= 0); | |
11859 ICData& result = ICData::Handle(); | |
11860 { | |
11861 // IC data objects are long living objects, allocate them in old generation. | |
11862 RawObject* raw = Object::Allocate(ICData::kClassId, | |
11863 ICData::InstanceSize(), | |
11864 Heap::kOld); | |
11865 NoGCScope no_gc; | |
11866 result ^= raw; | |
11867 } | |
11868 result.set_function(caller_function); | |
11869 result.set_target_name(target_name); | |
11870 result.set_arguments_descriptor(arguments_descriptor); | |
11871 result.set_deopt_id(deopt_id); | |
11872 result.set_num_args_tested(num_args_tested); | |
11873 result.set_deopt_reason(kDeoptUnknown); | |
11874 result.set_is_closure_call(false); | |
11875 // Number of array elements in one test entry. | |
11876 intptr_t len = result.TestEntryLength(); | |
11877 // IC data array must be null terminated (sentinel entry). | |
11878 const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld)); | |
11879 result.set_ic_data(ic_data); | |
11880 result.WriteSentinel(ic_data); | |
11881 return result.raw(); | |
11882 } | |
11883 | |
11884 | |
11885 void ICData::PrintToJSONStream(JSONStream* stream, bool ref) const { | |
11886 Object::PrintToJSONStream(stream, ref); | |
11887 } | |
11888 | |
11889 | |
11890 RawArray* MegamorphicCache::buckets() const { | 11939 RawArray* MegamorphicCache::buckets() const { |
11891 return raw_ptr()->buckets_; | 11940 return raw_ptr()->buckets_; |
11892 } | 11941 } |
11893 | 11942 |
11894 | 11943 |
11895 void MegamorphicCache::set_buckets(const Array& buckets) const { | 11944 void MegamorphicCache::set_buckets(const Array& buckets) const { |
11896 StorePointer(&raw_ptr()->buckets_, buckets.raw()); | 11945 StorePointer(&raw_ptr()->buckets_, buckets.raw()); |
11897 } | 11946 } |
11898 | 11947 |
11899 | 11948 |
(...skipping 6691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18591 return tag_label.ToCString(); | 18640 return tag_label.ToCString(); |
18592 } | 18641 } |
18593 | 18642 |
18594 | 18643 |
18595 void UserTag::PrintToJSONStream(JSONStream* stream, bool ref) const { | 18644 void UserTag::PrintToJSONStream(JSONStream* stream, bool ref) const { |
18596 Instance::PrintToJSONStream(stream, ref); | 18645 Instance::PrintToJSONStream(stream, ref); |
18597 } | 18646 } |
18598 | 18647 |
18599 | 18648 |
18600 } // namespace dart | 18649 } // namespace dart |
OLD | NEW |