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 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 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 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 ) 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 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 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 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 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 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 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> 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 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__ 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__ 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__ 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__ 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 ) 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 ) 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 ) 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__ 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__ 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 ) 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 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 ) 715 BUILTIN(ObjectGetOwnPropertyNames) { 716 return GetOwnPropertyKeys(isolate, args, SKIP_SYMBOLS); 717 } 718 719 // ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O ) 720 BUILTIN(ObjectGetOwnPropertySymbols) { 721 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS); 722 } 723 724 // ES#sec-object.is Object.is ( value1, value2 ) 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 ) 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 ) 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 ) 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 ) 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 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 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 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 ) 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 ) 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 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 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 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 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 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 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 ) 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 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