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 15namespace v8 { 16namespace internal { 17 18MaybeHandle<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 39static 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 121Maybe<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 134RUNTIME_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// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) 211// TODO(verwaest): Support the common cases with precached map directly in 212// an Object.create stub. 213RUNTIME_FUNCTION(Runtime_ObjectCreate) { 214 HandleScope scope(isolate); 215 Handle<Object> prototype = args.at<Object>(0); 216 if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { 217 THROW_NEW_ERROR_RETURN_FAILURE( 218 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); 219 } 220 221 // Generate the map with the specified {prototype} based on the Object 222 // function's initial map from the current native context. 223 // TODO(bmeurer): Use a dedicated cache for Object.create; think about 224 // slack tracking for Object.create. 225 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), 226 isolate); 227 if (map->prototype() != *prototype) { 228 if (prototype->IsNull(isolate)) { 229 map = isolate->slow_object_with_null_prototype_map(); 230 } else if (prototype->IsJSObject()) { 231 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); 232 if (!js_prototype->map()->is_prototype_map()) { 233 JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); 234 } 235 Handle<PrototypeInfo> info = 236 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); 237 // TODO(verwaest): Use inobject slack tracking for this map. 238 if (info->HasObjectCreateMap()) { 239 map = handle(info->ObjectCreateMap(), isolate); 240 } else { 241 map = Map::CopyInitialMap(map); 242 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 243 PrototypeInfo::SetObjectCreateMap(info, map); 244 } 245 } else { 246 map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); 247 } 248 } 249 250 bool is_dictionary_map = map->is_dictionary_map(); 251 Handle<FixedArray> object_properties; 252 if (is_dictionary_map) { 253 // Allocate the actual properties dictionay up front to avoid invalid object 254 // state. 255 object_properties = 256 NameDictionary::New(isolate, NameDictionary::kInitialCapacity); 257 } 258 // Actually allocate the object. 259 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map); 260 if (is_dictionary_map) { 261 object->set_properties(*object_properties); 262 } 263 264 // Define the properties if properties was specified and is not undefined. 265 Handle<Object> properties = args.at<Object>(1); 266 if (!properties->IsUndefined(isolate)) { 267 RETURN_FAILURE_ON_EXCEPTION( 268 isolate, JSReceiver::DefineProperties(isolate, object, properties)); 269 } 270 271 return *object; 272} 273 274MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, 275 Handle<Object> object, 276 Handle<Object> key, 277 Handle<Object> value, 278 LanguageMode language_mode) { 279 if (object->IsUndefined(isolate) || object->IsNull(isolate)) { 280 THROW_NEW_ERROR( 281 isolate, 282 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), 283 Object); 284 } 285 286 // Check if the given key is an array index. 287 bool success = false; 288 LookupIterator it = 289 LookupIterator::PropertyOrElement(isolate, object, key, &success); 290 if (!success) return MaybeHandle<Object>(); 291 292 MAYBE_RETURN_NULL(Object::SetProperty(&it, value, language_mode, 293 Object::MAY_BE_STORE_FROM_KEYED)); 294 return value; 295} 296 297 298RUNTIME_FUNCTION(Runtime_GetPrototype) { 299 HandleScope scope(isolate); 300 DCHECK(args.length() == 1); 301 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 302 RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj)); 303} 304 305 306RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { 307 HandleScope scope(isolate); 308 DCHECK(args.length() == 2); 309 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 310 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 311 MAYBE_RETURN( 312 JSReceiver::SetPrototype(obj, prototype, false, Object::THROW_ON_ERROR), 313 isolate->heap()->exception()); 314 return *obj; 315} 316 317RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { 318 HandleScope scope(isolate); 319 DCHECK(args.length() == 2); 320 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 321 CONVERT_SMI_ARG_CHECKED(properties, 1); 322 // Conservative upper limit to prevent fuzz tests from going OOM. 323 if (properties > 100000) return isolate->ThrowIllegalOperation(); 324 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { 325 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties, 326 "OptimizeForAdding"); 327 } 328 return *object; 329} 330 331 332RUNTIME_FUNCTION(Runtime_GetProperty) { 333 HandleScope scope(isolate); 334 DCHECK(args.length() == 2); 335 336 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 337 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 338 339 RETURN_RESULT_OR_FAILURE(isolate, 340 Runtime::GetObjectProperty(isolate, object, key)); 341} 342 343// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. 344RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { 345 HandleScope scope(isolate); 346 DCHECK(args.length() == 2); 347 348 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); 349 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); 350 351 RETURN_RESULT_OR_FAILURE( 352 isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj)); 353} 354 355RUNTIME_FUNCTION(Runtime_AddNamedProperty) { 356 HandleScope scope(isolate); 357 DCHECK_EQ(4, args.length()); 358 359 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 360 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 361 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 362 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 363 364#ifdef DEBUG 365 uint32_t index = 0; 366 DCHECK(!name->ToArrayIndex(&index)); 367 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); 368 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 369 if (!maybe.IsJust()) return isolate->heap()->exception(); 370 CHECK(!it.IsFound()); 371#endif 372 373 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnPropertyIgnoreAttributes( 374 object, name, value, attrs)); 375} 376 377 378// Adds an element to an array. 379// This is used to create an indexed data property into an array. 380RUNTIME_FUNCTION(Runtime_AddElement) { 381 HandleScope scope(isolate); 382 DCHECK_EQ(3, args.length()); 383 384 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 385 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 386 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 387 388 uint32_t index = 0; 389 CHECK(key->ToArrayIndex(&index)); 390 391#ifdef DEBUG 392 LookupIterator it(isolate, object, index, object, 393 LookupIterator::OWN_SKIP_INTERCEPTOR); 394 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 395 if (!maybe.IsJust()) return isolate->heap()->exception(); 396 CHECK(!it.IsFound()); 397 398 if (object->IsJSArray()) { 399 Handle<JSArray> array = Handle<JSArray>::cast(object); 400 CHECK(!JSArray::WouldChangeReadOnlyLength(array, index)); 401 } 402#endif 403 404 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnElementIgnoreAttributes( 405 object, index, value, NONE)); 406} 407 408 409RUNTIME_FUNCTION(Runtime_AppendElement) { 410 HandleScope scope(isolate); 411 DCHECK_EQ(2, args.length()); 412 413 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 414 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 415 CHECK(!value->IsTheHole(isolate)); 416 417 uint32_t index; 418 CHECK(array->length()->ToArrayIndex(&index)); 419 420 RETURN_FAILURE_ON_EXCEPTION( 421 isolate, JSObject::AddDataElement(array, index, value, NONE)); 422 JSObject::ValidateElements(array); 423 return *array; 424} 425 426 427RUNTIME_FUNCTION(Runtime_SetProperty) { 428 HandleScope scope(isolate); 429 DCHECK_EQ(4, args.length()); 430 431 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 432 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 433 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 434 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); 435 436 RETURN_RESULT_OR_FAILURE( 437 isolate, 438 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 439} 440 441 442namespace { 443 444// ES6 section 12.5.4. 445Object* DeleteProperty(Isolate* isolate, Handle<Object> object, 446 Handle<Object> key, LanguageMode language_mode) { 447 Handle<JSReceiver> receiver; 448 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 449 Object::ToObject(isolate, object)); 450 Maybe<bool> result = 451 Runtime::DeleteObjectProperty(isolate, receiver, key, language_mode); 452 MAYBE_RETURN(result, isolate->heap()->exception()); 453 return isolate->heap()->ToBoolean(result.FromJust()); 454} 455 456} // namespace 457 458 459RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy) { 460 HandleScope scope(isolate); 461 DCHECK_EQ(2, args.length()); 462 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 463 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 464 return DeleteProperty(isolate, object, key, SLOPPY); 465} 466 467 468RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict) { 469 HandleScope scope(isolate); 470 DCHECK_EQ(2, args.length()); 471 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 472 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 473 return DeleteProperty(isolate, object, key, STRICT); 474} 475 476 477// ES6 section 12.9.3, operator in. 478RUNTIME_FUNCTION(Runtime_HasProperty) { 479 HandleScope scope(isolate); 480 DCHECK_EQ(2, args.length()); 481 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 482 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 483 484 // Check that {object} is actually a receiver. 485 if (!object->IsJSReceiver()) { 486 THROW_NEW_ERROR_RETURN_FAILURE( 487 isolate, 488 NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object)); 489 } 490 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 491 492 // Convert the {key} to a name. 493 Handle<Name> name; 494 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 495 Object::ToName(isolate, key)); 496 497 // Lookup the {name} on {receiver}. 498 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name); 499 if (!maybe.IsJust()) return isolate->heap()->exception(); 500 return isolate->heap()->ToBoolean(maybe.FromJust()); 501} 502 503 504RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) { 505 HandleScope scope(isolate); 506 DCHECK(args.length() == 2); 507 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 508 CONVERT_SMI_ARG_CHECKED(filter_value, 1); 509 PropertyFilter filter = static_cast<PropertyFilter>(filter_value); 510 511 Handle<FixedArray> keys; 512 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 513 isolate, keys, 514 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, filter, 515 GetKeysConversion::kConvertToString)); 516 517 return *isolate->factory()->NewJSArrayWithElements(keys); 518} 519 520 521// Return information on whether an object has a named or indexed interceptor. 522// args[0]: object 523RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { 524 HandleScope scope(isolate); 525 DCHECK(args.length() == 1); 526 if (!args[0]->IsJSObject()) { 527 return Smi::kZero; 528 } 529 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 530 531 int result = 0; 532 if (obj->HasNamedInterceptor()) result |= 2; 533 if (obj->HasIndexedInterceptor()) result |= 1; 534 535 return Smi::FromInt(result); 536} 537 538 539RUNTIME_FUNCTION(Runtime_ToFastProperties) { 540 HandleScope scope(isolate); 541 DCHECK(args.length() == 1); 542 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 543 if (object->IsJSObject() && !object->IsJSGlobalObject()) { 544 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0, 545 "RuntimeToFastProperties"); 546 } 547 return *object; 548} 549 550 551RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { 552 HandleScope scope(isolate); 553 DCHECK(args.length() == 0); 554 return *isolate->factory()->NewHeapNumber(0); 555} 556 557 558RUNTIME_FUNCTION(Runtime_NewObject) { 559 HandleScope scope(isolate); 560 DCHECK_EQ(2, args.length()); 561 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 562 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); 563 RETURN_RESULT_OR_FAILURE(isolate, JSObject::New(target, new_target)); 564} 565 566 567RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) { 568 HandleScope scope(isolate); 569 DCHECK(args.length() == 1); 570 571 CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0); 572 initial_map->CompleteInobjectSlackTracking(); 573 574 return isolate->heap()->undefined_value(); 575} 576 577 578RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { 579 HandleScope scope(isolate); 580 DCHECK(args.length() == 2); 581 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 582 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); 583 CHECK((index->value() & 1) == 1); 584 FieldIndex field_index = 585 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); 586 if (field_index.is_inobject()) { 587 CHECK(field_index.property_index() < 588 object->map()->GetInObjectProperties()); 589 } else { 590 CHECK(field_index.outobject_array_index() < object->properties()->length()); 591 } 592 return *JSObject::FastPropertyAt(object, Representation::Double(), 593 field_index); 594} 595 596 597RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { 598 HandleScope scope(isolate); 599 DCHECK(args.length() == 1); 600 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 601 if (!object->IsJSObject()) return Smi::kZero; 602 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 603 if (!js_object->map()->is_deprecated()) return Smi::kZero; 604 // This call must not cause lazy deopts, because it's called from deferred 605 // code where we can't handle lazy deopts for lack of a suitable bailout 606 // ID. So we just try migration and signal failure if necessary, 607 // which will also trigger a deopt. 608 if (!JSObject::TryMigrateInstance(js_object)) return Smi::kZero; 609 return *object; 610} 611 612 613RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { 614 SealHandleScope shs(isolate); 615 DCHECK(args.length() == 1); 616 CONVERT_ARG_CHECKED(Object, obj, 0); 617 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); 618} 619 620static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) { 621 return obj->IsUndefined(isolate) || obj->IsCallable() || obj->IsNull(isolate); 622} 623 624 625// Implements part of 8.12.9 DefineOwnProperty. 626// There are 3 cases that lead here: 627// Step 4b - define a new accessor property. 628// Steps 9c & 12 - replace an existing data property with an accessor property. 629// Step 12 - update an existing accessor property with an accessor or generic 630// descriptor. 631RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) { 632 HandleScope scope(isolate); 633 DCHECK(args.length() == 5); 634 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 635 CHECK(!obj->IsNull(isolate)); 636 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 637 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 638 CHECK(IsValidAccessor(isolate, getter)); 639 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 640 CHECK(IsValidAccessor(isolate, setter)); 641 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 4); 642 643 RETURN_FAILURE_ON_EXCEPTION( 644 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs)); 645 return isolate->heap()->undefined_value(); 646} 647 648 649RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { 650 HandleScope scope(isolate); 651 DCHECK(args.length() == 5); 652 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 653 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 654 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 655 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 656 CONVERT_SMI_ARG_CHECKED(set_function_name, 4); 657 658 if (set_function_name) { 659 DCHECK(value->IsJSFunction()); 660 JSFunction::SetName(Handle<JSFunction>::cast(value), name, 661 isolate->factory()->empty_string()); 662 } 663 664 LookupIterator it = LookupIterator::PropertyOrElement( 665 isolate, object, name, object, LookupIterator::OWN); 666 // Cannot fail since this should only be called when 667 // creating an object literal. 668 CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attrs, 669 Object::DONT_THROW) 670 .IsJust()); 671 return *object; 672} 673 674RUNTIME_FUNCTION(Runtime_DefineDataProperty) { 675 HandleScope scope(isolate); 676 DCHECK(args.length() == 5); 677 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 678 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 679 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 680 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 681 CONVERT_SMI_ARG_CHECKED(set_function_name, 4); 682 683 if (set_function_name) { 684 DCHECK(value->IsJSFunction()); 685 JSFunction::SetName(Handle<JSFunction>::cast(value), name, 686 isolate->factory()->empty_string()); 687 } 688 689 PropertyDescriptor desc; 690 desc.set_writable(!(attrs & ReadOnly)); 691 desc.set_enumerable(!(attrs & DontEnum)); 692 desc.set_configurable(!(attrs & DontDelete)); 693 desc.set_value(value); 694 695 Maybe<bool> result = JSReceiver::DefineOwnProperty(isolate, receiver, name, 696 &desc, Object::DONT_THROW); 697 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 698 if (result.IsNothing()) { 699 DCHECK(isolate->has_pending_exception()); 700 return isolate->heap()->exception(); 701 } 702 703 return *receiver; 704} 705 706// Return property without being observable by accessors or interceptors. 707RUNTIME_FUNCTION(Runtime_GetDataProperty) { 708 HandleScope scope(isolate); 709 DCHECK(args.length() == 2); 710 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 711 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 712 return *JSReceiver::GetDataProperty(object, name); 713} 714 715RUNTIME_FUNCTION(Runtime_GetConstructorName) { 716 HandleScope scope(isolate); 717 DCHECK(args.length() == 1); 718 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 719 720 CHECK(!object->IsUndefined(isolate) && !object->IsNull(isolate)); 721 Handle<JSReceiver> recv = Object::ToObject(isolate, object).ToHandleChecked(); 722 return *JSReceiver::GetConstructorName(recv); 723} 724 725RUNTIME_FUNCTION(Runtime_HasFastPackedElements) { 726 SealHandleScope shs(isolate); 727 DCHECK(args.length() == 1); 728 CONVERT_ARG_CHECKED(HeapObject, obj, 0); 729 return isolate->heap()->ToBoolean( 730 IsFastPackedElementsKind(obj->map()->elements_kind())); 731} 732 733 734RUNTIME_FUNCTION(Runtime_ValueOf) { 735 SealHandleScope shs(isolate); 736 DCHECK(args.length() == 1); 737 CONVERT_ARG_CHECKED(Object, obj, 0); 738 if (!obj->IsJSValue()) return obj; 739 return JSValue::cast(obj)->value(); 740} 741 742 743RUNTIME_FUNCTION(Runtime_IsJSReceiver) { 744 SealHandleScope shs(isolate); 745 DCHECK(args.length() == 1); 746 CONVERT_ARG_CHECKED(Object, obj, 0); 747 return isolate->heap()->ToBoolean(obj->IsJSReceiver()); 748} 749 750 751RUNTIME_FUNCTION(Runtime_ClassOf) { 752 SealHandleScope shs(isolate); 753 DCHECK(args.length() == 1); 754 CONVERT_ARG_CHECKED(Object, obj, 0); 755 if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); 756 return JSReceiver::cast(obj)->class_name(); 757} 758 759 760RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) { 761 HandleScope scope(isolate); 762 DCHECK(args.length() == 4); 763 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 764 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 765 CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2); 766 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 767 768 if (String::cast(getter->shared()->name())->length() == 0) { 769 JSFunction::SetName(getter, name, isolate->factory()->get_string()); 770 } 771 772 RETURN_FAILURE_ON_EXCEPTION( 773 isolate, 774 JSObject::DefineAccessor(object, name, getter, 775 isolate->factory()->null_value(), attrs)); 776 return isolate->heap()->undefined_value(); 777} 778 779 780RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) { 781 HandleScope scope(isolate); 782 DCHECK(args.length() == 4); 783 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 784 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 785 CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2); 786 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); 787 788 if (String::cast(setter->shared()->name())->length() == 0) { 789 JSFunction::SetName(setter, name, isolate->factory()->set_string()); 790 } 791 792 RETURN_FAILURE_ON_EXCEPTION( 793 isolate, 794 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), 795 setter, attrs)); 796 return isolate->heap()->undefined_value(); 797} 798 799 800RUNTIME_FUNCTION(Runtime_ToObject) { 801 HandleScope scope(isolate); 802 DCHECK_EQ(1, args.length()); 803 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 804 RETURN_RESULT_OR_FAILURE(isolate, Object::ToObject(isolate, object)); 805} 806 807 808RUNTIME_FUNCTION(Runtime_ToPrimitive) { 809 HandleScope scope(isolate); 810 DCHECK_EQ(1, args.length()); 811 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 812 RETURN_RESULT_OR_FAILURE(isolate, Object::ToPrimitive(input)); 813} 814 815 816RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) { 817 HandleScope scope(isolate); 818 DCHECK_EQ(1, args.length()); 819 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 820 RETURN_RESULT_OR_FAILURE( 821 isolate, Object::ToPrimitive(input, ToPrimitiveHint::kNumber)); 822} 823 824RUNTIME_FUNCTION(Runtime_ToNumber) { 825 HandleScope scope(isolate); 826 DCHECK_EQ(1, args.length()); 827 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 828 RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input)); 829} 830 831 832RUNTIME_FUNCTION(Runtime_ToInteger) { 833 HandleScope scope(isolate); 834 DCHECK_EQ(1, args.length()); 835 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 836 RETURN_RESULT_OR_FAILURE(isolate, Object::ToInteger(isolate, input)); 837} 838 839 840RUNTIME_FUNCTION(Runtime_ToLength) { 841 HandleScope scope(isolate); 842 DCHECK_EQ(1, args.length()); 843 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 844 RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input)); 845} 846 847 848RUNTIME_FUNCTION(Runtime_ToString) { 849 HandleScope scope(isolate); 850 DCHECK_EQ(1, args.length()); 851 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 852 RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input)); 853} 854 855 856RUNTIME_FUNCTION(Runtime_ToName) { 857 HandleScope scope(isolate); 858 DCHECK_EQ(1, args.length()); 859 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 860 RETURN_RESULT_OR_FAILURE(isolate, Object::ToName(isolate, input)); 861} 862 863 864RUNTIME_FUNCTION(Runtime_SameValue) { 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->SameValue(y)); 870} 871 872 873RUNTIME_FUNCTION(Runtime_SameValueZero) { 874 SealHandleScope scope(isolate); 875 DCHECK_EQ(2, args.length()); 876 CONVERT_ARG_CHECKED(Object, x, 0); 877 CONVERT_ARG_CHECKED(Object, y, 1); 878 return isolate->heap()->ToBoolean(x->SameValueZero(y)); 879} 880 881 882// TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan, 883// GreaterThan, etc. which return true or false. 884RUNTIME_FUNCTION(Runtime_Compare) { 885 HandleScope scope(isolate); 886 DCHECK_EQ(3, args.length()); 887 CONVERT_ARG_HANDLE_CHECKED(Object, x, 0); 888 CONVERT_ARG_HANDLE_CHECKED(Object, y, 1); 889 CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2); 890 Maybe<ComparisonResult> result = Object::Compare(x, y); 891 if (result.IsJust()) { 892 switch (result.FromJust()) { 893 case ComparisonResult::kLessThan: 894 return Smi::FromInt(LESS); 895 case ComparisonResult::kEqual: 896 return Smi::FromInt(EQUAL); 897 case ComparisonResult::kGreaterThan: 898 return Smi::FromInt(GREATER); 899 case ComparisonResult::kUndefined: 900 return *ncr; 901 } 902 UNREACHABLE(); 903 } 904 return isolate->heap()->exception(); 905} 906 907RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) { 908 HandleScope scope(isolate); 909 DCHECK_EQ(2, args.length()); 910 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 911 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 912 Maybe<bool> result = 913 JSReceiver::HasInPrototypeChain(isolate, object, prototype); 914 MAYBE_RETURN(result, isolate->heap()->exception()); 915 return isolate->heap()->ToBoolean(result.FromJust()); 916} 917 918 919// ES6 section 7.4.7 CreateIterResultObject ( value, done ) 920RUNTIME_FUNCTION(Runtime_CreateIterResultObject) { 921 HandleScope scope(isolate); 922 DCHECK_EQ(2, args.length()); 923 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 924 CONVERT_ARG_HANDLE_CHECKED(Object, done, 1); 925 return *isolate->factory()->NewJSIteratorResult(value, done->BooleanValue()); 926} 927 928RUNTIME_FUNCTION(Runtime_CreateKeyValueArray) { 929 HandleScope scope(isolate); 930 DCHECK_EQ(2, args.length()); 931 CONVERT_ARG_HANDLE_CHECKED(Object, key, 0); 932 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 933 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(2); 934 elements->set(0, *key); 935 elements->set(1, *value); 936 return *isolate->factory()->NewJSArrayWithElements(elements, FAST_ELEMENTS, 937 2); 938} 939 940RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) { 941 SealHandleScope shs(isolate); 942 DCHECK_EQ(1, args.length()); 943 CONVERT_ARG_CHECKED(Object, object, 0); 944 return isolate->heap()->ToBoolean(object->IsAccessCheckNeeded()); 945} 946 947 948RUNTIME_FUNCTION(Runtime_CreateDataProperty) { 949 HandleScope scope(isolate); 950 DCHECK(args.length() == 3); 951 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, o, 0); 952 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 953 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 954 bool success; 955 LookupIterator it = LookupIterator::PropertyOrElement( 956 isolate, o, key, &success, LookupIterator::OWN); 957 if (!success) return isolate->heap()->exception(); 958 MAYBE_RETURN( 959 JSReceiver::CreateDataProperty(&it, value, Object::THROW_ON_ERROR), 960 isolate->heap()->exception()); 961 return *value; 962} 963 964 965} // namespace internal 966} // namespace v8 967