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; | |
Toon Verwaest
2015/10/13 11:51:26
The properties below could have been added to Obje
Jakob Kummerow
2015/10/13 12:04:43
Is the map check on the next line not enough to ad
Toon Verwaest
2015/10/13 13:32:14
Acknowledged.
| |
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 // Specifically, instead of taking the attributes != ABSENT shortcut, we | |
122 // have to implement proper HasProperty for proxies. | |
123 if (!obj->IsJSProxy()) { | |
124 { // enumerable? | |
125 Handle<Object> enumerable; | |
126 // 4 through 6b. | |
127 if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), | |
128 &enumerable)) { | |
129 return false; | |
130 } | |
131 // 6c. Set the [[Enumerable]] field of desc to enum. | |
132 if (!enumerable.is_null()) { | |
133 desc->set_enumerable(enumerable->BooleanValue()); | |
134 } | |
135 } | |
136 { // configurable? | |
137 Handle<Object> configurable; | |
138 // 7 through 9b. | |
139 if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), | |
140 &configurable)) { | |
141 return false; | |
142 } | |
143 // 9c. Set the [[Configurable]] field of desc to conf. | |
144 if (!configurable.is_null()) { | |
145 desc->set_configurable(configurable->BooleanValue()); | |
146 } | |
147 } | |
148 { // value? | |
149 Handle<Object> value; | |
150 // 10 through 12b. | |
151 if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), | |
152 &value)) | |
153 return false; | |
154 // 12c. Set the [[Value]] field of desc to value. | |
155 if (!value.is_null()) desc->set_value(value); | |
156 } | |
157 { // writable? | |
158 Handle<Object> writable; | |
159 // 13 through 15b. | |
160 if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), | |
161 &writable)) { | |
162 return false; | |
163 } | |
164 // 15c. Set the [[Writable]] field of desc to writable. | |
165 if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); | |
166 } | |
167 { // getter? | |
168 Handle<Object> getter; | |
169 // 16 through 18b. | |
170 if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) | |
171 return false; | |
172 if (!getter.is_null()) { | |
173 // 18c. If IsCallable(getter) is false and getter is not undefined, | |
174 // throw a TypeError exception. | |
175 if (!getter->IsCallable() && !getter->IsUndefined()) { | |
176 isolate->Throw(*isolate->factory()->NewTypeError( | |
177 MessageTemplate::kObjectGetterCallable, getter)); | |
178 return false; | |
179 } | |
180 // 18d. Set the [[Get]] field of desc to getter. | |
181 desc->set_get(getter); | |
182 } | |
183 { // setter? | |
184 Handle<Object> setter; | |
185 // 19 through 21b. | |
186 if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), | |
187 &setter)) | |
188 return false; | |
189 if (!setter.is_null()) { | |
190 // 21c. If IsCallable(setter) is false and setter is not undefined, | |
191 // throw a TypeError exception. | |
192 if (!setter->IsCallable() && !setter->IsUndefined()) { | |
193 isolate->Throw(*isolate->factory()->NewTypeError( | |
194 MessageTemplate::kObjectSetterCallable, setter)); | |
195 return false; | |
196 } | |
197 // 21d. Set the [[Set]] field of desc to setter. | |
198 desc->set_set(setter); | |
199 } | |
200 } | |
201 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then | |
202 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, | |
203 // throw a TypeError exception. | |
204 if ((desc->has_get() || desc->has_set()) && | |
205 (desc->has_value() || desc->has_writable())) { | |
206 isolate->Throw(*isolate->factory()->NewTypeError( | |
207 MessageTemplate::kValueAndAccessor, obj)); | |
208 return false; | |
209 } | |
210 } | |
211 } else { | |
212 DCHECK(obj->IsJSProxy()); | |
213 UNIMPLEMENTED(); | |
214 } | |
215 // 23. Return desc. | |
216 return true; | |
217 } | |
218 | |
219 | |
220 } // namespace internal | |
221 } // namespace v8 | |
OLD | NEW |