OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/property-descriptor.h" | |
6 | |
7 #include "src/factory.h" | |
8 #include "src/isolate-inl.h" | |
9 #include "src/lookup.h" | |
10 #include "src/objects-inl.h" | |
11 | |
12 namespace v8 { | |
13 namespace internal { | |
14 | |
15 // Helper function for ToPropertyDescriptor. Comments describe steps for | |
16 // "enumerable", other properties are handled the same way. | |
17 // Returns false if an exception was thrown. | |
18 bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name, | |
19 Handle<Object>* value) { | |
20 LookupIterator it(obj, name); | |
21 // 4. Let hasEnumerable be HasProperty(Obj, "enumerable"). | |
22 Maybe<PropertyAttributes> maybe_attr = JSReceiver::GetPropertyAttributes(&it); | |
23 // 5. ReturnIfAbrupt(hasEnumerable). | |
24 if (!maybe_attr.IsJust()) return false; | |
25 // 6. If hasEnumerable is true, then | |
26 if (maybe_attr.FromJust() != ABSENT) { | |
27 // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")). | |
28 // 6b. ReturnIfAbrupt(enum). | |
29 if (!JSObject::GetProperty(&it).ToHandle(value)) return false; | |
30 } | |
31 return true; | |
32 } | |
33 | |
34 | |
35 // Helper function for ToPropertyDescriptor. Handles the case of "simple" | |
36 // objects: nothing on the prototype chain, just own fast data properties. | |
37 // Must not have observable side effects, because the slow path will restart | |
38 // the entire conversion! | |
39 bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<Object> obj, | |
40 PropertyDescriptor* desc) { | |
41 if (!obj->IsJSObject()) return false; | |
42 Map* map = Handle<JSObject>::cast(obj)->map(); | |
43 if (map->instance_type() != JS_OBJECT_TYPE) return false; | |
44 if (map->is_access_check_needed()) return false; | |
45 if (map->prototype() != *isolate->initial_object_prototype()) return false; | |
46 if (JSObject::cast(map->prototype())->map() != | |
47 isolate->native_context()->object_function_prototype_map()) { | |
48 return false; | |
49 } | |
50 // TODO(jkummerow): support dictionary properties? | |
51 if (map->is_dictionary_map()) return false; | |
52 Handle<DescriptorArray> descs = | |
53 Handle<DescriptorArray>(map->instance_descriptors()); | |
54 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { | |
55 PropertyDetails details = descs->GetDetails(i); | |
56 Name* key = descs->GetKey(i); | |
57 Handle<Object> value; | |
58 switch (details.type()) { | |
59 case DATA: | |
60 value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj), | |
61 details.representation(), | |
62 FieldIndex::ForDescriptor(map, i)); | |
63 break; | |
64 case DATA_CONSTANT: | |
65 value = handle(descs->GetConstant(i), isolate); | |
66 break; | |
67 case ACCESSOR: | |
68 case ACCESSOR_CONSTANT: | |
69 // Bail out to slow path. | |
70 return false; | |
71 } | |
72 Heap* heap = isolate->heap(); | |
73 if (key == heap->enumerable_string()) { | |
74 desc->set_enumerable(value->BooleanValue()); | |
75 } else if (key == heap->configurable_string()) { | |
76 desc->set_configurable(value->BooleanValue()); | |
77 } else if (key == heap->value_string()) { | |
78 desc->set_value(value); | |
79 } else if (key == heap->writable_string()) { | |
80 desc->set_writable(value->BooleanValue()); | |
81 } else if (key == heap->get_string()) { | |
82 // Bail out to slow path to throw an exception if necessary. | |
83 if (!value->IsCallable()) return false; | |
84 desc->set_get(value); | |
85 } else if (key == heap->set_string()) { | |
86 // Bail out to slow path to throw an exception if necessary. | |
87 if (!value->IsCallable()) return false; | |
88 desc->set_set(value); | |
89 } | |
90 } | |
91 if ((desc->has_get() || desc->has_set()) && | |
92 (desc->has_value() || desc->has_writable())) { | |
93 // Bail out to slow path to throw an exception. | |
94 return false; | |
95 } | |
96 return true; | |
97 } | |
98 | |
99 | |
100 // ES6 6.2.4.5 | |
101 // Returns false in case of exception. | |
102 // static | |
103 bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate, | |
104 Handle<Object> obj, | |
105 PropertyDescriptor* desc) { | |
106 // 1. ReturnIfAbrupt(Obj). | |
107 // 2. If Type(Obj) is not Object, throw a TypeError exception. | |
108 if (!obj->IsSpecObject()) { | |
109 isolate->Throw(*isolate->factory()->NewTypeError( | |
110 MessageTemplate::kPropertyDescObject, obj)); | |
111 return false; | |
112 } | |
113 // 3. Let desc be a new Property Descriptor that initially has no fields. | |
114 DCHECK(desc->is_empty()); | |
115 | |
116 if (ToPropertyDescriptorFastPath(isolate, obj, desc)) { | |
117 return true; | |
118 } | |
119 | |
120 // TODO(jkummerow): Implement JSProxy support. | |
121 if (!obj->IsJSProxy()) { | |
Toon Verwaest
2015/10/06 15:55:18
I don't think this is good enough. GetPropertyIfPr
Jakob Kummerow
2015/10/09 13:46:12
Acknowledged. I'd prefer to do this in a follow-up
| |
122 { // enumerable? | |
123 Handle<Object> enumerable; | |
124 // 4 through 6b. | |
125 if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), | |
126 &enumerable)) { | |
127 return false; | |
128 } | |
129 // 6c. Set the [[Enumerable]] field of desc to enum. | |
130 if (!enumerable.is_null()) { | |
131 desc->set_enumerable(enumerable->BooleanValue()); | |
132 } | |
133 } | |
134 { // configurable? | |
135 Handle<Object> configurable; | |
136 // 7 through 9b. | |
137 if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), | |
138 &configurable)) { | |
139 return false; | |
140 } | |
141 // 9c. Set the [[Configurable]] field of desc to conf. | |
142 if (!configurable.is_null()) { | |
143 desc->set_configurable(configurable->BooleanValue()); | |
144 } | |
145 } | |
146 { // value? | |
147 Handle<Object> value; | |
148 // 10 through 12b. | |
149 if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), | |
150 &value)) | |
151 return false; | |
152 // 12c. Set the [[Value]] field of desc to value. | |
153 if (!value.is_null()) desc->set_value(value); | |
154 } | |
155 { // writable? | |
156 Handle<Object> writable; | |
157 // 13 through 15b. | |
158 if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), | |
159 &writable)) { | |
160 return false; | |
161 } | |
162 // 15c. Set the [[Writable]] field of desc to writable. | |
163 if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); | |
164 } | |
165 { // getter? | |
166 Handle<Object> getter; | |
167 // 16 through 18b. | |
168 if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) | |
169 return false; | |
170 if (!getter.is_null()) { | |
171 // 18c. If IsCallable(getter) is false and getter is not undefined, | |
172 // throw a TypeError exception. | |
173 if (!getter->IsCallable() && !getter->IsUndefined()) { | |
174 isolate->Throw(*isolate->factory()->NewTypeError( | |
175 MessageTemplate::kObjectGetterCallable, getter)); | |
176 return false; | |
177 } | |
178 // 18d. Set the [[Get]] field of desc to getter. | |
179 desc->set_get(getter); | |
180 } | |
181 { // setter? | |
182 Handle<Object> setter; | |
183 // 19 through 21b. | |
184 if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), | |
185 &setter)) | |
186 return false; | |
187 if (!setter.is_null()) { | |
188 // 21c. If IsCallable(setter) is false and setter is not undefined, | |
189 // throw a TypeError exception. | |
190 if (!setter->IsCallable() && !setter->IsUndefined()) { | |
191 isolate->Throw(*isolate->factory()->NewTypeError( | |
192 MessageTemplate::kObjectSetterCallable, setter)); | |
193 return false; | |
194 } | |
195 // 21d. Set the [[Set]] field of desc to setter. | |
196 desc->set_set(setter); | |
197 } | |
198 } | |
199 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then | |
200 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, | |
201 // throw a TypeError exception. | |
202 if ((desc->has_get() || desc->has_set()) && | |
203 (desc->has_value() || desc->has_writable())) { | |
204 isolate->Throw(*isolate->factory()->NewTypeError( | |
205 MessageTemplate::kValueAndAccessor, obj)); | |
206 return false; | |
207 } | |
208 } | |
209 } else { | |
210 DCHECK(obj->IsJSProxy()); | |
211 UNIMPLEMENTED(); | |
212 } | |
213 // 23. Return desc. | |
214 return true; | |
215 } | |
216 | |
217 | |
218 } // namespace internal | |
219 } // namespace v8 | |
OLD | NEW |