1 // Copyright 2014 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/runtime/runtime-utils.h" 6 7 #include "src/arguments.h" 8 #include "src/bootstrapper.h" 9 #include "src/debug/debug.h" 10 #include "src/isolate-inl.h" 11 #include "src/messages.h" 12 #include "src/property-descriptor.h" 13 #include "src/runtime/runtime.h" 14 15 namespace v8 { 16 namespace internal { 17 18 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, 19 Handle<Object> object, 20 Handle<Object> key, 21 bool* is_found_out) { 22 if (object->IsNullOrUndefined(isolate)) { 23 THROW_NEW_ERROR( 24 isolate, 25 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), 26 Object); 27 } 28 29 bool success = false; 30 LookupIterator it = 31 LookupIterator::PropertyOrElement(isolate, object, key, &success); 32 if (!success) return MaybeHandle<Object>(); 33 34 MaybeHandle<Object> result = Object::GetProperty(&it); 35 if (is_found_out) *is_found_out = it.IsFound(); 36 return result; 37 } 38 39 static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate, 40 Handle<Object> receiver_obj, 41 Handle<Object> key_obj) { 42 // Fast cases for getting named properties of the receiver JSObject 43 // itself. 44 // 45 // The global proxy objects has to be excluded since LookupOwn on 46 // the global proxy object can return a valid result even though the 47 // global proxy object never has properties. This is the case 48 // because the global proxy object forwards everything to its hidden 49 // prototype including own lookups. 50 // 51 // Additionally, we need to make sure that we do not cache results 52 // for objects that require access checks. 53 if (receiver_obj->IsJSObject()) { 54 if (!receiver_obj->IsJSGlobalProxy() && 55 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { 56 DisallowHeapAllocation no_allocation; 57 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); 58 Handle<Name> key = Handle<Name>::cast(key_obj); 59 // Get to a ThinString's referenced internalized string, but don't 60 // otherwise force internalization. We assume that internalization 61 // (which is a dictionary lookup with a non-internalized key) is 62 // about as expensive as doing the property dictionary lookup with 63 // the non-internalized key directly. 64 if (key->IsThinString()) { 65 key = handle(Handle<ThinString>::cast(key)->actual(), isolate); 66 } 67 if (receiver->IsJSGlobalObject()) { 68 // Attempt dictionary lookup. 69 GlobalDictionary* dictionary = receiver->global_dictionary(); 70 int entry = dictionary->FindEntry(key); 71 if (entry != GlobalDictionary::kNotFound) { 72 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); 73 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); 74 if (cell->property_details().kind() == kData) { 75 Object* value = cell->value(); 76 if (!value->IsTheHole(isolate)) { 77 return Handle<Object>(value, isolate); 78 } 79 // If value is the hole (meaning, absent) do the general lookup. 80 } 81 } 82 } else if (!receiver->HasFastProperties()) { 83 // Attempt dictionary lookup. 84 NameDictionary* dictionary = receiver->property_dictionary(); 85 int entry = dictionary->FindEntry(key); 86 if ((entry != NameDictionary::kNotFound) && 87 (dictionary->DetailsAt(entry).kind() == kData)) { 88 Object* value = dictionary->ValueAt(entry); 89 return Handle<Object>(value, isolate); 90 } 91 } 92 } else if (key_obj->IsSmi()) { 93 // JSObject without a name key. If the key is a Smi, check for a 94 // definite out-of-bounds access to elements, which is a strong indicator 95 // that subsequent accesses will also call the runtime. Proactively 96 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of 97 // doubles for those future calls in the case that the elements would 98 // become FAST_DOUBLE_ELEMENTS. 99 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); 100 ElementsKind elements_kind = js_object->GetElementsKind(); 101 if (IsFastDoubleElementsKind(elements_kind)) { 102 if (Smi::cast(*key_obj)->value() >= js_object->elements()->length()) { 103 elements_kind = IsFastHoleyElementsKind(elements_kind) 104 ? FAST_HOLEY_ELEMENTS 105 : FAST_ELEMENTS; 106 JSObject::TransitionElementsKind(js_object, elements_kind); 107 } 108 } else { 109 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || 110 !IsFastElementsKind(elements_kind)); 111 } 112 } 113 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { 114 // Fast case for string indexing using [] with a smi index. 115 Handle<String> str = Handle<String>::cast(receiver_obj); 116 int index = Handle<Smi>::cast(key_obj)->value(); 117 if (index >= 0 && index < str->length()) { 118 Factory* factory = isolate->factory(); 119 return factory->LookupSingleCharacterStringFromCode( 120 String::Flatten(str)->Get(index)); 121 } 122 } 123 124 // Fall back to GetObjectProperty. 125 return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj); 126 } 127 128 129 Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate, 130 Handle<JSReceiver> receiver, 131 Handle<Object> key, 132 LanguageMode language_mode) { 133 bool success = false; 134 LookupIterator it = LookupIterator::PropertyOrElement( 135 isolate, receiver, key, &success, LookupIterator::OWN); 136 if (!success) return Nothing<bool>(); 137 138 return JSReceiver::DeleteProperty(&it, language_mode); 139 } 140 141 // ES6 19.1.3.2 142 RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) { 143 HandleScope scope(isolate); 144 Handle<Object> property = args.at(1); 145 146 Handle<Name> key; 147 uint32_t index; 148 bool key_is_array_index = property->ToArrayIndex(&index); 149 150 if (!key_is_array_index) { 151 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, 152 Object::ToName(isolate, property)); 153 key_is_array_index = key->AsArrayIndex(&index); 154 } 155 156 Handle<Object> object = args.at(0); 157 158 if (object->IsJSObject()) { 159 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); 160 // Fast case: either the key is a real named property or it is not 161 // an array index and there are no interceptors or hidden 162 // prototypes. 163 // TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to 164 // handle all cases directly (without this custom fast path). 165 { 166 LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR; 167 LookupIterator it = 168 key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c) 169 : LookupIterator(js_obj, key, js_obj, c); 170 Maybe<bool> maybe = JSReceiver::HasProperty(&it); 171 if (maybe.IsNothing()) return isolate->heap()->exception(); 172 DCHECK(!isolate->has_pending_exception()); 173 if (maybe.FromJust()) return isolate->heap()->true_value(); 174 } 175 176 Map* map = js_obj->map(); 177 if (!map->has_hidden_prototype() && 178 (key_is_array_index ? !map->has_indexed_interceptor() 179 : !map->has_named_interceptor())) { 180 return isolate->heap()->false_value(); 181 } 182 183 // Slow case. 184 LookupIterator::Configuration c = LookupIterator::OWN; 185 LookupIterator it = key_is_array_index 186 ? LookupIterator(isolate, js_obj, index, js_obj, c) 187 : LookupIterator(js_obj, key, js_obj, c); 188 189 Maybe<bool> maybe = JSReceiver::HasProperty(&it); 190 if (maybe.IsNothing()) return isolate->heap()->exception(); 191 DCHECK(!isolate->has_pending_exception()); 192 return isolate->heap()->ToBoolean(maybe.FromJust()); 193 194 } else if (object->IsJSProxy()) { 195 if (key.is_null()) { 196 DCHECK(key_is_array_index); 197 key = isolate->factory()->Uint32ToString(index); 198 } 199 200 Maybe<bool> result = 201 JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key); 202 if (!result.IsJust()) return isolate->heap()->exception(); 203 return isolate->heap()->ToBoolean(result.FromJust()); 204 205 } else if (object->IsString()) { 206 return isolate->heap()->ToBoolean( 207 key_is_array_index 208 ? index < static_cast<uint32_t>(String::cast(*object)->length()) 209 : key->Equals(isolate->heap()->length_string())); 210 } else if (object->IsNullOrUndefined(isolate)) { 211 THROW_NEW_ERROR_RETURN_FAILURE( 212 isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject)); 213 } 214 215 return isolate->heap()->false_value(); 216 } 217 218 // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) 219 // TODO(verwaest): Support the common cases with precached map directly in 220 // an Object.create stub. 221 RUNTIME_FUNCTION(Runtime_ObjectCreate) { 222 HandleScope scope(isolate); 223 Handle<Object> prototype = args.at(0); 224 if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { 225 THROW_NEW_ERROR_RETURN_FAILURE( 226 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); 227 } 228 229 // Generate the map with the specified {prototype} based on the Object 230 // function's initial map from the current native context. 231 // TODO(bmeurer): Use a dedicated cache for Object.create; think about 232 // slack tracking for Object.create. 233 Handle<Map> map = 234 Map::GetObjectCreateMap(Handle<HeapObject>::cast(prototype)); 235 236 bool is_dictionary_map = map->is_dictionary_map(); 237 Handle<FixedArray> object_properties; 238 if (is_dictionary_map) { 239 // Allocate the actual properties dictionay up front to avoid invalid object 240 // state. 241 object_properties = 242 NameDictionary::New(isolate, NameDictionary::kInitialCapacity); 243 } 244 // Actually allocate the object. 245 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map); 246 if (is_dictionary_map) { 247 object->set_properties(*object_properties); 248 } 249 250 // Define the properties if properties was specified and is not undefined. 251 Handle<Object> properties = args.at(1); 252 if (!properties->IsUndefined(isolate)) { 253 RETURN_FAILURE_ON_EXCEPTION( 254 isolate, JSReceiver::DefineProperties(isolate, object, properties)); 255 } 256 257 return *object; 258 } 259 260 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, 261 Handle<Object> object, 262 Handle<Object> key, 263 Handle<Object> value, 264 LanguageMode language_mode) { 265 if (object->IsNullOrUndefined(isolate)) { 266 THROW_NEW_ERROR( 267 isolate, 268 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), 269 Object); 270 } 271 272 // Check if the given key is an array index. 273 bool success = false; 274 LookupIterator it = 275 LookupIterator::PropertyOrElement(isolate, object, key, &success); 276 if (!success) return MaybeHandle<Object>(); 277 278 MAYBE_RETURN_NULL(Object::SetProperty(&it, value, language_mode, 279 Object::MAY_BE_STORE_FROM_KEYED)); 280 return value; 281 } 282 283 284 RUNTIME_FUNCTION(Runtime_GetPrototype) { 285 HandleScope scope(isolate); 286 DCHECK_EQ(1, args.length()); 287 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 288 RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj)); 289 } 290 291 292 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { 293 HandleScope scope(isolate); 294 DCHECK_EQ(2, args.length()); 295 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 296 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 297 MAYBE_RETURN( 298 JSReceiver::SetPrototype(obj, prototype, false, Object::THROW_ON_ERROR), 299 isolate->heap()->exception()); 300 return *obj; 301 } 302 303 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { 304 HandleScope scope(isolate); 305 DCHECK_EQ(2, args.length()); 306 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 307 CONVERT_SMI_ARG_CHECKED(properties, 1); 308 // Conservative upper limit to prevent fuzz tests from going OOM. 309 if (properties > 100000) return isolate->ThrowIllegalOperation(); 310 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { 311 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties, 312 "OptimizeForAdding"); 313 } 314 return *object; 315 } 316 317 318 RUNTIME_FUNCTION(Runtime_GetProperty) { 319 HandleScope scope(isolate); 320 DCHECK_EQ(2, args.length()); 321 322 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 323 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 324 325 RETURN_RESULT_OR_FAILURE(isolate, 326 Runtime::GetObjectProperty(isolate, object, key)); 327 } 328 329 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. 330 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { 331 HandleScope scope(isolate); 332 DCHECK_EQ(2, args.length()); 333 334 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); 335 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); 336 337 RETURN_RESULT_OR_FAILURE( 338 isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj)); 339 } 340 341 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { 342 HandleScope scope(isolate); 343 DCHECK_EQ(4, args.length()); 344 345 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 346 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 347 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 348 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 349 350 #ifdef DEBUG 351 uint32_t index = 0; 352 DCHECK(!name->ToArrayIndex(&index)); 353 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); 354 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 355 if (!maybe.IsJust()) return isolate->heap()->exception(); 356 CHECK(!it.IsFound()); 357 #endif 358 359 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnPropertyIgnoreAttributes( 360 object, name, value, attrs)); 361 } 362 363 364 // Adds an element to an array. 365 // This is used to create an indexed data property into an array. 366 RUNTIME_FUNCTION(Runtime_AddElement) { 367 HandleScope scope(isolate); 368 DCHECK_EQ(3, args.length()); 369 370 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 371 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 372 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 373 374 uint32_t index = 0; 375 CHECK(key->ToArrayIndex(&index)); 376 377 #ifdef DEBUG 378 LookupIterator it(isolate, object, index, object, 379 LookupIterator::OWN_SKIP_INTERCEPTOR); 380 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 381 if (!maybe.IsJust()) return isolate->heap()->exception(); 382 CHECK(!it.IsFound()); 383 384 if (object->IsJSArray()) { 385 Handle<JSArray> array = Handle<JSArray>::cast(object); 386 CHECK(!JSArray::WouldChangeReadOnlyLength(array, index)); 387 } 388 #endif 389 390 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnElementIgnoreAttributes( 391 object, index, value, NONE)); 392 } 393 394 395 RUNTIME_FUNCTION(Runtime_AppendElement) { 396 HandleScope scope(isolate); 397 DCHECK_EQ(2, args.length()); 398 399 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 400 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 401 CHECK(!value->IsTheHole(isolate)); 402 403 uint32_t index; 404 CHECK(array->length()->ToArrayIndex(&index)); 405 406 RETURN_FAILURE_ON_EXCEPTION( 407 isolate, JSObject::AddDataElement(array, index, value, NONE)); 408 JSObject::ValidateElements(array); 409 return *array; 410 } 411 412 413 RUNTIME_FUNCTION(Runtime_SetProperty) { 414 HandleScope scope(isolate); 415 DCHECK_EQ(4, args.length()); 416 417 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 418 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 419 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 420 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); 421 422 RETURN_RESULT_OR_FAILURE( 423 isolate, 424 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 425 } 426 427 428 namespace { 429 430 // ES6 section 12.5.4. 431 Object* DeleteProperty(Isolate* isolate, Handle<Object> object, 432 Handle<Object> key, LanguageMode language_mode) { 433 Handle<JSReceiver> receiver; 434 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 435 Object::ToObject(isolate, object)); 436 Maybe<bool> result = 437 Runtime::DeleteObjectProperty(isolate, receiver, key, language_mode); 438 MAYBE_RETURN(result, isolate->heap()->exception()); 439 return isolate->heap()->ToBoolean(result.FromJust()); 440 } 441 442 } // namespace 443 444 445 RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy) { 446 HandleScope scope(isolate); 447 DCHECK_EQ(2, args.length()); 448 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 449 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 450 return DeleteProperty(isolate, object, key, SLOPPY); 451 } 452 453 454 RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict) { 455 HandleScope scope(isolate); 456 DCHECK_EQ(2, args.length()); 457 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 458 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 459 return DeleteProperty(isolate, object, key, STRICT); 460 } 461 462 463 // ES6 section 12.9.3, operator in. 464 RUNTIME_FUNCTION(Runtime_HasProperty) { 465 HandleScope scope(isolate); 466 DCHECK_EQ(2, args.length()); 467 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 468 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 469 470 // Check that {object} is actually a receiver. 471 if (!object->IsJSReceiver()) { 472 THROW_NEW_ERROR_RETURN_FAILURE( 473 isolate, 474 NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object)); 475 } 476 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 477 478 // Convert the {key} to a name. 479 Handle<Name> name; 480 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 481 Object::ToName(isolate, key)); 482 483 // Lookup the {name} on {receiver}. 484 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name); 485 if (!maybe.IsJust()) return isolate->heap()->exception(); 486 return isolate->heap()->ToBoolean(maybe.FromJust()); 487 } 488 489 490 RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) { 491 HandleScope scope(isolate); 492 DCHECK_EQ(2, args.length()); 493 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 494 CONVERT_SMI_ARG_CHECKED(filter_value, 1); 495 PropertyFilter filter = static_cast<PropertyFilter>(filter_value); 496 497 Handle<FixedArray> keys; 498 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 499 isolate, keys, 500 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, filter, 501 GetKeysConversion::kConvertToString)); 502 503 return *isolate->factory()->NewJSArrayWithElements(keys); 504 } 505 506 507 // Return information on whether an object has a named or indexed interceptor. 508 // args[0]: object 509 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { 510 HandleScope scope(isolate); 511 DCHECK_EQ(1, args.length()); 512 if (!args[0]->IsJSObject()) { 513 return Smi::kZero; 514 } 515 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 516 517 int result = 0; 518 if (obj->HasNamedInterceptor()) result |= 2; 519 if (obj->HasIndexedInterceptor()) result |= 1; 520 521 return Smi::FromInt(result); 522 } 523 524 525 RUNTIME_FUNCTION(Runtime_ToFastProperties) { 526 HandleScope scope(isolate); 527 DCHECK_EQ(1, args.length()); 528 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 529 if (object->IsJSObject() && !object->IsJSGlobalObject()) { 530 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0, 531 "RuntimeToFastProperties"); 532 } 533 return *object; 534 } 535 536 537 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { 538 HandleScope scope(isolate); 539 DCHECK_EQ(0, args.length()); 540 return *isolate->factory()->NewHeapNumber(0); 541 } 542 543 544 RUNTIME_FUNCTION(Runtime_NewObject) { 545 HandleScope scope(isolate); 546 DCHECK_EQ(2, args.length()); 547 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 548 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); 549 RETURN_RESULT_OR_FAILURE(isolate, JSObject::New(target, new_target)); 550 } 551 552 553 RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) { 554 HandleScope scope(isolate); 555 DCHECK_EQ(1, args.length()); 556 557 CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0); 558 initial_map->CompleteInobjectSlackTracking(); 559 560 return isolate->heap()->undefined_value(); 561 } 562 563 564 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { 565 HandleScope scope(isolate); 566 DCHECK_EQ(2, args.length()); 567 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 568 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); 569 CHECK((index->value() & 1) == 1); 570 FieldIndex field_index = 571 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); 572 if (field_index.is_inobject()) { 573 CHECK(field_index.property_index() < 574 object->map()->GetInObjectProperties()); 575 } else { 576 CHECK(field_index.outobject_array_index() < object->properties()->length()); 577 } 578 return *JSObject::FastPropertyAt(object, Representation::Double(), 579 field_index); 580 } 581 582 583 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { 584 HandleScope scope(isolate); 585 DCHECK_EQ(1, args.length()); 586 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 587 if (!object->IsJSObject()) return Smi::kZero; 588 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 589 // It could have been a DCHECK but we call this function directly from tests. 590 if (!js_object->map()->is_deprecated()) return Smi::kZero; 591 // This call must not cause lazy deopts, because it's called from deferred 592 // code where we can't handle lazy deopts for lack of a suitable bailout 593 // ID. So we just try migration and signal failure if necessary, 594 // which will also trigger a deopt. 595 if (!JSObject::TryMigrateInstance(js_object)) return Smi::kZero; 596 return *object; 597 } 598 599 600 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { 601 SealHandleScope shs(isolate); 602 DCHECK_EQ(1, args.length()); 603 CONVERT_ARG_CHECKED(Object, obj, 0); 604 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); 605 } 606 607 static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) { 608 return obj->IsNullOrUndefined(isolate) || obj->IsCallable(); 609 } 610 611 612 // Implements part of 8.12.9 DefineOwnProperty. 613 // There are 3 cases that lead here: 614 // Step 4b - define a new accessor property. 615 // Steps 9c & 12 - replace an existing data property with an accessor property. 616 // Step 12 - update an existing accessor property with an accessor or generic 617 // descriptor. 618 RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) { 619 HandleScope scope(isolate); 620 DCHECK_EQ(5, args.length()); 621 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 622 CHECK(!obj->IsNull(isolate)); 623 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 624 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 625 CHECK(IsValidAccessor(isolate, getter)); 626 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 627 CHECK(IsValidAccessor(isolate, setter)); 628 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 4); 629 630 RETURN_FAILURE_ON_EXCEPTION( 631 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs)); 632 return isolate->heap()->undefined_value(); 633 } 634 635 636 RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { 637 HandleScope scope(isolate); 638 DCHECK_EQ(6, args.length()); 639 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 640 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 641 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 642 CONVERT_SMI_ARG_CHECKED(flag, 3); 643 CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 4); 644 CONVERT_SMI_ARG_CHECKED(index, 5); 645 646 StoreDataPropertyInLiteralICNexus nexus(vector, vector->ToSlot(index)); 647 if (nexus.ic_state() == UNINITIALIZED) { 648 if (name->IsUniqueName()) { 649 nexus.ConfigureMonomorphic(name, handle(object->map())); 650 } else { 651 nexus.ConfigureMegamorphic(); 652 } 653 } else if (nexus.ic_state() == MONOMORPHIC) { 654 if (nexus.FindFirstMap() != object->map() || 655 nexus.GetFeedbackExtra() != *name) { 656 nexus.ConfigureMegamorphic(); 657 } 658 } 659 660 DataPropertyInLiteralFlags flags = 661 static_cast<DataPropertyInLiteralFlag>(flag); 662 663 PropertyAttributes attrs = (flags & DataPropertyInLiteralFlag::kDontEnum) 664 ? PropertyAttributes::DONT_ENUM 665 : PropertyAttributes::NONE; 666 667 if (flags & DataPropertyInLiteralFlag::kSetFunctionName) { 668 DCHECK(value->IsJSFunction()); 669 JSFunction::SetName(Handle<JSFunction>::cast(value), name, 670 isolate->factory()->empty_string()); 671 } 672 673 LookupIterator it = LookupIterator::PropertyOrElement( 674 isolate, object, name, object, LookupIterator::OWN); 675 // Cannot fail since this should only be called when 676 // creating an object literal. 677 CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attrs, 678 Object::DONT_THROW) 679 .IsJust()); 680 return *object; 681 } 682 683 // Return property without being observable by accessors or interceptors. 684 RUNTIME_FUNCTION(Runtime_GetDataProperty) { 685 HandleScope scope(isolate); 686 DCHECK_EQ(2, args.length()); 687 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 688 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 689 return *JSReceiver::GetDataProperty(object, name); 690 } 691 692 RUNTIME_FUNCTION(Runtime_GetConstructorName) { 693 HandleScope scope(isolate); 694 DCHECK_EQ(1, args.length()); 695 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 696 697 CHECK(!object->IsNullOrUndefined(isolate)); 698 Handle<JSReceiver> recv = Object::ToObject(isolate, object).ToHandleChecked(); 699 return *JSReceiver::GetConstructorName(recv); 700 } 701 702 RUNTIME_FUNCTION(Runtime_HasFastPackedElements) { 703 SealHandleScope shs(isolate); 704 DCHECK_EQ(1, args.length()); 705 CONVERT_ARG_CHECKED(HeapObject, obj, 0); 706 return isolate->heap()->ToBoolean( 707 IsFastPackedElementsKind(obj->map()->elements_kind())); 708 } 709 710 711 RUNTIME_FUNCTION(Runtime_ValueOf) { 712 SealHandleScope shs(isolate); 713 DCHECK_EQ(1, args.length()); 714 CONVERT_ARG_CHECKED(Object, obj, 0); 715 if (!obj->IsJSValue()) return obj; 716 return JSValue::cast(obj)->value(); 717 } 718 719 720 RUNTIME_FUNCTION(Runtime_IsJSReceiver) { 721 SealHandleScope shs(isolate); 722 DCHECK_EQ(1, args.length()); 723 CONVERT_ARG_CHECKED(Object, obj, 0); 724 return isolate->heap()->ToBoolean(obj->IsJSReceiver()); 725 } 726 727 728 RUNTIME_FUNCTION(Runtime_ClassOf) { 729 SealHandleScope shs(isolate); 730 DCHECK_EQ(1, args.length()); 731 CONVERT_ARG_CHECKED(Object, obj, 0); 732 if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); 733 return JSReceiver::cast(obj)->class_name(); 734 } 735 736 737 RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) { 738 HandleScope scope(isolate); 739 DCHECK_EQ(4, args.length()); 740 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 741 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 742 CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2); 743 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 744 745 if (String::cast(getter->shared()->name())->length() == 0) { 746 JSFunction::SetName(getter, name, isolate->factory()->get_string()); 747 } 748 749 RETURN_FAILURE_ON_EXCEPTION( 750 isolate, 751 JSObject::DefineAccessor(object, name, getter, 752 isolate->factory()->null_value(), attrs)); 753 return isolate->heap()->undefined_value(); 754 } 755 756 RUNTIME_FUNCTION(Runtime_CopyDataProperties) { 757 HandleScope scope(isolate); 758 DCHECK_EQ(2, args.length()); 759 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); 760 CONVERT_ARG_HANDLE_CHECKED(Object, source, 1); 761 762 // 2. If source is undefined or null, let keys be an empty List. 763 if (source->IsUndefined(isolate) || source->IsNull(isolate)) { 764 return isolate->heap()->undefined_value(); 765 } 766 767 MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source, 768 nullptr, false), 769 isolate->heap()->exception()); 770 return isolate->heap()->undefined_value(); 771 } 772 773 RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) { 774 HandleScope scope(isolate); 775 DCHECK_LE(1, args.length()); 776 CONVERT_ARG_HANDLE_CHECKED(Object, source, 0); 777 778 // 2. If source is undefined or null, let keys be an empty List. 779 if (source->IsUndefined(isolate) || source->IsNull(isolate)) { 780 return isolate->heap()->undefined_value(); 781 } 782 783 ScopedVector<Handle<Object>> excluded_properties(args.length() - 1); 784 for (int i = 1; i < args.length(); i++) { 785 Handle<Object> property = args.at(i); 786 uint32_t property_num; 787 // We convert string to number if possible, in cases of computed 788 // properties resolving to numbers, which would've been strings 789 // instead because of our call to %ToName() in the desugaring for 790 // computed properties. 791 if (property->IsString() && 792 String::cast(*property)->AsArrayIndex(&property_num)) { 793 property = isolate->factory()->NewNumberFromUint(property_num); 794 } 795 796 excluded_properties[i - 1] = property; 797 } 798 799 Handle<JSObject> target = 800 isolate->factory()->NewJSObject(isolate->object_function()); 801 MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source, 802 &excluded_properties, false), 803 isolate->heap()->exception()); 804 return *target; 805 } 806 807 RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) { 808 HandleScope scope(isolate); 809 DCHECK_EQ(4, args.length()); 810 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 811 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 812 CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2); 813 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 814 815 if (String::cast(setter->shared()->name())->length() == 0) { 816 JSFunction::SetName(setter, name, isolate->factory()->set_string()); 817 } 818 819 RETURN_FAILURE_ON_EXCEPTION( 820 isolate, 821 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), 822 setter, attrs)); 823 return isolate->heap()->undefined_value(); 824 } 825 826 827 RUNTIME_FUNCTION(Runtime_ToObject) { 828 HandleScope scope(isolate); 829 DCHECK_EQ(1, args.length()); 830 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 831 RETURN_RESULT_OR_FAILURE(isolate, Object::ToObject(isolate, object)); 832 } 833 834 835 RUNTIME_FUNCTION(Runtime_ToPrimitive) { 836 HandleScope scope(isolate); 837 DCHECK_EQ(1, args.length()); 838 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 839 RETURN_RESULT_OR_FAILURE(isolate, Object::ToPrimitive(input)); 840 } 841 842 843 RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) { 844 HandleScope scope(isolate); 845 DCHECK_EQ(1, args.length()); 846 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 847 RETURN_RESULT_OR_FAILURE( 848 isolate, Object::ToPrimitive(input, ToPrimitiveHint::kNumber)); 849 } 850 851 RUNTIME_FUNCTION(Runtime_ToNumber) { 852 HandleScope scope(isolate); 853 DCHECK_EQ(1, args.length()); 854 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 855 RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input)); 856 } 857 858 859 RUNTIME_FUNCTION(Runtime_ToInteger) { 860 HandleScope scope(isolate); 861 DCHECK_EQ(1, args.length()); 862 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 863 RETURN_RESULT_OR_FAILURE(isolate, Object::ToInteger(isolate, input)); 864 } 865 866 867 RUNTIME_FUNCTION(Runtime_ToLength) { 868 HandleScope scope(isolate); 869 DCHECK_EQ(1, args.length()); 870 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 871 RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input)); 872 } 873 874 875 RUNTIME_FUNCTION(Runtime_ToString) { 876 HandleScope scope(isolate); 877 DCHECK_EQ(1, args.length()); 878 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 879 RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input)); 880 } 881 882 883 RUNTIME_FUNCTION(Runtime_ToName) { 884 HandleScope scope(isolate); 885 DCHECK_EQ(1, args.length()); 886 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 887 RETURN_RESULT_OR_FAILURE(isolate, Object::ToName(isolate, input)); 888 } 889 890 891 RUNTIME_FUNCTION(Runtime_SameValue) { 892 SealHandleScope scope(isolate); 893 DCHECK_EQ(2, args.length()); 894 CONVERT_ARG_CHECKED(Object, x, 0); 895 CONVERT_ARG_CHECKED(Object, y, 1); 896 return isolate->heap()->ToBoolean(x->SameValue(y)); 897 } 898 899 900 RUNTIME_FUNCTION(Runtime_SameValueZero) { 901 SealHandleScope scope(isolate); 902 DCHECK_EQ(2, args.length()); 903 CONVERT_ARG_CHECKED(Object, x, 0); 904 CONVERT_ARG_CHECKED(Object, y, 1); 905 return isolate->heap()->ToBoolean(x->SameValueZero(y)); 906 } 907 908 909 // TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan, 910 // GreaterThan, etc. which return true or false. 911 RUNTIME_FUNCTION(Runtime_Compare) { 912 HandleScope scope(isolate); 913 DCHECK_EQ(3, args.length()); 914 CONVERT_ARG_HANDLE_CHECKED(Object, x, 0); 915 CONVERT_ARG_HANDLE_CHECKED(Object, y, 1); 916 CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2); 917 Maybe<ComparisonResult> result = Object::Compare(x, y); 918 if (result.IsJust()) { 919 switch (result.FromJust()) { 920 case ComparisonResult::kLessThan: 921 return Smi::FromInt(LESS); 922 case ComparisonResult::kEqual: 923 return Smi::FromInt(EQUAL); 924 case ComparisonResult::kGreaterThan: 925 return Smi::FromInt(GREATER); 926 case ComparisonResult::kUndefined: 927 return *ncr; 928 } 929 UNREACHABLE(); 930 } 931 return isolate->heap()->exception(); 932 } 933 934 RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) { 935 HandleScope scope(isolate); 936 DCHECK_EQ(2, args.length()); 937 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 938 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 939 Maybe<bool> result = 940 JSReceiver::HasInPrototypeChain(isolate, object, prototype); 941 MAYBE_RETURN(result, isolate->heap()->exception()); 942 return isolate->heap()->ToBoolean(result.FromJust()); 943 } 944 945 946 // ES6 section 7.4.7 CreateIterResultObject ( value, done ) 947 RUNTIME_FUNCTION(Runtime_CreateIterResultObject) { 948 HandleScope scope(isolate); 949 DCHECK_EQ(2, args.length()); 950 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 951 CONVERT_ARG_HANDLE_CHECKED(Object, done, 1); 952 return *isolate->factory()->NewJSIteratorResult(value, done->BooleanValue()); 953 } 954 955 RUNTIME_FUNCTION(Runtime_CreateKeyValueArray) { 956 HandleScope scope(isolate); 957 DCHECK_EQ(2, args.length()); 958 CONVERT_ARG_HANDLE_CHECKED(Object, key, 0); 959 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 960 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(2); 961 elements->set(0, *key); 962 elements->set(1, *value); 963 return *isolate->factory()->NewJSArrayWithElements(elements, FAST_ELEMENTS, 964 2); 965 } 966 967 RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) { 968 SealHandleScope shs(isolate); 969 DCHECK_EQ(1, args.length()); 970 CONVERT_ARG_CHECKED(Object, object, 0); 971 return isolate->heap()->ToBoolean(object->IsAccessCheckNeeded()); 972 } 973 974 975 RUNTIME_FUNCTION(Runtime_CreateDataProperty) { 976 HandleScope scope(isolate); 977 DCHECK_EQ(3, args.length()); 978 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, o, 0); 979 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 980 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 981 bool success; 982 LookupIterator it = LookupIterator::PropertyOrElement( 983 isolate, o, key, &success, LookupIterator::OWN); 984 if (!success) return isolate->heap()->exception(); 985 MAYBE_RETURN( 986 JSReceiver::CreateDataProperty(&it, value, Object::THROW_ON_ERROR), 987 isolate->heap()->exception()); 988 return *value; 989 } 990 991 992 } // namespace internal 993 } // namespace v8 994