| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 DEFINE_FLAG(bool, show_internal_names, false, | 57 DEFINE_FLAG(bool, show_internal_names, false, |
| 58 "Show names of internal classes (e.g. \"OneByteString\") in error messages " | 58 "Show names of internal classes (e.g. \"OneByteString\") in error messages " |
| 59 "instead of showing the corresponding interface names (e.g. \"String\")"); | 59 "instead of showing the corresponding interface names (e.g. \"String\")"); |
| 60 DEFINE_FLAG(bool, trace_disabling_optimized_code, false, | 60 DEFINE_FLAG(bool, trace_disabling_optimized_code, false, |
| 61 "Trace disabling optimized code."); | 61 "Trace disabling optimized code."); |
| 62 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false, | 62 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false, |
| 63 "Throw an exception when the result of an integer calculation will not " | 63 "Throw an exception when the result of an integer calculation will not " |
| 64 "fit into a javascript integer."); | 64 "fit into a javascript integer."); |
| 65 DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids."); | 65 DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids."); |
| 66 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache"); | 66 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache"); |
| 67 DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids."); |
| 67 | 68 |
| 68 DECLARE_FLAG(bool, enable_type_checks); | 69 DECLARE_FLAG(bool, enable_type_checks); |
| 69 DECLARE_FLAG(bool, error_on_bad_override); | 70 DECLARE_FLAG(bool, error_on_bad_override); |
| 70 DECLARE_FLAG(bool, trace_compiler); | 71 DECLARE_FLAG(bool, trace_compiler); |
| 71 DECLARE_FLAG(bool, trace_deoptimization); | 72 DECLARE_FLAG(bool, trace_deoptimization); |
| 72 DECLARE_FLAG(bool, trace_deoptimization_verbose); | 73 DECLARE_FLAG(bool, trace_deoptimization_verbose); |
| 73 DECLARE_FLAG(bool, verbose_stacktrace); | 74 DECLARE_FLAG(bool, verbose_stacktrace); |
| 74 DECLARE_FLAG(charp, coverage_dir); | 75 DECLARE_FLAG(charp, coverage_dir); |
| 75 DECLARE_FLAG(bool, write_protect_code); | 76 DECLARE_FLAG(bool, write_protect_code); |
| 76 | 77 |
| (...skipping 6690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6767 result.SetOffset(0); | 6768 result.SetOffset(0); |
| 6768 } | 6769 } |
| 6769 result.set_is_final(is_final); | 6770 result.set_is_final(is_final); |
| 6770 result.set_is_const(is_const); | 6771 result.set_is_const(is_const); |
| 6771 result.set_owner(owner); | 6772 result.set_owner(owner); |
| 6772 result.set_token_pos(token_pos); | 6773 result.set_token_pos(token_pos); |
| 6773 result.set_has_initializer(false); | 6774 result.set_has_initializer(false); |
| 6774 result.set_is_unboxing_candidate(true); | 6775 result.set_is_unboxing_candidate(true); |
| 6775 result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid); | 6776 result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid); |
| 6776 result.set_is_nullable(FLAG_use_field_guards ? false : true); | 6777 result.set_is_nullable(FLAG_use_field_guards ? false : true); |
| 6778 result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset); |
| 6777 // Presently, we only attempt to remember the list length for final fields. | 6779 // Presently, we only attempt to remember the list length for final fields. |
| 6778 if (is_final && FLAG_use_field_guards) { | 6780 if (is_final && FLAG_use_field_guards) { |
| 6779 result.set_guarded_list_length(Field::kUnknownFixedLength); | 6781 result.set_guarded_list_length(Field::kUnknownFixedLength); |
| 6780 } else { | 6782 } else { |
| 6781 result.set_guarded_list_length(Field::kNoFixedLength); | 6783 result.set_guarded_list_length(Field::kNoFixedLength); |
| 6782 } | 6784 } |
| 6783 result.set_dependent_code(Object::null_array()); | 6785 result.set_dependent_code(Object::null_array()); |
| 6784 return result.raw(); | 6786 return result.raw(); |
| 6785 } | 6787 } |
| 6786 | 6788 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 6815 intptr_t Field::guarded_list_length() const { | 6817 intptr_t Field::guarded_list_length() const { |
| 6816 return Smi::Value(raw_ptr()->guarded_list_length_); | 6818 return Smi::Value(raw_ptr()->guarded_list_length_); |
| 6817 } | 6819 } |
| 6818 | 6820 |
| 6819 | 6821 |
| 6820 void Field::set_guarded_list_length(intptr_t list_length) const { | 6822 void Field::set_guarded_list_length(intptr_t list_length) const { |
| 6821 raw_ptr()->guarded_list_length_ = Smi::New(list_length); | 6823 raw_ptr()->guarded_list_length_ = Smi::New(list_length); |
| 6822 } | 6824 } |
| 6823 | 6825 |
| 6824 | 6826 |
| 6827 intptr_t Field::guarded_list_length_in_object_offset() const { |
| 6828 return raw_ptr()->guarded_list_length_in_object_offset_ + kHeapObjectTag; |
| 6829 } |
| 6830 |
| 6831 |
| 6832 void Field::set_guarded_list_length_in_object_offset( |
| 6833 intptr_t list_length_offset) const { |
| 6834 raw_ptr()->guarded_list_length_in_object_offset_ = |
| 6835 static_cast<int8_t>(list_length_offset - kHeapObjectTag); |
| 6836 ASSERT(guarded_list_length_in_object_offset() == list_length_offset); |
| 6837 } |
| 6838 |
| 6839 |
| 6825 bool Field::IsUnboxedField() const { | 6840 bool Field::IsUnboxedField() const { |
| 6826 bool valid_class = (FlowGraphCompiler::SupportsUnboxedDoubles() && | 6841 bool valid_class = (FlowGraphCompiler::SupportsUnboxedDoubles() && |
| 6827 (guarded_cid() == kDoubleCid)) || | 6842 (guarded_cid() == kDoubleCid)) || |
| 6828 (FlowGraphCompiler::SupportsUnboxedSimd128() && | 6843 (FlowGraphCompiler::SupportsUnboxedSimd128() && |
| 6829 (guarded_cid() == kFloat32x4Cid)) || | 6844 (guarded_cid() == kFloat32x4Cid)) || |
| 6830 (FlowGraphCompiler::SupportsUnboxedSimd128() && | 6845 (FlowGraphCompiler::SupportsUnboxedSimd128() && |
| 6831 (guarded_cid() == kFloat64x2Cid)); | 6846 (guarded_cid() == kFloat64x2Cid)); |
| 6832 return is_unboxing_candidate() && !is_final() && !is_nullable() && | 6847 return is_unboxing_candidate() && !is_final() && !is_nullable() && |
| 6833 valid_class; | 6848 valid_class; |
| 6834 } | 6849 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6976 | 6991 |
| 6977 | 6992 |
| 6978 bool Field::IsUninitialized() const { | 6993 bool Field::IsUninitialized() const { |
| 6979 const Instance& value = Instance::Handle(raw_ptr()->value_); | 6994 const Instance& value = Instance::Handle(raw_ptr()->value_); |
| 6980 ASSERT(value.raw() != Object::transition_sentinel().raw()); | 6995 ASSERT(value.raw() != Object::transition_sentinel().raw()); |
| 6981 return value.raw() == Object::sentinel().raw(); | 6996 return value.raw() == Object::sentinel().raw(); |
| 6982 } | 6997 } |
| 6983 | 6998 |
| 6984 | 6999 |
| 6985 static intptr_t GetListLength(const Object& value) { | 7000 static intptr_t GetListLength(const Object& value) { |
| 6986 const intptr_t cid = value.GetClassId(); | |
| 6987 ASSERT(RawObject::IsBuiltinListClassId(cid)); | |
| 6988 // Extract list length. | |
| 6989 if (value.IsTypedData()) { | 7001 if (value.IsTypedData()) { |
| 6990 const TypedData& list = TypedData::Cast(value); | 7002 const TypedData& list = TypedData::Cast(value); |
| 6991 return list.Length(); | 7003 return list.Length(); |
| 6992 } else if (value.IsArray()) { | 7004 } else if (value.IsArray()) { |
| 6993 const Array& list = Array::Cast(value); | 7005 const Array& list = Array::Cast(value); |
| 6994 return list.Length(); | 7006 return list.Length(); |
| 6995 } else if (value.IsGrowableObjectArray()) { | 7007 } else if (value.IsGrowableObjectArray()) { |
| 6996 // List length is variable. | 7008 // List length is variable. |
| 6997 return Field::kNoFixedLength; | 7009 return Field::kNoFixedLength; |
| 6998 } else if (value.IsExternalTypedData()) { | 7010 } else if (value.IsExternalTypedData()) { |
| 6999 // TODO(johnmccutchan): Enable for external typed data. | 7011 // TODO(johnmccutchan): Enable for external typed data. |
| 7000 return Field::kNoFixedLength; | 7012 return Field::kNoFixedLength; |
| 7001 } else if (RawObject::IsTypedDataViewClassId(cid)) { | 7013 } else if (RawObject::IsTypedDataViewClassId(value.GetClassId())) { |
| 7002 // TODO(johnmccutchan): Enable for typed data views. | 7014 // TODO(johnmccutchan): Enable for typed data views. |
| 7003 return Field::kNoFixedLength; | 7015 return Field::kNoFixedLength; |
| 7004 } | 7016 } |
| 7005 UNIMPLEMENTED(); | |
| 7006 return Field::kNoFixedLength; | 7017 return Field::kNoFixedLength; |
| 7007 } | 7018 } |
| 7008 | 7019 |
| 7009 | 7020 |
| 7021 static intptr_t GetListLengthOffset(intptr_t cid) { |
| 7022 if (RawObject::IsTypedDataClassId(cid)) { |
| 7023 return TypedData::length_offset(); |
| 7024 } else if (cid == kArrayCid || cid == kImmutableArrayCid) { |
| 7025 return Array::length_offset(); |
| 7026 } else if (cid == kGrowableObjectArrayCid) { |
| 7027 // List length is variable. |
| 7028 return Field::kUnknownLengthOffset; |
| 7029 } else if (RawObject::IsExternalTypedDataClassId(cid)) { |
| 7030 // TODO(johnmccutchan): Enable for external typed data. |
| 7031 return Field::kUnknownLengthOffset; |
| 7032 } else if (RawObject::IsTypedDataViewClassId(cid)) { |
| 7033 // TODO(johnmccutchan): Enable for typed data views. |
| 7034 return Field::kUnknownLengthOffset; |
| 7035 } |
| 7036 return Field::kUnknownLengthOffset; |
| 7037 } |
| 7038 |
| 7039 |
| 7040 const char* Field::GuardedPropertiesAsCString() const { |
| 7041 if (guarded_cid() == kIllegalCid) { |
| 7042 return "<?>"; |
| 7043 } else if (guarded_cid() == kDynamicCid) { |
| 7044 return "<*>"; |
| 7045 } |
| 7046 |
| 7047 const Class& cls = Class::Handle( |
| 7048 Isolate::Current()->class_table()->At(guarded_cid())); |
| 7049 const char* class_name = String::Handle(cls.Name()).ToCString(); |
| 7050 |
| 7051 if (RawObject::IsBuiltinListClassId(guarded_cid()) && |
| 7052 !is_nullable() && |
| 7053 is_final()) { |
| 7054 ASSERT(guarded_list_length() != kUnknownFixedLength); |
| 7055 if (guarded_list_length() == kNoFixedLength) { |
| 7056 return Isolate::Current()->current_zone()->PrintToString( |
| 7057 "<%s [*]>", class_name); |
| 7058 } else { |
| 7059 return Isolate::Current()->current_zone()->PrintToString( |
| 7060 "<%s [%" Pd " @%" Pd "]>", |
| 7061 class_name, |
| 7062 guarded_list_length(), |
| 7063 guarded_list_length_in_object_offset()); |
| 7064 } |
| 7065 } |
| 7066 |
| 7067 return Isolate::Current()->current_zone()->PrintToString("<%s %s>", |
| 7068 is_nullable() ? "nullable" : "not-nullable", |
| 7069 class_name); |
| 7070 } |
| 7071 |
| 7072 |
| 7073 void Field::InitializeGuardedListLengthInObjectOffset() const { |
| 7074 if (needs_length_check() && |
| 7075 (guarded_list_length() != Field::kUnknownFixedLength)) { |
| 7076 const intptr_t offset = GetListLengthOffset(guarded_cid()); |
| 7077 set_guarded_list_length_in_object_offset(offset); |
| 7078 ASSERT(offset != Field::kUnknownLengthOffset); |
| 7079 } else { |
| 7080 set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset); |
| 7081 } |
| 7082 } |
| 7083 |
| 7084 |
| 7010 bool Field::UpdateGuardedCidAndLength(const Object& value) const { | 7085 bool Field::UpdateGuardedCidAndLength(const Object& value) const { |
| 7011 const intptr_t cid = value.GetClassId(); | 7086 const intptr_t cid = value.GetClassId(); |
| 7012 bool deoptimize = UpdateCid(cid); | |
| 7013 intptr_t list_length = Field::kNoFixedLength; | |
| 7014 if ((guarded_cid() != kDynamicCid) && | |
| 7015 is_final() && RawObject::IsBuiltinListClassId(cid)) { | |
| 7016 list_length = GetListLength(value); | |
| 7017 } | |
| 7018 deoptimize = UpdateLength(list_length) || deoptimize; | |
| 7019 if (deoptimize) { | |
| 7020 DeoptimizeDependentCode(); | |
| 7021 } | |
| 7022 return deoptimize; | |
| 7023 } | |
| 7024 | 7087 |
| 7025 | |
| 7026 bool Field::UpdateCid(intptr_t cid) const { | |
| 7027 if (guarded_cid() == kIllegalCid) { | 7088 if (guarded_cid() == kIllegalCid) { |
| 7028 // Field is assigned first time. | 7089 // Field is assigned first time. |
| 7029 set_guarded_cid(cid); | 7090 set_guarded_cid(cid); |
| 7030 set_is_nullable(cid == kNullCid); | 7091 set_is_nullable(cid == kNullCid); |
| 7092 |
| 7093 // Start tracking length if needed. |
| 7094 ASSERT((guarded_list_length() == Field::kUnknownFixedLength) || |
| 7095 (guarded_list_length() == Field::kNoFixedLength)); |
| 7096 if (needs_length_check()) { |
| 7097 ASSERT(guarded_list_length() == Field::kUnknownFixedLength); |
| 7098 set_guarded_list_length(GetListLength(value)); |
| 7099 InitializeGuardedListLengthInObjectOffset(); |
| 7100 } |
| 7101 |
| 7102 if (FLAG_trace_field_guards) { |
| 7103 OS::Print(" => %s\n", GuardedPropertiesAsCString()); |
| 7104 } |
| 7105 |
| 7031 return false; | 7106 return false; |
| 7032 } | 7107 } |
| 7033 | 7108 |
| 7034 if ((cid == guarded_cid()) || ((cid == kNullCid) && is_nullable())) { | 7109 if ((cid == guarded_cid()) || ((cid == kNullCid) && is_nullable())) { |
| 7035 // Class id of the assigned value matches expected class id and nullability. | 7110 // Class id of the assigned value matches expected class id and nullability. |
| 7111 |
| 7112 // If we are tracking length check if it has matches. |
| 7113 if (needs_length_check() && |
| 7114 (guarded_list_length() != GetListLength(value))) { |
| 7115 ASSERT(guarded_list_length() != Field::kUnknownFixedLength); |
| 7116 set_guarded_list_length(Field::kNoFixedLength); |
| 7117 set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset); |
| 7118 return true; |
| 7119 } |
| 7120 |
| 7121 // Everything matches. |
| 7036 return false; | 7122 return false; |
| 7037 } | 7123 } |
| 7038 | 7124 |
| 7039 if ((cid == kNullCid) && !is_nullable()) { | 7125 if ((cid == kNullCid) && !is_nullable()) { |
| 7040 // Assigning null value to a non-nullable field makes it nullable. | 7126 // Assigning null value to a non-nullable field makes it nullable. |
| 7041 set_is_nullable(true); | 7127 set_is_nullable(true); |
| 7042 } else if ((cid != kNullCid) && (guarded_cid() == kNullCid)) { | 7128 } else if ((cid != kNullCid) && (guarded_cid() == kNullCid)) { |
| 7043 // Assigning non-null value to a field that previously contained only null | 7129 // Assigning non-null value to a field that previously contained only null |
| 7044 // turns it into a nullable field with the given class id. | 7130 // turns it into a nullable field with the given class id. |
| 7045 ASSERT(is_nullable()); | 7131 ASSERT(is_nullable()); |
| 7046 set_guarded_cid(cid); | 7132 set_guarded_cid(cid); |
| 7047 } else { | 7133 } else { |
| 7048 // Give up on tracking class id of values contained in this field. | 7134 // Give up on tracking class id of values contained in this field. |
| 7049 ASSERT(guarded_cid() != cid); | 7135 ASSERT(guarded_cid() != cid); |
| 7050 set_guarded_cid(kDynamicCid); | 7136 set_guarded_cid(kDynamicCid); |
| 7051 set_is_nullable(true); | 7137 set_is_nullable(true); |
| 7052 } | 7138 } |
| 7053 | 7139 |
| 7140 // If we were tracking length drop collected feedback. |
| 7141 if (needs_length_check()) { |
| 7142 ASSERT(guarded_list_length() != Field::kUnknownFixedLength); |
| 7143 set_guarded_list_length(Field::kNoFixedLength); |
| 7144 set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset); |
| 7145 } |
| 7146 |
| 7054 // Expected class id or nullability of the field changed. | 7147 // Expected class id or nullability of the field changed. |
| 7055 return true; | 7148 return true; |
| 7056 } | 7149 } |
| 7057 | 7150 |
| 7058 | 7151 |
| 7059 bool Field::UpdateLength(intptr_t list_length) const { | 7152 void Field::RecordStore(const Object& value) const { |
| 7060 ASSERT(is_final() || (!is_final() && | 7153 if (FLAG_trace_field_guards) { |
| 7061 (list_length < Field::kUnknownFixedLength))); | 7154 OS::Print("Store %s %s <- %s\n", |
| 7062 ASSERT((list_length == Field::kNoFixedLength) || | 7155 ToCString(), |
| 7063 (list_length > Field::kUnknownFixedLength)); | 7156 GuardedPropertiesAsCString(), |
| 7064 ASSERT(guarded_cid() != kIllegalCid); | 7157 value.ToCString()); |
| 7065 | |
| 7066 const bool force_invalidate = (guarded_cid() == kDynamicCid) && | |
| 7067 (list_length != Field::kNoFixedLength); | |
| 7068 | |
| 7069 const bool list_length_unknown = | |
| 7070 (guarded_list_length() == Field::kUnknownFixedLength); | |
| 7071 const bool list_length_changed = (guarded_list_length() != list_length); | |
| 7072 | |
| 7073 if (list_length_unknown && list_length_changed && !force_invalidate) { | |
| 7074 // List length set for first time. | |
| 7075 set_guarded_list_length(list_length); | |
| 7076 return false; | |
| 7077 } | 7158 } |
| 7078 | 7159 |
| 7079 if (!list_length_changed && !force_invalidate) { | 7160 if (UpdateGuardedCidAndLength(value)) { |
| 7080 // List length unchanged. | 7161 if (FLAG_trace_field_guards) { |
| 7081 return false; | 7162 OS::Print(" => %s\n", GuardedPropertiesAsCString()); |
| 7163 } |
| 7164 |
| 7165 DeoptimizeDependentCode(); |
| 7082 } | 7166 } |
| 7083 // Multiple list lengths assigned here, stop tracking length. | |
| 7084 set_guarded_list_length(Field::kNoFixedLength); | |
| 7085 return true; | |
| 7086 } | 7167 } |
| 7087 | 7168 |
| 7088 | 7169 |
| 7089 void LiteralToken::set_literal(const String& literal) const { | 7170 void LiteralToken::set_literal(const String& literal) const { |
| 7090 StorePointer(&raw_ptr()->literal_, literal.raw()); | 7171 StorePointer(&raw_ptr()->literal_, literal.raw()); |
| 7091 } | 7172 } |
| 7092 | 7173 |
| 7093 | 7174 |
| 7094 void LiteralToken::set_value(const Object& value) const { | 7175 void LiteralToken::set_value(const Object& value) const { |
| 7095 StorePointer(&raw_ptr()->value_, value.raw()); | 7176 StorePointer(&raw_ptr()->value_, value.raw()); |
| (...skipping 11803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 18899 return tag_label.ToCString(); | 18980 return tag_label.ToCString(); |
| 18900 } | 18981 } |
| 18901 | 18982 |
| 18902 | 18983 |
| 18903 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 18984 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 18904 Instance::PrintJSONImpl(stream, ref); | 18985 Instance::PrintJSONImpl(stream, ref); |
| 18905 } | 18986 } |
| 18906 | 18987 |
| 18907 | 18988 |
| 18908 } // namespace dart | 18989 } // namespace dart |
| OLD | NEW |