| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/deoptimizer.h" |
| 8 #include "src/lookup.h" | 9 #include "src/lookup.h" |
| 9 #include "src/lookup-inl.h" | 10 #include "src/lookup-inl.h" |
| 10 | 11 |
| 11 namespace v8 { | 12 namespace v8 { |
| 12 namespace internal { | 13 namespace internal { |
| 13 | 14 |
| 14 | 15 |
| 15 void LookupIterator::Next() { | 16 void LookupIterator::Next() { |
| 16 DisallowHeapAllocation no_gc; | 17 DisallowHeapAllocation no_gc; |
| 17 has_property_ = false; | 18 has_property_ = false; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 case v8::internal::NONEXISTENT: | 103 case v8::internal::NONEXISTENT: |
| 103 case v8::internal::INTERCEPTOR: | 104 case v8::internal::INTERCEPTOR: |
| 104 UNREACHABLE(); | 105 UNREACHABLE(); |
| 105 } | 106 } |
| 106 | 107 |
| 107 has_property_ = true; | 108 has_property_ = true; |
| 108 return true; | 109 return true; |
| 109 } | 110 } |
| 110 | 111 |
| 111 | 112 |
| 113 void LookupIterator::ReloadPropertyInformation() { |
| 114 state_ = BEFORE_PROPERTY; |
| 115 state_ = LookupInHolder(*holder_map_); |
| 116 DCHECK(IsFound()); |
| 117 HasProperty(); |
| 118 } |
| 119 |
| 120 |
| 112 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { | 121 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
| 113 DCHECK(has_property_); | 122 DCHECK(has_property_); |
| 114 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 123 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
| 115 if (property_encoding_ == DICTIONARY) return; | 124 if (property_encoding_ == DICTIONARY) return; |
| 116 holder_map_ = | 125 holder_map_ = |
| 117 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); | 126 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); |
| 118 JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_); | 127 JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_); |
| 119 // Reload property information. | 128 ReloadPropertyInformation(); |
| 120 if (holder_map_->is_dictionary_map()) { | |
| 121 property_encoding_ = DICTIONARY; | |
| 122 } else { | |
| 123 property_encoding_ = DESCRIPTOR; | |
| 124 } | |
| 125 CHECK(HasProperty()); | |
| 126 } | 129 } |
| 127 | 130 |
| 128 | 131 |
| 129 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, | 132 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
| 130 PropertyAttributes attributes) { | 133 PropertyAttributes attributes) { |
| 131 DCHECK(has_property_); | 134 DCHECK(has_property_); |
| 132 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 135 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
| 133 Handle<JSObject> holder = GetHolder<JSObject>(); | 136 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 134 if (property_encoding_ != DICTIONARY) { | 137 if (property_encoding_ != DICTIONARY) { |
| 135 holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(), | 138 holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(), |
| 136 attributes); | 139 attributes); |
| 137 JSObject::MigrateToMap(holder, holder_map_); | 140 JSObject::MigrateToMap(holder, holder_map_); |
| 138 } | 141 } |
| 139 | 142 |
| 140 // Reload property information and update the descriptor if in dictionary | |
| 141 // mode. | |
| 142 if (holder_map_->is_dictionary_map()) { | 143 if (holder_map_->is_dictionary_map()) { |
| 143 property_encoding_ = DICTIONARY; | |
| 144 PropertyDetails details(attributes, NORMAL, 0); | 144 PropertyDetails details(attributes, NORMAL, 0); |
| 145 JSObject::SetNormalizedProperty(holder, name(), value, details); | 145 JSObject::SetNormalizedProperty(holder, name(), value, details); |
| 146 } else { | |
| 147 property_encoding_ = DESCRIPTOR; | |
| 148 } | 146 } |
| 149 | 147 |
| 150 CHECK(HasProperty()); | 148 ReloadPropertyInformation(); |
| 151 } | 149 } |
| 152 | 150 |
| 153 | 151 |
| 154 void LookupIterator::TransitionToDataProperty( | 152 void LookupIterator::TransitionToDataProperty( |
| 155 Handle<Object> value, PropertyAttributes attributes, | 153 Handle<Object> value, PropertyAttributes attributes, |
| 156 Object::StoreFromKeyed store_mode) { | 154 Object::StoreFromKeyed store_mode) { |
| 157 DCHECK(!has_property_ || !HolderIsReceiverOrHiddenPrototype()); | 155 DCHECK(!has_property_ || !HolderIsReceiverOrHiddenPrototype()); |
| 158 | 156 |
| 159 // Can only be called when the receiver is a JSObject. JSProxy has to be | 157 // Can only be called when the receiver is a JSObject. JSProxy has to be |
| 160 // handled via a trap. Adding properties to primitive values is not | 158 // handled via a trap. Adding properties to primitive values is not |
| 161 // observable. | 159 // observable. |
| 162 Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); | 160 Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); |
| 163 | 161 |
| 164 if (receiver->IsJSGlobalProxy()) { | 162 if (receiver->IsJSGlobalProxy()) { |
| 165 PrototypeIterator iter(isolate(), receiver); | 163 PrototypeIterator iter(isolate(), receiver); |
| 166 receiver = | 164 receiver = |
| 167 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); | 165 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| 168 } | 166 } |
| 169 | 167 |
| 170 maybe_holder_ = receiver; | 168 maybe_holder_ = receiver; |
| 171 holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_, | 169 holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_, |
| 172 value, attributes, store_mode); | 170 value, attributes, store_mode); |
| 173 JSObject::MigrateToMap(receiver, holder_map_); | 171 JSObject::MigrateToMap(receiver, holder_map_); |
| 174 | 172 |
| 175 // Reload the information. | 173 ReloadPropertyInformation(); |
| 176 state_ = NOT_FOUND; | |
| 177 configuration_ = CHECK_PROPERTY; | |
| 178 state_ = LookupInHolder(*holder_map_); | |
| 179 DCHECK(IsFound()); | |
| 180 HasProperty(); | |
| 181 } | 174 } |
| 182 | 175 |
| 183 | 176 |
| 177 void LookupIterator::TransitionToAccessorProperty( |
| 178 AccessorComponent component, Handle<Object> accessor, |
| 179 PropertyAttributes attributes) { |
| 180 DCHECK(!accessor->IsNull()); |
| 181 // Can only be called when the receiver is a JSObject. JSProxy has to be |
| 182 // handled via a trap. Adding properties to primitive values is not |
| 183 // observable. |
| 184 Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); |
| 185 |
| 186 if (receiver->IsJSGlobalProxy()) { |
| 187 PrototypeIterator iter(isolate(), receiver); |
| 188 receiver = |
| 189 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| 190 } |
| 191 |
| 192 maybe_holder_ = receiver; |
| 193 holder_map_ = Map::TransitionToAccessorProperty( |
| 194 handle(receiver->map()), name_, component, accessor, attributes); |
| 195 JSObject::MigrateToMap(receiver, holder_map_); |
| 196 |
| 197 ReloadPropertyInformation(); |
| 198 |
| 199 if (!holder_map_->is_dictionary_map()) return; |
| 200 |
| 201 // We have to deoptimize since accesses to data properties may have been |
| 202 // inlined without a corresponding map-check. |
| 203 if (holder_map_->IsGlobalObjectMap()) { |
| 204 Deoptimizer::DeoptimizeGlobalObject(*receiver); |
| 205 } |
| 206 |
| 207 // Install the accessor into the dictionary-mode object. |
| 208 PropertyDetails details(attributes, CALLBACKS, 0); |
| 209 Handle<AccessorPair> pair; |
| 210 if (IsFound() && HasProperty() && property_kind() == ACCESSOR && |
| 211 GetAccessors()->IsAccessorPair()) { |
| 212 pair = Handle<AccessorPair>::cast(GetAccessors()); |
| 213 // If the component and attributes are identical, nothing has to be done. |
| 214 if (pair->get(component) == *accessor) { |
| 215 if (property_details().attributes() == attributes) return; |
| 216 } else { |
| 217 pair = AccessorPair::Copy(pair); |
| 218 pair->set(component, *accessor); |
| 219 } |
| 220 } else { |
| 221 pair = isolate()->factory()->NewAccessorPair(); |
| 222 pair->set(component, *accessor); |
| 223 } |
| 224 JSObject::SetNormalizedProperty(receiver, name_, pair, details); |
| 225 |
| 226 JSObject::ReoptimizeIfPrototype(receiver); |
| 227 holder_map_ = handle(receiver->map()); |
| 228 ReloadPropertyInformation(); |
| 229 } |
| 230 |
| 231 |
| 184 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { | 232 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
| 185 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); | 233 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
| 186 // Optimization that only works if configuration_ is not mutable. | 234 // Optimization that only works if configuration_ is not mutable. |
| 187 if (!check_derived()) return true; | 235 if (!check_derived()) return true; |
| 188 DisallowHeapAllocation no_gc; | 236 DisallowHeapAllocation no_gc; |
| 189 Handle<Object> receiver = GetReceiver(); | 237 Handle<Object> receiver = GetReceiver(); |
| 190 if (!receiver->IsJSReceiver()) return false; | 238 if (!receiver->IsJSReceiver()) return false; |
| 191 Object* current = *receiver; | 239 Object* current = *receiver; |
| 192 JSReceiver* holder = *maybe_holder_.ToHandleChecked(); | 240 JSReceiver* holder = *maybe_holder_.ToHandleChecked(); |
| 193 // JSProxy do not occur as hidden prototypes. | 241 // JSProxy do not occur as hidden prototypes. |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); | 347 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); |
| 300 } | 348 } |
| 301 } | 349 } |
| 302 | 350 |
| 303 | 351 |
| 304 void LookupIterator::InternalizeName() { | 352 void LookupIterator::InternalizeName() { |
| 305 if (name_->IsUniqueName()) return; | 353 if (name_->IsUniqueName()) return; |
| 306 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); | 354 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); |
| 307 } | 355 } |
| 308 } } // namespace v8::internal | 356 } } // namespace v8::internal |
| OLD | NEW |