1 // Copyright 2016 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/builtins/builtins-object.h"
6 #include "src/builtins/builtins-utils.h"
7 #include "src/builtins/builtins.h"
8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h"
10 #include "src/counters.h"
11 #include "src/keys.h"
12 #include "src/lookup.h"
13 #include "src/objects-inl.h"
14 #include "src/property-descriptor.h"
15
16 namespace v8 {
17 namespace internal {
18
19 typedef compiler::Node Node;
20
EmitForInPrepare(Node * object,Node * context,Label * call_runtime,Label * nothing_to_iterate)21 std::tuple<Node*, Node*, Node*> ObjectBuiltinsAssembler::EmitForInPrepare(
22 Node* object, Node* context, Label* call_runtime,
23 Label* nothing_to_iterate) {
24 Label use_cache(this);
25 CSA_ASSERT(this, IsJSReceiver(object));
26
27 CheckEnumCache(object, &use_cache, call_runtime);
28 Bind(&use_cache);
29 Node* map = LoadMap(object);
30 Node* enum_length = EnumLength(map);
31 GotoIf(WordEqual(enum_length, SmiConstant(0)), nothing_to_iterate);
32 Node* descriptors = LoadMapDescriptors(map);
33 Node* cache_offset =
34 LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
35 Node* enum_cache = LoadObjectField(
36 cache_offset, DescriptorArray::kEnumCacheBridgeCacheOffset);
37
38 return std::make_tuple(map, enum_cache, enum_length);
39 }
40 // -----------------------------------------------------------------------------
41 // ES6 section 19.1 Object Objects
42
TF_BUILTIN(ObjectHasOwnProperty,ObjectBuiltinsAssembler)43 TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
44 Node* object = Parameter(0);
45 Node* key = Parameter(1);
46 Node* context = Parameter(4);
47
48 Label call_runtime(this), return_true(this), return_false(this);
49
50 // Smi receivers do not have own properties.
51 Label if_objectisnotsmi(this);
52 Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi);
53 Bind(&if_objectisnotsmi);
54
55 Node* map = LoadMap(object);
56 Node* instance_type = LoadMapInstanceType(map);
57
58 {
59 Variable var_index(this, MachineType::PointerRepresentation());
60 Variable var_unique(this, MachineRepresentation::kTagged);
61
62 Label keyisindex(this), if_iskeyunique(this);
63 TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique,
64 &call_runtime);
65
66 Bind(&if_iskeyunique);
67 TryHasOwnProperty(object, map, instance_type, var_unique.value(),
68 &return_true, &return_false, &call_runtime);
69
70 Bind(&keyisindex);
71 // Handle negative keys in the runtime.
72 GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime);
73 TryLookupElement(object, map, instance_type, var_index.value(),
74 &return_true, &return_false, &call_runtime);
75 }
76 Bind(&return_true);
77 Return(BooleanConstant(true));
78
79 Bind(&return_false);
80 Return(BooleanConstant(false));
81
82 Bind(&call_runtime);
83 Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
84 }
85
86 // ES6 19.1.2.1 Object.assign
BUILTIN(ObjectAssign)87 BUILTIN(ObjectAssign) {
88 HandleScope scope(isolate);
89 Handle<Object> target = args.atOrUndefined(isolate, 1);
90
91 // 1. Let to be ? ToObject(target).
92 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target,
93 Object::ToObject(isolate, target));
94 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target);
95 // 2. If only one argument was passed, return to.
96 if (args.length() == 2) return *to;
97 // 3. Let sources be the List of argument values starting with the
98 // second argument.
99 // 4. For each element nextSource of sources, in ascending index order,
100 for (int i = 2; i < args.length(); ++i) {
101 Handle<Object> next_source = args.at(i);
102 MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, to, next_source),
103 isolate->heap()->exception());
104 }
105 // 5. Return to.
106 return *to;
107 }
108
109 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V )
BUILTIN(ObjectPrototypePropertyIsEnumerable)110 BUILTIN(ObjectPrototypePropertyIsEnumerable) {
111 HandleScope scope(isolate);
112 Handle<JSReceiver> object;
113 Handle<Name> name;
114 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
115 isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1)));
116 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
117 isolate, object, JSReceiver::ToObject(isolate, args.receiver()));
118 Maybe<PropertyAttributes> maybe =
119 JSReceiver::GetOwnPropertyAttributes(object, name);
120 if (!maybe.IsJust()) return isolate->heap()->exception();
121 if (maybe.FromJust() == ABSENT) return isolate->heap()->false_value();
122 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
123 }
124
IsString(Node * object,Label * if_string,Label * if_notstring)125 void ObjectBuiltinsAssembler::IsString(Node* object, Label* if_string,
126 Label* if_notstring) {
127 Label if_notsmi(this);
128 Branch(TaggedIsSmi(object), if_notstring, &if_notsmi);
129
130 Bind(&if_notsmi);
131 {
132 Node* instance_type = LoadInstanceType(object);
133
134 Branch(IsStringInstanceType(instance_type), if_string, if_notstring);
135 }
136 }
137
ReturnToStringFormat(Node * context,Node * string)138 void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
139 Node* string) {
140 Node* lhs = HeapConstant(factory()->NewStringFromStaticChars("[object "));
141 Node* rhs = HeapConstant(factory()->NewStringFromStaticChars("]"));
142
143 Callable callable =
144 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
145
146 Return(CallStub(callable, context, CallStub(callable, context, lhs, string),
147 rhs));
148 }
149
150 // ES6 section 19.1.3.6 Object.prototype.toString
TF_BUILTIN(ObjectProtoToString,ObjectBuiltinsAssembler)151 TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) {
152 Label return_undefined(this, Label::kDeferred),
153 return_null(this, Label::kDeferred),
154 return_arguments(this, Label::kDeferred), return_array(this),
155 return_api(this, Label::kDeferred), return_object(this),
156 return_regexp(this), return_function(this), return_error(this),
157 return_date(this), return_jsvalue(this),
158 return_jsproxy(this, Label::kDeferred);
159
160 Label if_isproxy(this, Label::kDeferred);
161
162 Label checkstringtag(this);
163 Label if_tostringtag(this), if_notostringtag(this);
164
165 Node* receiver = Parameter(0);
166 Node* context = Parameter(3);
167
168 GotoIf(WordEqual(receiver, UndefinedConstant()), &return_undefined);
169
170 GotoIf(WordEqual(receiver, NullConstant()), &return_null);
171
172 Callable to_object = CodeFactory::ToObject(isolate());
173 receiver = CallStub(to_object, context, receiver);
174
175 Node* receiver_instance_type = LoadInstanceType(receiver);
176
177 // for proxies, check IsArray before getting @@toStringTag
178 Variable var_proxy_is_array(this, MachineRepresentation::kTagged);
179 var_proxy_is_array.Bind(BooleanConstant(false));
180
181 Branch(Word32Equal(receiver_instance_type, Int32Constant(JS_PROXY_TYPE)),
182 &if_isproxy, &checkstringtag);
183
184 Bind(&if_isproxy);
185 {
186 // This can throw
187 var_proxy_is_array.Bind(
188 CallRuntime(Runtime::kArrayIsArray, context, receiver));
189 Goto(&checkstringtag);
190 }
191
192 Bind(&checkstringtag);
193 {
194 Node* to_string_tag_symbol =
195 HeapConstant(isolate()->factory()->to_string_tag_symbol());
196
197 GetPropertyStub stub(isolate());
198 Callable get_property =
199 Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
200 Node* to_string_tag_value =
201 CallStub(get_property, context, receiver, to_string_tag_symbol);
202
203 IsString(to_string_tag_value, &if_tostringtag, &if_notostringtag);
204
205 Bind(&if_tostringtag);
206 ReturnToStringFormat(context, to_string_tag_value);
207 }
208 Bind(&if_notostringtag);
209 {
210 size_t const kNumCases = 11;
211 Label* case_labels[kNumCases];
212 int32_t case_values[kNumCases];
213 case_labels[0] = &return_api;
214 case_values[0] = JS_API_OBJECT_TYPE;
215 case_labels[1] = &return_api;
216 case_values[1] = JS_SPECIAL_API_OBJECT_TYPE;
217 case_labels[2] = &return_arguments;
218 case_values[2] = JS_ARGUMENTS_TYPE;
219 case_labels[3] = &return_array;
220 case_values[3] = JS_ARRAY_TYPE;
221 case_labels[4] = &return_function;
222 case_values[4] = JS_BOUND_FUNCTION_TYPE;
223 case_labels[5] = &return_function;
224 case_values[5] = JS_FUNCTION_TYPE;
225 case_labels[6] = &return_error;
226 case_values[6] = JS_ERROR_TYPE;
227 case_labels[7] = &return_date;
228 case_values[7] = JS_DATE_TYPE;
229 case_labels[8] = &return_regexp;
230 case_values[8] = JS_REGEXP_TYPE;
231 case_labels[9] = &return_jsvalue;
232 case_values[9] = JS_VALUE_TYPE;
233 case_labels[10] = &return_jsproxy;
234 case_values[10] = JS_PROXY_TYPE;
235
236 Switch(receiver_instance_type, &return_object, case_values, case_labels,
237 arraysize(case_values));
238
239 Bind(&return_undefined);
240 Return(HeapConstant(isolate()->factory()->undefined_to_string()));
241
242 Bind(&return_null);
243 Return(HeapConstant(isolate()->factory()->null_to_string()));
244
245 Bind(&return_arguments);
246 Return(HeapConstant(isolate()->factory()->arguments_to_string()));
247
248 Bind(&return_array);
249 Return(HeapConstant(isolate()->factory()->array_to_string()));
250
251 Bind(&return_function);
252 Return(HeapConstant(isolate()->factory()->function_to_string()));
253
254 Bind(&return_error);
255 Return(HeapConstant(isolate()->factory()->error_to_string()));
256
257 Bind(&return_date);
258 Return(HeapConstant(isolate()->factory()->date_to_string()));
259
260 Bind(&return_regexp);
261 Return(HeapConstant(isolate()->factory()->regexp_to_string()));
262
263 Bind(&return_api);
264 {
265 Node* class_name = CallRuntime(Runtime::kClassOf, context, receiver);
266 ReturnToStringFormat(context, class_name);
267 }
268
269 Bind(&return_jsvalue);
270 {
271 Label return_boolean(this), return_number(this), return_string(this);
272
273 Node* value = LoadJSValueValue(receiver);
274 GotoIf(TaggedIsSmi(value), &return_number);
275 Node* instance_type = LoadInstanceType(value);
276
277 GotoIf(IsStringInstanceType(instance_type), &return_string);
278 GotoIf(Word32Equal(instance_type, Int32Constant(HEAP_NUMBER_TYPE)),
279 &return_number);
280 GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)),
281 &return_boolean);
282
283 CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE)));
284 Goto(&return_object);
285
286 Bind(&return_string);
287 Return(HeapConstant(isolate()->factory()->string_to_string()));
288
289 Bind(&return_number);
290 Return(HeapConstant(isolate()->factory()->number_to_string()));
291
292 Bind(&return_boolean);
293 Return(HeapConstant(isolate()->factory()->boolean_to_string()));
294 }
295
296 Bind(&return_jsproxy);
297 {
298 GotoIf(WordEqual(var_proxy_is_array.value(), BooleanConstant(true)),
299 &return_array);
300
301 Node* map = LoadMap(receiver);
302
303 // Return object if the proxy {receiver} is not callable.
304 Branch(IsCallableMap(map), &return_function, &return_object);
305 }
306
307 // Default
308 Bind(&return_object);
309 Return(HeapConstant(isolate()->factory()->object_to_string()));
310 }
311 }
312
TF_BUILTIN(ObjectCreate,ObjectBuiltinsAssembler)313 TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
314 Node* prototype = Parameter(1);
315 Node* properties = Parameter(2);
316 Node* context = Parameter(3 + 2);
317
318 Label call_runtime(this, Label::kDeferred), prototype_valid(this),
319 no_properties(this);
320 {
321 Comment("Argument 1 check: prototype");
322 GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid);
323 BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
324 }
325
326 Bind(&prototype_valid);
327 {
328 Comment("Argument 2 check: properties");
329 // Check that we have a simple object
330 GotoIf(TaggedIsSmi(properties), &call_runtime);
331 // Undefined implies no properties.
332 GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties);
333 Node* properties_map = LoadMap(properties);
334 GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
335 // Stay on the fast path only if there are no elements.
336 GotoIfNot(WordEqual(LoadElements(properties),
337 LoadRoot(Heap::kEmptyFixedArrayRootIndex)),
338 &call_runtime);
339 // Handle dictionary objects or fast objects with properties in runtime.
340 Node* bit_field3 = LoadMapBitField3(properties_map);
341 GotoIf(IsSetWord32<Map::DictionaryMap>(bit_field3), &call_runtime);
342 Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
343 &call_runtime, &no_properties);
344 }
345
346 // Create a new object with the given prototype.
347 Bind(&no_properties);
348 {
349 Variable map(this, MachineRepresentation::kTagged);
350 Variable properties(this, MachineRepresentation::kTagged);
351 Label non_null_proto(this), instantiate_map(this), good(this);
352
353 Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto);
354
355 Bind(&good);
356 {
357 map.Bind(LoadContextElement(
358 context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
359 properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
360 Goto(&instantiate_map);
361 }
362
363 Bind(&non_null_proto);
364 {
365 properties.Bind(EmptyFixedArrayConstant());
366 Node* object_function =
367 LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
368 Node* object_function_map = LoadObjectField(
369 object_function, JSFunction::kPrototypeOrInitialMapOffset);
370 map.Bind(object_function_map);
371 GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
372 &instantiate_map);
373 // Try loading the prototype info.
374 Node* prototype_info =
375 LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
376 Comment("Load ObjectCreateMap from PrototypeInfo");
377 Node* weak_cell =
378 LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap);
379 GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime);
380 map.Bind(LoadWeakCellValue(weak_cell, &call_runtime));
381 Goto(&instantiate_map);
382 }
383
384 Bind(&instantiate_map);
385 {
386 Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
387 Return(instance);
388 }
389 }
390
391 Bind(&call_runtime);
392 {
393 Return(CallRuntime(Runtime::kObjectCreate, context, prototype, properties));
394 }
395 }
396
397 // ES6 section 19.1.2.3 Object.defineProperties
BUILTIN(ObjectDefineProperties)398 BUILTIN(ObjectDefineProperties) {
399 HandleScope scope(isolate);
400 DCHECK_EQ(3, args.length());
401 Handle<Object> target = args.at(1);
402 Handle<Object> properties = args.at(2);
403
404 RETURN_RESULT_OR_FAILURE(
405 isolate, JSReceiver::DefineProperties(isolate, target, properties));
406 }
407
408 // ES6 section 19.1.2.4 Object.defineProperty
BUILTIN(ObjectDefineProperty)409 BUILTIN(ObjectDefineProperty) {
410 HandleScope scope(isolate);
411 DCHECK_EQ(4, args.length());
412 Handle<Object> target = args.at(1);
413 Handle<Object> key = args.at(2);
414 Handle<Object> attributes = args.at(3);
415
416 return JSReceiver::DefineProperty(isolate, target, key, attributes);
417 }
418
419 namespace {
420
421 template <AccessorComponent which_accessor>
ObjectDefineAccessor(Isolate * isolate,Handle<Object> object,Handle<Object> name,Handle<Object> accessor)422 Object* ObjectDefineAccessor(Isolate* isolate, Handle<Object> object,
423 Handle<Object> name, Handle<Object> accessor) {
424 // 1. Let O be ? ToObject(this value).
425 Handle<JSReceiver> receiver;
426 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
427 Object::ConvertReceiver(isolate, object));
428 // 2. If IsCallable(getter) is false, throw a TypeError exception.
429 if (!accessor->IsCallable()) {
430 MessageTemplate::Template message =
431 which_accessor == ACCESSOR_GETTER
432 ? MessageTemplate::kObjectGetterExpectingFunction
433 : MessageTemplate::kObjectSetterExpectingFunction;
434 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message));
435 }
436 // 3. Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true,
437 // [[Configurable]]: true}.
438 PropertyDescriptor desc;
439 if (which_accessor == ACCESSOR_GETTER) {
440 desc.set_get(accessor);
441 } else {
442 DCHECK(which_accessor == ACCESSOR_SETTER);
443 desc.set_set(accessor);
444 }
445 desc.set_enumerable(true);
446 desc.set_configurable(true);
447 // 4. Let key be ? ToPropertyKey(P).
448 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
449 Object::ToPropertyKey(isolate, name));
450 // 5. Perform ? DefinePropertyOrThrow(O, key, desc).
451 // To preserve legacy behavior, we ignore errors silently rather than
452 // throwing an exception.
453 Maybe<bool> success = JSReceiver::DefineOwnProperty(
454 isolate, receiver, name, &desc, Object::DONT_THROW);
455 MAYBE_RETURN(success, isolate->heap()->exception());
456 if (!success.FromJust()) {
457 isolate->CountUsage(v8::Isolate::kDefineGetterOrSetterWouldThrow);
458 }
459 // 6. Return undefined.
460 return isolate->heap()->undefined_value();
461 }
462
ObjectLookupAccessor(Isolate * isolate,Handle<Object> object,Handle<Object> key,AccessorComponent component)463 Object* ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
464 Handle<Object> key, AccessorComponent component) {
465 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object,
466 Object::ConvertReceiver(isolate, object));
467 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
468 Object::ToPropertyKey(isolate, key));
469 bool success = false;
470 LookupIterator it = LookupIterator::PropertyOrElement(
471 isolate, object, key, &success,
472 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
473 DCHECK(success);
474
475 for (; it.IsFound(); it.Next()) {
476 switch (it.state()) {
477 case LookupIterator::INTERCEPTOR:
478 case LookupIterator::NOT_FOUND:
479 case LookupIterator::TRANSITION:
480 UNREACHABLE();
481
482 case LookupIterator::ACCESS_CHECK:
483 if (it.HasAccess()) continue;
484 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
485 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
486 return isolate->heap()->undefined_value();
487
488 case LookupIterator::JSPROXY: {
489 PropertyDescriptor desc;
490 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
491 isolate, it.GetHolder<JSProxy>(), it.GetName(), &desc);
492 MAYBE_RETURN(found, isolate->heap()->exception());
493 if (found.FromJust()) {
494 if (component == ACCESSOR_GETTER && desc.has_get()) {
495 return *desc.get();
496 }
497 if (component == ACCESSOR_SETTER && desc.has_set()) {
498 return *desc.set();
499 }
500 return isolate->heap()->undefined_value();
501 }
502 Handle<Object> prototype;
503 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
504 isolate, prototype, JSProxy::GetPrototype(it.GetHolder<JSProxy>()));
505 if (prototype->IsNull(isolate)) {
506 return isolate->heap()->undefined_value();
507 }
508 return ObjectLookupAccessor(isolate, prototype, key, component);
509 }
510
511 case LookupIterator::INTEGER_INDEXED_EXOTIC:
512 case LookupIterator::DATA:
513 return isolate->heap()->undefined_value();
514
515 case LookupIterator::ACCESSOR: {
516 Handle<Object> maybe_pair = it.GetAccessors();
517 if (maybe_pair->IsAccessorPair()) {
518 return *AccessorPair::GetComponent(
519 Handle<AccessorPair>::cast(maybe_pair), component);
520 }
521 }
522 }
523 }
524
525 return isolate->heap()->undefined_value();
526 }
527
528 } // namespace
529
530 // ES6 B.2.2.2 a.k.a.
531 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__
BUILTIN(ObjectDefineGetter)532 BUILTIN(ObjectDefineGetter) {
533 HandleScope scope(isolate);
534 Handle<Object> object = args.at(0); // Receiver.
535 Handle<Object> name = args.at(1);
536 Handle<Object> getter = args.at(2);
537 return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter);
538 }
539
540 // ES6 B.2.2.3 a.k.a.
541 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__
BUILTIN(ObjectDefineSetter)542 BUILTIN(ObjectDefineSetter) {
543 HandleScope scope(isolate);
544 Handle<Object> object = args.at(0); // Receiver.
545 Handle<Object> name = args.at(1);
546 Handle<Object> setter = args.at(2);
547 return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter);
548 }
549
550 // ES6 B.2.2.4 a.k.a.
551 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__
BUILTIN(ObjectLookupGetter)552 BUILTIN(ObjectLookupGetter) {
553 HandleScope scope(isolate);
554 Handle<Object> object = args.at(0);
555 Handle<Object> name = args.at(1);
556 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER);
557 }
558
559 // ES6 B.2.2.5 a.k.a.
560 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__
BUILTIN(ObjectLookupSetter)561 BUILTIN(ObjectLookupSetter) {
562 HandleScope scope(isolate);
563 Handle<Object> object = args.at(0);
564 Handle<Object> name = args.at(1);
565 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER);
566 }
567
568 // ES6 section 19.1.2.5 Object.freeze ( O )
BUILTIN(ObjectFreeze)569 BUILTIN(ObjectFreeze) {
570 HandleScope scope(isolate);
571 Handle<Object> object = args.atOrUndefined(isolate, 1);
572 if (object->IsJSReceiver()) {
573 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
574 FROZEN, Object::THROW_ON_ERROR),
575 isolate->heap()->exception());
576 }
577 return *object;
578 }
579
580 // ES section 19.1.2.9 Object.getPrototypeOf ( O )
BUILTIN(ObjectGetPrototypeOf)581 BUILTIN(ObjectGetPrototypeOf) {
582 HandleScope scope(isolate);
583 Handle<Object> object = args.atOrUndefined(isolate, 1);
584
585 Handle<JSReceiver> receiver;
586 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
587 Object::ToObject(isolate, object));
588
589 RETURN_RESULT_OR_FAILURE(isolate,
590 JSReceiver::GetPrototype(isolate, receiver));
591 }
592
593 // ES6 section 19.1.2.21 Object.setPrototypeOf ( O, proto )
BUILTIN(ObjectSetPrototypeOf)594 BUILTIN(ObjectSetPrototypeOf) {
595 HandleScope scope(isolate);
596
597 // 1. Let O be ? RequireObjectCoercible(O).
598 Handle<Object> object = args.atOrUndefined(isolate, 1);
599 if (object->IsNullOrUndefined(isolate)) {
600 THROW_NEW_ERROR_RETURN_FAILURE(
601 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
602 isolate->factory()->NewStringFromAsciiChecked(
603 "Object.setPrototypeOf")));
604 }
605
606 // 2. If Type(proto) is neither Object nor Null, throw a TypeError exception.
607 Handle<Object> proto = args.atOrUndefined(isolate, 2);
608 if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
609 THROW_NEW_ERROR_RETURN_FAILURE(
610 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto));
611 }
612
613 // 3. If Type(O) is not Object, return O.
614 if (!object->IsJSReceiver()) return *object;
615 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
616
617 // 4. Let status be ? O.[[SetPrototypeOf]](proto).
618 // 5. If status is false, throw a TypeError exception.
619 MAYBE_RETURN(
620 JSReceiver::SetPrototype(receiver, proto, true, Object::THROW_ON_ERROR),
621 isolate->heap()->exception());
622
623 // 6. Return O.
624 return *receiver;
625 }
626
627 // ES6 section B.2.2.1.1 get Object.prototype.__proto__
BUILTIN(ObjectPrototypeGetProto)628 BUILTIN(ObjectPrototypeGetProto) {
629 HandleScope scope(isolate);
630 // 1. Let O be ? ToObject(this value).
631 Handle<JSReceiver> receiver;
632 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
633 isolate, receiver, Object::ToObject(isolate, args.receiver()));
634
635 // 2. Return ? O.[[GetPrototypeOf]]().
636 RETURN_RESULT_OR_FAILURE(isolate,
637 JSReceiver::GetPrototype(isolate, receiver));
638 }
639
640 // ES6 section B.2.2.1.2 set Object.prototype.__proto__
BUILTIN(ObjectPrototypeSetProto)641 BUILTIN(ObjectPrototypeSetProto) {
642 HandleScope scope(isolate);
643 // 1. Let O be ? RequireObjectCoercible(this value).
644 Handle<Object> object = args.receiver();
645 if (object->IsNullOrUndefined(isolate)) {
646 THROW_NEW_ERROR_RETURN_FAILURE(
647 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
648 isolate->factory()->NewStringFromAsciiChecked(
649 "set Object.prototype.__proto__")));
650 }
651
652 // 2. If Type(proto) is neither Object nor Null, return undefined.
653 Handle<Object> proto = args.at(1);
654 if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
655 return isolate->heap()->undefined_value();
656 }
657
658 // 3. If Type(O) is not Object, return undefined.
659 if (!object->IsJSReceiver()) return isolate->heap()->undefined_value();
660 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
661
662 // 4. Let status be ? O.[[SetPrototypeOf]](proto).
663 // 5. If status is false, throw a TypeError exception.
664 MAYBE_RETURN(
665 JSReceiver::SetPrototype(receiver, proto, true, Object::THROW_ON_ERROR),
666 isolate->heap()->exception());
667
668 // Return undefined.
669 return isolate->heap()->undefined_value();
670 }
671
672 // ES6 section 19.1.2.6 Object.getOwnPropertyDescriptor ( O, P )
BUILTIN(ObjectGetOwnPropertyDescriptor)673 BUILTIN(ObjectGetOwnPropertyDescriptor) {
674 HandleScope scope(isolate);
675 // 1. Let obj be ? ToObject(O).
676 Handle<Object> object = args.atOrUndefined(isolate, 1);
677 Handle<JSReceiver> receiver;
678 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
679 Object::ToObject(isolate, object));
680 // 2. Let key be ? ToPropertyKey(P).
681 Handle<Object> property = args.atOrUndefined(isolate, 2);
682 Handle<Name> key;
683 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
684 Object::ToName(isolate, property));
685 // 3. Let desc be ? obj.[[GetOwnProperty]](key).
686 PropertyDescriptor desc;
687 Maybe<bool> found =
688 JSReceiver::GetOwnPropertyDescriptor(isolate, receiver, key, &desc);
689 MAYBE_RETURN(found, isolate->heap()->exception());
690 // 4. Return FromPropertyDescriptor(desc).
691 if (!found.FromJust()) return isolate->heap()->undefined_value();
692 return *desc.ToObject(isolate);
693 }
694
695 namespace {
696
GetOwnPropertyKeys(Isolate * isolate,BuiltinArguments args,PropertyFilter filter)697 Object* GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args,
698 PropertyFilter filter) {
699 HandleScope scope(isolate);
700 Handle<Object> object = args.atOrUndefined(isolate, 1);
701 Handle<JSReceiver> receiver;
702 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
703 Object::ToObject(isolate, object));
704 Handle<FixedArray> keys;
705 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
706 isolate, keys,
707 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
708 GetKeysConversion::kConvertToString));
709 return *isolate->factory()->NewJSArrayWithElements(keys);
710 }
711
712 } // namespace
713
714 // ES6 section 19.1.2.7 Object.getOwnPropertyNames ( O )
BUILTIN(ObjectGetOwnPropertyNames)715 BUILTIN(ObjectGetOwnPropertyNames) {
716 return GetOwnPropertyKeys(isolate, args, SKIP_SYMBOLS);
717 }
718
719 // ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O )
BUILTIN(ObjectGetOwnPropertySymbols)720 BUILTIN(ObjectGetOwnPropertySymbols) {
721 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS);
722 }
723
724 // ES#sec-object.is Object.is ( value1, value2 )
BUILTIN(ObjectIs)725 BUILTIN(ObjectIs) {
726 SealHandleScope shs(isolate);
727 DCHECK_EQ(3, args.length());
728 Handle<Object> value1 = args.at(1);
729 Handle<Object> value2 = args.at(2);
730 return isolate->heap()->ToBoolean(value1->SameValue(*value2));
731 }
732
733 // ES6 section 19.1.2.11 Object.isExtensible ( O )
BUILTIN(ObjectIsExtensible)734 BUILTIN(ObjectIsExtensible) {
735 HandleScope scope(isolate);
736 Handle<Object> object = args.atOrUndefined(isolate, 1);
737 Maybe<bool> result =
738 object->IsJSReceiver()
739 ? JSReceiver::IsExtensible(Handle<JSReceiver>::cast(object))
740 : Just(false);
741 MAYBE_RETURN(result, isolate->heap()->exception());
742 return isolate->heap()->ToBoolean(result.FromJust());
743 }
744
745 // ES6 section 19.1.2.12 Object.isFrozen ( O )
BUILTIN(ObjectIsFrozen)746 BUILTIN(ObjectIsFrozen) {
747 HandleScope scope(isolate);
748 Handle<Object> object = args.atOrUndefined(isolate, 1);
749 Maybe<bool> result = object->IsJSReceiver()
750 ? JSReceiver::TestIntegrityLevel(
751 Handle<JSReceiver>::cast(object), FROZEN)
752 : Just(true);
753 MAYBE_RETURN(result, isolate->heap()->exception());
754 return isolate->heap()->ToBoolean(result.FromJust());
755 }
756
757 // ES6 section 19.1.2.13 Object.isSealed ( O )
BUILTIN(ObjectIsSealed)758 BUILTIN(ObjectIsSealed) {
759 HandleScope scope(isolate);
760 Handle<Object> object = args.atOrUndefined(isolate, 1);
761 Maybe<bool> result = object->IsJSReceiver()
762 ? JSReceiver::TestIntegrityLevel(
763 Handle<JSReceiver>::cast(object), SEALED)
764 : Just(true);
765 MAYBE_RETURN(result, isolate->heap()->exception());
766 return isolate->heap()->ToBoolean(result.FromJust());
767 }
768
769 // ES6 section 19.1.2.14 Object.keys ( O )
BUILTIN(ObjectKeys)770 BUILTIN(ObjectKeys) {
771 HandleScope scope(isolate);
772 Handle<Object> object = args.atOrUndefined(isolate, 1);
773 Handle<JSReceiver> receiver;
774 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
775 Object::ToObject(isolate, object));
776
777 Handle<FixedArray> keys;
778 int enum_length = receiver->map()->EnumLength();
779 if (enum_length != kInvalidEnumCacheSentinel &&
780 JSObject::cast(*receiver)->elements() ==
781 isolate->heap()->empty_fixed_array()) {
782 DCHECK(receiver->IsJSObject());
783 DCHECK(!JSObject::cast(*receiver)->HasNamedInterceptor());
784 DCHECK(!JSObject::cast(*receiver)->IsAccessCheckNeeded());
785 DCHECK(!receiver->map()->has_hidden_prototype());
786 DCHECK(JSObject::cast(*receiver)->HasFastProperties());
787 if (enum_length == 0) {
788 keys = isolate->factory()->empty_fixed_array();
789 } else {
790 Handle<FixedArray> cache(
791 receiver->map()->instance_descriptors()->GetEnumCache());
792 keys = isolate->factory()->CopyFixedArrayUpTo(cache, enum_length);
793 }
794 } else {
795 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
796 isolate, keys,
797 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly,
798 ENUMERABLE_STRINGS,
799 GetKeysConversion::kConvertToString));
800 }
801 return *isolate->factory()->NewJSArrayWithElements(keys, FAST_ELEMENTS);
802 }
803
BUILTIN(ObjectValues)804 BUILTIN(ObjectValues) {
805 HandleScope scope(isolate);
806 Handle<Object> object = args.atOrUndefined(isolate, 1);
807 Handle<JSReceiver> receiver;
808 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
809 Object::ToObject(isolate, object));
810 Handle<FixedArray> values;
811 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
812 isolate, values, JSReceiver::GetOwnValues(receiver, ENUMERABLE_STRINGS));
813 return *isolate->factory()->NewJSArrayWithElements(values);
814 }
815
BUILTIN(ObjectEntries)816 BUILTIN(ObjectEntries) {
817 HandleScope scope(isolate);
818 Handle<Object> object = args.atOrUndefined(isolate, 1);
819 Handle<JSReceiver> receiver;
820 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
821 Object::ToObject(isolate, object));
822 Handle<FixedArray> entries;
823 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
824 isolate, entries,
825 JSReceiver::GetOwnEntries(receiver, ENUMERABLE_STRINGS));
826 return *isolate->factory()->NewJSArrayWithElements(entries);
827 }
828
BUILTIN(ObjectGetOwnPropertyDescriptors)829 BUILTIN(ObjectGetOwnPropertyDescriptors) {
830 HandleScope scope(isolate);
831 Handle<Object> object = args.atOrUndefined(isolate, 1);
832
833 Handle<JSReceiver> receiver;
834 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
835 Object::ToObject(isolate, object));
836
837 Handle<FixedArray> keys;
838 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
839 isolate, keys, KeyAccumulator::GetKeys(
840 receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
841 GetKeysConversion::kConvertToString));
842
843 Handle<JSObject> descriptors =
844 isolate->factory()->NewJSObject(isolate->object_function());
845
846 for (int i = 0; i < keys->length(); ++i) {
847 Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
848 PropertyDescriptor descriptor;
849 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
850 isolate, receiver, key, &descriptor);
851 MAYBE_RETURN(did_get_descriptor, isolate->heap()->exception());
852
853 if (!did_get_descriptor.FromJust()) continue;
854 Handle<Object> from_descriptor = descriptor.ToObject(isolate);
855
856 LookupIterator it = LookupIterator::PropertyOrElement(
857 isolate, descriptors, key, descriptors, LookupIterator::OWN);
858 Maybe<bool> success = JSReceiver::CreateDataProperty(&it, from_descriptor,
859 Object::DONT_THROW);
860 CHECK(success.FromJust());
861 }
862
863 return *descriptors;
864 }
865
866 // ES6 section 19.1.2.15 Object.preventExtensions ( O )
BUILTIN(ObjectPreventExtensions)867 BUILTIN(ObjectPreventExtensions) {
868 HandleScope scope(isolate);
869 Handle<Object> object = args.atOrUndefined(isolate, 1);
870 if (object->IsJSReceiver()) {
871 MAYBE_RETURN(JSReceiver::PreventExtensions(Handle<JSReceiver>::cast(object),
872 Object::THROW_ON_ERROR),
873 isolate->heap()->exception());
874 }
875 return *object;
876 }
877
878 // ES6 section 19.1.2.17 Object.seal ( O )
BUILTIN(ObjectSeal)879 BUILTIN(ObjectSeal) {
880 HandleScope scope(isolate);
881 Handle<Object> object = args.atOrUndefined(isolate, 1);
882 if (object->IsJSReceiver()) {
883 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
884 SEALED, Object::THROW_ON_ERROR),
885 isolate->heap()->exception());
886 }
887 return *object;
888 }
889
TF_BUILTIN(CreateIterResultObject,ObjectBuiltinsAssembler)890 TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
891 typedef CreateIterResultObjectDescriptor Descriptor;
892
893 Node* const value = Parameter(Descriptor::kValue);
894 Node* const done = Parameter(Descriptor::kDone);
895 Node* const context = Parameter(Descriptor::kContext);
896
897 Node* const native_context = LoadNativeContext(context);
898 Node* const map =
899 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
900
901 Node* const result = AllocateJSObjectFromMap(map);
902
903 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
904 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
905
906 Return(result);
907 }
908
TF_BUILTIN(HasProperty,ObjectBuiltinsAssembler)909 TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) {
910 typedef HasPropertyDescriptor Descriptor;
911
912 Node* key = Parameter(Descriptor::kKey);
913 Node* object = Parameter(Descriptor::kObject);
914 Node* context = Parameter(Descriptor::kContext);
915
916 Return(HasProperty(object, key, context, Runtime::kHasProperty));
917 }
918
TF_BUILTIN(ForInFilter,ObjectBuiltinsAssembler)919 TF_BUILTIN(ForInFilter, ObjectBuiltinsAssembler) {
920 typedef ForInFilterDescriptor Descriptor;
921
922 Node* key = Parameter(Descriptor::kKey);
923 Node* object = Parameter(Descriptor::kObject);
924 Node* context = Parameter(Descriptor::kContext);
925
926 Return(ForInFilter(key, object, context));
927 }
928
TF_BUILTIN(ForInNext,ObjectBuiltinsAssembler)929 TF_BUILTIN(ForInNext, ObjectBuiltinsAssembler) {
930 typedef ForInNextDescriptor Descriptor;
931
932 Label filter(this);
933 Node* object = Parameter(Descriptor::kObject);
934 Node* cache_array = Parameter(Descriptor::kCacheArray);
935 Node* cache_type = Parameter(Descriptor::kCacheType);
936 Node* index = Parameter(Descriptor::kIndex);
937 Node* context = Parameter(Descriptor::kContext);
938
939 Node* key = LoadFixedArrayElement(cache_array, SmiUntag(index));
940 Node* map = LoadMap(object);
941 GotoIfNot(WordEqual(map, cache_type), &filter);
942 Return(key);
943 Bind(&filter);
944 Return(ForInFilter(key, object, context));
945 }
946
TF_BUILTIN(ForInPrepare,ObjectBuiltinsAssembler)947 TF_BUILTIN(ForInPrepare, ObjectBuiltinsAssembler) {
948 typedef ForInPrepareDescriptor Descriptor;
949
950 Label call_runtime(this), nothing_to_iterate(this);
951 Node* object = Parameter(Descriptor::kObject);
952 Node* context = Parameter(Descriptor::kContext);
953
954 Node* cache_type;
955 Node* cache_array;
956 Node* cache_length;
957 std::tie(cache_type, cache_array, cache_length) =
958 EmitForInPrepare(object, context, &call_runtime, ¬hing_to_iterate);
959
960 Return(cache_type, cache_array, cache_length);
961
962 Bind(&call_runtime);
963 TailCallRuntime(Runtime::kForInPrepare, context, object);
964
965 Bind(¬hing_to_iterate);
966 {
967 Node* zero = SmiConstant(0);
968 Return(zero, zero, zero);
969 }
970 }
971
TF_BUILTIN(InstanceOf,ObjectBuiltinsAssembler)972 TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
973 typedef CompareDescriptor Descriptor;
974
975 Node* object = Parameter(Descriptor::kLeft);
976 Node* callable = Parameter(Descriptor::kRight);
977 Node* context = Parameter(Descriptor::kContext);
978
979 Return(InstanceOf(object, callable, context));
980 }
981
982 // ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
TF_BUILTIN(OrdinaryHasInstance,ObjectBuiltinsAssembler)983 TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
984 typedef CompareDescriptor Descriptor;
985
986 Node* constructor = Parameter(Descriptor::kLeft);
987 Node* object = Parameter(Descriptor::kRight);
988 Node* context = Parameter(Descriptor::kContext);
989
990 Return(OrdinaryHasInstance(context, constructor, object));
991 }
992
TF_BUILTIN(GetSuperConstructor,ObjectBuiltinsAssembler)993 TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
994 typedef TypeofDescriptor Descriptor;
995
996 Node* object = Parameter(Descriptor::kObject);
997 Node* context = Parameter(Descriptor::kContext);
998
999 Return(GetSuperConstructor(object, context));
1000 }
1001
1002 } // namespace internal
1003 } // namespace v8
1004