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/heap/factory.h"
9 : #include "src/isolate-inl.h"
10 : #include "src/lookup.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/property-descriptor-object-inl.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 : namespace {
18 :
19 : // Helper function for ToPropertyDescriptor. Comments describe steps for
20 : // "enumerable", other properties are handled the same way.
21 : // Returns false if an exception was thrown.
22 34788 : bool GetPropertyIfPresent(Handle<JSReceiver> receiver, Handle<String> name,
23 : Handle<Object>* value) {
24 34788 : LookupIterator it(receiver, name, receiver);
25 : // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
26 34788 : Maybe<bool> has_property = JSReceiver::HasProperty(&it);
27 : // 5. ReturnIfAbrupt(hasEnumerable).
28 34788 : if (has_property.IsNothing()) return false;
29 : // 6. If hasEnumerable is true, then
30 34788 : if (has_property.FromJust() == true) {
31 : // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
32 : // 6b. ReturnIfAbrupt(enum).
33 22150 : if (!Object::GetProperty(&it).ToHandle(value)) return false;
34 : }
35 : return true;
36 : }
37 :
38 :
39 : // Helper function for ToPropertyDescriptor. Handles the case of "simple"
40 : // objects: nothing on the prototype chain, just own fast data properties.
41 : // Must not have observable side effects, because the slow path will restart
42 : // the entire conversion!
43 276742 : bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<JSReceiver> obj,
44 : PropertyDescriptor* desc) {
45 280592 : if (!obj->IsJSObject()) return false;
46 279170 : Map map = Handle<JSObject>::cast(obj)->map();
47 139585 : if (map->instance_type() != JS_OBJECT_TYPE) return false;
48 139170 : if (map->is_access_check_needed()) return false;
49 278340 : if (map->prototype() != *isolate->initial_object_prototype()) return false;
50 : // During bootstrapping, the object_function_prototype_map hasn't been
51 : // set up yet.
52 136446 : if (isolate->bootstrapper()->IsActive()) return false;
53 409338 : if (JSObject::cast(map->prototype())->map() !=
54 409338 : isolate->native_context()->object_function_prototype_map()) {
55 : return false;
56 : }
57 : // TODO(jkummerow): support dictionary properties?
58 135752 : if (map->is_dictionary_map()) return false;
59 : Handle<DescriptorArray> descs =
60 135320 : Handle<DescriptorArray>(map->instance_descriptors(), isolate);
61 720274 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
62 225675 : PropertyDetails details = descs->GetDetails(i);
63 225675 : Name key = descs->GetKey(i);
64 : Handle<Object> value;
65 225675 : if (details.location() == kField) {
66 225576 : if (details.kind() == kData) {
67 : value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
68 : details.representation(),
69 451152 : FieldIndex::ForDescriptor(map, i));
70 : } else {
71 : DCHECK_EQ(kAccessor, details.kind());
72 : // Bail out to slow path.
73 : return false;
74 : }
75 :
76 : } else {
77 : DCHECK_EQ(kDescriptor, details.location());
78 99 : if (details.kind() == kData) {
79 180 : value = handle(descs->GetStrongValue(i), isolate);
80 : } else {
81 : DCHECK_EQ(kAccessor, details.kind());
82 : // Bail out to slow path.
83 : return false;
84 : }
85 : }
86 : ReadOnlyRoots roots(isolate);
87 225666 : if (key == roots.enumerable_string()) {
88 50502 : desc->set_enumerable(value->BooleanValue(isolate));
89 200415 : } else if (key == roots.configurable_string()) {
90 83404 : desc->set_configurable(value->BooleanValue(isolate));
91 158713 : } else if (key == roots.value_string()) {
92 : desc->set_value(value);
93 93527 : } else if (key == roots.writable_string()) {
94 35830 : desc->set_writable(value->BooleanValue(isolate));
95 57697 : } else if (key == roots.get_string()) {
96 : // Bail out to slow path to throw an exception if necessary.
97 76088 : if (!value->IsCallable()) return false;
98 : desc->set_get(value);
99 19653 : } else if (key == roots.set_string()) {
100 : // Bail out to slow path to throw an exception if necessary.
101 38802 : if (!value->IsCallable()) return false;
102 : desc->set_set(value);
103 : }
104 : }
105 410958 : if ((desc->has_get() || desc->has_set()) &&
106 45163 : (desc->has_value() || desc->has_writable())) {
107 : // Bail out to slow path to throw an exception.
108 : return false;
109 : }
110 134390 : return true;
111 : }
112 :
113 1629 : void CreateDataProperty(Handle<JSObject> object, Handle<String> name,
114 : Handle<Object> value) {
115 1629 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
116 1629 : Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
117 3258 : CHECK(result.IsJust() && result.FromJust());
118 1629 : }
119 :
120 : } // namespace
121 :
122 :
123 : // ES6 6.2.4.4 "FromPropertyDescriptor"
124 18322 : Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
125 : DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
126 : PropertyDescriptor::IsDataDescriptor(this)));
127 : Factory* factory = isolate->factory();
128 18322 : if (IsRegularAccessorProperty()) {
129 : // Fast case for regular accessor properties.
130 : Handle<JSObject> result = factory->NewJSObjectFromMap(
131 86 : isolate->accessor_property_descriptor_map());
132 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
133 86 : *get());
134 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
135 86 : *set());
136 : result->InObjectPropertyAtPut(
137 : JSAccessorPropertyDescriptor::kEnumerableIndex,
138 172 : isolate->heap()->ToBoolean(enumerable()));
139 : result->InObjectPropertyAtPut(
140 : JSAccessorPropertyDescriptor::kConfigurableIndex,
141 172 : isolate->heap()->ToBoolean(configurable()));
142 86 : return result;
143 : }
144 18236 : if (IsRegularDataProperty()) {
145 : // Fast case for regular data properties.
146 : Handle<JSObject> result =
147 9745 : factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
148 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
149 9745 : *value());
150 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
151 19490 : isolate->heap()->ToBoolean(writable()));
152 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
153 19490 : isolate->heap()->ToBoolean(enumerable()));
154 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
155 19490 : isolate->heap()->ToBoolean(configurable()));
156 9745 : return result;
157 : }
158 8491 : Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
159 8491 : if (has_value()) {
160 936 : CreateDataProperty(result, factory->value_string(), value());
161 : }
162 8491 : if (has_writable()) {
163 : CreateDataProperty(result, factory->writable_string(),
164 198 : factory->ToBoolean(writable()));
165 : }
166 8491 : if (has_get()) {
167 108 : CreateDataProperty(result, factory->get_string(), get());
168 : }
169 8491 : if (has_set()) {
170 36 : CreateDataProperty(result, factory->set_string(), set());
171 : }
172 8491 : if (has_enumerable()) {
173 : CreateDataProperty(result, factory->enumerable_string(),
174 216 : factory->ToBoolean(enumerable()));
175 : }
176 8491 : if (has_configurable()) {
177 : CreateDataProperty(result, factory->configurable_string(),
178 684 : factory->ToBoolean(configurable()));
179 : }
180 8491 : return result;
181 : }
182 :
183 :
184 : // ES6 6.2.4.5
185 : // Returns false in case of exception.
186 : // static
187 140449 : 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 280898 : if (!obj->IsJSReceiver()) {
193 : isolate->Throw(*isolate->factory()->NewTypeError(
194 306 : MessageTemplate::kPropertyDescObject, obj));
195 153 : return false;
196 : }
197 : // 3. Let desc be a new Property Descriptor that initially has no fields.
198 : DCHECK(desc->is_empty());
199 :
200 140296 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(obj);
201 140296 : if (ToPropertyDescriptorFastPath(isolate, receiver, desc)) {
202 : return true;
203 : }
204 :
205 : // enumerable?
206 : Handle<Object> enumerable;
207 : // 4 through 6b.
208 5906 : if (!GetPropertyIfPresent(receiver, isolate->factory()->enumerable_string(),
209 5906 : &enumerable)) {
210 : return false;
211 : }
212 : // 6c. Set the [[Enumerable]] field of desc to enum.
213 5870 : if (!enumerable.is_null()) {
214 1508 : desc->set_enumerable(enumerable->BooleanValue(isolate));
215 : }
216 :
217 : // configurable?
218 : Handle<Object> configurable;
219 : // 7 through 9b.
220 5870 : if (!GetPropertyIfPresent(receiver, isolate->factory()->configurable_string(),
221 5870 : &configurable)) {
222 : return false;
223 : }
224 : // 9c. Set the [[Configurable]] field of desc to conf.
225 5870 : if (!configurable.is_null()) {
226 2766 : desc->set_configurable(configurable->BooleanValue(isolate));
227 : }
228 :
229 : // value?
230 : Handle<Object> value;
231 : // 10 through 12b.
232 5870 : if (!GetPropertyIfPresent(receiver, isolate->factory()->value_string(),
233 5870 : &value)) {
234 : return false;
235 : }
236 : // 12c. Set the [[Value]] field of desc to value.
237 5726 : if (!value.is_null()) desc->set_value(value);
238 :
239 : // writable?
240 : Handle<Object> writable;
241 : // 13 through 15b.
242 5726 : if (!GetPropertyIfPresent(receiver, isolate->factory()->writable_string(),
243 5726 : &writable)) {
244 : return false;
245 : }
246 : // 15c. Set the [[Writable]] field of desc to writable.
247 7274 : if (!writable.is_null()) desc->set_writable(writable->BooleanValue(isolate));
248 :
249 : // getter?
250 : Handle<Object> getter;
251 : // 16 through 18b.
252 5726 : if (!GetPropertyIfPresent(receiver, isolate->factory()->get_string(),
253 5726 : &getter)) {
254 : return false;
255 : }
256 5726 : if (!getter.is_null()) {
257 : // 18c. If IsCallable(getter) is false and getter is not undefined,
258 : // throw a TypeError exception.
259 7130 : if (!getter->IsCallable() && !getter->IsUndefined(isolate)) {
260 : isolate->Throw(*isolate->factory()->NewTypeError(
261 72 : MessageTemplate::kObjectGetterCallable, getter));
262 36 : 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 5690 : if (!GetPropertyIfPresent(receiver, isolate->factory()->set_string(),
271 5690 : &setter)) {
272 : return false;
273 : }
274 5690 : if (!setter.is_null()) {
275 : // 21c. If IsCallable(setter) is false and setter is not undefined,
276 : // throw a TypeError exception.
277 8880 : if (!setter->IsCallable() && !setter->IsUndefined(isolate)) {
278 : isolate->Throw(*isolate->factory()->NewTypeError(
279 54 : MessageTemplate::kObjectSetterCallable, setter));
280 27 : 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 17763 : if ((desc->has_get() || desc->has_set()) &&
290 3943 : (desc->has_value() || desc->has_writable())) {
291 : isolate->Throw(*isolate->factory()->NewTypeError(
292 180 : MessageTemplate::kValueAndAccessor, obj));
293 90 : return false;
294 : }
295 :
296 : // 23. Return desc.
297 : return true;
298 : }
299 :
300 :
301 : // ES6 6.2.4.6
302 : // static
303 4185 : 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 4185 : if (!IsAccessorDescriptor(desc)) {
314 : // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
315 : // like.[[Value]].
316 3978 : 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 3978 : 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 207 : 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 207 : 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 4185 : 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 4185 : if (!desc->has_configurable()) desc->set_configurable(false);
341 : // 8. Return Desc.
342 4185 : }
343 :
344 74258 : Handle<PropertyDescriptorObject> PropertyDescriptor::ToPropertyDescriptorObject(
345 : Isolate* isolate) {
346 : Handle<PropertyDescriptorObject> obj = Handle<PropertyDescriptorObject>::cast(
347 74258 : isolate->factory()->NewFixedArray(PropertyDescriptorObject::kLength));
348 :
349 : int flags =
350 148516 : PropertyDescriptorObject::IsEnumerableBit::encode(enumerable_) |
351 148516 : PropertyDescriptorObject::HasEnumerableBit::encode(has_enumerable_) |
352 148516 : PropertyDescriptorObject::IsConfigurableBit::encode(configurable_) |
353 148516 : PropertyDescriptorObject::HasConfigurableBit::encode(has_configurable_) |
354 148516 : PropertyDescriptorObject::IsWritableBit::encode(writable_) |
355 148516 : PropertyDescriptorObject::HasWritableBit::encode(has_writable_) |
356 74258 : PropertyDescriptorObject::HasValueBit::encode(has_value()) |
357 74258 : PropertyDescriptorObject::HasGetBit::encode(has_get()) |
358 74258 : PropertyDescriptorObject::HasSetBit::encode(has_set());
359 :
360 : obj->set(PropertyDescriptorObject::kFlagsIndex, Smi::FromInt(flags));
361 :
362 148516 : obj->set(PropertyDescriptorObject::kValueIndex,
363 150314 : has_value() ? *value_ : ReadOnlyRoots(isolate).the_hole_value());
364 148516 : obj->set(PropertyDescriptorObject::kGetIndex,
365 220976 : has_get() ? *get_ : ReadOnlyRoots(isolate).the_hole_value());
366 148516 : obj->set(PropertyDescriptorObject::kSetIndex,
367 220976 : has_set() ? *set_ : ReadOnlyRoots(isolate).the_hole_value());
368 :
369 74258 : return obj;
370 : }
371 :
372 : } // namespace internal
373 183867 : } // namespace v8
|