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 |