Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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/property-descriptor.h" | 5 #include "src/property-descriptor.h" |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/factory.h" | 8 #include "src/factory.h" |
| 9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
| 10 #include "src/lookup.h" | 10 #include "src/lookup.h" |
| 11 #include "src/objects-inl.h" | 11 #include "src/objects-inl.h" |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 | 15 |
| 16 // Helper function for ToPropertyDescriptor. Comments describe steps for | 16 // Helper function for ToPropertyDescriptor. Comments describe steps for |
| 17 // "enumerable", other properties are handled the same way. | 17 // "enumerable", other properties are handled the same way. |
| 18 // Returns false if an exception was thrown. | 18 // Returns false if an exception was thrown. |
| 19 bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name, | 19 bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name, |
|
Camillo Bruni
2015/11/12 13:52:19
Probably this will (as so many other methods) need
Jakob Kummerow
2015/11/12 14:01:45
Maybe. Let's introduce them as needed.
| |
| 20 Handle<Object>* value) { | 20 Handle<Object>* value) { |
| 21 LookupIterator it(obj, name); | 21 LookupIterator it(obj, name); |
| 22 // 4. Let hasEnumerable be HasProperty(Obj, "enumerable"). | 22 // 4. Let hasEnumerable be HasProperty(Obj, "enumerable"). |
| 23 Maybe<PropertyAttributes> maybe_attr = JSReceiver::GetPropertyAttributes(&it); | 23 Maybe<bool> has_property = JSReceiver::HasProperty(&it); |
| 24 // 5. ReturnIfAbrupt(hasEnumerable). | 24 // 5. ReturnIfAbrupt(hasEnumerable). |
| 25 if (!maybe_attr.IsJust()) return false; | 25 if (has_property.IsNothing()) return false; |
| 26 // 6. If hasEnumerable is true, then | 26 // 6. If hasEnumerable is true, then |
| 27 if (maybe_attr.FromJust() != ABSENT) { | 27 if (has_property.FromJust() == true) { |
| 28 // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")). | 28 // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")). |
| 29 // 6b. ReturnIfAbrupt(enum). | 29 // 6b. ReturnIfAbrupt(enum). |
| 30 if (!JSObject::GetProperty(&it).ToHandle(value)) return false; | 30 if (!JSObject::GetProperty(&it).ToHandle(value)) return false; |
| 31 } | 31 } |
| 32 return true; | 32 return true; |
| 33 } | 33 } |
| 34 | 34 |
| 35 | 35 |
| 36 // Helper function for ToPropertyDescriptor. Handles the case of "simple" | 36 // Helper function for ToPropertyDescriptor. Handles the case of "simple" |
| 37 // objects: nothing on the prototype chain, just own fast data properties. | 37 // objects: nothing on the prototype chain, just own fast data properties. |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 MessageTemplate::kPropertyDescObject, obj)); | 153 MessageTemplate::kPropertyDescObject, obj)); |
| 154 return false; | 154 return false; |
| 155 } | 155 } |
| 156 // 3. Let desc be a new Property Descriptor that initially has no fields. | 156 // 3. Let desc be a new Property Descriptor that initially has no fields. |
| 157 DCHECK(desc->is_empty()); | 157 DCHECK(desc->is_empty()); |
| 158 | 158 |
| 159 if (ToPropertyDescriptorFastPath(isolate, obj, desc)) { | 159 if (ToPropertyDescriptorFastPath(isolate, obj, desc)) { |
| 160 return true; | 160 return true; |
| 161 } | 161 } |
| 162 | 162 |
| 163 // TODO(jkummerow): Implement JSProxy support. | 163 // enumerable? |
|
Jakob Kummerow
2015/11/12 13:44:45
This is the same as old lines 167 through 253 with
| |
| 164 // Specifically, instead of taking the attributes != ABSENT shortcut, we | 164 Handle<Object> enumerable; |
| 165 // have to implement proper HasProperty for proxies. | 165 // 4 through 6b. |
| 166 if (!obj->IsJSProxy()) { | 166 if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), |
| 167 { // enumerable? | 167 &enumerable)) { |
| 168 Handle<Object> enumerable; | |
| 169 // 4 through 6b. | |
| 170 if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), | |
| 171 &enumerable)) { | |
| 172 return false; | |
| 173 } | |
| 174 // 6c. Set the [[Enumerable]] field of desc to enum. | |
| 175 if (!enumerable.is_null()) { | |
| 176 desc->set_enumerable(enumerable->BooleanValue()); | |
| 177 } | |
| 178 } | |
| 179 { // configurable? | |
| 180 Handle<Object> configurable; | |
| 181 // 7 through 9b. | |
| 182 if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), | |
| 183 &configurable)) { | |
| 184 return false; | |
| 185 } | |
| 186 // 9c. Set the [[Configurable]] field of desc to conf. | |
| 187 if (!configurable.is_null()) { | |
| 188 desc->set_configurable(configurable->BooleanValue()); | |
| 189 } | |
| 190 } | |
| 191 { // value? | |
| 192 Handle<Object> value; | |
| 193 // 10 through 12b. | |
| 194 if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), | |
| 195 &value)) | |
| 196 return false; | |
| 197 // 12c. Set the [[Value]] field of desc to value. | |
| 198 if (!value.is_null()) desc->set_value(value); | |
| 199 } | |
| 200 { // writable? | |
| 201 Handle<Object> writable; | |
| 202 // 13 through 15b. | |
| 203 if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), | |
| 204 &writable)) { | |
| 205 return false; | |
| 206 } | |
| 207 // 15c. Set the [[Writable]] field of desc to writable. | |
| 208 if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); | |
| 209 } | |
| 210 { // getter? | |
| 211 Handle<Object> getter; | |
| 212 // 16 through 18b. | |
| 213 if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) | |
| 214 return false; | |
| 215 if (!getter.is_null()) { | |
| 216 // 18c. If IsCallable(getter) is false and getter is not undefined, | |
| 217 // throw a TypeError exception. | |
| 218 if (!getter->IsCallable() && !getter->IsUndefined()) { | |
| 219 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 220 MessageTemplate::kObjectGetterCallable, getter)); | |
| 221 return false; | |
| 222 } | |
| 223 // 18d. Set the [[Get]] field of desc to getter. | |
| 224 desc->set_get(getter); | |
| 225 } | |
| 226 { // setter? | |
| 227 Handle<Object> setter; | |
| 228 // 19 through 21b. | |
| 229 if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), | |
| 230 &setter)) | |
| 231 return false; | |
| 232 if (!setter.is_null()) { | |
| 233 // 21c. If IsCallable(setter) is false and setter is not undefined, | |
| 234 // throw a TypeError exception. | |
| 235 if (!setter->IsCallable() && !setter->IsUndefined()) { | |
| 236 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 237 MessageTemplate::kObjectSetterCallable, setter)); | |
| 238 return false; | |
| 239 } | |
| 240 // 21d. Set the [[Set]] field of desc to setter. | |
| 241 desc->set_set(setter); | |
| 242 } | |
| 243 } | |
| 244 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then | |
| 245 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, | |
| 246 // throw a TypeError exception. | |
| 247 if ((desc->has_get() || desc->has_set()) && | |
| 248 (desc->has_value() || desc->has_writable())) { | |
| 249 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 250 MessageTemplate::kValueAndAccessor, obj)); | |
| 251 return false; | |
| 252 } | |
| 253 } | |
| 254 } else { | |
| 255 DCHECK(obj->IsJSProxy()); | |
| 256 // Having an UNIMPLEMENTED() here would upset ClusterFuzz, because | |
| 257 // --harmony-proxies makes it possible to reach this branch. | |
| 258 isolate->Throw( | |
| 259 *isolate->factory()->NewTypeError(MessageTemplate::kUnsupported)); | |
| 260 return false; | 168 return false; |
| 261 } | 169 } |
| 170 // 6c. Set the [[Enumerable]] field of desc to enum. | |
| 171 if (!enumerable.is_null()) { | |
| 172 desc->set_enumerable(enumerable->BooleanValue()); | |
| 173 } | |
| 174 | |
| 175 // configurable? | |
| 176 Handle<Object> configurable; | |
| 177 // 7 through 9b. | |
| 178 if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), | |
| 179 &configurable)) { | |
| 180 return false; | |
| 181 } | |
| 182 // 9c. Set the [[Configurable]] field of desc to conf. | |
| 183 if (!configurable.is_null()) { | |
| 184 desc->set_configurable(configurable->BooleanValue()); | |
| 185 } | |
| 186 | |
| 187 // value? | |
| 188 Handle<Object> value; | |
| 189 // 10 through 12b. | |
| 190 if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), &value)) { | |
| 191 return false; | |
| 192 } | |
| 193 // 12c. Set the [[Value]] field of desc to value. | |
| 194 if (!value.is_null()) desc->set_value(value); | |
| 195 | |
| 196 // writable? | |
| 197 Handle<Object> writable; | |
| 198 // 13 through 15b. | |
| 199 if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), | |
| 200 &writable)) { | |
| 201 return false; | |
| 202 } | |
| 203 // 15c. Set the [[Writable]] field of desc to writable. | |
| 204 if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); | |
| 205 | |
| 206 // getter? | |
| 207 Handle<Object> getter; | |
| 208 // 16 through 18b. | |
| 209 if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) { | |
| 210 return false; | |
| 211 } | |
| 212 if (!getter.is_null()) { | |
| 213 // 18c. If IsCallable(getter) is false and getter is not undefined, | |
| 214 // throw a TypeError exception. | |
| 215 if (!getter->IsCallable() && !getter->IsUndefined()) { | |
| 216 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 217 MessageTemplate::kObjectGetterCallable, getter)); | |
| 218 return false; | |
| 219 } | |
| 220 // 18d. Set the [[Get]] field of desc to getter. | |
| 221 desc->set_get(getter); | |
| 222 } | |
| 223 // setter? | |
| 224 Handle<Object> setter; | |
| 225 // 19 through 21b. | |
| 226 if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), &setter)) { | |
| 227 return false; | |
| 228 } | |
| 229 if (!setter.is_null()) { | |
| 230 // 21c. If IsCallable(setter) is false and setter is not undefined, | |
| 231 // throw a TypeError exception. | |
| 232 if (!setter->IsCallable() && !setter->IsUndefined()) { | |
| 233 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 234 MessageTemplate::kObjectSetterCallable, setter)); | |
| 235 return false; | |
| 236 } | |
| 237 // 21d. Set the [[Set]] field of desc to setter. | |
| 238 desc->set_set(setter); | |
| 239 } | |
| 240 | |
| 241 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then | |
| 242 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, | |
| 243 // throw a TypeError exception. | |
| 244 if ((desc->has_get() || desc->has_set()) && | |
| 245 (desc->has_value() || desc->has_writable())) { | |
| 246 isolate->Throw(*isolate->factory()->NewTypeError( | |
| 247 MessageTemplate::kValueAndAccessor, obj)); | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 262 // 23. Return desc. | 251 // 23. Return desc. |
| 263 return true; | 252 return true; |
| 264 } | 253 } |
| 265 | 254 |
| 266 | 255 |
| 256 // ES6 6.2.4.6 | |
| 257 // static | |
| 258 void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate, | |
|
Jakob Kummerow
2015/11/12 13:44:45
I'm not using this yet, but my next CL is going to
| |
| 259 PropertyDescriptor* desc) { | |
| 260 // 1. ReturnIfAbrupt(Desc). | |
| 261 // 2. Assert: Desc is a Property Descriptor. | |
| 262 // 3. Let like be Record{ | |
| 263 // [[Value]]: undefined, [[Writable]]: false, | |
| 264 // [[Get]]: undefined, [[Set]]: undefined, | |
| 265 // [[Enumerable]]: false, [[Configurable]]: false}. | |
| 266 // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, | |
| 267 // then: | |
| 268 if (!IsAccessorDescriptor(desc)) { | |
| 269 // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to | |
| 270 // like.[[Value]]. | |
| 271 if (!desc->has_value()) { | |
| 272 desc->set_value(isolate->factory()->undefined_value()); | |
| 273 } | |
| 274 // 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] | |
| 275 // to like.[[Writable]]. | |
| 276 if (!desc->has_writable()) desc->set_writable(false); | |
| 277 } else { | |
| 278 // 5. Else, | |
| 279 // 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to | |
| 280 // like.[[Get]]. | |
| 281 if (!desc->has_get()) { | |
| 282 desc->set_get(isolate->factory()->undefined_value()); | |
| 283 } | |
| 284 // 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to | |
| 285 // like.[[Set]]. | |
| 286 if (!desc->has_set()) { | |
| 287 desc->set_set(isolate->factory()->undefined_value()); | |
| 288 } | |
| 289 } | |
| 290 // 6. If Desc does not have an [[Enumerable]] field, set | |
| 291 // Desc.[[Enumerable]] to like.[[Enumerable]]. | |
| 292 if (!desc->has_enumerable()) desc->set_enumerable(false); | |
| 293 // 7. If Desc does not have a [[Configurable]] field, set | |
| 294 // Desc.[[Configurable]] to like.[[Configurable]]. | |
| 295 if (!desc->has_configurable()) desc->set_configurable(false); | |
| 296 // 8. Return Desc. | |
| 297 } | |
| 298 | |
| 267 } // namespace internal | 299 } // namespace internal |
| 268 } // namespace v8 | 300 } // namespace v8 |
| OLD | NEW |