Line data Source code
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/bootstrapper.h"
8 : #include "src/factory.h"
9 : #include "src/isolate-inl.h"
10 : #include "src/lookup.h"
11 : #include "src/objects-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : namespace {
17 :
18 : // Helper function for ToPropertyDescriptor. Comments describe steps for
19 : // "enumerable", other properties are handled the same way.
20 : // Returns false if an exception was thrown.
21 50109 : bool GetPropertyIfPresent(Handle<JSReceiver> receiver, Handle<String> name,
22 : Handle<Object>* value) {
23 50109 : LookupIterator it(receiver, name, receiver);
24 : // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
25 50109 : Maybe<bool> has_property = JSReceiver::HasProperty(&it);
26 : // 5. ReturnIfAbrupt(hasEnumerable).
27 50109 : if (has_property.IsNothing()) return false;
28 : // 6. If hasEnumerable is true, then
29 50109 : if (has_property.FromJust() == true) {
30 : // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
31 : // 6b. ReturnIfAbrupt(enum).
32 32734 : if (!Object::GetProperty(&it).ToHandle(value)) return false;
33 : }
34 : return true;
35 : }
36 :
37 :
38 : // Helper function for ToPropertyDescriptor. Handles the case of "simple"
39 : // objects: nothing on the prototype chain, just own fast data properties.
40 : // Must not have observable side effects, because the slow path will restart
41 : // the entire conversion!
42 949071 : bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<JSReceiver> obj,
43 : PropertyDescriptor* desc) {
44 476562 : if (!obj->IsJSObject()) return false;
45 : Map* map = Handle<JSObject>::cast(obj)->map();
46 475456 : if (map->instance_type() != JS_OBJECT_TYPE) return false;
47 474857 : if (map->is_access_check_needed()) return false;
48 949714 : if (map->prototype() != *isolate->initial_object_prototype()) return false;
49 : // During bootstrapping, the object_function_prototype_map hasn't been
50 : // set up yet.
51 472509 : if (isolate->bootstrapper()->IsActive()) return false;
52 472114 : if (JSObject::cast(map->prototype())->map() !=
53 944228 : isolate->native_context()->object_function_prototype_map()) {
54 : return false;
55 : }
56 : // TODO(jkummerow): support dictionary properties?
57 470147 : if (map->is_dictionary_map()) return false;
58 : Handle<DescriptorArray> descs =
59 : Handle<DescriptorArray>(map->instance_descriptors());
60 2719442 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
61 891564 : PropertyDetails details = descs->GetDetails(i);
62 : Name* key = descs->GetKey(i);
63 : Handle<Object> value;
64 891564 : if (details.location() == kField) {
65 891415 : if (details.kind() == kData) {
66 : value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
67 : details.representation(),
68 1782830 : FieldIndex::ForDescriptor(map, i));
69 : } else {
70 : DCHECK_EQ(kAccessor, details.kind());
71 : // Bail out to slow path.
72 : return false;
73 : }
74 :
75 : } else {
76 : DCHECK_EQ(kDescriptor, details.location());
77 149 : if (details.kind() == kData) {
78 : value = handle(descs->GetValue(i), isolate);
79 : } else {
80 : DCHECK_EQ(kAccessor, details.kind());
81 : // Bail out to slow path.
82 : return false;
83 : }
84 : }
85 2862859 : Heap* heap = isolate->heap();
86 891549 : if (key == heap->enumerable_string()) {
87 130293 : desc->set_enumerable(value->BooleanValue());
88 761256 : } else if (key == heap->configurable_string()) {
89 84684 : desc->set_configurable(value->BooleanValue());
90 676572 : } else if (key == heap->value_string()) {
91 : desc->set_value(value);
92 415733 : } else if (key == heap->writable_string()) {
93 328272 : desc->set_writable(value->BooleanValue());
94 87461 : } else if (key == heap->get_string()) {
95 : // Bail out to slow path to throw an exception if necessary.
96 57173 : if (!value->IsCallable()) return false;
97 : desc->set_get(value);
98 30288 : } else if (key == heap->set_string()) {
99 : // Bail out to slow path to throw an exception if necessary.
100 29794 : if (!value->IsCallable()) return false;
101 : desc->set_set(value);
102 : }
103 : }
104 1416170 : if ((desc->has_get() || desc->has_set()) &&
105 68186 : (desc->has_value() || desc->has_writable())) {
106 : // Bail out to slow path to throw an exception.
107 : return false;
108 : }
109 468042 : return true;
110 : }
111 :
112 :
113 2562 : void CreateDataProperty(Isolate* isolate, Handle<JSObject> object,
114 : Handle<String> name, Handle<Object> value) {
115 2562 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
116 2562 : Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
117 5124 : CHECK(result.IsJust() && result.FromJust());
118 2562 : }
119 :
120 : } // namespace
121 :
122 :
123 : // ES6 6.2.4.4 "FromPropertyDescriptor"
124 3487879 : Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
125 : DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
126 : PropertyDescriptor::IsDataDescriptor(this)));
127 : Factory* factory = isolate->factory();
128 3487879 : if (IsRegularAccessorProperty()) {
129 : // Fast case for regular accessor properties.
130 : Handle<JSObject> result = factory->NewJSObjectFromMap(
131 16335 : isolate->accessor_property_descriptor_map());
132 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
133 16335 : *get());
134 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
135 16335 : *set());
136 : result->InObjectPropertyAtPut(
137 : JSAccessorPropertyDescriptor::kEnumerableIndex,
138 16335 : isolate->heap()->ToBoolean(enumerable()));
139 : result->InObjectPropertyAtPut(
140 : JSAccessorPropertyDescriptor::kConfigurableIndex,
141 16335 : isolate->heap()->ToBoolean(configurable()));
142 16335 : return result;
143 : }
144 3471544 : if (IsRegularDataProperty()) {
145 : // Fast case for regular data properties.
146 : Handle<JSObject> result =
147 3469402 : factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
148 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
149 3469402 : *value());
150 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
151 3469402 : isolate->heap()->ToBoolean(writable()));
152 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
153 3469402 : isolate->heap()->ToBoolean(enumerable()));
154 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
155 3469402 : isolate->heap()->ToBoolean(configurable()));
156 3469402 : return result;
157 : }
158 2142 : Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
159 2142 : if (has_value()) {
160 1442 : CreateDataProperty(isolate, result, factory->value_string(), value());
161 : }
162 2142 : if (has_writable()) {
163 : CreateDataProperty(isolate, result, factory->writable_string(),
164 308 : factory->ToBoolean(writable()));
165 : }
166 2142 : if (has_get()) {
167 175 : CreateDataProperty(isolate, result, factory->get_string(), get());
168 : }
169 2142 : if (has_set()) {
170 63 : CreateDataProperty(isolate, result, factory->set_string(), set());
171 : }
172 2142 : if (has_enumerable()) {
173 : CreateDataProperty(isolate, result, factory->enumerable_string(),
174 364 : factory->ToBoolean(enumerable()));
175 : }
176 2142 : if (has_configurable()) {
177 : CreateDataProperty(isolate, result, factory->configurable_string(),
178 1092 : factory->ToBoolean(configurable()));
179 : }
180 2142 : return result;
181 : }
182 :
183 :
184 : // ES6 6.2.4.5
185 : // Returns false in case of exception.
186 : // static
187 476805 : bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
188 : Handle<Object> obj,
189 : PropertyDescriptor* desc) {
190 : // 1. ReturnIfAbrupt(Obj).
191 : // 2. If Type(Obj) is not Object, throw a TypeError exception.
192 476805 : if (!obj->IsJSReceiver()) {
193 : isolate->Throw(*isolate->factory()->NewTypeError(
194 486 : MessageTemplate::kPropertyDescObject, obj));
195 243 : return false;
196 : }
197 : // 3. Let desc be a new Property Descriptor that initially has no fields.
198 : DCHECK(desc->is_empty());
199 :
200 476562 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(obj);
201 476562 : if (ToPropertyDescriptorFastPath(isolate, receiver, desc)) {
202 : return true;
203 : }
204 :
205 : // enumerable?
206 : Handle<Object> enumerable;
207 : // 4 through 6b.
208 8520 : if (!GetPropertyIfPresent(receiver, isolate->factory()->enumerable_string(),
209 8520 : &enumerable)) {
210 : return false;
211 : }
212 : // 6c. Set the [[Enumerable]] field of desc to enum.
213 8464 : if (!enumerable.is_null()) {
214 1887 : desc->set_enumerable(enumerable->BooleanValue());
215 : }
216 :
217 : // configurable?
218 : Handle<Object> configurable;
219 : // 7 through 9b.
220 8464 : if (!GetPropertyIfPresent(receiver, isolate->factory()->configurable_string(),
221 8464 : &configurable)) {
222 : return false;
223 : }
224 : // 9c. Set the [[Configurable]] field of desc to conf.
225 8464 : if (!configurable.is_null()) {
226 2591 : desc->set_configurable(configurable->BooleanValue());
227 : }
228 :
229 : // value?
230 : Handle<Object> value;
231 : // 10 through 12b.
232 8464 : if (!GetPropertyIfPresent(receiver, isolate->factory()->value_string(),
233 8464 : &value)) {
234 : return false;
235 : }
236 : // 12c. Set the [[Value]] field of desc to value.
237 8240 : if (!value.is_null()) desc->set_value(value);
238 :
239 : // writable?
240 : Handle<Object> writable;
241 : // 13 through 15b.
242 8240 : if (!GetPropertyIfPresent(receiver, isolate->factory()->writable_string(),
243 8240 : &writable)) {
244 : return false;
245 : }
246 : // 15c. Set the [[Writable]] field of desc to writable.
247 10384 : if (!writable.is_null()) desc->set_writable(writable->BooleanValue());
248 :
249 : // getter?
250 : Handle<Object> getter;
251 : // 16 through 18b.
252 8240 : if (!GetPropertyIfPresent(receiver, isolate->factory()->get_string(),
253 8240 : &getter)) {
254 : return false;
255 : }
256 8240 : if (!getter.is_null()) {
257 : // 18c. If IsCallable(getter) is false and getter is not undefined,
258 : // throw a TypeError exception.
259 3634 : if (!getter->IsCallable() && !getter->IsUndefined(isolate)) {
260 : isolate->Throw(*isolate->factory()->NewTypeError(
261 118 : MessageTemplate::kObjectGetterCallable, getter));
262 59 : return false;
263 : }
264 : // 18d. Set the [[Get]] field of desc to getter.
265 : desc->set_get(getter);
266 : }
267 : // setter?
268 : Handle<Object> setter;
269 : // 19 through 21b.
270 8181 : if (!GetPropertyIfPresent(receiver, isolate->factory()->set_string(),
271 8181 : &setter)) {
272 : return false;
273 : }
274 8181 : if (!setter.is_null()) {
275 : // 21c. If IsCallable(setter) is false and setter is not undefined,
276 : // throw a TypeError exception.
277 4918 : if (!setter->IsCallable() && !setter->IsUndefined(isolate)) {
278 : isolate->Throw(*isolate->factory()->NewTypeError(
279 88 : MessageTemplate::kObjectSetterCallable, setter));
280 44 : return false;
281 : }
282 : // 21d. Set the [[Set]] field of desc to setter.
283 : desc->set_set(setter);
284 : }
285 :
286 : // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
287 : // 22a. If either desc.[[Value]] or desc.[[Writable]] is present,
288 : // throw a TypeError exception.
289 25578 : if ((desc->has_get() || desc->has_set()) &&
290 4167 : (desc->has_value() || desc->has_writable())) {
291 : isolate->Throw(*isolate->factory()->NewTypeError(
292 288 : MessageTemplate::kValueAndAccessor, obj));
293 144 : return false;
294 : }
295 :
296 : // 23. Return desc.
297 : return true;
298 : }
299 :
300 :
301 : // ES6 6.2.4.6
302 : // static
303 6062 : void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate,
304 : PropertyDescriptor* desc) {
305 : // 1. ReturnIfAbrupt(Desc).
306 : // 2. Assert: Desc is a Property Descriptor.
307 : // 3. Let like be Record{
308 : // [[Value]]: undefined, [[Writable]]: false,
309 : // [[Get]]: undefined, [[Set]]: undefined,
310 : // [[Enumerable]]: false, [[Configurable]]: false}.
311 : // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true,
312 : // then:
313 6062 : if (!IsAccessorDescriptor(desc)) {
314 : // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
315 : // like.[[Value]].
316 5768 : if (!desc->has_value()) {
317 : desc->set_value(isolate->factory()->undefined_value());
318 : }
319 : // 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]]
320 : // to like.[[Writable]].
321 5768 : if (!desc->has_writable()) desc->set_writable(false);
322 : } else {
323 : // 5. Else,
324 : // 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to
325 : // like.[[Get]].
326 294 : if (!desc->has_get()) {
327 : desc->set_get(isolate->factory()->undefined_value());
328 : }
329 : // 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to
330 : // like.[[Set]].
331 294 : if (!desc->has_set()) {
332 : desc->set_set(isolate->factory()->undefined_value());
333 : }
334 : }
335 : // 6. If Desc does not have an [[Enumerable]] field, set
336 : // Desc.[[Enumerable]] to like.[[Enumerable]].
337 6062 : if (!desc->has_enumerable()) desc->set_enumerable(false);
338 : // 7. If Desc does not have a [[Configurable]] field, set
339 : // Desc.[[Configurable]] to like.[[Configurable]].
340 6062 : if (!desc->has_configurable()) desc->set_configurable(false);
341 : // 8. Return Desc.
342 6062 : }
343 :
344 : } // namespace internal
345 : } // namespace v8
|