Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(809)

Side by Side Diff: runtime/vm/object.cc

Issue 254723003: Remember all deopt reasons in ic_data, not just the last one. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/object_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/object_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698