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