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/lookup.h" | 8 #include "src/lookup.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 ASSERT(is_guaranteed_to_have_holder()); | 109 ASSERT(is_guaranteed_to_have_holder()); |
110 | 110 |
111 if (property_encoding_ == DICTIONARY) { | 111 if (property_encoding_ == DICTIONARY) { |
112 Handle<JSObject> holder = GetHolder(); | 112 Handle<JSObject> holder = GetHolder(); |
113 number_ = holder->property_dictionary()->FindEntry(name_); | 113 number_ = holder->property_dictionary()->FindEntry(name_); |
114 if (number_ == NameDictionary::kNotFound) return false; | 114 if (number_ == NameDictionary::kNotFound) return false; |
115 | 115 |
116 property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_); | 116 property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_); |
117 // Holes in dictionary cells are absent values unless marked as read-only. | 117 // Holes in dictionary cells are absent values unless marked as read-only. |
118 if (holder->IsGlobalObject() && | 118 if (holder->IsGlobalObject() && |
119 (property_details_.IsDeleted() || | 119 (property_details_.IsDeleted() || FetchValue()->IsTheHole())) { |
120 (!property_details_.IsReadOnly() && FetchValue()->IsTheHole()))) { | |
121 return false; | 120 return false; |
122 } | 121 } |
123 } else { | 122 } else { |
124 property_details_ = holder_map_->instance_descriptors()->GetDetails( | 123 property_details_ = holder_map_->instance_descriptors()->GetDetails( |
125 number_); | 124 number_); |
126 } | 125 } |
127 | 126 |
128 switch (property_details_.type()) { | 127 switch (property_details_.type()) { |
129 case v8::internal::FIELD: | 128 case v8::internal::FIELD: |
130 case v8::internal::NORMAL: | 129 case v8::internal::NORMAL: |
131 case v8::internal::CONSTANT: | 130 case v8::internal::CONSTANT: |
132 property_kind_ = DATA; | 131 property_kind_ = DATA; |
133 break; | 132 break; |
134 case v8::internal::CALLBACKS: | 133 case v8::internal::CALLBACKS: |
135 property_kind_ = ACCESSOR; | 134 property_kind_ = ACCESSOR; |
136 break; | 135 break; |
137 case v8::internal::HANDLER: | 136 case v8::internal::HANDLER: |
138 case v8::internal::NONEXISTENT: | 137 case v8::internal::NONEXISTENT: |
139 case v8::internal::INTERCEPTOR: | 138 case v8::internal::INTERCEPTOR: |
140 UNREACHABLE(); | 139 UNREACHABLE(); |
141 } | 140 } |
142 | 141 |
143 has_property_ = true; | 142 has_property_ = true; |
144 return true; | 143 return true; |
145 } | 144 } |
146 | 145 |
147 | 146 |
| 147 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
| 148 ASSERT(has_property_); |
| 149 ASSERT(HolderIsReceiver()); |
| 150 if (property_encoding_ == DICTIONARY) return; |
| 151 holder_map_ = Map::PrepareForDataProperty(holder_map_, number_, value); |
| 152 JSObject::MigrateToMap(GetHolder(), holder_map_); |
| 153 // Reload property information. |
| 154 if (holder_map_->is_dictionary_map()) { |
| 155 property_encoding_ = DICTIONARY; |
| 156 } else { |
| 157 property_encoding_ = DESCRIPTOR; |
| 158 } |
| 159 CHECK(HasProperty()); |
| 160 } |
| 161 |
| 162 |
| 163 void LookupIterator::TransitionToDataProperty( |
| 164 Handle<Object> value, PropertyAttributes attributes, |
| 165 Object::StoreFromKeyed store_mode) { |
| 166 ASSERT(!has_property_ || !HolderIsReceiver()); |
| 167 |
| 168 // Can only be called when the receiver is a JSObject. JSProxy has to be |
| 169 // handled via a trap. Adding properties to primitive values is not |
| 170 // observable. |
| 171 Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); |
| 172 |
| 173 // Properties have to be added to context extension objects through |
| 174 // SetOwnPropertyIgnoreAttributes. |
| 175 ASSERT(!receiver->IsJSContextExtensionObject()); |
| 176 |
| 177 if (receiver->IsJSGlobalProxy()) { |
| 178 receiver = handle(JSGlobalObject::cast(receiver->GetPrototype())); |
| 179 } |
| 180 |
| 181 maybe_holder_ = receiver; |
| 182 holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_, |
| 183 value, attributes, store_mode); |
| 184 JSObject::MigrateToMap(receiver, holder_map_); |
| 185 |
| 186 // Reload the information. |
| 187 state_ = NOT_FOUND; |
| 188 configuration_ = CHECK_OWN_REAL; |
| 189 state_ = LookupInHolder(); |
| 190 ASSERT(IsFound()); |
| 191 HasProperty(); |
| 192 } |
| 193 |
| 194 |
| 195 bool LookupIterator::HolderIsReceiver() const { |
| 196 ASSERT(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
| 197 DisallowHeapAllocation no_gc; |
| 198 Handle<Object> receiver = GetReceiver(); |
| 199 if (!receiver->IsJSReceiver()) return false; |
| 200 Object* current = *receiver; |
| 201 JSReceiver* holder = *maybe_holder_.ToHandleChecked(); |
| 202 // JSProxy do not occur as hidden prototypes. |
| 203 if (current->IsJSProxy()) { |
| 204 return JSReceiver::cast(current) == holder; |
| 205 } |
| 206 do { |
| 207 if (JSReceiver::cast(current) == holder) return true; |
| 208 ASSERT(!current->IsJSProxy()); |
| 209 current = JSObject::cast(current)->GetPrototype(); |
| 210 } while (!current->IsNull() && |
| 211 (current->IsJSGlobalObject() || |
| 212 JSReceiver::cast(current)->map()->is_hidden_prototype())); |
| 213 return false; |
| 214 } |
| 215 |
| 216 |
148 Handle<Object> LookupIterator::FetchValue() const { | 217 Handle<Object> LookupIterator::FetchValue() const { |
149 Object* result = NULL; | 218 Object* result = NULL; |
150 switch (property_encoding_) { | 219 switch (property_encoding_) { |
151 case DICTIONARY: | 220 case DICTIONARY: |
152 result = GetHolder()->property_dictionary()->ValueAt(number_); | 221 result = GetHolder()->property_dictionary()->ValueAt(number_); |
153 if (GetHolder()->IsGlobalObject()) { | 222 if (GetHolder()->IsGlobalObject()) { |
154 result = PropertyCell::cast(result)->value(); | 223 result = PropertyCell::cast(result)->value(); |
155 } | 224 } |
156 break; | 225 break; |
157 case DESCRIPTOR: | 226 case DESCRIPTOR: |
(...skipping 21 matching lines...) Expand all Loading... |
179 ASSERT_EQ(DATA, property_kind_); | 248 ASSERT_EQ(DATA, property_kind_); |
180 Handle<Object> value = FetchValue(); | 249 Handle<Object> value = FetchValue(); |
181 if (value->IsTheHole()) { | 250 if (value->IsTheHole()) { |
182 ASSERT(property_details_.IsReadOnly()); | 251 ASSERT(property_details_.IsReadOnly()); |
183 return factory()->undefined_value(); | 252 return factory()->undefined_value(); |
184 } | 253 } |
185 return value; | 254 return value; |
186 } | 255 } |
187 | 256 |
188 | 257 |
| 258 void LookupIterator::WriteDataValue(Handle<Object> value) { |
| 259 ASSERT(is_guaranteed_to_have_holder()); |
| 260 ASSERT(has_property_); |
| 261 if (property_encoding_ == DICTIONARY) { |
| 262 Handle<JSObject> holder = GetHolder(); |
| 263 NameDictionary* property_dictionary = holder->property_dictionary(); |
| 264 if (holder->IsGlobalObject()) { |
| 265 Handle<PropertyCell> cell( |
| 266 PropertyCell::cast(property_dictionary->ValueAt(number_))); |
| 267 PropertyCell::SetValueInferType(cell, value); |
| 268 } else { |
| 269 property_dictionary->ValueAtPut(number_, *value); |
| 270 } |
| 271 } else if (property_details_.type() == v8::internal::FIELD) { |
| 272 GetHolder()->WriteToField(number_, *value); |
| 273 } else { |
| 274 ASSERT_EQ(v8::internal::CONSTANT, property_details_.type()); |
| 275 } |
| 276 } |
| 277 |
| 278 |
| 279 void LookupIterator::InternalizeName() { |
| 280 if (name_->IsUniqueName()) return; |
| 281 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); |
| 282 } |
189 } } // namespace v8::internal | 283 } } // namespace v8::internal |
OLD | NEW |