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/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
10 : #include "src/isolate-inl.h"
11 : #include "src/lookup.h"
12 : #include "src/objects-inl.h"
13 : #include "src/objects/property-descriptor-object-inl.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : namespace {
19 :
20 : // Helper function for ToPropertyDescriptor. Comments describe steps for
21 : // "enumerable", other properties are handled the same way.
22 : // Returns false if an exception was thrown.
23 35646 : bool GetPropertyIfPresent(Handle<JSReceiver> receiver, Handle<String> name,
24 : Handle<Object>* value) {
25 : LookupIterator it(receiver, name, receiver);
26 : // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
27 35646 : Maybe<bool> has_property = JSReceiver::HasProperty(&it);
28 : // 5. ReturnIfAbrupt(hasEnumerable).
29 35646 : if (has_property.IsNothing()) return false;
30 : // 6. If hasEnumerable is true, then
31 35646 : if (has_property.FromJust() == true) {
32 : // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
33 : // 6b. ReturnIfAbrupt(enum).
34 22382 : if (!Object::GetProperty(&it).ToHandle(value)) return false;
35 : }
36 : return true;
37 : }
38 :
39 :
40 : // Helper function for ToPropertyDescriptor. Handles the case of "simple"
41 : // objects: nothing on the prototype chain, just own fast data properties.
42 : // Must not have observable side effects, because the slow path will restart
43 : // the entire conversion!
44 141188 : bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<JSReceiver> obj,
45 : PropertyDescriptor* desc) {
46 141188 : if (!obj->IsJSObject()) return false;
47 : Map map = Handle<JSObject>::cast(obj)->map();
48 140477 : if (map->instance_type() != JS_OBJECT_TYPE) return false;
49 140053 : if (map->is_access_check_needed()) return false;
50 280106 : if (map->prototype() != *isolate->initial_object_prototype()) return false;
51 : // During bootstrapping, the object_function_prototype_map hasn't been
52 : // set up yet.
53 137329 : if (isolate->bootstrapper()->IsActive()) return false;
54 137329 : if (JSObject::cast(map->prototype())->map() !=
55 411987 : isolate->native_context()->object_function_prototype_map()) {
56 : return false;
57 : }
58 : // TODO(jkummerow): support dictionary properties?
59 136501 : if (map->is_dictionary_map()) return false;
60 : Handle<DescriptorArray> descs =
61 : Handle<DescriptorArray>(map->instance_descriptors(), isolate);
62 584603 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
63 225125 : PropertyDetails details = descs->GetDetails(i);
64 : Name key = descs->GetKey(i);
65 : Handle<Object> value;
66 225125 : if (details.location() == kField) {
67 225116 : if (details.kind() == kData) {
68 : value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
69 : details.representation(),
70 450232 : FieldIndex::ForDescriptor(map, i));
71 : } else {
72 : DCHECK_EQ(kAccessor, details.kind());
73 : // Bail out to slow path.
74 : return false;
75 : }
76 :
77 : } else {
78 : DCHECK_EQ(kDescriptor, details.location());
79 9 : if (details.kind() == kData) {
80 : value = handle(descs->GetStrongValue(i), isolate);
81 : } else {
82 : DCHECK_EQ(kAccessor, details.kind());
83 : // Bail out to slow path.
84 : return false;
85 : }
86 : }
87 : ReadOnlyRoots roots(isolate);
88 225116 : if (key == roots.enumerable_string()) {
89 50260 : desc->set_enumerable(value->BooleanValue(isolate));
90 199986 : } else if (key == roots.configurable_string()) {
91 83148 : desc->set_configurable(value->BooleanValue(isolate));
92 158412 : } else if (key == roots.value_string()) {
93 : desc->set_value(value);
94 93373 : } else if (key == roots.writable_string()) {
95 71408 : desc->set_writable(value->BooleanValue(isolate));
96 57669 : } else if (key == roots.get_string()) {
97 : // Bail out to slow path to throw an exception if necessary.
98 38012 : if (!value->IsCallable()) return false;
99 : desc->set_get(value);
100 19657 : } else if (key == roots.set_string()) {
101 : // Bail out to slow path to throw an exception if necessary.
102 19396 : if (!value->IsCallable()) return false;
103 : desc->set_set(value);
104 : }
105 : }
106 413240 : if ((desc->has_get() || desc->has_set()) &&
107 45166 : (desc->has_value() || desc->has_writable())) {
108 : // Bail out to slow path to throw an exception.
109 : return false;
110 : }
111 135139 : return true;
112 : }
113 :
114 1629 : void CreateDataProperty(Handle<JSObject> object, Handle<String> name,
115 : Handle<Object> value) {
116 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
117 1629 : Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
118 3258 : CHECK(result.IsJust() && result.FromJust());
119 1629 : }
120 :
121 : } // namespace
122 :
123 :
124 : // ES6 6.2.4.4 "FromPropertyDescriptor"
125 19037 : Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
126 : DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
127 : PropertyDescriptor::IsDataDescriptor(this)));
128 : Factory* factory = isolate->factory();
129 19037 : if (IsRegularAccessorProperty()) {
130 : // Fast case for regular accessor properties.
131 : Handle<JSObject> result = factory->NewJSObjectFromMap(
132 86 : isolate->accessor_property_descriptor_map());
133 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
134 86 : *get());
135 : result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
136 86 : *set());
137 : result->InObjectPropertyAtPut(
138 : JSAccessorPropertyDescriptor::kEnumerableIndex,
139 172 : isolate->heap()->ToBoolean(enumerable()));
140 : result->InObjectPropertyAtPut(
141 : JSAccessorPropertyDescriptor::kConfigurableIndex,
142 172 : isolate->heap()->ToBoolean(configurable()));
143 86 : return result;
144 : }
145 18951 : if (IsRegularDataProperty()) {
146 : // Fast case for regular data properties.
147 : Handle<JSObject> result =
148 9565 : factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
149 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
150 9565 : *value());
151 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
152 19130 : isolate->heap()->ToBoolean(writable()));
153 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
154 19130 : isolate->heap()->ToBoolean(enumerable()));
155 : result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
156 19130 : isolate->heap()->ToBoolean(configurable()));
157 9565 : return result;
158 : }
159 9386 : Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
160 9386 : if (has_value()) {
161 936 : CreateDataProperty(result, factory->value_string(), value());
162 : }
163 9386 : if (has_writable()) {
164 99 : CreateDataProperty(result, factory->writable_string(),
165 99 : factory->ToBoolean(writable()));
166 : }
167 9386 : if (has_get()) {
168 108 : CreateDataProperty(result, factory->get_string(), get());
169 : }
170 9386 : if (has_set()) {
171 36 : CreateDataProperty(result, factory->set_string(), set());
172 : }
173 9386 : if (has_enumerable()) {
174 108 : CreateDataProperty(result, factory->enumerable_string(),
175 108 : factory->ToBoolean(enumerable()));
176 : }
177 9386 : if (has_configurable()) {
178 342 : CreateDataProperty(result, factory->configurable_string(),
179 342 : factory->ToBoolean(configurable()));
180 : }
181 9386 : return result;
182 : }
183 :
184 :
185 : // ES6 6.2.4.5
186 : // Returns false in case of exception.
187 : // static
188 141341 : bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
189 : Handle<Object> obj,
190 : PropertyDescriptor* desc) {
191 : // 1. ReturnIfAbrupt(Obj).
192 : // 2. If Type(Obj) is not Object, throw a TypeError exception.
193 141341 : if (!obj->IsJSReceiver()) {
194 306 : isolate->Throw(*isolate->factory()->NewTypeError(
195 306 : MessageTemplate::kPropertyDescObject, obj));
196 153 : return false;
197 : }
198 : // 3. Let desc be a new Property Descriptor that initially has no fields.
199 : DCHECK(desc->is_empty());
200 :
201 141188 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(obj);
202 141188 : if (ToPropertyDescriptorFastPath(isolate, receiver, desc)) {
203 : return true;
204 : }
205 :
206 : // enumerable?
207 : Handle<Object> enumerable;
208 : // 4 through 6b.
209 6049 : if (!GetPropertyIfPresent(receiver, isolate->factory()->enumerable_string(),
210 : &enumerable)) {
211 : return false;
212 : }
213 : // 6c. Set the [[Enumerable]] field of desc to enum.
214 6013 : if (!enumerable.is_null()) {
215 1508 : desc->set_enumerable(enumerable->BooleanValue(isolate));
216 : }
217 :
218 : // configurable?
219 : Handle<Object> configurable;
220 : // 7 through 9b.
221 6013 : if (!GetPropertyIfPresent(receiver, isolate->factory()->configurable_string(),
222 : &configurable)) {
223 : return false;
224 : }
225 : // 9c. Set the [[Configurable]] field of desc to conf.
226 6013 : if (!configurable.is_null()) {
227 2730 : desc->set_configurable(configurable->BooleanValue(isolate));
228 : }
229 :
230 : // value?
231 : Handle<Object> value;
232 : // 10 through 12b.
233 6013 : if (!GetPropertyIfPresent(receiver, isolate->factory()->value_string(),
234 : &value)) {
235 : return false;
236 : }
237 : // 12c. Set the [[Value]] field of desc to value.
238 5869 : if (!value.is_null()) desc->set_value(value);
239 :
240 : // writable?
241 : Handle<Object> writable;
242 : // 13 through 15b.
243 5869 : if (!GetPropertyIfPresent(receiver, isolate->factory()->writable_string(),
244 : &writable)) {
245 : return false;
246 : }
247 : // 15c. Set the [[Writable]] field of desc to writable.
248 7417 : if (!writable.is_null()) desc->set_writable(writable->BooleanValue(isolate));
249 :
250 : // getter?
251 : Handle<Object> getter;
252 : // 16 through 18b.
253 5869 : if (!GetPropertyIfPresent(receiver, isolate->factory()->get_string(),
254 : &getter)) {
255 : return false;
256 : }
257 5869 : if (!getter.is_null()) {
258 : // 18c. If IsCallable(getter) is false and getter is not undefined,
259 : // throw a TypeError exception.
260 3528 : if (!getter->IsCallable() && !getter->IsUndefined(isolate)) {
261 72 : isolate->Throw(*isolate->factory()->NewTypeError(
262 72 : MessageTemplate::kObjectGetterCallable, getter));
263 36 : return false;
264 : }
265 : // 18d. Set the [[Get]] field of desc to getter.
266 : desc->set_get(getter);
267 : }
268 : // setter?
269 : Handle<Object> setter;
270 : // 19 through 21b.
271 5833 : if (!GetPropertyIfPresent(receiver, isolate->factory()->set_string(),
272 : &setter)) {
273 : return false;
274 : }
275 5833 : if (!setter.is_null()) {
276 : // 21c. If IsCallable(setter) is false and setter is not undefined,
277 : // throw a TypeError exception.
278 4611 : if (!setter->IsCallable() && !setter->IsUndefined(isolate)) {
279 54 : isolate->Throw(*isolate->factory()->NewTypeError(
280 54 : MessageTemplate::kObjectSetterCallable, setter));
281 27 : return false;
282 : }
283 : // 21d. Set the [[Set]] field of desc to setter.
284 : desc->set_set(setter);
285 : }
286 :
287 : // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
288 : // 22a. If either desc.[[Value]] or desc.[[Writable]] is present,
289 : // throw a TypeError exception.
290 18363 : if ((desc->has_get() || desc->has_set()) &&
291 4077 : (desc->has_value() || desc->has_writable())) {
292 180 : isolate->Throw(*isolate->factory()->NewTypeError(
293 180 : MessageTemplate::kValueAndAccessor, obj));
294 90 : return false;
295 : }
296 :
297 : // 23. Return desc.
298 : return true;
299 : }
300 :
301 :
302 : // ES6 6.2.4.6
303 : // static
304 3987 : void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate,
305 : PropertyDescriptor* desc) {
306 : // 1. ReturnIfAbrupt(Desc).
307 : // 2. Assert: Desc is a Property Descriptor.
308 : // 3. Let like be Record{
309 : // [[Value]]: undefined, [[Writable]]: false,
310 : // [[Get]]: undefined, [[Set]]: undefined,
311 : // [[Enumerable]]: false, [[Configurable]]: false}.
312 : // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true,
313 : // then:
314 3987 : if (!IsAccessorDescriptor(desc)) {
315 : // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
316 : // like.[[Value]].
317 3780 : if (!desc->has_value()) {
318 : desc->set_value(isolate->factory()->undefined_value());
319 : }
320 : // 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]]
321 : // to like.[[Writable]].
322 3780 : if (!desc->has_writable()) desc->set_writable(false);
323 : } else {
324 : // 5. Else,
325 : // 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to
326 : // like.[[Get]].
327 207 : if (!desc->has_get()) {
328 : desc->set_get(isolate->factory()->undefined_value());
329 : }
330 : // 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to
331 : // like.[[Set]].
332 207 : if (!desc->has_set()) {
333 : desc->set_set(isolate->factory()->undefined_value());
334 : }
335 : }
336 : // 6. If Desc does not have an [[Enumerable]] field, set
337 : // Desc.[[Enumerable]] to like.[[Enumerable]].
338 3987 : if (!desc->has_enumerable()) desc->set_enumerable(false);
339 : // 7. If Desc does not have a [[Configurable]] field, set
340 : // Desc.[[Configurable]] to like.[[Configurable]].
341 3987 : if (!desc->has_configurable()) desc->set_configurable(false);
342 : // 8. Return Desc.
343 3987 : }
344 :
345 74072 : Handle<PropertyDescriptorObject> PropertyDescriptor::ToPropertyDescriptorObject(
346 : Isolate* isolate) {
347 : Handle<PropertyDescriptorObject> obj = Handle<PropertyDescriptorObject>::cast(
348 74072 : isolate->factory()->NewFixedArray(PropertyDescriptorObject::kLength));
349 :
350 : int flags =
351 148144 : PropertyDescriptorObject::IsEnumerableBit::encode(enumerable_) |
352 148144 : PropertyDescriptorObject::HasEnumerableBit::encode(has_enumerable_) |
353 148144 : PropertyDescriptorObject::IsConfigurableBit::encode(configurable_) |
354 148144 : PropertyDescriptorObject::HasConfigurableBit::encode(has_configurable_) |
355 148144 : PropertyDescriptorObject::IsWritableBit::encode(writable_) |
356 148144 : PropertyDescriptorObject::HasWritableBit::encode(has_writable_) |
357 74072 : PropertyDescriptorObject::HasValueBit::encode(has_value()) |
358 74072 : PropertyDescriptorObject::HasGetBit::encode(has_get()) |
359 74072 : PropertyDescriptorObject::HasSetBit::encode(has_set());
360 :
361 : obj->set(PropertyDescriptorObject::kFlagsIndex, Smi::FromInt(flags));
362 :
363 224014 : obj->set(PropertyDescriptorObject::kValueIndex,
364 74072 : has_value() ? *value_ : ReadOnlyRoots(isolate).the_hole_value());
365 294490 : obj->set(PropertyDescriptorObject::kGetIndex,
366 74072 : has_get() ? *get_ : ReadOnlyRoots(isolate).the_hole_value());
367 294490 : obj->set(PropertyDescriptorObject::kSetIndex,
368 74072 : has_set() ? *set_ : ReadOnlyRoots(isolate).the_hole_value());
369 :
370 74072 : return obj;
371 : }
372 :
373 : } // namespace internal
374 122036 : } // namespace v8
|