Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #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(-1); | |
|
Florian Schneider
2014/05/28 14:57:36
s/-1/kUnknownLengthOffset/
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 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_; | |
| 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_ = list_length_offset; | |
| 6835 } | |
| 6836 | |
| 6837 | |
| 6825 bool Field::IsUnboxedField() const { | 6838 bool Field::IsUnboxedField() const { |
| 6826 bool valid_class = (FlowGraphCompiler::SupportsUnboxedDoubles() && | 6839 bool valid_class = (FlowGraphCompiler::SupportsUnboxedDoubles() && |
| 6827 (guarded_cid() == kDoubleCid)) || | 6840 (guarded_cid() == kDoubleCid)) || |
| 6828 (FlowGraphCompiler::SupportsUnboxedSimd128() && | 6841 (FlowGraphCompiler::SupportsUnboxedSimd128() && |
| 6829 (guarded_cid() == kFloat32x4Cid)) || | 6842 (guarded_cid() == kFloat32x4Cid)) || |
| 6830 (FlowGraphCompiler::SupportsUnboxedSimd128() && | 6843 (FlowGraphCompiler::SupportsUnboxedSimd128() && |
| 6831 (guarded_cid() == kFloat64x2Cid)); | 6844 (guarded_cid() == kFloat64x2Cid)); |
| 6832 return is_unboxing_candidate() && !is_final() && !is_nullable() && | 6845 return is_unboxing_candidate() && !is_final() && !is_nullable() && |
| 6833 valid_class; | 6846 valid_class; |
| 6834 } | 6847 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6976 | 6989 |
| 6977 | 6990 |
| 6978 bool Field::IsUninitialized() const { | 6991 bool Field::IsUninitialized() const { |
| 6979 const Instance& value = Instance::Handle(raw_ptr()->value_); | 6992 const Instance& value = Instance::Handle(raw_ptr()->value_); |
| 6980 ASSERT(value.raw() != Object::transition_sentinel().raw()); | 6993 ASSERT(value.raw() != Object::transition_sentinel().raw()); |
| 6981 return value.raw() == Object::sentinel().raw(); | 6994 return value.raw() == Object::sentinel().raw(); |
| 6982 } | 6995 } |
| 6983 | 6996 |
| 6984 | 6997 |
| 6985 static intptr_t GetListLength(const Object& value) { | 6998 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()) { | 6999 if (value.IsTypedData()) { |
| 6990 const TypedData& list = TypedData::Cast(value); | 7000 const TypedData& list = TypedData::Cast(value); |
| 6991 return list.Length(); | 7001 return list.Length(); |
| 6992 } else if (value.IsArray()) { | 7002 } else if (value.IsArray()) { |
| 6993 const Array& list = Array::Cast(value); | 7003 const Array& list = Array::Cast(value); |
| 6994 return list.Length(); | 7004 return list.Length(); |
| 6995 } else if (value.IsGrowableObjectArray()) { | 7005 } else if (value.IsGrowableObjectArray()) { |
| 6996 // List length is variable. | 7006 // List length is variable. |
| 6997 return Field::kNoFixedLength; | 7007 return Field::kNoFixedLength; |
| 6998 } else if (value.IsExternalTypedData()) { | 7008 } else if (value.IsExternalTypedData()) { |
| 6999 // TODO(johnmccutchan): Enable for external typed data. | 7009 // TODO(johnmccutchan): Enable for external typed data. |
| 7000 return Field::kNoFixedLength; | 7010 return Field::kNoFixedLength; |
| 7001 } else if (RawObject::IsTypedDataViewClassId(cid)) { | 7011 } else if (RawObject::IsTypedDataViewClassId(value.GetClassId())) { |
| 7002 // TODO(johnmccutchan): Enable for typed data views. | 7012 // TODO(johnmccutchan): Enable for typed data views. |
| 7003 return Field::kNoFixedLength; | 7013 return Field::kNoFixedLength; |
| 7004 } | 7014 } |
| 7005 UNIMPLEMENTED(); | |
| 7006 return Field::kNoFixedLength; | 7015 return Field::kNoFixedLength; |
| 7007 } | 7016 } |
| 7008 | 7017 |
| 7009 | 7018 |
| 7019 static intptr_t GetListLengthOffset(const Object& value) { | |
| 7020 if (value.IsTypedData()) { | |
| 7021 return TypedData::length_offset(); | |
| 7022 } else if (value.IsArray()) { | |
| 7023 return Array::length_offset(); | |
| 7024 } else if (value.IsGrowableObjectArray()) { | |
| 7025 // List length is variable. | |
| 7026 return Field::kUnknownLengthOffset; | |
| 7027 } else if (value.IsExternalTypedData()) { | |
| 7028 // TODO(johnmccutchan): Enable for external typed data. | |
| 7029 return Field::kUnknownLengthOffset; | |
| 7030 } else if (RawObject::IsTypedDataViewClassId(value.GetClassId())) { | |
| 7031 // TODO(johnmccutchan): Enable for typed data views. | |
| 7032 return Field::kUnknownLengthOffset; | |
| 7033 } | |
| 7034 return Field::kUnknownLengthOffset; | |
| 7035 } | |
| 7036 | |
| 7037 | |
| 7038 const char* Field::GuardedPropertiesAsCString() const { | |
| 7039 if (guarded_cid() == kIllegalCid) { | |
| 7040 return "<?>"; | |
| 7041 } else if (guarded_cid() == kDynamicCid) { | |
| 7042 return "<*>"; | |
| 7043 } | |
| 7044 | |
| 7045 const Class& cls = Class::Handle( | |
| 7046 Isolate::Current()->class_table()->At(guarded_cid())); | |
| 7047 const char* class_name = String::Handle(cls.Name()).ToCString(); | |
| 7048 | |
| 7049 if (RawObject::IsBuiltinListClassId(guarded_cid()) && | |
| 7050 !is_nullable() && | |
| 7051 is_final()) { | |
| 7052 ASSERT(guarded_list_length() != kUnknownFixedLength); | |
| 7053 if (guarded_list_length() == kNoFixedLength) { | |
| 7054 return Isolate::Current()->current_zone()->PrintToString( | |
| 7055 "<%s [*]>", class_name); | |
| 7056 } else { | |
| 7057 return Isolate::Current()->current_zone()->PrintToString("<%s [%d @%d]>", | |
| 7058 class_name, | |
| 7059 guarded_list_length(), | |
| 7060 guarded_list_length_in_object_offset()); | |
| 7061 } | |
| 7062 } | |
| 7063 | |
| 7064 return Isolate::Current()->current_zone()->PrintToString("<%s %s>", | |
| 7065 is_nullable() ? "nullable" : "not-nullable", | |
| 7066 class_name); | |
| 7067 } | |
| 7068 | |
| 7069 | |
| 7010 bool Field::UpdateGuardedCidAndLength(const Object& value) const { | 7070 bool Field::UpdateGuardedCidAndLength(const Object& value) const { |
| 7011 const intptr_t cid = value.GetClassId(); | 7071 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 | 7072 |
| 7025 | |
| 7026 bool Field::UpdateCid(intptr_t cid) const { | |
| 7027 if (guarded_cid() == kIllegalCid) { | 7073 if (guarded_cid() == kIllegalCid) { |
| 7028 // Field is assigned first time. | 7074 // Field is assigned first time. |
| 7029 set_guarded_cid(cid); | 7075 set_guarded_cid(cid); |
| 7030 set_is_nullable(cid == kNullCid); | 7076 set_is_nullable(cid == kNullCid); |
| 7077 | |
| 7078 // Start tracking length if needed. | |
| 7079 ASSERT((guarded_list_length() == Field::kUnknownFixedLength) || | |
| 7080 (guarded_list_length() == Field::kNoFixedLength)); | |
| 7081 if (needs_length_check()) { | |
| 7082 ASSERT(guarded_list_length() == Field::kUnknownFixedLength); | |
| 7083 set_guarded_list_length(GetListLength(value)); | |
| 7084 set_guarded_list_length_in_object_offset(GetListLengthOffset(value)); | |
| 7085 } | |
| 7086 | |
| 7031 return false; | 7087 return false; |
| 7032 } | 7088 } |
| 7033 | 7089 |
| 7034 if ((cid == guarded_cid()) || ((cid == kNullCid) && is_nullable())) { | 7090 if ((cid == guarded_cid()) || ((cid == kNullCid) && is_nullable())) { |
| 7035 // Class id of the assigned value matches expected class id and nullability. | 7091 // Class id of the assigned value matches expected class id and nullability. |
| 7092 | |
| 7093 // If we are tracking length check if it has matches. | |
| 7094 if (needs_length_check() && | |
| 7095 (guarded_list_length() != GetListLength(value))) { | |
| 7096 ASSERT(guarded_list_length() != Field::kUnknownFixedLength); | |
| 7097 set_guarded_list_length(Field::kNoFixedLength); | |
| 7098 set_guarded_list_length_in_object_offset(-1); | |
|
Florian Schneider
2014/05/28 14:57:36
s/-1/kUnknownLengthOffset/
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 7099 return true; | |
| 7100 } | |
| 7101 | |
| 7102 // Everything matches. | |
| 7036 return false; | 7103 return false; |
| 7037 } | 7104 } |
| 7038 | 7105 |
| 7039 if ((cid == kNullCid) && !is_nullable()) { | 7106 if ((cid == kNullCid) && !is_nullable()) { |
| 7040 // Assigning null value to a non-nullable field makes it nullable. | 7107 // Assigning null value to a non-nullable field makes it nullable. |
| 7041 set_is_nullable(true); | 7108 set_is_nullable(true); |
| 7042 } else if ((cid != kNullCid) && (guarded_cid() == kNullCid)) { | 7109 } else if ((cid != kNullCid) && (guarded_cid() == kNullCid)) { |
| 7043 // Assigning non-null value to a field that previously contained only null | 7110 // Assigning non-null value to a field that previously contained only null |
| 7044 // turns it into a nullable field with the given class id. | 7111 // turns it into a nullable field with the given class id. |
| 7045 ASSERT(is_nullable()); | 7112 ASSERT(is_nullable()); |
| 7046 set_guarded_cid(cid); | 7113 set_guarded_cid(cid); |
| 7047 } else { | 7114 } else { |
| 7048 // Give up on tracking class id of values contained in this field. | 7115 // Give up on tracking class id of values contained in this field. |
| 7049 ASSERT(guarded_cid() != cid); | 7116 ASSERT(guarded_cid() != cid); |
| 7050 set_guarded_cid(kDynamicCid); | 7117 set_guarded_cid(kDynamicCid); |
| 7051 set_is_nullable(true); | 7118 set_is_nullable(true); |
| 7052 } | 7119 } |
| 7053 | 7120 |
| 7121 // If we were tracking length drop collected feedback. | |
| 7122 if (needs_length_check()) { | |
| 7123 ASSERT(guarded_list_length() != Field::kUnknownFixedLength); | |
| 7124 set_guarded_list_length(Field::kNoFixedLength); | |
| 7125 set_guarded_list_length_in_object_offset(-1); | |
|
Florian Schneider
2014/05/28 14:57:36
s/-1/kUnknownLengthOffset/
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 7126 } | |
| 7127 | |
| 7054 // Expected class id or nullability of the field changed. | 7128 // Expected class id or nullability of the field changed. |
| 7055 return true; | 7129 return true; |
| 7056 } | 7130 } |
| 7057 | 7131 |
| 7058 | 7132 |
| 7059 bool Field::UpdateLength(intptr_t list_length) const { | 7133 void Field::RecordStore(const Object& value) const { |
| 7060 ASSERT(is_final() || (!is_final() && | 7134 if (FLAG_trace_field_guards) { |
| 7061 (list_length < Field::kUnknownFixedLength))); | 7135 OS::Print("Store %s %s <- %s\n", |
| 7062 ASSERT((list_length == Field::kNoFixedLength) || | 7136 ToCString(), |
| 7063 (list_length > Field::kUnknownFixedLength)); | 7137 GuardedPropertiesAsCString(), |
| 7064 ASSERT(guarded_cid() != kIllegalCid); | 7138 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 } | 7139 } |
| 7078 | 7140 |
| 7079 if (!list_length_changed && !force_invalidate) { | 7141 if (UpdateGuardedCidAndLength(value)) { |
| 7080 // List length unchanged. | 7142 if (FLAG_trace_field_guards) { |
| 7081 return false; | 7143 OS::Print(" => %s\n", GuardedPropertiesAsCString()); |
| 7144 } | |
| 7145 | |
| 7146 DeoptimizeDependentCode(); | |
| 7082 } | 7147 } |
| 7083 // Multiple list lengths assigned here, stop tracking length. | |
| 7084 set_guarded_list_length(Field::kNoFixedLength); | |
| 7085 return true; | |
| 7086 } | 7148 } |
| 7087 | 7149 |
| 7088 | 7150 |
| 7089 void LiteralToken::set_literal(const String& literal) const { | 7151 void LiteralToken::set_literal(const String& literal) const { |
| 7090 StorePointer(&raw_ptr()->literal_, literal.raw()); | 7152 StorePointer(&raw_ptr()->literal_, literal.raw()); |
| 7091 } | 7153 } |
| 7092 | 7154 |
| 7093 | 7155 |
| 7094 void LiteralToken::set_value(const Object& value) const { | 7156 void LiteralToken::set_value(const Object& value) const { |
| 7095 StorePointer(&raw_ptr()->value_, value.raw()); | 7157 StorePointer(&raw_ptr()->value_, value.raw()); |
| (...skipping 11803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 18899 return tag_label.ToCString(); | 18961 return tag_label.ToCString(); |
| 18900 } | 18962 } |
| 18901 | 18963 |
| 18902 | 18964 |
| 18903 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 18965 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 18904 Instance::PrintJSONImpl(stream, ref); | 18966 Instance::PrintJSONImpl(stream, ref); |
| 18905 } | 18967 } |
| 18906 | 18968 |
| 18907 | 18969 |
| 18908 } // namespace dart | 18970 } // namespace dart |
| OLD | NEW |